diff --git a/api/app/lib/controllers/label/index.js b/api/app/lib/controllers/label/index.js
new file mode 100644
index 0000000..1875cdf
--- /dev/null
+++ b/api/app/lib/controllers/label/index.js
@@ -0,0 +1,71 @@
+'use strict';
+
+async function getLabels(ctx, next) {
+ try {
+ const models = ctx.fs.dc.models;
+
+ const res = await models.QrcodeLabels.findAll({
+ order: [['id', 'DESC']],
+ })
+
+ ctx.status = 200;
+ ctx.body = res
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ "message": "获取标签失败"
+ }
+ }
+}
+
+async function createLabels(ctx, next) {
+ const models = ctx.fs.dc.models;
+ try {
+ let rslt = ctx.request.body;
+ await models.Department.create(Object.assign({}, rslt, { read: 1 }))
+ ctx.status = 204;
+ ctx.body = { message: '新建部门成功' }
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: '新建部门失败' }
+ }
+}
+
+async function delLabels(ctx, next) {
+ let errMsg = "删除部门失败";
+ try {
+ const models = ctx.fs.dc.models;
+ const { id } = ctx.params;
+ let list = await models.Department.findAll({});
+ let deptIds = list.map(l => l.id);
+ const allUsers = await models.User.findAll({
+ where: {
+ departmentId: { $in: deptIds },
+ delete: false
+ }
+ })
+ const childrenDept = await models.Department.findAll({ where: { dependence: id } })
+ const childrenUser = allUsers.filter(au => au.departmentId == id);
+ if (childrenUser.length || childrenDept.length) {
+ errMsg = '请先删除部门下的用户或子部门';
+ throw errMsg;
+ }
+ await models.Department.destroy({ where: { id: id } });
+ await models.Department.destroy({ where: { dependence: id } });
+ ctx.status = 204;
+ ctx.body = { message: '删除部门成功' }
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: error }
+ }
+}
+
+
+module.exports = {
+ getLabels,
+ createLabels,
+ delLabels,
+}
\ No newline at end of file
diff --git a/api/app/lib/controllers/publicityInfo/index.js b/api/app/lib/controllers/publicityInfo/index.js
new file mode 100644
index 0000000..0d5ade5
--- /dev/null
+++ b/api/app/lib/controllers/publicityInfo/index.js
@@ -0,0 +1,173 @@
+'use strict';
+const Hex = require('crypto-js/enc-hex');
+const MD5 = require('crypto-js/md5');
+
+async function getPublicityInfo(ctx, next) {
+ try {
+ const models = ctx.fs.dc.models;
+ const { limit, page, name, label } = ctx.query
+
+ let findOption = {
+ where: {},
+ order: [['time', 'DESC']],
+ include: [
+ {
+ model: models.Qrcode,
+ },
+ {
+ model: models.QrcodeLabels,
+ attributes: ["name"],
+ },
+ {
+ model: models.QrcodeFiles,
+ },
+ ],
+ distinct: true
+ }
+ if (limit) {
+ findOption.limit = Number(limit)
+ }
+ if (page && limit) {
+ findOption.offset = page * limit
+ }
+ // if (startTime && endTime) {
+ // findOption.where.time = { $between: [startTime, endTime] };
+ // }
+ if (name) {
+ findOption.where.name = { $like: `%${name}%` }
+ }
+
+ const res = await models.PublicityInfo.findAndCountAll(findOption)
+
+ ctx.status = 200;
+ ctx.body = res
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ "message": "获取宣传信息失败"
+ }
+ }
+}
+
+async function createPublicityInfo(ctx, next) {
+ const models = ctx.fs.dc.models;
+ const transaction = await ctx.fs.dc.orm.transaction();
+ try {
+ const body = ctx.request.body;
+ const { type, name, labels, qrcode, files } = body;
+
+ const dbQrcode = await models.Qrcode.create({
+ name, type, url: qrcode.url, key: qrcode.key, logo: qrcode.logo,
+ }, { transaction });
+
+ const dbPublicityInfo = await models.PublicityInfo.create({
+ ...body,
+ qrcodeId: dbQrcode.id,
+ time: new Date().getTime(),
+ }, { transaction });
+
+ if (labels && labels.length) {
+ let labelIds = []
+ let createLabels = [];
+ for (const l of labels) {
+ if (typeof l === 'string') {
+ createLabels.push({ name: l });
+ } else {
+ labelIds.push(l);
+ }
+ }
+ if (createLabels.length) {
+ const dbLabels = await models.QrcodeLabels.bulkCreate(createLabels, { returning: true, transaction });
+ labelIds = labelIds.concat(dbLabels.map(l => l.id));
+ }
+ if (labelIds.length) {
+ await models.QrcodeLabelsQrcode.bulkCreate(labelIds.map(l => ({
+ labelId: l, qrcodeId: dbQrcode.id, publicityInfoId: dbPublicityInfo.id
+ })), { transaction });
+ }
+ }
+
+ if (type !== '链接') {
+ if (!files || !files.length) throw new Error('缺少请求参数: files');
+ await models.QrcodeFiles.bulkCreate(files.map(f => ({
+ fileName: f.customFileName ? f.customFileName : f.name.split('.').slice(0, -1).join('.'),
+ fileSize: f.size,
+ fileUrl: f.storageUrl,
+ previewImgUrl: f.previewImgUrl,
+ qrcodeId: dbQrcode.id,
+ publicityInfoId: dbPublicityInfo.id,
+ })), { transaction });
+ }
+
+ ctx.status = 204;
+ ctx.body = { message: '新建宣传信息成功' };
+ await transaction.commit();
+ } catch (error) {
+ await transaction.rollback();
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: '新建宣传信息失败' };
+ }
+}
+
+async function updatePublicityInfo(ctx, next) {
+ try {
+ const models = ctx.fs.dc.models;
+ const { id } = ctx.params;
+ const body = ctx.request.body;
+ await models.Department.update(
+ body,
+ { where: { id: id } }
+ )
+ ctx.status = 204;
+ ctx.body = { message: '修改部门成功' }
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: '修改部门失败' }
+ }
+}
+
+async function delPublicityInfo(ctx, next) {
+ const transaction = await ctx.fs.dc.orm.transaction();
+ let errMsg = "删除宣传信息失败";
+ try {
+ const models = ctx.fs.dc.models;
+ const { id } = ctx.params;
+ const { qrcodeId } = ctx.query;
+
+ await models.QrcodeLabelsQrcode.destroy({
+ where: { publicityInfoId: id },
+ transaction
+ });
+ await models.QrcodeFiles.destroy({
+ where: { publicityInfoId: id },
+ transaction
+ });
+ await models.PublicityInfo.destroy({
+ where: { id: id },
+ transaction: transaction,
+ });
+ await models.Qrcode.destroy({
+ where: { id: qrcodeId },
+ transaction
+ });
+
+ ctx.status = 204;
+ ctx.body = { message: '删除宣传信息成功' }
+ transaction.commit();
+ } catch (error) {
+ transaction.rollback();
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: error }
+ }
+}
+
+module.exports = {
+ getPublicityInfo,
+ createPublicityInfo,
+ updatePublicityInfo,
+ delPublicityInfo,
+}
\ No newline at end of file
diff --git a/api/app/lib/controllers/qrcode/index.js b/api/app/lib/controllers/qrcode/index.js
new file mode 100644
index 0000000..eed0b95
--- /dev/null
+++ b/api/app/lib/controllers/qrcode/index.js
@@ -0,0 +1,56 @@
+'use strict';
+
+async function getQrcode(ctx, next) {
+ try {
+ const models = ctx.fs.dc.models;
+ const { limit, page, name, key } = ctx.query
+
+ let options = {
+ where: {},
+ order: [['id', 'DESC']],
+ include: []
+ }
+ if (name) {
+ options.where.name = { $like: `%${name}%` }
+ }
+ if (key) {
+ options.where.key = key
+ options.include.push({
+ model: models.QrcodeFiles,
+ })
+ options.distinct = true
+ }
+
+ const res = await models.Qrcode.findAndCountAll(options)
+
+ ctx.status = 200;
+ ctx.body = res
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = {
+ "message": "获取二维码失败"
+ }
+ }
+}
+
+async function createQrcode(ctx, next) {
+ const models = ctx.fs.dc.models;
+ try {
+ let rslt = ctx.request.body;
+
+ const qrcode = await models.Qrcode.create(rslt)
+
+ ctx.status = 204;
+ ctx.body = { message: '新增二维码成果', id: qrcode.id }
+ } catch (error) {
+ ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
+ ctx.status = 400;
+ ctx.body = { message: '新增二维码失败' }
+ }
+}
+
+module.exports = {
+ getQrcode,
+ createQrcode,
+}
\ No newline at end of file
diff --git a/api/app/lib/index.js b/api/app/lib/index.js
index 4ff7bca..56b24e8 100644
--- a/api/app/lib/index.js
+++ b/api/app/lib/index.js
@@ -53,7 +53,10 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
require(`./models/${filename}`)(dc)
});
- const { Department, User, UserResource, Resource, } = dc.models;
+ const {
+ Department, User, UserResource, Resource, Qrcode, QrcodeFiles, QrcodeLabels,
+ QrcodeLabelsQrcode, PublicityInfo,
+ } = dc.models;
UserResource.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' });
User.hasMany(UserResource, { foreignKey: 'userId', sourceKey: 'id' });
@@ -65,4 +68,15 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
User.belongsTo(Department, { foreignKey: 'departmentId', targetKey: 'id' });
Department.hasMany(User, { foreignKey: 'departmentId', sourceKey: 'id' });
+ Qrcode.belongsToMany(QrcodeLabels, { through: QrcodeLabelsQrcode, foreignKey: 'qrcodeId', otherKey: 'labelId' });
+ QrcodeLabels.belongsToMany(Qrcode, { through: QrcodeLabelsQrcode, foreignKey: 'labelId', otherKey: 'qrcodeId' });
+ PublicityInfo.belongsToMany(QrcodeLabels, { through: QrcodeLabelsQrcode, foreignKey: 'publicityInfoId', otherKey: 'labelId' });
+ QrcodeLabels.belongsToMany(PublicityInfo, { through: QrcodeLabelsQrcode, foreignKey: 'labelId', otherKey: 'publicityInfoId' });
+
+ QrcodeFiles.belongsTo(Qrcode, { foreignKey: 'qrcodeId', targetKey: 'id' });
+ Qrcode.hasMany(QrcodeFiles, { foreignKey: 'qrcodeId', sourceKey: 'id' });
+ QrcodeFiles.belongsTo(PublicityInfo, { foreignKey: 'publicityInfoId', targetKey: 'id' });
+ PublicityInfo.hasMany(QrcodeFiles, { foreignKey: 'publicityInfoId', sourceKey: 'id' });
+ PublicityInfo.belongsTo(Qrcode, { foreignKey: 'qrcodeId', targetKey: 'id' });
+ Qrcode.hasMany(PublicityInfo, { foreignKey: 'qrcodeId', sourceKey: 'id' });
};
diff --git a/api/app/lib/middlewares/authenticator.js b/api/app/lib/middlewares/authenticator.js
index 447690d..bce3ec1 100644
--- a/api/app/lib/middlewares/authenticator.js
+++ b/api/app/lib/middlewares/authenticator.js
@@ -13,13 +13,13 @@ class ExcludesUrls {
this.reload(opts);
}
- sanitizePath (path) {
+ sanitizePath(path) {
if (!path) return '/';
const p = '/' + path.replace(/^\/+/i, '').replace(/\/+$/, '').replace(/\/{2,}/, '/');
return p;
}
- reload (opts) {
+ reload(opts) {
// load all url
if (!this.allUrls) {
this.allUrls = opts;
@@ -37,7 +37,7 @@ class ExcludesUrls {
}
}
- isExcluded (path, method) {
+ isExcluded(path, method) {
return this.allUrls.some(function (url) {
return !url.auth
&& url.pregexp.test(path)
@@ -59,6 +59,7 @@ let isPathExcluded = function (opts, path, method) {
let excludeOpts = opts.exclude || [];
excludeOpts.push({ p: '/login', o: 'POST' });
excludeOpts.push({ p: '/logout', o: 'PUT' });
+ excludeOpts.push({ p: '/qrcode', o: 'GET' });
excludes = new ExcludesUrls(excludeOpts);
}
let excluded = excludeAll || excludes.isExcluded(path, method);
@@ -110,8 +111,8 @@ let isResourceAvailable = function (resources, options) {
return !authCode || (resources || []).some(code => code === authCode);
};
-function factory (app, opts) {
- return async function auth (ctx, next) {
+function factory(app, opts) {
+ return async function auth(ctx, next) {
const { path, method, header, query } = ctx;
ctx.fs.logger.log('[AUTH] start', path, method);
ctx.fs.api = ctx.fs.api || {};
diff --git a/api/app/lib/models/publicity_info.js b/api/app/lib/models/publicity_info.js
new file mode 100644
index 0000000..7746009
--- /dev/null
+++ b/api/app/lib/models/publicity_info.js
@@ -0,0 +1,74 @@
+/* eslint-disable*/
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const PublicityInfo = sequelize.define("publicityInfo", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ },
+ name: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "宣传标题",
+ primaryKey: false,
+ field: "name",
+ autoIncrement: false,
+ },
+ type: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "类型(图片|文件|链接|视频)",
+ primaryKey: false,
+ field: "type",
+ autoIncrement: false,
+ },
+ time: {
+ type: DataTypes.DATE,
+ allowNull: false,
+ defaultValue: null,
+ comment: "创建/更新时间",
+ primaryKey: false,
+ field: "time",
+ autoIncrement: false,
+ },
+ qrcodeId: {
+ type: DataTypes.INTEGER,
+ allowNull: true,
+ defaultValue: null,
+ comment: "关联二维码ID",
+ primaryKey: false,
+ field: "qrcode_id",
+ autoIncrement: false,
+ references: {
+ model: "qrcode",
+ key: "id"
+ }
+ },
+ link: {
+ type: DataTypes.STRING,
+ allowNull: true,
+ defaultValue: null,
+ comment: "type为链接时的链接地址",
+ primaryKey: false,
+ field: "link",
+ autoIncrement: false,
+ },
+ }, {
+ tableName: "publicity_info",
+ comment: "",
+ indexes: []
+ });
+
+ dc.models.PublicityInfo = PublicityInfo;
+ return PublicityInfo;
+};
\ No newline at end of file
diff --git a/api/app/lib/models/qrcode.js b/api/app/lib/models/qrcode.js
new file mode 100644
index 0000000..497386a
--- /dev/null
+++ b/api/app/lib/models/qrcode.js
@@ -0,0 +1,70 @@
+/* eslint-disable*/
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const Qrcode = sequelize.define("qrcode", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ },
+ url: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "二维码图片存储链接",
+ primaryKey: false,
+ field: "url",
+ autoIncrement: false,
+ },
+ name: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "二维码名称",
+ primaryKey: false,
+ field: "name",
+ autoIncrement: false,
+ },
+ type: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "类型(图片|文件|链接|视频)",
+ primaryKey: false,
+ field: "type",
+ autoIncrement: false,
+ },
+ key: {
+ type: DataTypes.UUID,
+ allowNull: false,
+ defaultValue: null,
+ comment: "二维码唯一标识",
+ primaryKey: false,
+ field: "key",
+ autoIncrement: false,
+ },
+ logo: {
+ type: DataTypes.STRING,
+ allowNull: true,
+ defaultValue: null,
+ comment: "二维码中间的照片",
+ primaryKey: false,
+ field: "logo",
+ autoIncrement: false,
+ },
+ }, {
+ tableName: "qrcode",
+ comment: "",
+ indexes: []
+ });
+
+ dc.models.Qrcode = Qrcode;
+ return Qrcode;
+};
\ No newline at end of file
diff --git a/api/app/lib/models/qrcode_files.js b/api/app/lib/models/qrcode_files.js
new file mode 100644
index 0000000..c6315b8
--- /dev/null
+++ b/api/app/lib/models/qrcode_files.js
@@ -0,0 +1,87 @@
+/* eslint-disable*/
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const QrcodeFiles = sequelize.define("qrcodeFiles", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ },
+ fileName: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "文件名",
+ primaryKey: false,
+ field: "file_name",
+ autoIncrement: false,
+ },
+ fileSize: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: "文件大小(byte)",
+ primaryKey: false,
+ field: "file_size",
+ autoIncrement: false,
+ },
+ fileUrl: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "文件存储链接",
+ primaryKey: false,
+ field: "file_url",
+ autoIncrement: false,
+ },
+ previewImgUrl: {
+ type: DataTypes.STRING,
+ allowNull: true,
+ defaultValue: null,
+ comment: "文件预览图链接",
+ primaryKey: false,
+ field: "preview_img_url",
+ autoIncrement: false,
+ },
+ qrcodeId: {
+ type: DataTypes.INTEGER,
+ allowNull: true,
+ defaultValue: null,
+ comment: "关联二维码ID",
+ primaryKey: false,
+ field: "qrcode_id",
+ autoIncrement: false,
+ references: {
+ model: "qrcode",
+ key: "id"
+ }
+ },
+ publicityInfoId: {
+ type: DataTypes.INTEGER,
+ allowNull: true,
+ defaultValue: null,
+ comment: "关联宣传信息ID",
+ primaryKey: false,
+ field: "publicity_info_id",
+ autoIncrement: false,
+ references: {
+ model: "publicity_info",
+ key: "id"
+ }
+ },
+ }, {
+ tableName: "qrcode_files",
+ comment: "",
+ indexes: []
+ });
+
+ dc.models.QrcodeFiles = QrcodeFiles;
+ return QrcodeFiles;
+};
\ No newline at end of file
diff --git a/api/app/lib/models/qrcode_labels.js b/api/app/lib/models/qrcode_labels.js
new file mode 100644
index 0000000..ac99322
--- /dev/null
+++ b/api/app/lib/models/qrcode_labels.js
@@ -0,0 +1,34 @@
+/* eslint-disable*/
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const QrcodeLabels = sequelize.define("qrcodeLabels", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ },
+ name: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ defaultValue: null,
+ comment: "标签名",
+ primaryKey: false,
+ field: "name",
+ autoIncrement: false,
+ },
+ }, {
+ tableName: "qrcode_labels",
+ comment: "",
+ indexes: []
+ });
+
+ dc.models.QrcodeLabels = QrcodeLabels;
+ return QrcodeLabels;
+};
\ No newline at end of file
diff --git a/api/app/lib/models/qrcode_labels_qrcode.js b/api/app/lib/models/qrcode_labels_qrcode.js
new file mode 100644
index 0000000..d7b694a
--- /dev/null
+++ b/api/app/lib/models/qrcode_labels_qrcode.js
@@ -0,0 +1,64 @@
+/* eslint-disable*/
+'use strict';
+
+module.exports = dc => {
+ const DataTypes = dc.ORM;
+ const sequelize = dc.orm;
+ const QrcodeLabelsQrcode = sequelize.define("qrcode_labels_qrcode", {
+ id: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: true,
+ field: "id",
+ autoIncrement: true,
+ },
+ labelId: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: false,
+ field: "label_id",
+ autoIncrement: false,
+ references: {
+ model: "qrcode_labels",
+ key: "id"
+ }
+ },
+ qrcodeId: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: null,
+ comment: null,
+ primaryKey: false,
+ field: "qrcode_id",
+ autoIncrement: false,
+ references: {
+ model: "qrcode",
+ key: "id"
+ }
+ },
+ publicityInfoId: {
+ type: DataTypes.INTEGER,
+ allowNull: true,
+ defaultValue: null,
+ comment: null,
+ primaryKey: false,
+ field: "publicity_info_id",
+ autoIncrement: false,
+ references: {
+ model: "publicity_info",
+ key: "id"
+ }
+ },
+ }, {
+ tableName: "qrcode_labels_qrcode",
+ comment: "",
+ indexes: []
+ });
+
+ dc.models.QrcodeLabelsQrcode = QrcodeLabelsQrcode;
+ return QrcodeLabelsQrcode;
+};
\ No newline at end of file
diff --git a/api/app/lib/routes/label/index.js b/api/app/lib/routes/label/index.js
new file mode 100644
index 0000000..4fbac74
--- /dev/null
+++ b/api/app/lib/routes/label/index.js
@@ -0,0 +1,15 @@
+'use strict';
+
+const label = require('../../controllers/label/index');
+
+module.exports = function (app, router, opts) {
+
+ app.fs.api.logAttr['GET/label'] = { content: '获取标签', visible: false };
+ router.get('/label', label.getLabels);
+
+ app.fs.api.logAttr['POST/label/add'] = { content: '新增标签', visible: true };
+ router.post('/label/add', label.createLabels);
+
+ app.fs.api.logAttr['DELETE/label/:id'] = { content: '删除标签', visible: true };
+ router.del('/label/:id', label.delLabels);
+};
\ No newline at end of file
diff --git a/api/app/lib/routes/publicityInfo/index.js b/api/app/lib/routes/publicityInfo/index.js
new file mode 100644
index 0000000..5a95905
--- /dev/null
+++ b/api/app/lib/routes/publicityInfo/index.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const publicityInfo = require('../../controllers/publicityInfo/index');
+
+module.exports = function (app, router, opts) {
+
+ app.fs.api.logAttr['GET/publicityInfo'] = { content: '获取宣传信息', visible: false };
+ router.get('/publicityInfo', publicityInfo.getPublicityInfo);
+
+ app.fs.api.logAttr['POST/publicityInfo/add'] = { content: '新增宣传信息', visible: true };
+ router.post('/publicityInfo/add', publicityInfo.createPublicityInfo);
+
+ app.fs.api.logAttr['PUT/publicityInfo/:id/modify'] = { content: '修改宣传信息', visible: true };
+ router.put('/publicityInfo/:id/modify', publicityInfo.updatePublicityInfo);
+
+ app.fs.api.logAttr['DELETE/publicityInfo/:id/del'] = { content: '删除宣传信息', visible: true };
+ router.del('/publicityInfo/:id/del', publicityInfo.delPublicityInfo);
+};
\ No newline at end of file
diff --git a/api/app/lib/routes/qrcode/index.js b/api/app/lib/routes/qrcode/index.js
new file mode 100644
index 0000000..00856c1
--- /dev/null
+++ b/api/app/lib/routes/qrcode/index.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const qrcode = require('../../controllers/qrcode/index');
+
+module.exports = function (app, router, opts) {
+
+ app.fs.api.logAttr['GET/qrcode'] = { content: '获取二维码', visible: false };
+ router.get('/qrcode', qrcode.getQrcode);
+
+ app.fs.api.logAttr['POST/qrcode/add'] = { content: '新增二维码', visible: true };
+ router.post('/qrcode/add', qrcode.createQrcode);
+
+};
\ No newline at end of file
diff --git a/script/1.0.0/schema/2.init_qrcode.sql b/script/1.0.0/schema/2.init_qrcode.sql
index 4fdf83c..33c582a 100644
--- a/script/1.0.0/schema/2.init_qrcode.sql
+++ b/script/1.0.0/schema/2.init_qrcode.sql
@@ -4,11 +4,15 @@ CREATE TABLE "public"."qrcode" (
"url" varchar(255) NOT NULL,
"name" varchar(128) NOT NULL,
"type" varchar(32) NOT NULL,
+ "key" uuid NOT NULL,
+ "logo" varchar(255),
PRIMARY KEY ("id")
);
-COMMENT ON COLUMN "public"."qrcode"."name" IS '二维码名称';
-COMMENT ON COLUMN "public"."qrcode"."type" IS '类型(文件|链接)';
COMMENT ON COLUMN "public"."qrcode"."url" IS '二维码图片存储链接';
+COMMENT ON COLUMN "public"."qrcode"."name" IS '二维码名称';
+COMMENT ON COLUMN "public"."qrcode"."type" IS '类型(图片|文件|链接|视频)';
+COMMENT ON COLUMN "public"."qrcode"."key" IS '二维码唯一标识';
+COMMENT ON COLUMN "public"."qrcode"."logo" IS '二维码中间的照片';
DROP TABLE IF EXISTS "public"."publicity_info";
@@ -17,27 +21,56 @@ CREATE TABLE "public"."publicity_info" (
"name" varchar(128) NOT NULL,
"type" varchar(32) NOT NULL,
"time" timestamptz NOT NULL,
- "qrcode_id" int4 NOT NULL,
+ "link" varchar(255),
+ "qrcode_id" int4,
PRIMARY KEY ("id"),
CONSTRAINT "publicity_info_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id")
);
COMMENT ON COLUMN "public"."publicity_info"."name" IS '宣传标题';
-COMMENT ON COLUMN "public"."publicity_info"."type" IS '类型';
+COMMENT ON COLUMN "public"."publicity_info"."type" IS '类型(图片|文件|链接|视频)';
COMMENT ON COLUMN "public"."publicity_info"."time" IS '创建/更新时间';
+COMMENT ON COLUMN "public"."publicity_info"."link" IS 'type为链接时的链接地址';
COMMENT ON COLUMN "public"."publicity_info"."qrcode_id" IS '关联二维码ID';
DROP TABLE IF EXISTS "public"."qrcode_files";
CREATE TABLE "public"."qrcode_files" (
"id" serial,
- "qrcode_id" int4 NOT NULL,
"file_name" varchar(128) NOT NULL,
"file_size" int4 NOT NULL,
"file_url" varchar(255) NOT NULL,
+ "preview_img_url" varchar(255),
+ "qrcode_id" int4,
+ "publicity_info_id" int4,
PRIMARY KEY ("id"),
- CONSTRAINT "qrcode_files_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id")
+ CONSTRAINT "qrcode_files_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id"),
+ CONSTRAINT "qrcode_files_publicity_info_id_fk" FOREIGN KEY ("publicity_info_id") REFERENCES "public"."publicity_info" ("id")
);
-COMMENT ON COLUMN "public"."qrcode_files"."qrcode_id" IS '关联二维码ID';
COMMENT ON COLUMN "public"."qrcode_files"."file_name" IS '文件名';
COMMENT ON COLUMN "public"."qrcode_files"."file_size" IS '文件大小(byte)';
COMMENT ON COLUMN "public"."qrcode_files"."file_url" IS '文件存储链接';
+COMMENT ON COLUMN "public"."qrcode_files"."preview_img_url" IS '文件预览图链接';
+COMMENT ON COLUMN "public"."qrcode_files"."qrcode_id" IS '关联二维码ID';
+COMMENT ON COLUMN "public"."qrcode_files"."publicity_info_id" IS '关联宣传信息ID';
+
+
+DROP TABLE IF EXISTS "public"."qrcode_labels";
+CREATE TABLE "public"."qrcode_labels" (
+ "id" serial,
+ "name" varchar(128) NOT NULL,
+ PRIMARY KEY ("id")
+);
+COMMENT ON COLUMN "public"."qrcode_labels"."name" IS '标签名';
+
+
+DROP TABLE IF EXISTS "public"."qrcode_labels_qrcode";
+CREATE TABLE "public"."qrcode_labels_qrcode" (
+ "id" serial,
+ "label_id" int4 NOT NULL,
+ "qrcode_id" int4 NOT NULL,
+ "publicity_info_id" int4,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "qrcode_labels_label_id_fk" FOREIGN KEY ("label_id") REFERENCES "public"."qrcode_labels" ("id"),
+ CONSTRAINT "qrcode_labels_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id"),
+ CONSTRAINT "qrcode_labels_publicity_info_id_fk" FOREIGN KEY ("publicity_info_id") REFERENCES "public"."publicity_info" ("id")
+);
\ No newline at end of file
diff --git a/web/client/assets/images/document.svg b/web/client/assets/images/document.svg
new file mode 100644
index 0000000..9efb51f
--- /dev/null
+++ b/web/client/assets/images/document.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/web/client/assets/images/logo.png b/web/client/assets/images/logo.png
index 87a6aa3..6a79c8b 100644
Binary files a/web/client/assets/images/logo.png and b/web/client/assets/images/logo.png differ
diff --git a/web/client/assets/images/logo.svg b/web/client/assets/images/logo.svg
deleted file mode 100644
index cc6e46d..0000000
--- a/web/client/assets/images/logo.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/web/client/assets/images/logo_white.png b/web/client/assets/images/logo_white.png
new file mode 100644
index 0000000..3016c79
Binary files /dev/null and b/web/client/assets/images/logo_white.png differ
diff --git a/web/client/index.ejs b/web/client/index.ejs
index 5a73b8d..0431b54 100644
--- a/web/client/index.ejs
+++ b/web/client/index.ejs
@@ -3,13 +3,14 @@
+
-
+ -->
diff --git a/web/client/index.html b/web/client/index.html
index 95afad8..276534f 100644
--- a/web/client/index.html
+++ b/web/client/index.html
@@ -3,14 +3,15 @@
+
-
+
-
+ -->
diff --git a/web/client/src/components/QrcodeFilesUpload/fileInfoForm.js b/web/client/src/components/QrcodeFilesUpload/fileInfoForm.js
new file mode 100644
index 0000000..519cfdd
--- /dev/null
+++ b/web/client/src/components/QrcodeFilesUpload/fileInfoForm.js
@@ -0,0 +1,52 @@
+import React, { useRef } from 'react'
+import { Spin, Upload, message, Modal, Card, Button, Input, Form } from 'antd'
+import Uploads from '../Uploads'
+export default function FileInfoForm({ }) {
+ const [form] = Form.useForm();
+
+ const handleOk = () => {
+ form.validateFields()
+ .then((values) => {
+ console.log(values, 'valuesvalues')
+ })
+ .catch((info) => {
+ console.log('Validate Failed:', info);
+ });
+ }
+
+ return (
+
+
+
+
+ {
+ return {
+ storageUrl: s
+ }
+ })}
+ />
+
+
+ )
+}
diff --git a/web/client/src/components/QrcodeFilesUpload/index.js b/web/client/src/components/QrcodeFilesUpload/index.js
new file mode 100644
index 0000000..c05dfc6
--- /dev/null
+++ b/web/client/src/components/QrcodeFilesUpload/index.js
@@ -0,0 +1,413 @@
+'use strict';
+
+import React, { Component, useRef } from 'react';
+import { connect } from 'react-redux';
+import { Spin, Upload, message, Modal, Card, Button, Input, Form } from 'antd';
+import Uploads from '../Uploads';
+import moment from 'moment';
+import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons';
+import './index.less'
+
+class QrcodeFilesUpload extends Component {
+ constructor(props) {
+ super(props);
+ this.ApiRoot = localStorage.getItem('tyApiRoot')
+ this.qnDomain = localStorage.getItem('qnDomain');
+ this.aliAdmin = localStorage.getItem('aliAdmin');
+ this.state = {
+ fileUploading: false,
+ fileList: [],
+ curPreviewPic: '',
+ curPreviewVideo: '',
+ delPicIng: false,
+ removeFilesList: []
+ };
+ }
+
+ dealName = (uploaded) => {
+ let realName = uploaded?.split('/')[2]
+ return realName
+ }
+
+ setFileList = (nextEditData, isQiniu, isAli) => {
+ let defaultFileList = [];
+ defaultFileList = nextEditData.map((u, index) => {
+ let fileUrl =
+ isQiniu ? `/_file-server/${u.storageUrl}`
+ : isAli ? `/_file-ali-server/${u.storageUrl}`
+ : `${this.ApiRoot}/${u.storageUrl}`;
+
+ return {
+ uid: -index - 1,
+ name: this.dealName(u.storageUrl),
+ status: 'done',
+ storageUrl: u.storageUrl,
+ url: fileUrl,
+ size: u.size || -1,
+ customFileName: u.customFileName,
+ previewImgUrl: u.previewImgUrl,
+ };
+ });
+ this.setState({
+ fileList: defaultFileList
+ });
+ };
+
+ componentDidMount() {
+ const { value, defaultValue, isQiniu, isAli } = this.props;
+ if (defaultValue) {
+ this.setFileList(defaultValue, isQiniu, isAli)
+ }
+ }
+
+ UNSAFE_componentWillReceiveProps(np) {
+ const { dispatch, value: thisEditData, onChange } = this.props;
+ const { value: nextEditData, isQiniu, isAli } = np;
+ if (nextEditData && nextEditData.length) {
+ if (!thisEditData || !this.state.fileList.length) {
+ this.setFileList(nextEditData, isQiniu, isAli);
+ } else if (nextEditData.length != thisEditData.length) {
+ this.setFileList(nextEditData, isQiniu, isAli);
+ } else {
+ let repeat = true;
+ for (let i = 0; i < thisEditData.length; i++) {
+ if (thisEditData[i] != nextEditData[i]) {
+ repeat = false;
+ break;
+ }
+ }
+ if (!repeat) {
+ this.setFileList(nextEditData, isQiniu, isAli);
+ }
+ }
+ }
+ }
+
+ render() {
+ const UploadPath = {
+ project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf', 'pptx', 'png', 'jpg', 'svg', 'jpeg', 'rar', 'zip', 'jpeg', 'mp4'],
+ report: ['doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf'],
+ data: ['txt', 'xls', 'xlsx', 'csv'],
+ image: ['png', 'jpg', 'svg', 'jpeg'],
+ three: ['js'],
+ video: ['mp4']
+ };
+ /**
+ * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project;
+ * disabled 【boolean】 上传是否可用
+ * maxFilesNum 【number】 最大上传数量
+ * fileTypes 【array[string]】 可允许上传的文件类型;
+ * maxFileSize 【number】 单个文件最大大小 M
+ * listType 【antd】 upload 组件的属性
+ * onChange 【function】 文件数量变化时候回调 返回文件
+ * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}]
+ * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false }
+ */
+ const {
+ uploadType,
+ disabled,
+ maxFilesNum,
+ fileTypes,
+ maxFileSize,
+ listType,
+ onChange = () => { },
+ value,
+ showUploadList,
+ onStateChange,
+ isQiniu,
+ isAli,
+ } = this.props;
+ const { fileList, curPreviewPic, curPreviewVideo, delPicIng, removeFilesList } = this.state;
+ const that = this;
+ let uploadType_ = uploadType || 'project';
+ let maxFilesNum_ = maxFilesNum || 1;
+ let defaultFileTypes = fileTypes || UploadPath[uploadType_];
+ // debugger
+ const uploadProps = {
+ name: 'checkFile_',
+ multiple: false,
+ showUploadList: showUploadList || true,
+ action:
+ isQiniu ? `/_upload/attachments/${uploadType_}`
+ : isAli ? `/_upload/attachments/ali/${uploadType_}`
+ : `${this.ApiRoot}/attachments/${uploadType_}`,
+ listType: listType || 'text',
+ disabled: disabled,
+ beforeUpload: (file) => {
+ if (fileList.length >= maxFilesNum_) {
+ message.warning(`最多选择${maxFilesNum_}个文件上传`);
+ return false;
+ }
+ if (file.name.length > 60) {
+ message.warning(`文件名过长(大于60字符),请修改后上传`);
+ return false;
+ }
+ const extNames = file.name?.split('.');
+ // var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/;
+ // if (!reg.exec(file.name)) {
+ // message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
+ // return false;
+ // }
+ let isDAE = false;
+ if (extNames.length > 0) {
+ let fileType = extNames[extNames.length - 1].toLowerCase();
+ isDAE = defaultFileTypes.some((f) => f == fileType);
+ }
+ if (!isDAE) {
+ message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`);
+ return false;
+ }
+ const isLt = file.size / 1024 / 1024 < (maxFileSize || 3);
+ if (!isLt) {
+ message.error(`文件必须小于${maxFileSize || 3}MB!`);
+ return false;
+ }
+ this.setState({
+ fileUploading: true
+ });
+ if (onStateChange) {
+ onStateChange({ uploading: true });
+ }
+ },
+ onChange(info) {
+ const status = info.file.status;
+ if (status === 'uploading') {
+ that.setState({
+ fileList: info.fileList
+ });
+ }
+ if (status === 'done') {
+ let { uploaded, url } = info.file.response;
+ let size = info.file.size;
+ let nextFileList = fileList;
+ nextFileList[nextFileList.length - 1] = {
+ uid: -moment().unix(),
+ name: that.dealName(uploaded),
+ status: 'done',
+ storageUrl: uploaded,
+ url:
+ isQiniu ? '/_file-server/' + uploaded :
+ isAli ? `/_file-ali-server/${uploaded}` :
+ url,
+ size: size
+ };
+ onChange(nextFileList);
+ that.setState({
+ fileUploading: false,
+ fileList: nextFileList
+ });
+ if (onStateChange) {
+ onStateChange({ uploading: false });
+ }
+ } else if (status === 'error') {
+ that.setState({
+ fileUploading: false
+ });
+ message.error(`${info.file.name} 上传失败,请重试`);
+ if (onStateChange) {
+ onStateChange({ uploading: false });
+ }
+ }
+ },
+ onRemove(file) {
+ let nextFileList = [];
+ fileList.map((f, i) => {
+ if (f.uid != file.uid) {
+ nextFileList.push(f);
+ }
+ });
+ let nextRemoveFiles = removeFilesList.concat([file.storageUrl]);
+ if (curPreviewPic == file.url) {
+ that.setState({
+ curPreviewPic: ''
+ });
+ }
+ if (curPreviewVideo == file.url) {
+ that.setState({
+ curPreviewVideo: ''
+ });
+ }
+ onChange(nextFileList);
+ that.setState({
+ fileList: nextFileList,
+ removeFilesList: nextRemoveFiles
+ });
+ },
+ onPreview(file) {
+ let filePostfix = file.url?.split('.').pop();
+ filePostfix = filePostfix.toLowerCase();
+ if (UploadPath.image.some((img) => img == filePostfix)) {
+ that.setState({
+ curPreviewPic: file.url
+ });
+ } else if (UploadPath.video.some((img) => img == filePostfix)) {
+ that.setState({
+ curPreviewVideo: file.url
+ });
+ } else {
+ //message.warn('仅支持图片预览');
+ preview(file.storageUrl)
+ }
+ }
+ };
+
+ const preview = (url) => {
+ let link = isQiniu ? encodeURI(`${this.qnDomain}/${url}`) :
+ isAli ? encodeURI(`${this.aliAdmin}/${url}`) : ''
+ if (link)
+ if (url.indexOf("pdf") !== -1 || url.indexOf("csv") !== -1) {
+ window.open(link)
+ } else {
+ window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`)
+ }
+ }
+
+ let fileList_ = fileList
+ //下载文件
+ const handleDownload = (file) => {
+ saveAs(file)
+ };
+ const saveAs = (file) => {
+ const link = document.createElement('a');
+ link.href = file.url;
+ link.download = file.name;
+ link.style.display = 'none';
+ link.click();
+ }
+
+ //自定义下载
+
+ return (
+
+
+ {
+ const fileName = file.name?.split('.').slice(0, -1).join('.')
+ const extension = file.name?.split('.').pop()
+ return <>
+ {originNode}
+
+ {
+ const fileInfo = {
+ ...file,
+ customFileName: value,
+ };
+ const nextFileList = currFileList.toSpliced(
+ currFileList.findIndex(item => item.storageUrl === file.storageUrl),
+ 1,
+ fileInfo,
+ );
+ onChange(nextFileList);
+ this.setState({ fileList: nextFileList })
+ }}
+ placeholder="不填写默认为上传的文件名"
+ style={{ width: '220px' }}
+ />
+
+ {!UploadPath.image.includes(extension) &&
+ {
+ const fileInfo = {
+ ...file,
+ previewImgUrl: previewFile[0]?.storageUrl,
+ };
+ const nextFileList = currFileList.toSpliced(
+ currFileList.findIndex(item => item.storageUrl === file.storageUrl),
+ 1,
+ fileInfo,
+ );
+ onChange(nextFileList);
+ this.setState({ fileList: nextFileList })
+ }}
+ defaultValue={([]).map(s => {
+ return {
+ storageUrl: s
+ }
+ })}
+ />
+ }
+
+ >
+ }}
+ >
+ {
+ disabled ? ('') :
+ listType == 'picture-card' ?
+ (
+ fileList.length >= maxFilesNum_ ? null : (
+
+ )
+ ) : (
+
+ )
+ }
+
+ {
+ curPreviewPic ? (
+
+
+ 图片预览
+ { this.setState({ curPreviewPic: '' }) }}>
+
+
+
+
+
+ ) : ''
+ }
+ {
+ curPreviewVideo ? (
+
+ 视频预览
+ { this.setState({ curPreviewVideo: '' }) }}>
+
+
+
+
+ ) : ''
+ }
+
+
+ );
+ }
+}
+
+function mapStateToProps(state) {
+ const { auth } = state
+ return {
+ user: auth.user
+ };
+}
+
+export default connect(mapStateToProps)(QrcodeFilesUpload);
\ No newline at end of file
diff --git a/web/client/src/components/QrcodeFilesUpload/index.less b/web/client/src/components/QrcodeFilesUpload/index.less
new file mode 100644
index 0000000..e69de29
diff --git a/web/client/src/layout/components/header/index.js b/web/client/src/layout/components/header/index.js
index 2e78564..8425cfe 100644
--- a/web/client/src/layout/components/header/index.js
+++ b/web/client/src/layout/components/header/index.js
@@ -29,7 +29,7 @@ const Header = props => {
return (
-
+
飞尚码尚来二维码管理系统
FREESUN QRCODE MANAGEMENT SYSTEM
diff --git a/web/client/src/sections/organization/actions/authority.js b/web/client/src/sections/organization/actions/authority.js
index d5f0719..40f3d2c 100644
--- a/web/client/src/sections/organization/actions/authority.js
+++ b/web/client/src/sections/organization/actions/authority.js
@@ -3,16 +3,16 @@
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
-export function getAuthority(orgId) {
- return dispatch => basicAction({
- type: 'get',
- dispatch: dispatch,
- actionType: 'GET_MEMBERS',
- url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`,
- msg: { error: '获取用户列表失败' },
- reducer: { name: 'members' }
- });
-}
+// export function getAuthority(orgId) {
+// return dispatch => basicAction({
+// type: 'get',
+// dispatch: dispatch,
+// actionType: 'GET_MEMBERS',
+// url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`,
+// msg: { error: '获取用户列表失败' },
+// reducer: { name: 'members' }
+// });
+// }
export function getResource(userId) {
return dispatch => basicAction({
type: 'get',
@@ -44,7 +44,7 @@ export function postUserRes(body) {
});
}
export default {
- getAuthority,
+ // getAuthority,
getResource,
getUserResource,
postUserRes
diff --git a/web/client/src/sections/publicityInfoConfig/actions/index.js b/web/client/src/sections/publicityInfoConfig/actions/index.js
index 7ee4de2..7a5b3eb 100644
--- a/web/client/src/sections/publicityInfoConfig/actions/index.js
+++ b/web/client/src/sections/publicityInfoConfig/actions/index.js
@@ -2,7 +2,9 @@
import * as publicityInfoConfig from './publicityInfoConfig'
+import * as label from './label'
export default {
...publicityInfoConfig,
+ ...label,
}
\ No newline at end of file
diff --git a/web/client/src/sections/publicityInfoConfig/actions/label.js b/web/client/src/sections/publicityInfoConfig/actions/label.js
new file mode 100644
index 0000000..c3b1da0
--- /dev/null
+++ b/web/client/src/sections/publicityInfoConfig/actions/label.js
@@ -0,0 +1,38 @@
+'use strict';
+
+import { basicAction } from '@peace/utils'
+import { ApiTable } from '$utils'
+
+export function getLabels(query) {
+ return (dispatch) => basicAction({
+ type: 'get',
+ query,
+ dispatch,
+ actionType: 'GET_LABELS',
+ url: ApiTable.getLabels,
+ msg: { error: '获取标签失败', },
+ reducer: { name: 'labels' }
+ });
+}
+
+export function createLabels(data) {
+ return (dispatch) => basicAction({
+ type: 'post',
+ data,
+ dispatch,
+ actionType: 'POST_LABELS',
+ url: ApiTable.createLabels,
+ msg: { option: '新增标签', },
+ });
+}
+
+export function delLabels(id) {
+ return (dispatch) => basicAction({
+ type: 'del',
+ dispatch,
+ actionType: 'DEL_LABELS',
+ url: ApiTable.delLabels.replace('{id}', id),
+ msg: { option: '删除标签', },
+ });
+}
+
diff --git a/web/client/src/sections/publicityInfoConfig/actions/publicityInfoConfig.js b/web/client/src/sections/publicityInfoConfig/actions/publicityInfoConfig.js
index f159551..3386879 100644
--- a/web/client/src/sections/publicityInfoConfig/actions/publicityInfoConfig.js
+++ b/web/client/src/sections/publicityInfoConfig/actions/publicityInfoConfig.js
@@ -3,82 +3,50 @@
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
-
-export function getProjectList (query) {
+export function getPublicityInfo(query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
- actionType: 'GET_PROJEECT_LIST',
- url: ApiTable.getProjectList,
- msg: { error: '获取结构物列表失败', },
+ actionType: 'GET_PUBLICITY_INFO',
+ url: ApiTable.getPublicityInfo,
+ msg: { error: '获取宣传信息失败', },
});
}
-
-export function postAddProject (data) {
+export function createPublicityInfo(data) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
- actionType: 'POST_ADD_PROJECT',
- url: ApiTable.postAddProject,
- msg: { option: data?.id ? '编辑结构物' : '新增结构物', },
- });
-}
-
-
-export function delProject (id) {
- return (dispatch) => basicAction({
- type: 'del',
- dispatch,
- actionType: 'DEL_PROJECT',
- url: ApiTable.delProject.replace('{id}', id),
- msg: {
- option: '删除结构物',
- },
+ actionType: 'POST_PUBLICITY_INFO',
+ url: ApiTable.createPublicityInfo,
+ msg: { option: '新增宣传信息', },
});
}
-
-export function addPosition (data, point) {
+export function updatePublicityInfo(data, id) {
return (dispatch) => basicAction({
- type: 'post',
+ type: 'put',
data,
dispatch,
- actionType: 'ADD_POSITION',
- url: ApiTable.position,
- msg: { option: point ? '二维码生成' : data?.id ? '编辑点位' : '新增点位', },
- });
-}
-
-export function positionList (query) {
- return (dispatch) => basicAction({
- type: 'get',
- query,
- dispatch,
- actionType: 'POSITION_LIST',
- url: ApiTable.position,
- msg: { error: '获取点位列表失败', },
- reducer: { name: 'projectPoints' }
+ actionType: 'PUT_PUBLICITY_INFO',
+ url: ApiTable.updatePublicityInfo.replace('{id}', id),
+ msg: { option: '修改宣传信息', },
});
}
-
-export function delPosition (id) {
+export function delPublicityInfo(id, qrcodeId) {
return (dispatch) => basicAction({
type: 'del',
dispatch,
- actionType: 'DEL_POSITION',
- url: ApiTable.delPosition.replace('{id}', id),
- msg: {
- option: '删除点位',
- },
+ actionType: 'DEL_PUBLICITY_INFO',
+ url: ApiTable.delPublicityInfo.replace('{id}', id).replace('{qrcodeId}', qrcodeId),
+ msg: { option: '删除宣传信息', },
});
}
-
-export function qrCodeShow (query) {
+export function qrCodeShow(query) {
return (dispatch) => basicAction({
type: 'get',
query,
@@ -88,14 +56,3 @@ export function qrCodeShow (query) {
msg: { error: '获取二维码列表失败', },
});
}
-
-export function q () {
- return (dispatch) => basicAction({
- type: 'get',
- dispatch,
- actionType: 'GET_CODE',
- url: ApiTable.q,
- msg: { error: '获取二维码列表失败', },
- });
-}
-
diff --git a/web/client/src/sections/publicityInfoConfig/components/publicityInfoModal.js b/web/client/src/sections/publicityInfoConfig/components/publicityInfoModal.js
new file mode 100644
index 0000000..590c2a8
--- /dev/null
+++ b/web/client/src/sections/publicityInfoConfig/components/publicityInfoModal.js
@@ -0,0 +1,273 @@
+import React, { useState, useEffect } from 'react';
+import { Button, Form, Input, Modal, Select, Divider, Row, Col, Image, message } from 'antd';
+import QrcodeFilesUpload from '../../../components/QrcodeFilesUpload';
+import { Uploads } from '../../../components';
+import { connect } from 'react-redux';
+import { getLabels } from '../actions/label';
+import { createPublicityInfo, updatePublicityInfo } from '../actions/publicityInfoConfig';
+import QrCodeWithLogo from 'qr-code-with-logo'
+import { v4 as uuidv4 } from 'uuid';
+import request from 'superagent';
+
+const PublicityInfoModal = ({ visible, onCancel, updateList, dispatch, curRecord, labels }) => {
+ const [form] = Form.useForm();
+
+ const [type, setType] = useState('图片');
+ const [qrcode, setQrcode] = useState('');
+
+ useEffect(() => {
+ getLabelsData()
+ if (curRecord) {
+ console.log(curRecord, 'curRecord')
+ setType(curRecord.type)
+ } else {
+ draw()
+ }
+ }, [])
+
+ const getLabelsData = () => {
+ dispatch(getLabels({}));
+ }
+
+ const draw = () => {
+ const ctx = document.getElementById("qrcodeCanvas").getContext("2d");
+ ctx.fillStyle = "#f5f5f5";
+ ctx.fillRect(0, 0, 220, 220);
+ ctx.fillStyle = "black";
+ ctx.font = "14px serif";
+ ctx.fillText("此处预览二维码", 60, 110);
+ }
+
+ const handleSubmit = async (values) => {
+ console.log(values, 'values')
+ if (curRecord) {
+ // dispatch(updatePublicityInfo(params)).then(res => {
+ // if (res.success) {
+ // // form.resetFields();
+ // // onCancel();
+ // }
+ // })
+ } else {
+ const key = uuidv4();
+ // 生成二维码
+ let qrcodeUrl = '';
+ const qrcodeCanvas = document.getElementById('qrcodeCanvas')
+ let options = {
+ canvas: qrcodeCanvas,
+ width: 220,
+ content: values.type === '链接'
+ ? values.link
+ : `${window.location.protocol}//${window.location.host}/scan?key=${key}`,
+ }
+ if (values.qrcodeImg?.length) {
+ options.logo = {
+ src: '/_file-server/' + values.qrcodeImg[0].storageUrl,
+ radius: 8
+ }
+ }
+ await QrCodeWithLogo.toCanvas(options)
+
+ // 上传二维码
+ try {
+ const blob = await canvasToBlob(qrcodeCanvas);
+ const formData = new FormData();
+ formData.append('image', blob, values.name + '.png');
+ const res = await request.post('/_upload/attachments/image', formData)
+ qrcodeUrl = res.body.uploaded
+ } catch (error) {
+ console.log(error);
+ message.error('二维码上传失败');
+ return;
+ }
+ console.log(qrcodeUrl, 'qrcodeUrl')
+ dispatch(createPublicityInfo({
+ ...values,
+ qrcode: { url: qrcodeUrl, key },
+ })).then(res => {
+ if (res.success) {
+ form.resetFields();
+ onCancel();
+ updateList();
+ }
+ })
+ }
+ }
+
+ const handleChange = (value) => {
+ console.log(`selected ${value}`);
+ };
+
+ return (
+
{
+ form.validateFields()
+ .then((values) => {
+ handleSubmit(values)
+ })
+ .catch((info) => {
+ console.log('Validate Failed:', info);
+ });
+ }}>
+ 生成二维码并保存
+ ,
+ // ,
+ ,
+ ]}
+ onCancel={() => {
+ form.resetFields();
+ onCancel();
+ }}
+ >
+
+
+
+
+
+ {type === '链接' ?
+
+ :
+ {
+ return {
+ storageUrl: s
+ }
+ })}
+ />
+ }
+
+
+
+
+ {
+ return {
+ storageUrl: s
+ }
+ })}
+ />
+
+
+
+
+
+
+ {qrcode
+ ?
+ :
+ }
+
+
+
+
+ );
+};
+
+function mapStateToProps(state) {
+ const { auth, labels } = state
+
+ return {
+ user: auth.user,
+ labels: labels.data || [],
+ }
+}
+export default connect(mapStateToProps)(PublicityInfoModal);
+
+function canvasToBlob(canvas) {
+ return new Promise((resolve, reject) => {
+ canvas.toBlob((blob) => {
+ if (blob) {
+ resolve(blob);
+ } else {
+ reject(new Error('无法生成Blob对象'));
+ }
+ });
+ });
+}
\ No newline at end of file
diff --git a/web/client/src/sections/publicityInfoConfig/containers/publicityInfoConfig.js b/web/client/src/sections/publicityInfoConfig/containers/publicityInfoConfig.js
index 69531ed..500961d 100644
--- a/web/client/src/sections/publicityInfoConfig/containers/publicityInfoConfig.js
+++ b/web/client/src/sections/publicityInfoConfig/containers/publicityInfoConfig.js
@@ -1,16 +1,147 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
-import { Form, Input, Select, Button, message } from 'antd';
+import { Form, Input, Select, Button, message, Popconfirm } from 'antd';
+import ProTable from '@ant-design/pro-table';
+import PublicityInfoModal from '../components/publicityInfoModal';
+import moment from 'moment';
import './publicityInfoConfig.less';
const PublicityInfoConfig = (props) => {
const { dispatch, actions } = props
+ const { getPublicityInfo, delPublicityInfo } = actions.publicityInfoConfig
+ const ref = useRef()
- return (
-
- 宣传信息配置
-
- )
+ const [dataSource, setDataSource] = useState([]);
+ const [visible, setVisible] = useState(false);
+ const [curRecord, setCurRecord] = useState();
+
+ const columns = [
+ {
+ title: '宣传标题',
+ dataIndex: 'name',
+ key: 'name',
+ ellipsis: true,
+ },
+ {
+ title: '标签',
+ dataIndex: 'label',
+ key: 'label',
+ ellipsis: true,
+ search: false,
+ render: (_, record) => {
+ return
{record.qrcodeLabels?.map(l => l.name)?.join() || '-'}
+ }
+ },
+ {
+ title: '类型',
+ dataIndex: 'type',
+ key: 'type',
+ width: 100,
+ ellipsis: true,
+ search: false,
+ },
+ {
+ title: '附件',
+ dataIndex: 'files',
+ key: 'files',
+ search: false,
+ ellipsis: true,
+ render: (_, record) => {
+ return
{
+ record.type === '链接'
+ ?
{record.link}
+ : record.qrcodeFiles?.map(f =>
)
+ }
+ }
+ },
+ {
+ title: '时间',
+ dataIndex: 'time',
+ key: 'time',
+ search: false,
+ ellipsis: true,
+ width: 150,
+ render: (_, record) => {
+ return
{moment(record.time).format('YYYY-MM-DD HH:mm:ss')}
+ }
+ },
+ {
+ title: '操作',
+ dataIndex: 'action',
+ key: 'action',
+ search: false,
+ ellipsis: true,
+ width: 150,
+ render: (_, record) => {
+ return <>
+ {/*
*/}
+
{
+ dispatch(delPublicityInfo(record.id, record.qrcodeId)).then(() => {
+ message.success('删除成功');
+ ref.current.reloadAndRest();
+ })
+ }}
+ onCancel={() => { }}
+ okText="确定"
+ cancelText="取消"
+ >
+
+
+ >
+ }
+ },
+ ];
+
+ return (<>
+
{
+ const res = await dispatch(getPublicityInfo({
+ limit: params?.pageSize,
+ page: params?.current - 1,
+ name: params?.name,
+ }));
+ setDataSource(res?.payload.data?.rows);
+ return {
+ ...res,
+ total: res.payload.data.count ? res.payload.data.count : 0,
+ };
+ }}
+ search={{
+ defaultCollapsed: false,
+ optionRender: (searchConfig, formProps, dom) => [
+ ...dom.reverse(),
+ ,
+ ],
+ }}
+ onReset={() => { }}
+ />
+ {visible && { ref.current.reloadAndRest() }}
+ onCancel={() => {
+ setVisible(false)
+ setCurRecord()
+ }}
+ />}
+ >)
}
function mapStateToProps(state) {
diff --git a/web/client/src/sections/qrCode/actions/qrCode.js b/web/client/src/sections/qrCode/actions/qrCode.js
index f159551..4c6ee22 100644
--- a/web/client/src/sections/qrCode/actions/qrCode.js
+++ b/web/client/src/sections/qrCode/actions/qrCode.js
@@ -3,98 +3,13 @@
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
-
-export function getProjectList (query) {
- return (dispatch) => basicAction({
- type: 'get',
- query,
- dispatch,
- actionType: 'GET_PROJEECT_LIST',
- url: ApiTable.getProjectList,
- msg: { error: '获取结构物列表失败', },
- });
-}
-
-
-export function postAddProject (data) {
- return (dispatch) => basicAction({
- type: 'post',
- data,
- dispatch,
- actionType: 'POST_ADD_PROJECT',
- url: ApiTable.postAddProject,
- msg: { option: data?.id ? '编辑结构物' : '新增结构物', },
- });
-}
-
-
-export function delProject (id) {
- return (dispatch) => basicAction({
- type: 'del',
- dispatch,
- actionType: 'DEL_PROJECT',
- url: ApiTable.delProject.replace('{id}', id),
- msg: {
- option: '删除结构物',
- },
- });
-}
-
-
-export function addPosition (data, point) {
- return (dispatch) => basicAction({
- type: 'post',
- data,
- dispatch,
- actionType: 'ADD_POSITION',
- url: ApiTable.position,
- msg: { option: point ? '二维码生成' : data?.id ? '编辑点位' : '新增点位', },
- });
-}
-
-export function positionList (query) {
- return (dispatch) => basicAction({
- type: 'get',
- query,
- dispatch,
- actionType: 'POSITION_LIST',
- url: ApiTable.position,
- msg: { error: '获取点位列表失败', },
- reducer: { name: 'projectPoints' }
- });
-}
-
-
-export function delPosition (id) {
- return (dispatch) => basicAction({
- type: 'del',
- dispatch,
- actionType: 'DEL_POSITION',
- url: ApiTable.delPosition.replace('{id}', id),
- msg: {
- option: '删除点位',
- },
- });
-}
-
-
-export function qrCodeShow (query) {
+export function getQrCode (query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'GET_QR_CODE',
- url: ApiTable.qrCodeShow,
- msg: { error: '获取二维码列表失败', },
- });
-}
-
-export function q () {
- return (dispatch) => basicAction({
- type: 'get',
- dispatch,
- actionType: 'GET_CODE',
- url: ApiTable.q,
+ url: ApiTable.getQrCode,
msg: { error: '获取二维码列表失败', },
});
}
diff --git a/web/client/src/sections/qrCode/containers/index.js b/web/client/src/sections/qrCode/containers/index.js
index c8506c6..308c264 100644
--- a/web/client/src/sections/qrCode/containers/index.js
+++ b/web/client/src/sections/qrCode/containers/index.js
@@ -2,5 +2,6 @@
import QrCode from './qrCode'
+import ScanCode from './scanCode'
-export { QrCode, };
\ No newline at end of file
+export { QrCode, ScanCode };
\ No newline at end of file
diff --git a/web/client/src/sections/qrCode/containers/qrCode.js b/web/client/src/sections/qrCode/containers/qrCode.js
index 622aeea..266b6e8 100644
--- a/web/client/src/sections/qrCode/containers/qrCode.js
+++ b/web/client/src/sections/qrCode/containers/qrCode.js
@@ -17,7 +17,7 @@ const QrCode = (props) => {
const projectList = (obj) => {
const { projectId, name } = obj
- dispatch(qrCode.qrCodeShow({ projectId, name })).then(res => {
+ dispatch(qrCode.getQrCode({ name })).then(res => {
if (res.success) {
setTableList(res.payload.data?.rows)
}
@@ -39,7 +39,7 @@ const QrCode = (props) => {
let promiseArr = [], nameArr = []
tableList.forEach(l => {
promiseArr.push(
- window.fetch(`/_file-server/${l.qrCode}`, {
+ window.fetch(`/_file-server/${l.url}`, {
method: 'get',
headers: {
"Accept": "application/json",
@@ -60,7 +60,7 @@ const QrCode = (props) => {
}
zip.generateAsync({ type: "blob" }).then(blob => {
const url = window.URL.createObjectURL(blob)
- downloadFile(url, "点位二维码.zip")
+ downloadFile(url, "二维码.zip")
setDownloading(false)
message.success('下载成功')
});
@@ -87,11 +87,11 @@ const QrCode = (props) => {
}}
>
-
+
@@ -111,22 +111,22 @@ const QrCode = (props) => {
borderRadius: '3px'
}}
>
-
+
{firmList?.filter(u => u.value == v.projectId)[0]?.label}
- 点位名称:{v.name}
+ 名称:{v.name}
diff --git a/web/client/src/sections/qrCode/containers/scanCode.js b/web/client/src/sections/qrCode/containers/scanCode.js
new file mode 100644
index 0000000..8f95275
--- /dev/null
+++ b/web/client/src/sections/qrCode/containers/scanCode.js
@@ -0,0 +1,141 @@
+import React, { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { SafeArea, AutoCenter, Button, Card, Toast, Image, Popup, Tag, Space, WaterMark, Divider } from 'antd-mobile';
+import { getQrCode } from '../actions/qrCode';
+import './scanCode.less';
+
+const fileType = {
+ report: ['doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf', 'pptx'],
+ image: ['png', 'jpg', 'svg', 'jpeg'],
+ video: ['mp4']
+};
+
+const ScanCode = ({ dispatch }) => {
+ const urlParams = new URLSearchParams(window.location.search);
+ const key = urlParams.get('key');
+ const qnDomain = localStorage.getItem('qnDomain');
+
+ const [qrCode, setQrCode] = useState({});
+ const [visible, setVisible] = useState(false)
+ const [link, setLink] = useState('')
+
+ useEffect(() => {
+ if (!key) {
+ Toast.show({
+ icon: 'fail',
+ content: '二维码参数错误',
+ })
+ return
+ }
+ getQrCodeData(key)
+ }, [])
+
+ const getQrCodeData = (key) => {
+ dispatch(getQrCode({ key })).then(res => {
+ console.log(res, 'res')
+ if (!res.payload?.data?.rows?.length) {
+ Toast.show({ icon: 'fail', content: '该二维码已被删除,无法访问' })
+ return
+ }
+ setQrCode(res.payload.data.rows[0])
+ })
+ }
+
+ const { qrcodeFiles } = qrCode;
+
+ return (<>
+
+
{qrCode.name}
+
+ {
+ qrcodeFiles?.map((f, i) => {
+ const extensionName = getFileExtension(f.fileUrl)
+ if (fileType.report.includes(extensionName)) {
+ return
+ {f.fileName}
+ {extensionName}
+ }
+ extra={}
+ >
+ {
+ // const link = encodeURI(`https://view.officeapps.live.com/op/view.aspx?src=${qnDomain}/${f.fileUrl}`);
+ const nextLink = encodeURI(`https://view.xdocin.com/view?src=${qnDomain}/${f.fileUrl}`);
+ setLink(nextLink)
+ setVisible(true)
+ }}
+ />
+
+ }
+ else if (fileType.image.includes(extensionName)) {
+ return
+ {f.fileName}
+ {extensionName}
+ }>
+
+
+ }
+ else if (fileType.video.includes(extensionName)) {
+ return
+ {f.fileName}
+ {extensionName}
+ }>
+
+
+ }
+ })
+ }
+
{
+ setVisible(false)
+ }}
+ position='bottom'
+ bodyStyle={{ height: '80vh' }}
+ closeOnMaskClick
+ >
+
+
+
+
+ >)
+}
+
+function mapStateToProps(state) {
+ const { global } = state;
+ return {
+ actions: global.actions,
+ };
+}
+
+export default connect(mapStateToProps)(ScanCode);
+
+const getFileExtension = (fileUrl) => {
+ const fileNameWithExtension = fileUrl.split('/').pop(); // 获取URL的最后一部分(即文件名和扩展名)
+ const extension = fileNameWithExtension.split('.').pop(); // 从文件名中分离出扩展名
+
+ // 如果没有扩展名或文件名不含点,则返回空字符串
+ return extension ? extension.toLowerCase() : '';
+};
\ No newline at end of file
diff --git a/web/client/src/sections/qrCode/containers/scanCode.less b/web/client/src/sections/qrCode/containers/scanCode.less
new file mode 100644
index 0000000..842ed88
--- /dev/null
+++ b/web/client/src/sections/qrCode/containers/scanCode.less
@@ -0,0 +1,16 @@
+// @import '~antd-mobile/dist/antd-mobile.css';
+
+html {
+ font-size: 24px;
+}
+
+body {
+ font-size: 1rem;
+}
+
+.text--- {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ word-break: break-all;
+ white-space: nowrap;
+}
\ No newline at end of file
diff --git a/web/client/src/sections/qrCode/routes.js b/web/client/src/sections/qrCode/routes.js
index 5c9960e..187c8f1 100644
--- a/web/client/src/sections/qrCode/routes.js
+++ b/web/client/src/sections/qrCode/routes.js
@@ -1,21 +1,32 @@
'use strict';
-import { QrCode, } from './containers';
+import { QrCode, ScanCode } from './containers';
-export default [{
- type: 'inner',
- route: {
- path: '/qrCode',
- key: 'qrCode',
- breadcrumb: '二维码管理',
- component: QrCode,
- // 不设置 component 则面包屑禁止跳转
- // childRoutes: [
- // {
- // path: '/qrCode',
- // key: 'qrCode',
- // component: QrCode,
- // breadcrumb: '二维码管理',
- // },
- // ]
+export default [
+ {
+ type: 'inner',
+ route: {
+ path: '/qrCode',
+ key: 'qrCode',
+ breadcrumb: '二维码管理',
+ component: QrCode,
+ // 不设置 component 则面包屑禁止跳转
+ // childRoutes: [
+ // {
+ // path: '/qrCode',
+ // key: 'qrCode',
+ // component: QrCode,
+ // breadcrumb: '二维码管理',
+ // },
+ // ]
+ }
+ },
+ {
+ type: 'outer',
+ route: {
+ path: '/scan',
+ key: 'scan',
+ component: ScanCode,
+ breadcrumb: '扫码页面',
+ }
}
-}];
\ No newline at end of file
+];
\ No newline at end of file
diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js
index b54b2f0..2245165 100644
--- a/web/client/src/utils/webapi.js
+++ b/web/client/src/utils/webapi.js
@@ -4,8 +4,6 @@ import request from 'superagent';
export const ApiTable = {
login: 'login',
logout: 'logout',
- validatePhone: 'validate/phone',
- getUserSiteList: 'user/site/list',
// 组织管理-用户管理
getDepMessage: 'organization/department',
@@ -19,131 +17,24 @@ export const ApiTable = {
delUser: 'organization/department/user/{ids}',
resetPwd: '/organization/department/user/resetPwd/{id}',
- // 巡检计划
- patrolPlan: 'patrolPlan', // 增改查
- delPatrolPlan: 'patrolPlan/{id}',
-
- // 巡检模板
- patrolTemplate: 'patrolTemplate', // 增改查
- delPatrolTemplate: 'patrolTemplate/{id}',
-
- // 巡检记录
- patrolRecord: 'patrolRecord/:patrolPlanId/:startTime/:endTime/:alarm/:pointId',
-
- // 巡检报告
- patrolReport: 'patrolReport',
-
- // 检查项设定
- checkItems: 'checkItems', // 获取/新增
- updateCheckItems: 'checkItems/{id}',
- delCheckItems: 'checkItems/{ids}',
- checkItemsGroup: 'checkItems/group', // 获取/新增
- delCheckItemsGroup: 'checkItems/group/{id}',
-
// 用户权限
getResource: 'resource',
getUserResource: 'user/resource',
postUserRes: 'user/resource',
- //安全风险预报
- getSiteWeekRegiste: 'sites/report',
- getRiskReportList: 'risk/report',
- modifyRiskReport: 'risk/report/{riskId}',
- riskExport: 'risk/export',
- getEnterprisesMembers: 'enterprises/{enterpriseId}/members',
-
- //工程交底
- getProjectDisclosureList: 'project/disclosure',
- addProjectDisclosure: 'project/disclosure',
- editProjectDisclosure: 'project/disclosure/{id}',
- delProjectDisclosure: 'project/disclosure/{id}',
-
- //安全巡检
- getCheckTask: '/getcheckTask',
- addCheckTask: '/addcheckTask',
- editCheckTask: '/editcheckTask',
- delCheckTask: '/delcheckTask/:id',
- addPatrolRecordIssueHandle: 'patrolRecord/issue/handle',
- modifyPatrolRecordIssueHandle: 'patrolRecord/issue/handle/{id}',
- yujingguanli: '/yujingguanli',
-
- //协调申请
- getCoordinateList: 'risk/coordinate',
- addCoordinate: 'risk/coordinate',
- delCoordinate: 'risk/coordinate/{id}',
- editCoordinate: 'risk/coordinate/{id}',
-
- //会议
- mettingList: 'metting/list',
- editMetting: 'metting',
-
- //隐患整改
- getRectifyList: 'rectify/list',
- addRectify: 'rectify',
- editRectify: 'rectify/{id}',
- delRectify: 'rectify/{id}',
- disposeRectify: 'rectify/dispose',
- rectifyReport: 'rectify/report',
-
- //问题上报
- problemReport: 'report/problem',
- //查阅人员
- problemReportConsult: 'report/problem/consult',
-
- //花名册管理
- getWorkerList: 'get/worker/list',
- addWorker: 'add/worker',
- editWorker: 'worker/{id}',
- delWorker: 'worker/{id}',
- getWorkerIdcards: 'worker/idcards',
- //安全管理
- getTring: 'training/list/:siteid',
- postTring: 'training',
- putTring: 'training',
- delTring: 'training/:id',
-
- //考情信息
- getChcekList: 'get/worker/attendance/list',
- addCheck: 'add/worker/attendance',
- editCheck: 'worker/attendance/:id',
- delCheck: 'worker/attendance/:id',
- verifyWoker: 'verify/worker/exist',
-
- //首页-我的待办
- getDealTodoList: 'user/deal/list',
- addDealTodo: 'user/deal',
-
- //结构物
- getProjectList: 'projectList',
- postAddProject: 'addProject',
- delProject: 'delProject/{id}',
-
- //点位
- position: 'position',
- delPosition: 'delPosition/{id}',
- qrCodeShow: 'qrCodeShow',
- q: 'q',
-
- //视频接入配置
- siteList: 'siteList',
- addCamera: 'camera',
- delCamera: 'camera/{id}',
+ // 标签
+ getLabels: 'label',
+ createLabels: 'label/add',
+ delLabels: 'label/{id}',
- //项目状态配置
- editProjectStatus: 'project/status',
- //工地平面图
- getProjectGraph: 'project/{projectId}/planarGraph',
- createGraph: 'planarGraph/add',
- updateGraph: 'planarGraph/{id}/modify',
- deleteGraph: 'project/graph/{id}',
- getProjectPoints: 'project/{projectId}/all/points',
- getDeployPoints: 'picture/{pictureId}/deploy/points',
- setDeployPoints: 'set/picture/{pictureId}/deploy/points',
+ // 宣传信息配置
+ getPublicityInfo: 'publicityInfo',
+ createPublicityInfo: 'publicityInfo/add',
+ updatePublicityInfo: 'publicityInfo/{id}/modify',
+ delPublicityInfo: 'publicityInfo/{id}/del?qrcodeId={qrcodeId}',
- //设备管理
- getDeviceList: 'device',
- addDevice: 'device',
- modifyDevice: 'device/{id}',
+ // 二维码
+ getQrCode: 'qrcode',
};
export const RouteTable = {
diff --git a/web/package.json b/web/package.json
index f2ee917..5b69bd4 100644
--- a/web/package.json
+++ b/web/package.json
@@ -72,6 +72,7 @@
"ahooks": "^3.7.4",
"ali-oss": "^6.17.1",
"antd": "^4.24.5",
+ "antd-mobile": "^5.34.0",
"antd-theme-generator": "^1.2.8",
"args": "^5.0.1",
"array-move": "^3.0.1",
@@ -94,11 +95,12 @@
"mini-dynamic-antd-theme": "^0.5.3",
"moment": "^2.22.0",
"npm": "^7.20.6",
+ "qr-code-with-logo": "^1.1.0",
"qrcode": "^1.5.1",
"qs": "^6.10.1",
+ "react-color": "^2.19.3",
"react-dnd": "^7",
"react-dnd-html5-backend": "^7",
- "react-color": "^2.19.3",
"react-router-breadcrumbs-hoc": "^4.0.1",
"react-sortable-hoc": "^2.0.0",
"shortid": "^2.2.16",
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 7f421c8..37fb881 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -37,6 +37,7 @@ module.exports = {
module: {
rules: [{
test: /\.css$/,
+ exclude: path.resolve(__dirname, 'node_modules', 'antd-mobile'),
use: ['style-loader', {
loader: 'css-loader',
options: {
@@ -44,6 +45,16 @@ module.exports = {
}
}]
},
+ {
+ test: /\.css$/,
+ include: path.resolve(__dirname, 'node_modules', 'antd-mobile'),
+ use: ['style-loader', {
+ loader: 'css-loader',
+ options: {
+ modules: false
+ }
+ }]
+ },
{
test: /\.less$/,
use: ['style-loader', 'css-loader', {
diff --git a/web/webpack.config.prod.js b/web/webpack.config.prod.js
index af8ef36..3a41abc 100644
--- a/web/webpack.config.prod.js
+++ b/web/webpack.config.prod.js
@@ -46,6 +46,7 @@ module.exports = {
module: {
rules: [{
test: /\.css$/,
+ exclude: path.resolve(__dirname, 'node_modules', 'antd-mobile'),
use: ['style-loader', {
loader: 'css-loader',
options: {
@@ -53,6 +54,16 @@ module.exports = {
}
}]
},
+ {
+ test: /\.css$/,
+ include: path.resolve(__dirname, 'node_modules', 'antd-mobile'),
+ use: ['style-loader', {
+ loader: 'css-loader',
+ options: {
+ modules: false
+ }
+ }]
+ },
{
test: /\.less$/,
use: ['style-loader', 'css-loader',
@@ -68,7 +79,7 @@ module.exports = {
test: /\.jsx?$/,
use: 'babel-loader',
include: [PATHS.app, path.resolve(__dirname, 'node_modules', '@peace')],
- },{
+ }, {
test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
loader: "file-loader"
}]