diff --git a/package.json b/package.json index 89f502b969b7342ce90fe79cf4f13df13b1da972..ac484f820cd5df4d5120354164f46efacd67a6a9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "co-wechat-api": "^3.3.2", "gt3-sdk": "^2.0.0", + "images": "^3.0.1", "jimp": "^0.2.28", "lodash": "4.x.x", "moment": "^2.19.4", diff --git a/src/controller/ext/attachment/adminfile.js b/src/controller/ext/attachment/adminfile.js index e637c6d9b577ff1ad523a722ca9be568648e8d7c..76fbf2656b76fa6a93040a7aa56a4595a206c27d 100644 --- a/src/controller/ext/attachment/adminfile.js +++ b/src/controller/ext/attachment/adminfile.js @@ -16,21 +16,24 @@ module.exports = class extends think.Controller { return this.fail('非法操作!'); } } + constructor(ctx) { super(ctx); this.pdb = this.model('ext_attachment_pic'); this.fdb = this.model('ext_attachment_file'); } + /** - * 判断是否登录 - * @returns {boolean} - */ + * 判断是否登录 + * @returns {boolean} + */ async islogin() { // 判断是否登录 const user = await this.session('userInfo'); const res = think.isEmpty(user) ? false : user.uid; return res; } + /** * index action * @return {Promise} [] @@ -39,6 +42,7 @@ module.exports = class extends think.Controller { // auto render template file index_index.html return this.display(); } + // 上传文件 async uploadAction() { const file = think.extend({}, this.file('file')); @@ -93,7 +97,6 @@ module.exports = class extends think.Controller { const res = await this.fdb.add(data); return this.json({id: res, size: file.size}); } - // 上传图片 async uploadpicAction() { const type = this.get('type'); @@ -129,45 +132,48 @@ module.exports = class extends think.Controller { }; } } else { - const uploadPath = think.resource + '/upload/picture/' + dateformat('Y-m-d', new Date().getTime()); - think.mkdir(uploadPath); - if (think.isFile(filepath)) { - fs.renameSync(filepath, uploadPath + '/' + basename); - } else { - console.log('文件不存在!'); - } - file.path = uploadPath + '/' + basename; + // 默认路径 + const uploadPath = this.saveFile(filepath, 'picture', basename, att); + // 返回最新路径 + file.path = uploadPath.path + '/' + basename; if (think.isFile(file.path)) { data = { - path: '/upload/picture/' + dateformat('Y-m-d', new Date().getTime()) + '/' + basename, + path: uploadPath.root + '/' + basename, create_time: new Date().getTime(), status: 1 - }; + // 添加水印 + if (att.mark == 1) { + const mark = this.extService('mark', 'mark'); + mark.mark(file.path); + } } else { console.log('not exist'); } } + + // 添加文件并返回结果 const res = await this.pdb.add(data); const r = {id: res, url: await get_pic(res), name: (file.name).trim()}; let rr = {}; if (!think.isEmpty(att) && !think.isEmpty(att.rule)) { const match = att.rule.match(/\${(\S+?)\}/g); - console.log(match); + // console.log(match); const replace = []; for (let val of match) { val = val.replace(/(^\${)|(\}$)/g, ''); replace.push(r[val]); } - console.log(replace); + // console.log(replace); rr = str_replace(match, replace, att.rule); - console.log(rr); + // console.log(rr); if (att.rule.indexOf('{') === 0) { rr = JSON.parse(rr); } } return think.isEmpty(rr) ? this.json(res) : this.json(rr); } + // 获取七牛token async getqiniuuptokenAction() { const qiniu = this.extService('qiniu', 'attachment'); @@ -177,6 +183,26 @@ module.exports = class extends think.Controller { 'uptoken': uptoken }); } + // 转移文件 + saveFile(filepath, defpath, basename, attr) { + // 处理路径 + if (attr.path != null && !think.isEmpty(attr.path.trim())) { + defpath = attr.path.trim(); + }; + // 生成目录 + const rootpath = `/upload/${defpath}/${dateformat('Y-m-d', new Date().getTime())}`; + const uploadPath = `${think.resource}${rootpath}`; + think.mkdir(uploadPath); + // 转移文件 + if (think.isFile(filepath)) { + fs.renameSync(filepath, uploadPath + '/' + basename); + } + return { + path: uploadPath, + root: rootpath, + def: defpath + }; + } // 添加 async qiniuaddAction() { const post = this.post(); @@ -194,6 +220,7 @@ module.exports = class extends think.Controller { const res = await this.fdb.add(data); return this.json(res); } + // 删除七牛资源 async delqiniufileAction() { const id = this.get('id'); @@ -207,10 +234,11 @@ module.exports = class extends think.Controller { return this.fail('删除文件失败!'); } } + // 文件信息 - async fileinfoAction(){ + async fileinfoAction() { const res = await this.fdb.find(this.get('id')); - if(!think.isEmpty(res)){ + if (!think.isEmpty(res)) { res.time = this.moment(res.create_time).format('lll'); } return this.json(res); diff --git a/src/controller/ext/attachment/homefile.js b/src/controller/ext/attachment/homefile.js index ae12f26c281af30606cc9382d53da8f9fdeaadc8..a0fb5f7b96f212af67cce725bb5cd5f3fde53712 100644 --- a/src/controller/ext/attachment/homefile.js +++ b/src/controller/ext/attachment/homefile.js @@ -126,21 +126,21 @@ module.exports = class extends think.cmswing.center { }; } } else { - const uploadPath = think.resource + '/upload/picture/' + dateformat('Y-m-d', new Date().getTime()); - think.mkdir(uploadPath); - if (think.isFile(filepath)) { - fs.renameSync(filepath, uploadPath + '/' + basename); - } else { - console.log('文件不存在!'); - } - file.path = uploadPath + '/' + basename; + // 默认路径 + const uploadPath = this.saveFile(filepath, 'picture', basename, att); + // 返回最新路径 + file.path = uploadPath.path + '/' + basename; if (think.isFile(file.path)) { data = { - path: '/upload/picture/' + dateformat('Y-m-d', new Date().getTime()) + '/' + basename, + path: uploadPath.root + '/' + basename, create_time: new Date().getTime(), status: 1 - }; + // 添加水印 + if (att.mark == 1) { + const mark = this.extService('mark', 'mark'); + mark.mark(file.path); + } } else { console.log('not exist'); } @@ -165,7 +165,26 @@ module.exports = class extends think.cmswing.center { } return think.isEmpty(rr) ? this.json(res) : this.json(rr); } - + // 转移文件 + saveFile(filepath, defpath, basename, attr) { + // 处理路径 + if (!think.isEmpty(attr.path.trim())) { + defpath = attr.path.trim(); + }; + // 生成目录 + const rootpath = `/upload/${defpath}/${dateformat('Y-m-d', new Date().getTime())}`; + const uploadPath = `${think.resource}${rootpath}`; + think.mkdir(uploadPath); + // 转移文件 + if (think.isFile(filepath)) { + fs.renameSync(filepath, uploadPath + '/' + basename); + } + return { + path: uploadPath, + root: rootpath, + def: defpath + }; + } // 获取七牛token async getqiniuuptokenAction() { const qiniu = this.extService('qiniu', 'attachment'); diff --git a/src/controller/ext/attachment/view/pc/admin_addapi.html b/src/controller/ext/attachment/view/pc/admin_addapi.html index fa04f81d832ef765439b7d11637c91ff7eb5eaa3..bd97e84111d11c0db7a2e98811c1817352db6337 100644 --- a/src/controller/ext/attachment/view/pc/admin_addapi.html +++ b/src/controller/ext/attachment/view/pc/admin_addapi.html @@ -3,8 +3,8 @@
@@ -12,21 +12,23 @@
-
- -
-
-
-
- +
+ +
+
+
+
+ 英文字母.比如 你的标识是biaoshi那么请求接口就是 /ext/attachment/adminfile/upload?type=biaoshi -
-
-
+
+
+
@@ -35,74 +37,110 @@ value="{{data.name}}" class="form-control">
- - 默认为file,不需要留给留空 - + + + 默认为file,不需要留给留空 +
-
- -
-
-
- -
- 200字以内 -
-
+
+ +
+
+
+
+ 200字以内
-
-
- -
-
-
- - -
-
- - 接口的类型
- 后台图片接口地址:/ext/attachment/adminfile/uploadpic?type=接口标识
- 后台文件接口地址:/ext/attachment/adminfile/upload?type=接口标识
- 前台图片接口地址:/ext/attachment/homefile/uploadpic?type=接口标识
- 前台文件接口地址:/ext/attachment/homefile/upload?type=接口标识
-
-
-
+
+
+
+
+ +
+
+
+ + +
+
+ + 开启后图片类型文件将添加水印
+
-
-
- -
-
-
-
-
- 输入接口返回规则,必填 , - ${id}图片id - ${url}图片地址,${name}图片名称,默认接口只返回 id - - -
-
+
+
+
+
+ +
+
+
+ +
+
+ + 文件相对于服务器的路径,有默认值,不需要请留空
+
-
- - - +
+
+
+
+ +
+
+
+ + +
+
+ + 接口的类型
+ 后台图片接口地址:/ext/attachment/adminfile/uploadpic?type=接口标识
+ 后台文件接口地址:/ext/attachment/adminfile/upload?type=接口标识
+ 前台图片接口地址:/ext/attachment/homefile/uploadpic?type=接口标识
+ 前台文件接口地址:/ext/attachment/homefile/upload?type=接口标识
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + 输入接口返回规则,必填 ,${id}图片id${url}图片地址,${name}图片名称,默认接口只返回 id + +
+
+
+
+
{%if data.id%} diff --git a/src/controller/ext/editor/adminueditor.js b/src/controller/ext/editor/adminueditor.js index 6d478dc19ea91a8c6cd5e22d44d79c8e132d00dc..9e3392fb5295fd02ac55ed4460d89742273bac82 100644 --- a/src/controller/ext/editor/adminueditor.js +++ b/src/controller/ext/editor/adminueditor.js @@ -205,7 +205,8 @@ module.exports = class extends think.Controller { config = { pathFormat: this.config['imagePathFormat'], maxSize: this.config['imageMaxSize'], - allowFiles: this.config['imageAllowFiles'] + allowFiles: this.config['imageAllowFiles'], + mark: true }; fieldName = this.config['imageFieldName']; break; diff --git a/src/controller/ext/editor/homeueditor.js b/src/controller/ext/editor/homeueditor.js index d246d9f54565a97e2fb9522f98b5c56a78800e93..069fef8351745addb70191f386c003d8cdcd186e 100644 --- a/src/controller/ext/editor/homeueditor.js +++ b/src/controller/ext/editor/homeueditor.js @@ -177,7 +177,8 @@ module.exports = class extends think.Controller { config = { pathFormat: this.config['imagePathFormat'], maxSize: this.config['imageMaxSize'], - allowFiles: this.config['imageAllowFiles'] + allowFiles: this.config['imageAllowFiles'], + mark: true }; fieldName = this.config['imageFieldName']; break; diff --git a/src/controller/ext/editor/service/ueditor.js b/src/controller/ext/editor/service/ueditor.js index 43c76f6acf8aee5e7ea362ea1ca65214c1fce502..3f71c73d874725f07dd8ec23e494ea70b7e333f3 100644 --- a/src/controller/ext/editor/service/ueditor.js +++ b/src/controller/ext/editor/service/ueditor.js @@ -65,6 +65,11 @@ module.exports = class extends think.Service { } // 移动文件 fs.renameSync(file.path, this.filePath); + // 添加水印 + if (this.config.mark == true) { + const mark = think.extService('mark', 'mark'); + mark.mark(this.filePath); + } if (think.isFile(this.filePath)) { this.stateInfo = 'SUCCESS'; } else { @@ -103,6 +108,11 @@ module.exports = class extends think.Service { // 移动文件 // fs.renameSync(img, this.filePath); fs.writeFileSync(this.filePath, img); + // 添加水印 + if (this.config.mark == true) { + const mark = think.extService('mark', 'mark'); + mark.mark(this.filePath); + } if (think.isFile(this.filePath)) { this.stateInfo = 'SUCCESS'; } else { diff --git a/src/controller/ext/mark/admin.js b/src/controller/ext/mark/admin.js new file mode 100644 index 0000000000000000000000000000000000000000..c2a2c9d5da9580cbc739f8aba51c00e2a3467c28 --- /dev/null +++ b/src/controller/ext/mark/admin.js @@ -0,0 +1,45 @@ +// +---------------------------------------------------------------------- +// | CmsWing [ 网站内容管理框架 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2015-2115 http://www.cmswing.com All rights reserved. +// +---------------------------------------------------------------------- +// | Author: arterli +// +---------------------------------------------------------------------- +// 本文件不能删除 +module.exports = class extends think.cmswing.extAdmin { + constructor(ctx) { + super(ctx); + } + /** + * index action + * 插件管理入口 + * @return {Promise} [] + */ + async indexAction() { + // 入口模版渲染 + return this.extDisplay(); + } + + /** + * 添加 + * @returns {*} + */ + async addAction() { + // d + + } + + /** + * 修改 + */ + async editAction() { + + } + + /** + * 删除 + */ + async delAction() { + + } +}; diff --git a/src/controller/ext/mark/config.js b/src/controller/ext/mark/config.js new file mode 100644 index 0000000000000000000000000000000000000000..5547694cf1528c2333f66af4f47b55b4a172e091 --- /dev/null +++ b/src/controller/ext/mark/config.js @@ -0,0 +1,61 @@ +module.exports = { + ext: 'mark', // 插件目录,必须为英文 + name: '图片水印', // 插件名称 + description: '为图片添加水印', // 插件描述 + isadm: 0, // 是否有后台管理,1:有,0:没有,入口地址:'/ext/amrk/admin/index' + isindex: 0, // 是否需要前台访问,1:需要,0:不需要,入口地址:'/ext/amrk/index/index' + version: '1.0', // 版本号 + author: '孙会鹏', // 作者 + table: [], // 插件包含的 数据库表,不包含表前缀,如:cmswing_ext_table 就是 table,多个['table','table_2']没有留空数组。 + sql: '', // 插件安装的时候会找个名字的sql文件导入,默认 插件目录名.sql; + hooks: [], // 挂载的钩子,数组格式,如['hooks1', 'hooks2'],不挂载留空:[] + setting: [ + { + '水印设置': [ + { + 'name': 'mark', + 'label': '图片:', + 'type': 'pic', + 'value': '960', + 'html': '水印图片' + }, + { + 'name': 'right', + 'label': '右边距:', + 'type': 'text', + 'value': '10', + 'html': '只需要填写数字,列如:10' + }, + { + 'name': 'bottom', + 'label': '下边距:', + 'type': 'text', + 'value': '10', + 'html': '只需要填写数字,列如:10' + }, + { + 'name': 'left', + 'label': '最小左边距:', + 'type': 'text', + 'value': '100', + 'html': '只需要填写数字,列如:100' + }, + { + 'name': 'top', + 'label': '最小上边距:', + 'type': 'text', + 'value': '100', + 'html': '只需要填写数字,列如:100' + }, + { + 'name': 'state', // 配置在表单中的键名 ,这个会是this.config('title') + 'label': '是否启用:', // 表单的文字 + 'type': 'radio', + 'options': {'1': '启用', '0': '禁用'}, + 'value': '0', + 'html': '选择启用后,符合条件的图片将会添加水印' + } + ] + } + ] +}; diff --git a/src/controller/ext/mark/index.js b/src/controller/ext/mark/index.js new file mode 100644 index 0000000000000000000000000000000000000000..82922395e7a01df95d614adb3b2a12308d42687c --- /dev/null +++ b/src/controller/ext/mark/index.js @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- +// | CmsWing [ 网站内容管理框架 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2015-2115 http://www.cmswing.com All rights reserved. +// +---------------------------------------------------------------------- +// | Author: arterli +// +---------------------------------------------------------------------- +/** + * 插件前台控制器 + * 如果插件有前台展示业务,写在这个控制器里面 + * 插件如需建立表务必遵循下面格式: + * 单表:表前缀_ext_插件目录名 + * 多表:表前缀_ext_插件目录名,表前缀_ext_插件目录名_分表1,表前缀_ext_插件目录名_分表2... + */ +module.exports = class extends think.cmswing.extIndex { + /** + * index action + * + * @return {Promise} [] + */ + + async indexAction() { + // -- 获取插件目录名 + // this.ext.ext; + + // -- 获取当前分类 + // await this.gettype() + + // -- model调用 + // const list = await this.extModel('demo').select(); + // const list2 = await this.extModel('demo').demo(); + // const list3 = await think.extModel('demo','demo').demo(); + + // -- 分页 + // const model = this.extModel('demo'); + // const data = await model.page(this.get('page')).countSelect(); // 获取分页数据 + // console.log(data); + // const html = this.pagination(data); // 调取分页 + // this.assign('pagerData', html); // 分页展示使用 + + // -- ext service + // 无参数类的实例化 + // const Ser1 = this.extService('demo'); + // const Ser1 = think.extService('demo','demo'); + // const ser1 = Ser1.bbb('bbb'); + // console.log(ser1); + // 有参数类的实例化 + // const Ser2 = this.extService('demo','demo','aaa','bbb'); + // const Ser2 = think.extService('demo','demo','aaa','bbb'); + // const ser2 = Ser2.aaa(); + // console.log(ser2); + + if (this.isMobile) { + return this.extDisplay('m'); + } else { + return this.extDisplay(); + } + } +}; diff --git a/src/controller/ext/mark/model/demo.js b/src/controller/ext/mark/model/demo.js new file mode 100644 index 0000000000000000000000000000000000000000..422c13722e8df0a85474c71a96d1b5843ea209d2 --- /dev/null +++ b/src/controller/ext/mark/model/demo.js @@ -0,0 +1,6 @@ +module.exports = class extends think.Model { + async demo() { + const list = await this.select(); + return list; + } +}; diff --git a/src/controller/ext/mark/service/mark.js b/src/controller/ext/mark/service/mark.js new file mode 100644 index 0000000000000000000000000000000000000000..9e32cf2e434b057ccfed5ced8d130804b343f5f5 --- /dev/null +++ b/src/controller/ext/mark/service/mark.js @@ -0,0 +1,65 @@ +var images = require('images'); +var path = require('path'); + +module.exports = class extends think.Service { + // 初始化构造函数 + constructor(...para) { + super(para); + // 白名单 + this.suffixs = ['.png', '.jpg']; + // 边距 + this.edge = { + right: think.config('ext.mark.right'), + bottom: think.config('ext.mark.bottom'), + minLeft: think.config('ext.mark.left'), + minTop: think.config('ext.mark.top') + }; + // 水印路径 + this.markpic = think.config('ext.mark.mark'); + // 状态 + this.state = think.config('ext.mark.state'); + this.markpath = '/Users/zzu/Desktop/demo/mark.png'; + } + + // 添加水印 + async mark(imgPath, option) { + try { + return this.draw(imgPath); + } catch (e) { + console.error(e); + return false; + } + } + + // 绘制 + async draw(imgPath) { + // 存在且是图片 + if (think.isFile(imgPath) && in_array(path.extname(imgPath), this.suffixs) && this.state == 1) { + // 加载资源 + const sourceImg = images(imgPath); + this.markpath = await this.GetPath(this.markpic); + const markImg = images(this.markpath); + // 计算水印位置 + const markX = sourceImg.width() - markImg.width() - this.edge.right; + const markY = sourceImg.height() - markImg.height() - this.edge.bottom; + // 判断最小范围 + if (markX < this.edge.minLeft || markY < this.edge.minTop) { + return false; + } + // 绘制水印 + images(sourceImg) + // 设置绘制的坐标位置,右下角距离 10px + .draw(markImg, markX, markY) + // 保存格式会自动识别 + .save(imgPath); + return false; + } + return false; + } + + // 获得水印路径 + async GetPath(pic){ + const path = await get_pic(pic); + return `${think.resource}/${path}`; + } +}; diff --git a/src/controller/ext/mark/view/mobile/index_index.html b/src/controller/ext/mark/view/mobile/index_index.html new file mode 100644 index 0000000000000000000000000000000000000000..bf09d501724c90fe4eb17607cb299347c2130800 --- /dev/null +++ b/src/controller/ext/mark/view/mobile/index_index.html @@ -0,0 +1,33 @@ + + + + +New ThinkJS Application + + + +
+
+

A New App Created By ThinkJS

+
+
+
+ mobile +
+
+ + \ No newline at end of file diff --git a/src/controller/ext/mark/view/pc/admin_index.html b/src/controller/ext/mark/view/pc/admin_index.html new file mode 100644 index 0000000000000000000000000000000000000000..0ac51aa577b87b68c5378cb5805f416e9122ffe3 --- /dev/null +++ b/src/controller/ext/mark/view/pc/admin_index.html @@ -0,0 +1,70 @@ +{% extends "view/admin/ext_admin.html" %} +{% block extadmin %} +
+
+ +
+ +
+ + + + + + + + + + + + + + + {% for item in list %} + + + + + + + + + + + + {% else %} + + + {% endfor %} + + +
排序网站名称网站logo分类链接类型状态操作
{{item.name}}{%if item.logo%}{%else%}无{%endif%}{{item.version}}{%if item.linktype ==1%}logo链接{%else%}文字链接{%endif%}{%if item.passed ==1%}已通过{%else%}待审核{%endif%} + + 修改 + 删除
+ +

这是后台插件模板的一个例子!

+
+
+ + +
+
+ +
+
+ 排序 + 删除 +
+
+ +
+ {{pagerData | safe}} +
+
+
+ +
+{% endblock %} diff --git a/src/controller/ext/mark/view/pc/index_index.html b/src/controller/ext/mark/view/pc/index_index.html new file mode 100644 index 0000000000000000000000000000000000000000..dac84b3324aa6418b15426b59f8c744c0d4a3272 --- /dev/null +++ b/src/controller/ext/mark/view/pc/index_index.html @@ -0,0 +1,33 @@ + + + + +New ThinkJS Application + + + +
+
+

A New App Created By ThinkJS

+
+
+
+ pc +
+
+ + \ No newline at end of file diff --git a/view/admin/public_signin.html b/view/admin/public_signin.html index ed49f8db8387f841c6d1ae2c631682ccc76377c6..9e3be3f327ee8bcb0bd3487686344b5ee1a1856b 100644 --- a/view/admin/public_signin.html +++ b/view/admin/public_signin.html @@ -3,7 +3,7 @@ - 登录 | CmsWing 管理后台 + 登录 | {{config.setup.WEB_SITE_TITLE}} - 后台管理 diff --git a/view/ext/setting.html b/view/ext/setting.html index 869ca625ed40c47c379e932eee2494fd01302b97..be001beea7fb00b2de2db58c4c39f9a3f4bb78dc 100644 --- a/view/ext/setting.html +++ b/view/ext/setting.html @@ -8,7 +8,8 @@ {%for v in extConfig.setting%} {%set index = loop.index%} {% for ingredient, amount in v %} -
  • {{ingredient}}
  • +
  • {{ingredient}}
  • {% endfor %} {%endfor%} @@ -27,11 +28,140 @@ {%if input.type == 'text'%} {{forms.text(setting,label= input.label, name= input.name, value=input.value, html= input.html)}} {%elif input.type == 'radio'%} - {{forms.radio(setting,label=input.label, name=input.name, value=input.value, options=input.options,html=input.html)}} + {{forms.radio(setting,label=input.label, name=input.name, value=input.value, + options=input.options,html=input.html)}} {%elif input.type == 'select'%} - {{forms.select(setting,label=input.label, name= input.name, value=input.value, options=input.options,html=input.html)}} + {{forms.select(setting,label=input.label, name= input.name, value=input.value, + options=input.options,html=input.html)}} {%elif input.type == 'textarea'%} - {{forms.textarea(setting,label= input.label, name= input.name, value=input.value, html= input.html)}} + {{forms.textarea(setting,label= input.label, name= input.name, value=input.value, html= + input.html)}} + {%elif input.type == 'pic'%} +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    选择图片
    +
    +
    + this.config('ext.{{setting.ext}}.{{input.name}}') + {%if html%} + {{html|safe}} + {%endif%} +
    +
    +
    +
    + + + + {%endif%} {%endfor%}
    @@ -53,11 +183,15 @@
    -
    {% endblock %} +{% block style %} +{{ super() }} + +{% endblock%} {% block script%} +{{ super() }} {% endblock%} \ No newline at end of file