Browse Source

(*) 小程序码实现

master
liujiangyong 2 years ago
parent
commit
ec97c14091
  1. 17
      api/.vscode/launch.json
  2. 73
      api/app/lib/controllers/projectRegime/projectSituation.js
  3. 23
      api/app/lib/middlewares/attachment.js
  4. 27
      api/config.js
  5. 1
      api/package.json
  6. 109
      weapp/package/startInspection/startInspection.js
  7. 22
      weapp/package/startInspection/startInspection.wxml
  8. 4
      weapp/package/startInspection/startInspection.wxss
  9. 18
      weapp/pages/login/login.js
  10. 348
      web/client/src/sections/projectRegime/containers/point.js
  11. 52
      web/client/src/sections/projectRegime/containers/qrCode.js

17
api/.vscode/launch.json

@ -15,18 +15,25 @@
"args": [ "args": [
"-p 4900", "-p 4900",
// //
"-g postgres://postgres:123456@10.8.30.166:5432/XunJian", "-g postgres://postgres:123456@10.8.16.184:5432/XunJian",
// //
// "--apiEmisUrl http://10.8.30.161:1111", // "--apiEmisUrl http://10.8.30.161:1111",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5", // "--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa", // "--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-hr", // "--qnbkt dev-hr",
// "--qndmn http://resources.anxinyun.cn", // "--qndmn http://resources.anxinyun.cn",
"--qndmn http://rjkwed13l.hn-bkt.clouddn.com", // "--qndmn http://rjkwed13l.hn-bkt.clouddn.com",
"--qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu",
"--qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5",
"--qnbkt anxinyun-test",
"--qndmn http://test.resources.anxinyun.cn",
"--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw", "--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw",
"--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv", "--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv",
"--aliOssBucket test-c371", "--aliOssBucket test-c371",
"--aliOssRegion oss-cn-hangzhou", "--aliOssRegion oss-cn-hangzhou",
"--wxDomain https://api.weixin.qq.com",
"--wxAppId wxdd82ae635b22ccdb",
"--wxAppSecret 08e3d4ea9484cd7837d171e7af7c7db8",
] ]
}, },
{ {

73
api/app/lib/controllers/projectRegime/projectSituation.js

@ -1,7 +1,9 @@
'use strict'; 'use strict';
const request = require('superagent');
const fs = require('fs');
const path = require('path');
async function projectList(ctx, next) {
async function projectList (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -48,7 +50,7 @@ async function projectList (ctx, next) {
} }
async function postAddProject (ctx, next) { async function postAddProject(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -89,7 +91,7 @@ async function postAddProject (ctx, next) {
} }
} }
async function delProject (ctx, next) { async function delProject(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -152,12 +154,17 @@ async function delProject (ctx, next) {
} }
} }
async function addPosition (ctx, next) { let wxAccessToken = {
access_token: null,
time: null
}
async function addPosition(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
const data = ctx.request.body; const data = ctx.request.body;
const { longitude, latitude, name, describe, qrCode, projectId, } = data const { longitude, latitude, name, describe, qrCode, projectId, } = data;
let errMsg = data.id ? '点位编辑失败' : '点位新增失败' let errMsg = data.id ? '点位编辑失败' : '点位新增失败'
let pointData = { longitude, latitude, name, describe, qrCode, projectId } let pointData = { longitude, latitude, name, describe, qrCode, projectId }
@ -170,11 +177,44 @@ async function addPosition (ctx, next) {
if (data && data.id) { if (data && data.id) {
if (qrCode) { if (qrCode) {
await models.Point.update({ ...alikeProject, qrCode }, { const { domain, appId, appSecret } = ctx.app.fs.opts.wx;
where: { // 获取小程序AccessToken, 两小时过期
id: data.id, if (!wxAccessToken.access_token || new Date().getTime() - wxAccessToken.time >= 7200000) {
const wxAccessTokenRes = await request.get(`${domain}/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`);
if (wxAccessTokenRes.body.access_token) {
wxAccessToken.access_token = wxAccessTokenRes.body.access_token;
wxAccessToken.time = new Date().getTime();
} else {
throw '请求微信AccessToken失败';
} }
}) }
// 获取小程序码
const QRCodeRes = await request.post(
`${domain}/wxa/getwxacodeunlimit?access_token=${wxAccessToken.access_token}`,
{
"page": "package/startInspection/startInspection",
"scene": data.id
}
);
if (QRCodeRes.ok) {
const pathname = path.join(__dirname, `${alikeProject.name}.jpeg`);
// 写入临时文件
fs.writeFileSync(pathname, QRCodeRes.body, async function (err) {
if (err) {
throw err;
}
});
const fileInfo = await ctx.app.fs.attachment.upload(pathname, { uploadPath: 'project' });
fs.unlinkSync(pathname); // 删除临时文件
let fkey = fileInfo.key;
await models.Point.update({ ...alikeProject, qrCode: fkey }, {
where: {
id: data.id,
}
})
} else {
throw '生成二维码失败'
}
} else { } else {
await models.Point.update({ pointData }, { await models.Point.update({ pointData }, {
where: { where: {
@ -187,18 +227,17 @@ async function addPosition (ctx, next) {
await models.Point.create(pointData) await models.Point.create(pointData)
} }
ctx.status = 204; ctx.status = 204;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
"message": errMsg message: error.message
} }
} }
} }
async function position (ctx, next) { async function position(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -231,7 +270,7 @@ async function position (ctx, next) {
} }
} }
async function delPosition (ctx, next) { async function delPosition(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -279,7 +318,7 @@ async function delPosition (ctx, next) {
userId: u.dataValues.userId, userId: u.dataValues.userId,
patrolCount: u.dataValues.patrolCount patrolCount: u.dataValues.patrolCount
} }
await models.PatrolPlan.update(data,{ await models.PatrolPlan.update(data, {
where: { where: {
id: u.dataValues.id id: u.dataValues.id
} }
@ -313,7 +352,7 @@ async function delPosition (ctx, next) {
} }
async function qrCodeShow (ctx, next) { async function qrCodeShow(ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -344,7 +383,7 @@ async function qrCodeShow (ctx, next) {
} }
async function q (ctx) { async function q(ctx) {
// let error = { // let error = {
// name: 'FindError', // name: 'FindError',
// message: "获取失败!" // message: "获取失败!"

23
api/app/lib/middlewares/attachment.js

@ -0,0 +1,23 @@
/**
* Created by PengLing on 2018/1/2.
*/
'use strict';
const Attachment = require('fs-attachment');
module.exports = {
entry: function (app, router, opts) {
const attachment = new Attachment(opts);
app.fs = app.fs || {};
app.fs.attachment = attachment;
app.fs.logger.log('debug', 'init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)');
return async (ctx, next) => {
ctx.fs = ctx.fs || {};
ctx.fs.attachment = attachment;
await next();
};
}
};

27
api/config.js

@ -20,6 +20,9 @@ args.option('aliOssAccessKey', '阿里OSS AccessKey');
args.option('aliOssSecretKey', '阿里OSS SecretKey'); args.option('aliOssSecretKey', '阿里OSS SecretKey');
args.option('aliOssBucket', '阿里OSS Bucket'); args.option('aliOssBucket', '阿里OSS Bucket');
args.option('aliOssRegion', '阿里OSS Region'); args.option('aliOssRegion', '阿里OSS Region');
args.option('wxDomain', '微信API Domain');
args.option('wxAppId', '微信小程序appid');
args.option('wxAppSecret', '微信小程序AppSecret');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
@ -37,8 +40,13 @@ const ALI_OSS_SECRETKET = process.env.ALI_OSS_SECRETKET || flags.aliOssSecretKey
const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket; const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket;
const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion; const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion;
// 微信小程序参数
const WX_DOMAIN = process.env.WX_DOMAIN || flags.wxDomain;
const WX_APP_ID = process.env.WX_APP_ID || flags.wxAppId;
const WX_APP_SECRET = process.env.WX_APP_SECRET || flags.wxAppSecret;
if (!XUNJIAN_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK) {
if (!XUNJIAN_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK || !WX_DOMAIN || !WX_APP_ID || !WX_APP_SECRET) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
process.exit(-1); process.exit(-1);
@ -59,6 +67,18 @@ const product = {
}, },
maxSize: 104857600, // 100M maxSize: 104857600, // 100M
} }
}, {
entry: require('./app/lib/middlewares/attachment').entry,
opts: {
qiniu: {
accessKey: QINIU_AK,
secretKey: QINIU_SK,
bucket: QINIU_BUCKET_RESOURCE,
domain: QINIU_DOMAIN_QNDMN_RESOURCE
},
maxSize: 104857600, // 100M
// uploadPath: 'other'
}
}, { }, {
entry: require('./app').entry, entry: require('./app').entry,
opts: { opts: {
@ -93,6 +113,11 @@ const product = {
password: 'Fs2689' password: 'Fs2689'
} }
}, },
wx: {
domain: WX_DOMAIN,
appId: WX_APP_ID,
appSecret: WX_APP_SECRET
}
} }
} }
], ],

1
api/package.json

@ -21,6 +21,7 @@
"clickhouse": "^2.6.0", "clickhouse": "^2.6.0",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"fs-attachment": "^1.0.0",
"fs-web-server-scaffold": "^2.0.2", "fs-web-server-scaffold": "^2.0.2",
"ioredis": "^5.0.4", "ioredis": "^5.0.4",
"kafka-node": "^2.2.3", "kafka-node": "^2.2.3",

109
weapp/package/startInspection/startInspection.js

@ -1,6 +1,12 @@
// package/startInspection/startInspection.js // package/startInspectiocurPlann/startInspection.js
import { addPatrolRecord, getPatrolRecord } from "../../utils/getApiUrl"; import {
import { Request } from "../../common"; addPatrolRecord,
getPatrolRecord,
getPatrolPlan
} from "../../utils/getApiUrl";
import {
Request
} from "../../common";
const moment = require("../../utils/moment"); const moment = require("../../utils/moment");
Page({ Page({
@ -9,6 +15,9 @@ Page({
* 页面的初始数据 * 页面的初始数据
*/ */
data: { data: {
scenePointId: null,
planList: null,
index: null,
dataList: '', dataList: '',
imgs: [], //上传图片 imgs: [], //上传图片
imgUrl: getApp().globalData.imgUrl, imgUrl: getApp().globalData.imgUrl,
@ -19,6 +28,23 @@ Page({
address: '', //当前位置 address: '', //当前位置
}, },
bindPickerChange: function (e) {
this.setData({
index: e.detail.value
})
const curPlan = this.data.planList[e.detail.value];
let points = curPlan.points.map(e => {
return e.name
}).join('、')
this.setData({
dataList: curPlan,
points,
showModal: true,
itemData: curPlan.points.find(p => p.id == this.data.scenePointId)
})
this.getPatrolRecord();
},
handleChangeTwo(e) { handleChangeTwo(e) {
this.setData({ this.setData({
changeTwo: e.detail.value changeTwo: e.detail.value
@ -137,7 +163,7 @@ Page({
data.i = i; data.i = i;
data.success = success; data.success = success;
data.fail = fail; data.fail = fail;
that.uploadimg(data);//递归,回调自己 that.uploadimg(data); //递归,回调自己
} }
} }
}); });
@ -176,7 +202,16 @@ Page({
// 开始巡检录入 // 开始巡检录入
addPatrolRecord: function () { addPatrolRecord: function () {
let that = this; let that = this;
let { itemData, imgs, msgInp, changeTwo, changeThree, dataList, imgUrl, address } = that.data; let {
itemData,
imgs,
msgInp,
changeTwo,
changeThree,
dataList,
imgUrl,
address
} = that.data;
let newImgs = imgs.map(i => { let newImgs = imgs.map(i => {
i = i.replace(imgUrl, ''); i = i.replace(imgUrl, '');
return i; return i;
@ -302,7 +337,7 @@ Page({
return ""; return "";
} }
var i = val.indexOf('.'); var i = val.indexOf('.');
var strDu = i < 0 ? val : val.substring(0, i);//获取度 var strDu = i < 0 ? val : val.substring(0, i); //获取度
var strFen = 0; var strFen = 0;
var strMiao = 0; var strMiao = 0;
if (i > 0) { if (i > 0) {
@ -311,11 +346,11 @@ Page({
i = strFen.indexOf('.'); i = strFen.indexOf('.');
if (i > 0) { if (i > 0) {
strMiao = "0" + strFen.substring(i); strMiao = "0" + strFen.substring(i);
strFen = strFen.substring(0, i);//获取分 strFen = strFen.substring(0, i); //获取分
strMiao = strMiao * 60 + ""; strMiao = strMiao * 60 + "";
i = strMiao.indexOf('.'); i = strMiao.indexOf('.');
strMiao = strMiao.substring(0, i + 4);//取到小数点后面三位 strMiao = strMiao.substring(0, i + 4); //取到小数点后面三位
strMiao = parseFloat(strMiao).toFixed(2);//精确小数点后面两位 strMiao = parseFloat(strMiao).toFixed(2); //精确小数点后面两位
} }
} }
return strDu + "°" + strFen + "′" + strMiao + "″"; return strDu + "°" + strFen + "′" + strMiao + "″";
@ -354,20 +389,58 @@ Page({
}); });
}, },
// 获取巡检计划
getPatrolPlan: function (scenePointId) {
let that = this;
wx.showLoading({
title: '加载中',
})
Request.get(getPatrolPlan(), {}).then(res => {
wx.hideLoading();
const pointPlan = res.rows.filter(plan => {
for (const point of plan.points) {
if (point.id == scenePointId) {
return true;
}
}
return false;
})
that.setData({
planList: pointPlan
})
})
},
/** /**
* 生命周期函数--监听页面加载 * 生命周期函数--监听页面加载
*/ */
onLoad(options) { onLoad(options) {
let that = this; let that = this;
let data = JSON.parse(decodeURIComponent(options.data)); const scenePointId = options.scene;
let points = data.points.map(e => { if (scenePointId) { // 扫小程序码进入
return e.name const userInfo = wx.getStorageSync('userInfo');
}).join('、') if (!userInfo || !userInfo.id) { // 如果没登录,先登录
that.setData({ wx.showToast({ title: '请先登录' })
dataList: data, wx.reLaunch({
points url: `/pages/login/login?scene=${scenePointId}`
}) });
that.getPatrolRecord(); return;
}
that.setData({
scenePointId
})
that.getPatrolPlan(scenePointId);
} else { // 正常点击进入
let data = JSON.parse(decodeURIComponent(options.data));
let points = data.points.map(e => {
return e.name
}).join('、')
that.setData({
dataList: data,
points
})
that.getPatrolRecord();
}
}, },
/** /**

22
weapp/package/startInspection/startInspection.wxml

@ -1,5 +1,13 @@
<!--package/startInspection/startInspection.wxml--> <!-- package/startInspection/startInspection.wxml -->
<view class="box"> <view class="box">
<view wx:if="{{planList}}">
<picker bindchange="bindPickerChange" value="{{index}}" range="{{planList}}" range-key="name">
<view class="picker" style="{{index===null ? 'color:red' : 'color:black'}}">
{{index===null ? '请选择巡检计划:' : '巡检计划:'}}{{planList[index].name}}
</view>
</picker>
<view class="line"></view>
</view>
<view class="titleFirst">巡检要求</view> <view class="titleFirst">巡检要求</view>
<view class="txt"> <view class="txt">
<view style="float: left;font-weight: bold;">结构物名称</view> <view style="float: left;font-weight: bold;">结构物名称</view>
@ -56,7 +64,6 @@
</view> </view>
</view> </view>
</block> </block>
<!-- 开始巡检弹框 --> <!-- 开始巡检弹框 -->
<view class="modal" wx:if="{{showModal}}"> <view class="modal" wx:if="{{showModal}}">
<view class="popBox"> <view class="popBox">
@ -66,8 +73,12 @@
</view> </view>
<view style="padding:20rpx 30rpx;overflow: hidden;"> <view style="padding:20rpx 30rpx;overflow: hidden;">
<view style="float: left;">当前位置:</view> <view style="float: left;">当前位置:</view>
<view style="float:left;width:480rpx;text-align: justify;" wx:if="{{address}}">{{address}}</view> <view style="float:left;width:480rpx;text-align: justify;" wx:if="{{address}}">
<view style="float:left;width:480rpx;text-align: justify;" bindtap="selfLocation" wx:if="{{!address}}">点击获取当前位置</view> {{address}}
</view>
<view style="float:left;width:480rpx;text-align: justify;" bindtap="selfLocation" wx:if="{{!address}}">
点击获取当前位置
</view>
</view> </view>
<radio-group style="padding:10px 15px;display:flex;justify-content: space-evenly;" bindchange="handleChangeTwo"> <radio-group style="padding:10px 15px;display:flex;justify-content: space-evenly;" bindchange="handleChangeTwo">
<radio style="color:#1979ff;" color="#1979ff" value="normal">正常</radio> <radio style="color:#1979ff;" color="#1979ff" value="normal">正常</radio>
@ -79,7 +90,6 @@
<radio style="color:#FF3300;" color="#FF3300" value="moderate">中度</radio> <radio style="color:#FF3300;" color="#FF3300" value="moderate">中度</radio>
<radio style="color:#990000;" color="#990000" value="severity">严重</radio> <radio style="color:#990000;" color="#990000" value="severity">严重</radio>
</radio-group> </radio-group>
<view class="weui-uploader" style="padding: 20rpx 30rpx;height:350rpx;overflow-y:scroll;" wx:if="{{changeTwo == 'abnormal'}}"> <view class="weui-uploader" style="padding: 20rpx 30rpx;height:350rpx;overflow-y:scroll;" wx:if="{{changeTwo == 'abnormal'}}">
<view class="img-v weui-uploader__bd" style="overflow:hidden;"> <view class="img-v weui-uploader__bd" style="overflow:hidden;">
<view class='pic' wx:for="{{imgs}}" wx:for-item="item" wx:key="*this"> <view class='pic' wx:for="{{imgs}}" wx:for-item="item" wx:key="*this">
@ -93,12 +103,10 @@
</view> </view>
</view> </view>
</view> </view>
<view class="btnBox"> <view class="btnBox">
<view class="cancel" bindtap="bindCancel">取消</view> <view class="cancel" bindtap="bindCancel">取消</view>
<view class="submit" bindtap="addPatrolRecord">提交</view> <view class="submit" bindtap="addPatrolRecord">提交</view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>

4
weapp/package/startInspection/startInspection.wxss

@ -5,6 +5,10 @@
padding: 30rpx 0; padding: 30rpx 0;
} }
.picker {
margin-bottom: 40rpx;
}
.titleFirst { .titleFirst {
font-size: 32rpx; font-size: 32rpx;
margin-bottom: 30rpx; margin-bottom: 30rpx;

18
weapp/pages/login/login.js

@ -8,7 +8,7 @@ Page({
* 页面的初始数据 * 页面的初始数据
*/ */
data: { data: {
scene: null,
}, },
// 登录 // 登录
@ -32,10 +32,16 @@ Page({
wx.setStorageSync('token', res.token); wx.setStorageSync('token', res.token);
wx.setStorageSync("userInfo", res); wx.setStorageSync("userInfo", res);
getApp().globalData.userInfo = res getApp().globalData.userInfo = res
wx.hideLoading()
if (this.data.scene) {
wx.redirectTo({
url: `/package/startInspection/startInspection?scene=${this.data.scene}`,
})
return;
}
wx.switchTab({ wx.switchTab({
url: '/pages/index/index', url: '/pages/index/index',
}) })
wx.hideLoading()
}) })
}, },
@ -66,7 +72,13 @@ Page({
* 生命周期函数--监听页面加载 * 生命周期函数--监听页面加载
*/ */
onLoad(options) { onLoad(options) {
let that = this;
const { scene } = options;
if (scene) {
that.setData({
scene
})
}
}, },
/** /**

348
web/client/src/sections/projectRegime/containers/point.js

@ -1,34 +1,22 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Spin, Card, Form, Input, Select, Button, Table, Modal, Popconfirm, Tooltip } from 'antd'; import { Button, Table, Popconfirm } from 'antd';
const { TextArea } = Input;
import moment from "moment";
import '../style.less'; import '../style.less';
import { push } from 'react-router-redux';
import PointModel from '../components/pointModel' import PointModel from '../components/pointModel'
import { Model } from 'qrcode';
const Information = (props) => { const Information = (props) => {
const { dispatch, actions, user, loading } = props const { dispatch, actions } = props
const { projectRegime } = actions const { projectRegime } = actions
const [firmList, setFirmList] = useState([])
const [tableList, settableList] = useState([]) const [tableList, settableList] = useState([])
const [addModel, setAddModel] = useState(false) const [addModel, setAddModel] = useState(false)
const [modelData, setModelData] = useState({}) const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 }) const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState() const [limits, setLimits] = useState()
const [search, setSearch] = useState({}) const [search, setSearch] = useState({})
const [isPicture, setIsPicture] = useState(false)
const [pictureUrl, setPictureUrl] = useState()
const [companyID, setCompanyId] = useState('') const [companyID, setCompanyId] = useState('')
const [select, setSelect] = useState([]) const [select, setSelect] = useState([])
const [selec, setSelec] = useState() const [selec, setSelec] = useState()
const [form] = Form.useForm(); const [qrCodeingIds, setQrCodeingIds] = useState(null)
var QRCode = require('qrcode')
const { createCanvas, loadImage, registerFont } = require('canvas')
const qrCodeId = props?.match?.params?.id const qrCodeId = props?.match?.params?.id
@ -53,213 +41,143 @@ const Information = (props) => {
}) })
} }
const createQrCode = (name) => { const columns = [
let url = '' {
QRCode.toDataURL(name, { title: '序号',
errorCorrectionLevel: 'low', dataIndex: 'index',
type: 'image/png', key: 'index',
quality: 0.3, render: (text, record, index) => index + 1
margin: 2, }, {
maskPattern: 9, title: '点位名称',
width: 400, dataIndex: 'name',
color: { key: 'name',
dark: "#000000ff", }, {
light: "#ffffffff" title: '所在地区',
dataIndex: 'position',
key: 'position',
render: (text, record, index) => {
return record.longitude && record.latitude ? <div style={{ width: 100 }}>{record.longitude},{record.latitude}</div> : "--"
} }
}, function (err, v) { }, {
url = v title: '描述',
}) dataIndex: 'describe',
return url key: 'describe',
} render: (text, record, index) => record.describe || '--'
}, {
// const createQrCode = (name) => { title: '操作',
// const CW = 400, FONTSIZE = 30, FR = 2, CH = CW + FONTSIZE * FR; dataIndex: 'operation',
// let url = '' key: 'operation',
// // QRCode.toFile('F',name, render: (text, record, index) => {
// // { return (
// // margin: 1,//二维码内边距,默认为4。单位px <>
// // height: CW,//二维码高度 <Button type="link" onClick={() => {
// // width: CW,//二维码宽度 setAddModel(true)
// // color: { setModelData(record)
// // dark: '#000', // }}>编辑</Button>
// // light: '#fff' // <Popconfirm
// // } title={<div style={{ width: 184 }}>删除该点位后与巡检计划关联的点位删除对应的巡检记录删除是否确认删除</div>}
// // }); position='topLeft'
onConfirm={() => {
// QRCode.toDataURL(name, { dispatch(projectRegime.delPosition(record.id)).then(res => {
// errorCorrectionLevel: 'low', if (res.success) {
// type: 'image/png', if ((limits > 11 && tableList.length > 1) || limits < 11) {
// quality: 0.3, projectList({ ...query, ...search })
// margin: 2, } else {
// maskPattern: 9, projectList({ limit: query?.limit, page: query?.page - 1, ...search })
// width: 400, setQuery({ limit: query?.limit, page: query?.page - 1 });
// color: { }
// dark: "#000000ff",
// light: "#ffffffff"
// }
// }, function (err, v) {
// url = v
// })
// // return url
// const canvas = createCanvas(CW, CH)
// const ctx = canvas.getContext('2d')
// ctx.clearRect(0, 0, CW, CH)
// ctx.fillStyle = 'rgba(255,255,255,1)'
// ctx.fillRect(0, 0, CW, CH)
// ctx.fillStyle = 'rgba(0,0,0,1)'
// ctx.font = `${FONTSIZE}px ZiTiQuanWeiJunHei`
// // ctx.font = `700 ${FONTSIZE}px `
// let image = loadImage(url)
// ctx.drawImage(image, 0, 0, CW, CW)
// const text = ctx.measureText(name)
// ctx.fillText(name, (CW - text.width) * 0.5, CH - FONTSIZE)
// canvas.toDataURL('image/png', (err, png) => {
// if (!err) {
// console.log(png);
// }
// })
// return url
// }
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (text, record, index) => index + 1
}, {
title: '点位名称',
dataIndex: 'name',
key: 'name',
}, {
title: '所在地区',
dataIndex: 'position',
key: 'position',
render: (text, record, index) => {
return record.longitude && record.latitude ? <div style={{ width: 100 }}>{record.longitude},{record.latitude}</div> : "--"
}
}, {
title: '描述',
dataIndex: 'describe',
key: 'describe',
render: (text, record, index) => record.describe || '--'
}, {
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
return (
<div style={{ width: 224 }}>
<Button type="link" onClick={() => {
setAddModel(true)
setModelData(record)
console.log(record);
}}
>编辑</Button>
<Popconfirm
title={<div style={{ width: 184 }}>删除该点位后与巡检计划关联的点位删除对应的巡检记录删除是否确认删除</div>}
position='topLeft'
onConfirm={() => {
dispatch(projectRegime.delPosition(record.id)).then(res => {
if (res.success) {
if ((limits > 11 && tableList.length > 1) || limits < 11) {
projectList({ ...query, ...search })
} else {
projectList({ limit: query?.limit, page: query?.page - 1, ...search })
setQuery({ limit: query?.limit, page: query?.page - 1 });
} }
})
}}
>
<Button type="link" danger >删除</Button>
</Popconfirm>
<Button type="link" onClick={() => {
setQrCodeingIds([record.id])
dispatch(projectRegime.addPosition({
qrCode: true,
id: record.id,
}, true)).then(() => {
setQrCodeingIds(null)
})
}} loading={qrCodeingIds?.includes(record.id)}>二维码生成</Button>
</>
)
}
}
]
return (
<>
<img src={selec} />
<div style={{ display: 'flex', marginBottom: 10 }}>
<Button type="primary" onClick={() => {
setAddModel(true)
}}>新建点位</Button>
<Button type="primary" style={{ marginLeft: 20 }} onClick={() => {
if (select.length) {
setQrCodeingIds(select.map(s => s.id));
select?.map((v, i) => {
dispatch(projectRegime.addPosition({
qrCode: true,
id: v.id,
}, true)).then(() => {
if (i === select.length - 1) {
setQrCodeingIds(null);
} }
}) })
})
}
}} disabled={qrCodeingIds?.length}>一键生成二维码</Button>
</div>
<Table
columns={columns}
dataSource={tableList}
pagination={{
current: query.page + 1,
total: limits,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span>
},
onChange: (page, pageSize) => {
setQuery({ limit: pageSize, page: page - 1 });
projectList({ limit: pageSize, page: page - 1, ...search, companyId: companyID || search?.companyId })
}
}}
rowSelection={{
selectedRowKeys: select?.map(v => v.id) || [],
onChange: (selectedRowKeys, selectedRows) => {
setSelect(selectedRows)
console.log(selectedRows);
}
}}
/>
{
addModel ?
<PointModel
modelData={modelData}
qrCodeId={qrCodeId}
close={() => {
setAddModel(false)
setModelData({})
}} }}
> success={() => {
<Button type="link" danger >删除</Button> setAddModel(false)
</Popconfirm> setModelData({})
{/* <Button type="link" danger >二维码生成</Button> */} setQuery({ limit: 10, page: 0 });
<Button type="link" onClick={() => { projectList({ limit: 10, page: 0 })
let url = createQrCode('FS' + Date.now() + record.id) }}
console.log(url); /> : ""
dispatch(projectRegime.addPosition({ }
qrCode: url, </>
id: record.id, )
}, true))
}} >二维码生成</Button>
</div>
)
}
}
]
return (
<>
<img src={selec} />
<div style={{ display: 'flex', marginBottom: 10 }}>
<Button type="primary" onClick={() => {
setAddModel(true)
}}>新建点位</Button>
<Button type="primary" style={{ marginLeft: 20 }} onClick={() => {
select?.map(v => {
let url = createQrCode('FS' + Date.now() + v.id)
console.log(url);
dispatch(projectRegime.addPosition({
qrCode: url,
id: v.id,
}, true))
})
}}>一键生成二维码</Button>
</div>
<Table
columns={columns}
dataSource={tableList}
pagination={{
current: query.page + 1,
total: limits,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span>
},
onChange: (page, pageSize) => {
setQuery({ limit: pageSize, page: page - 1 });
projectList({ limit: pageSize, page: page - 1, ...search, companyId: companyID || search?.companyId })
}
}}
rowSelection={{
selectedRowKeys: select?.map(v => v.id) || [],
onChange: (selectedRowKeys, selectedRows) => {
setSelect(selectedRows)
console.log(selectedRows);
}
}}
/>
{
addModel ?
<PointModel
modelData={modelData}
qrCodeId={qrCodeId}
close={() => {
setAddModel(false)
setModelData({})
}}
success={() => {
setAddModel(false)
setModelData({})
setQuery({ limit: 10, page: 0 });
projectList({ limit: 10, page: 0 })
}}
/> : ""
}
</>
)
} }
function mapStateToProps (state) { function mapStateToProps(state) {
const { auth, global } = state; const { auth, global } = state;
return { return {
user: auth.user, user: auth.user,

52
web/client/src/sections/projectRegime/containers/qrCode.js

@ -1,31 +1,13 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Spin, Card, Form, Input, Select, Button, Table, Modal, Popconfirm, Tooltip } from 'antd'; import { Form, Input, Select, Button } from 'antd';
import moment from "moment";
import '../style.less'; import '../style.less';
import ProjectAddModel from '../components/projectAddModel'
import QRCode from 'qrcode';
import { login } from '../../auth/actions/auth';
import { createCanvas, loadImage, registerFont } from 'canvas'
import { dataURItoBlob } from 'react-jsonschema-form/lib/utils';
const QrCode = (props) => { const QrCode = (props) => {
const { dispatch, actions, user, loading } = props const { dispatch, actions } = props
const { projectRegime } = actions const { projectRegime } = actions
const [firmList, setFirmList] = useState([]) const [firmList, setFirmList] = useState([])
const [tableList, settableList] = useState([]) const [tableList, settableList] = useState([])
const [addModel, setAddModel] = useState(false)
const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState()
const [search, setSearch] = useState({})
const [isPicture, setIsPicture] = useState(false)
const [pictureUrl, setPictureUrl] = useState()
const [companyID, setCompanyId] = useState('')
useEffect(() => { useEffect(() => {
dispatch(projectRegime.getProjectList({ justStructure: true })).then(res => { dispatch(projectRegime.getProjectList({ justStructure: true })).then(res => {
@ -34,8 +16,6 @@ const QrCode = (props) => {
} }
}) })
projectList({}) projectList({})
// dispatch(projectRegime.q())
}, []) }, [])
const projectList = (obj) => { const projectList = (obj) => {
@ -89,24 +69,22 @@ const QrCode = (props) => {
<span>结构物名称{firmList?.filter(u => u.value == v.projectId)[0]?.label}</span> <span>结构物名称{firmList?.filter(u => u.value == v.projectId)[0]?.label}</span>
<span>点位名称{v.name}</span> <span>点位名称{v.name}</span>
</div> </div>
<img src={v.qrCode} style={{ display: 'inline-block', width: 260 }} /> <img src={`/_file-server/${v.qrCode}`} style={{ display: 'inline-block', width: 260 }} />
<div style={{ <div style={{
width: 260, height: 60, background: '#e1d4d42e', display: 'flex', width: 260, height: 60, background: '#e1d4d42e', display: 'flex',
justifyContent: 'center', alignItems: 'center', borderTop: '1px solid #3c383824' justifyContent: 'center', alignItems: 'center', borderTop: '1px solid #3c383824'
}}> }}>
<a href={`${v.qrCode}.png`}> <Button type="primary" onClick={() => {
<Button type="primary" onClick={() => { const a = document.createElement('a')
const filenameArr = v.qrCode.split('/')
const a = document.createElement('a') const filename = filenameArr[filenameArr.length - 1]
const filename = firmList?.filter(u => u.value == v.projectId)[0]?.label + '(' + v.name + ')' a.href = `/_file-server/${v.qrCode}`
a.href = v.qrCode // picSrc 是图片 base64 码,可以直接给 img 的 src 属性,展示图片 a.download = filename
a.download = filename a.target = '_blank'
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
document.body.removeChild(a) document.body.removeChild(a)
}}>下载二维码</Button> }}>下载二维码</Button>
</a>
</div> </div>
</div> </div>
} }
@ -118,7 +96,7 @@ const QrCode = (props) => {
) )
} }
function mapStateToProps (state) { function mapStateToProps(state) {
const { auth, global } = state; const { auth, global } = state;
return { return {
user: auth.user, user: auth.user,

Loading…
Cancel
Save