1
0
Code Issues Pull Requests Packages Projects Releases Wiki Activity GitHub Gitee

Merge branch 'miniprogram' into backend

This commit is contained in:
程序员小墨 2022-11-27 21:02:04 +08:00
commit 0fd28a2150
23 changed files with 721 additions and 300 deletions

View File

@ -119,10 +119,10 @@
> # 您会看到以;分隔的很多路径,其中应该包括: > # 您会看到以;分隔的很多路径,其中应该包括:
> # JDK 所在文件夹下的 bin 目录:...\openjdk-11\bin > # JDK 所在文件夹下的 bin 目录:...\openjdk-11\bin
> # Maven 所在文件夹下的 bin 目录:...\apache-maven-3.6.3\bin > # Maven 所在文件夹下的 bin 目录:...\apache-maven-3.6.3\bin
> >
> echo %JAVA_HOME% > echo %JAVA_HOME%
> # 您会看到 JDK 所在文件夹 > # 您会看到 JDK 所在文件夹
> >
> echo %MAVEN_HOME% > echo %MAVEN_HOME%
> # 您会看到 Maven 所在文件夹 > # 您会看到 Maven 所在文件夹
> ``` > ```
@ -134,19 +134,19 @@
> git --version > git --version
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
> # git version 2.35.1.windows.2 > # git version 2.35.1.windows.2
> >
> # 查看 MySQL 版本(如果 MySQL 的 bin 目录没有配在环境变量中,则需要先 cd 切换到 bin 目录下) > # 查看 MySQL 版本(如果 MySQL 的 bin 目录没有配在环境变量中,则需要先 cd 切换到 bin 目录下)
> mysql --version > mysql --version
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
> # mysql Ver 8.0.12 for Win64 on x86_64 (MySQL Community Server - GPL) > # mysql Ver 8.0.12 for Win64 on x86_64 (MySQL Community Server - GPL)
> >
> # 查看 JDK 版本 > # 查看 JDK 版本
> java -version > java -version
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
> # openjdk version "11" 2018-09-25 > # openjdk version "11" 2018-09-25
> # OpenJDK Runtime Environment 18.9 (build 11+28) > # OpenJDK Runtime Environment 18.9 (build 11+28)
> # OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode) > # OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
> >
> # 查看 Maven 版本 > # 查看 Maven 版本
> mvn -v > mvn -v
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
@ -155,12 +155,12 @@
> # Java version: 11, vendor: Oracle Corporation, runtime: xxxxxx\openjdk-11 > # Java version: 11, vendor: Oracle Corporation, runtime: xxxxxx\openjdk-11
> # Default locale: zh_CN, platform encoding: GBK > # Default locale: zh_CN, platform encoding: GBK
> # OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows" > # OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
> >
> # 查看 node 版本 > # 查看 node 版本
> node -v > node -v
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
> # v14.18.0 > # v14.18.0
> >
> # 查看 npm 版本 > # 查看 npm 版本
> # 您应该看到类似如下输出👇 > # 您应该看到类似如下输出👇
> # 8.19.2 > # 8.19.2
@ -215,7 +215,7 @@
> npm config get registry > npm config get registry
> ``` > ```
> >
> >
@ -283,7 +283,7 @@ cd ../
##### 配置业务域名 ##### 配置业务域名
修改 `miniprogram/src/app.js` 文件 1.修改 `miniprogram/src/app.js` 文件
```javascript ```javascript
App.use(setGlobalDataPlugin, { App.use(setGlobalDataPlugin, {
@ -293,7 +293,13 @@ App.use(setGlobalDataPlugin, {
}) })
``` ```
同时记得在小程序后台填写小程序的业务域名。 2.配置服务域名
- 小程序:在[微信小程序后台](https://mp.weixin.qq.com/) - 左侧最下方**开发** - **开发管理** - 右侧上方**开发设置** - **服务器域名** 添加 `https://` 开头的**request合法域名**
- 小程序测试号:在[微信小程序后台](https://mp.weixin.qq.com/) - **服务器域名** 添加 `https://` 开头的**request合法域名**(注意不是业务域名)
- 支付宝沙箱应用:在[支付宝开放平台](https://open.alipay.com/develop/sandbox/app) - 左侧**沙箱应用** - **服务端域名白名单** 添加 `https://` 开头的**httpRequest接口请求域名白名单**
##### 配置微信小程序appid ##### 配置微信小程序appid

View File

@ -1,19 +1,23 @@
const sleepTime = 0; // 模拟弱网环境等待时间
// 1. 导入http模块 // 1. 导入http模块
const http = require("http"); const http = require("http");
var url = require("url");
// 2. 创建一个web服务器对象 // 2. 创建一个web服务器对象
const server = http.createServer(); const server = http.createServer();
// 3. 监听请求事件 // 3. 监听请求事件
server.on("request", (req, res) => { server.on("request", async (req, res) => {
console.log(new Date(), "req.url", req.url);
//req-->request 请求对象, res-->response 响应对象 //req-->request 请求对象, res-->response 响应对象
// 通过响应头设置返回前台数据格式及编码。(解决中文乱码的问题) // 通过响应头设置返回前台数据格式及编码。(解决中文乱码的问题)
// res.setHeader('Content-Type', 'text/html;charset=utf-8'); // res.setHeader('Content-Type', 'text/html;charset=utf-8');
//res.write()表示向客户端输出的方法 //res.write()表示向客户端输出的方法
// res.write("hello world你好nodejs") // res.write("hello world你好nodejs")
let urlObj = url.parse(req.url, true);
let query = urlObj.query;
res.setHeader('Content-Type', 'text/json;charset=utf-8'); res.setHeader('Content-Type', 'text/json;charset=utf-8');
let result = {}; let result = {};
@ -39,12 +43,32 @@ server.on("request", (req, res) => {
// msg: "用户名或密码不正确", // msg: "用户名或密码不正确",
// data: null // data: null
}; };
} else if (req.url.startsWith('/access/getCodeInfo')) {
result = {
success: true,
msg: "成功",
data: {
id: query.id,
qrcodeColor: "green",
infoText: "绿码 请通行",
infoTextColor: "green",
// qrcodeColor: "red",
// infoText: "红码 禁止通行",
// infoTextColor: "red",
}
// success: false,
// msg: "用户名或密码不正确",
// data: null
};
} else { } else {
result = { result = {
code: 500, success: false,
msg: "服务器内部错误", msg: "服务器内部错误",
data: null,
extra: { extra: {
url: req.url, url: req.url,
query: query,
urlObj: urlObj,
method: req.method, method: req.method,
headers: req.headers, headers: req.headers,
req: Object.keys(req), req: Object.keys(req),
@ -54,8 +78,14 @@ server.on("request", (req, res) => {
} }
res.write(JSON.stringify(result)); res.write(JSON.stringify(result));
// 模拟弱网等待时间
await new Promise((resolve) => {
setTimeout(resolve, sleepTime);
})
//res.end()每次响应完,需要调用此方法 来结束响束 //res.end()每次响应完,需要调用此方法 来结束响束
res.end(); res.end();
console.log(new Date(), "req.url", req.url);
}) })
// 4. 监听端口,为了避免端口冲突,这里给一个本机端口 // 4. 监听端口,为了避免端口冲突,这里给一个本机端口
@ -64,4 +94,5 @@ server.listen(80, () => {
console.log(`服务启动成功: ${baseUrl}/`); console.log(`服务启动成功: ${baseUrl}/`);
console.log(); console.log();
console.log(`${baseUrl}/user/login`); console.log(`${baseUrl}/user/login`);
console.log(`${baseUrl}/access/getCodeInfo`);
})  }) 

View File

@ -8,12 +8,13 @@ const config = {
828: 1.81 / 2 828: 1.81 / 2
}, },
sourceRoot: 'src', sourceRoot: 'src',
outputRoot: 'dist', outputRoot: `dist/${process.env.TARO_ENV}`,
plugins: [], plugins: [],
defineConstants: { defineConstants: {
}, },
copy: { copy: {
patterns: [ patterns: [
{ from: 'src/image/', to: `dist/${process.env.TARO_ENV}/image/`, ignore: ['*.js'] }, // 指定需要 copy 的目录
], ],
options: { options: {
} }

View File

@ -1,5 +1,5 @@
{ {
"enableAppxNg": true, "enableAppxNg": true,
"enableNodeModuleBabelTransform": false, "enableNodeModuleBabelTransform": true,
"miniprogramRoot": "./" "miniprogramRoot": "./"
} }

View File

@ -1,5 +1,5 @@
{ {
"miniprogramRoot": "dist/", "miniprogramRoot": "dist/weapp/",
"projectname": "epp", "projectname": "epp",
"description": "基于微服务的社区疫情防控系统", "description": "基于微服务的社区疫情防控系统",
"appid": "wxa70348746d2b562f", "appid": "wxa70348746d2b562f",
@ -18,7 +18,7 @@
}, },
"compileType": "miniprogram", "compileType": "miniprogram",
"libVersion": "2.27.1", "libVersion": "2.27.1",
"srcMiniprogramRoot": "dist/", "srcMiniprogramRoot": "dist/weapp/",
"packOptions": { "packOptions": {
"ignore": [], "ignore": [],
"include": [] "include": []

View File

@ -7,6 +7,7 @@ export default defineAppConfig({
* 用户侧 * 用户侧
*/ */
'pages/residents/code', // 进出码 'pages/residents/code', // 进出码
'pages/residents/report', // 体温上报
], ],
window: { window: {
backgroundTextStyle: 'dark', backgroundTextStyle: 'dark',
@ -29,25 +30,33 @@ export default defineAppConfig({
"iconPath": "image/icon/_code.png", "iconPath": "image/icon/_code.png",
"selectedIconPath": "image/icon/code.png" "selectedIconPath": "image/icon/code.png"
}, },
// { {
// "pagePath": "pages/report/report", "pagePath": "pages/residents/report",
// "text": "日报", "text": "体温上报",
// "iconPath": "/icon/_report.png", "iconPath": "image/icon/_report.png",
// "selectedIconPath": "/icon/report.png" "selectedIconPath": "image/icon/report.png"
// }, },
// { // {
// "pagePath": "pages/apply/apply", // "pagePath": "pages/apply/apply",
// "text": "申请", // "text": "申请",
// "iconPath": "/icon/_apply.png", // "iconPath": "image/icon/_apply.png",
// "selectedIconPath": "/icon/apply.png" // "selectedIconPath": "image/icon/apply.png"
// }, // },
// { // {
// "pagePath": "pages/person/person", // "pagePath": "pages/person/person",
// "text": "我的", // "text": "我的",
// "selectedColor": "#FF8966", // "selectedColor": "#FF8966",
// "iconPath": "/icon/_person.png", // "iconPath": "image/icon/_person.png",
// "selectedIconPath": "/icon/person.png" // "selectedIconPath": "image/icon/person.png"
// } // }
] ]
}, },
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于体温上报"
}
},
"requiredPrivateInfos": [
"chooseLocation"
]
}) })

View File

@ -0,0 +1,15 @@
/* 右上角小红点 */
.add-dot {
position: relative;
}
.add-dot::after {
content: " ";
position: absolute;
right: -8rpx;
top: -3rpx;
width: 12rpx;
height: 12rpx;
background-color: red;
border-radius: 50%;
}

View File

@ -12,7 +12,7 @@ App.use(setGlobalDataPlugin, {
globalData: { globalData: {
debugMode: true, // 是否展示调试内容 debugMode: true, // 是否展示调试内容
baseUrl: true baseUrl: true
? "http://39.99.244.156:5203" ? "https://epp.only4.work"
: "http://localhost", // 不带最后的 / : "http://localhost", // 不带最后的 /
} }
}) })

View File

@ -1,7 +1,11 @@
<template> <template>
<view v-if="debugMode"> <view v-if="debugMode">
<button @tap='debugCleanCache'>清除缓存</button> <button type="warn" size="mini" @tap='debugCleanCache'>清除缓存</button>
<textarea maxlength="-1" disabled="true" auto-height="true" :value="debugText"></textarea> <view style="border: 3px solid black;">
<input v-model="userRole" style="border: 1px solid grey; display: inline-block; width: 40%;" />
<button style="width: 50%;" type="primary" size="mini" @tap='updateUserRole'>更新role ({{ userGroup }})</button>
</view>
<textarea maxlength="-1" disabled="true" auto-height="true" style="width: 100%" :value="debugText"></textarea>
</view> </view>
</template> </template>
@ -9,25 +13,39 @@
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import { eventCenter, getCurrentInstance } from '@tarojs/taro' import { eventCenter, getCurrentInstance } from '@tarojs/taro'
import ENUM from '../utils/const'
export default { export default {
data() { data() {
return { return {
userInfo: null, userRole: -1,
debugMode: Taro.getApp().globalData.debugMode, debugMode: Taro.getApp().globalData.debugMode,
debugText: "", debugText: "",
} }
}, },
props: {
params: Object,
userGroup: String
},
mounted() { mounted() {
eventCenter.once(getCurrentInstance().router.onShow, () => { eventCenter.once(getCurrentInstance().router.onShow, () => {
this.userInfo = Taro.getStorageSync("userInfo"); this.userRole = Taro.getStorageSync("userInfo").role;
this.displayUsername = this.userInfo?.username ?? "请登录";
const res = Taro.getStorageInfoSync()
let storage = {};
res.keys.forEach(key => storage[key] = Taro.getStorageSync(key))
this.debugText = JSON.stringify({ this.debugText = JSON.stringify({
"TARO_ENV": process.env.TARO_ENV, TARO_ENV: process.env.TARO_ENV,
// "isVisitor": this.isVisitor, globalData: Taro.getApp().globalData,
// "isUser": this.isUser, params: this.params,
// "isAdmin": this.isAdmin, storage: storage,
"userInfo": this.userInfo || 'null' ENUM: ENUM,
}, null, 4) // storageInfo: {
// keys: res.keys,
// currentSize: res.currentSize,
// limitSize: res.limitSize
// },
}, null, 8)
}) })
}, },
methods: { methods: {
@ -43,6 +61,14 @@ export default {
}) })
} }
}) })
},
updateUserRole() {
let userInfo = Taro.getStorageSync("userInfo");
userInfo.role = this.userRole;
Taro.setStorageSync("userInfo", userInfo);
Taro.reLaunch({
url: '/pages/index/index'
})
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -1,3 +1,4 @@
export default definePageConfig({ export default definePageConfig({
navigationBarTitleText: '首页' navigationBarTitleText: '首页',
"navigationStyle": "custom"
}) })

View File

@ -0,0 +1,15 @@
#menu-view {
display: flex;
text-align: center;
flex-wrap: wrap;
}
.menu-item {
width: 25%;
margin-top: 50px;
}
.item-image {
width: 70px;
height: 70px;
}

View File

@ -1,164 +1,97 @@
<template> <template>
<view> <view>
<image src="../../image/home.jpg" style="width: 100%;height: 145px;"></image> <image src="../../image/home.jpg" style="width: 100vw; height: 41.5vw;"></image>
<view style="display: block; padding-left: 30px; padding-top: 12px;"> <view style="display: block; padding-left: 30px; padding-top: 12px;">
<text>欢迎你{{ displayUsername }}</text> <text>欢迎你{{ displayUsername }}</text>
</view> </view>
<view id="menu-view">
<view style="display: block;" v-if="isVisitor"> <view class="menu-item" v-for="menuItem in filterMenuItems" :key="menuItem.id">
<view style="display: flex;text-align: center;margin-top: 20px;"> <view :class="{ 'add-dot': menuItem.addDot }" style="display: inline-block;">
<view style="width: 25%;"> <image :src="'../../image/icon/' + menuItem.image" class="item-image"
<image src="../../image/icon/code.png" style="width: 40px;height: 40px;" @tap='goCode'></image> @tap='switchTo(menuItem.switchFunc, menuItem.url)'></image>
<view>进出码</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/feedback.png" style="width: 40px;height: 40px;" bindtap='goFeedback'></image>
<view>反馈查看</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/apply.png" style="width: 40px;height: 40px;" bindtap='goApply'></image>
<view>申请记录</view>
</view> </view>
<view>{{ menuItem.title }}</view>
</view> </view>
</view> </view>
<button type="primary" size="mini" @tap="toggleDot('code', true)">显示小红点</button>
<view style="display: block;" v-if="isUser"> <button type="primary" size="mini" @tap="toggleDot('code', false)">隐藏小红点</button>
<view style="display: flex;text-align: center;margin-top: 20px;"> <DebugComp :params="debugObject" :userGroup="userGroup" />
<view style="width: 25%;">
<image src="../../image/icon/code.png" style="width: 40px;height: 40px;" @tap='goCode'></image>
<view>进出码</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/feedback.png" style="width: 40px;height: 40px;" bindtap='goFeedback'></image>
<view>反馈查看</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/apply.png" style="width: 40px;height: 40px;" bindtap='goApply'></image>
<view>申请记录</view>
</view>
</view>
<view style="display: flex;text-align: center;margin-top: 20px;">
<view style="width: 25%;">
<image src="../../image/icon/yq.png" style="width: 40px;height: 40px;" data-web="xgPage" bindtap='goWebPage'>
</image>
<view>疫情追踪</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/report.png" style="width: 40px;height: 40px;" bindtap='goReport'></image>
<view>今日日报</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/updPwd.png" style="width: 40px;height: 40px;" bindtap='goUpdPwd'></image>
<view>密码修改</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/fk.png" style="width: 40px;height: 40px;" bindtap='goKf'></image>
<view>提交反馈</view>
</view>
</view>
</view>
<view style="display: block;" v-if="isAdmin">
<view style="display: flex;text-align: center;margin-top: 20px;">
<view style="width: 25%;">
<image src="../../image/icon/danger.png" style="width: 40px;height: 40px;" bindtap='goCode'></image>
<view>不健康人员</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/feedback.png" style="width: 40px;height: 40px;" bindtap='goFeedbackReplay'>
</image>
<view>反馈回复</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/apply.png" style="width: 40px;height: 40px;" bindtap='goApplyReplay'></image>
<view>申请审批</view>
</view>
</view>
<view style="display: flex;text-align: center;margin-top: 20px;">
<view style="width: 25%;">
<image src="../../image/icon/gg.png" style="width: 40px;height: 40px;" data-web="xgPage" bindtap='goNotice'>
</image>
<view>公告发布</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/visitor.png" style="width: 40px;height: 40px;" bindtap="goVisitor"></image>
<view>访客审批</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/count.png" style="width: 40px;height: 40px;" bindtap='goCount'></image>
<view>分配账号</view>
</view>
<view style="width: 25%;">
<image src="../../image/icon/_report.png" style="width: 40px;height: 40px;" bindtap='toRedList'></image>
<view>今日未填</view>
</view>
</view>
</view>
<DebugComp />
</view> </view>
</template> </template>
<script> <script>
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import { eventCenter, getCurrentInstance } from '@tarojs/taro'
import ENUM from '../../utils/const.js'
import DebugComp from '../../components/DebugComp.vue' import DebugComp from '../../components/DebugComp.vue'
import getUserGroupByRole from '../../utils/getUserGroupByRole'
import menuItemDict from '../../utils/menuList'
import './index.css' import './index.css'
export default { export default {
data() {
return {
userInfo: null,
displayUsername: "",
isVisitor: false,
isUser: false,
isAdmin: false,
}
},
components: { components: {
DebugComp DebugComp
}, },
mounted() { data() {
eventCenter.once(getCurrentInstance().router.onShow, () => { return {
console.log('onShow') ...Taro.getApp().globalData,
console.log("ENUM", ENUM) userInfo: null,
displayUsername: "",
userGroup: "unknown",
menuItemDict: menuItemDict,
debugObject: {},
}
},
computed: {
filterMenuItems() {
return Object.values(this.menuItemDict)
.filter((item) => item.for.indexOf(this.userGroup) != -1)
}
},
this.userInfo = Taro.getStorageSync("userInfo"); onLoad() {
this.displayUsername = this.userInfo?.username ?? "请登录"; //
if (!this.userInfo) { if (this.debugMode) {
console.log("用户未登录") Taro.switchTab({ url: '/pages/residents/report' })
Taro.redirectTo({ }
url: '/pages/index/login' },
})
} else { onShow() {
const role = ENUM.user.role; console.log('onShow')
this.isVisitor = [ console.log("menuItemDict", menuItemDict)
role.VISITOR, this.userInfo = Taro.getStorageSync("userInfo");
].includes(this.userInfo.role); this.displayUsername = this.userInfo?.username ?? "请登录";
this.isUser = [ if (!this.userInfo) {
role.RESIDENTS_OWNER, console.log("用户未登录")
role.RESIDENTS_MEMBER, Taro.redirectTo({
role.RESIDENTS_TENENT, url: '/pages/index/login'
].includes(this.userInfo.role); })
this.isAdmin = [ } else {
role.ADMIN, this.userGroup = getUserGroupByRole(this.userInfo.role);
role.STAFF, this.debugObject = { userGroup: this.userGroup };
].includes(this.userInfo.role); }
console.log(
"isVisitor", this.isVisitor,
"isUser", this.isUser,
"isAdmin", this.isAdmin
)
}
})
}, },
methods: { methods: {
switchTo(func, pageUrl) {
switch (func) {
case 'switchTab':
Taro.switchTab({ url: pageUrl })
break;
case 'navigateTo':
Taro.navigateTo({ url: pageUrl })
break;
default:
console.log("切换页面失败", func, pageUrl)
break;
}
},
goCode() { goCode() {
Taro.switchTab({ Taro.switchTab({
url: '/pages/residents/code' url: '/pages/residents/code'
}) })
},
toggleDot(iconName, status = true) {
this.menuItemDict[iconName].addDot = status;
} }
} }
} }

View File

@ -16,6 +16,7 @@
} }
.inputText { .inputText {
width: 95%;
border-bottom: solid 1px; border-bottom: solid 1px;
margin-bottom: 50px; margin-bottom: 50px;
} }

View File

@ -43,6 +43,7 @@ export default {
}) })
} else { } else {
let passwordHash = md5(this.password); let passwordHash = md5(this.password);
Taro.showLoading({ title: '加载中' })
Taro.request({ Taro.request({
url: `${this.baseUrl}/user/login`, url: `${this.baseUrl}/user/login`,
method: "POST", method: "POST",
@ -54,18 +55,14 @@ export default {
password: passwordHash, password: passwordHash,
}, },
success: function (d) { success: function (d) {
Taro.hideLoading()
let result = d.data; let result = d.data;
if (result.success) { if (result.success) {
//
Taro.setStorageSync("userInfo", result.data.userInfo); Taro.setStorageSync("userInfo", result.data.userInfo);
console.log("userInfo", Taro.getStorageSync("userInfo")) console.log("userInfo", Taro.getStorageSync("userInfo"))
Taro.showToast({ Taro.switchTab({
title: "登录成功", url: '/pages/index/index'
icon: 'success',
success: function () {
Taro.switchTab({
url: '/pages/index/index'
})
}
}) })
} else { } else {
Taro.showToast({ Taro.showToast({
@ -76,6 +73,7 @@ export default {
} }
}, },
fail: function () { fail: function () {
Taro.hideLoading()
Taro.showToast({ Taro.showToast({
title: "请求失败", title: "请求失败",
icon: 'error', icon: 'error',

View File

@ -1,11 +1,30 @@
.time-text { #codeView {
text-align: center;
margin-top: 100px;
}
#user-text {
font-size: 35px;
}
#time-text {
font-weight: bold; font-weight: bold;
font-size: 40px;
margin-top: 50px;
} }
#myQrcode { #myQrcode {
display: block; display: block;
margin: 0 auto; margin: 30px auto;
}
margin-top: 50px;
margin-bottom: 40px; #show-text {
font-weight: bold;
font-size: 45px;
}
#small-text {
margin-top: 80px;
color: grey;
font-size: small;
} }

View File

@ -1,16 +1,16 @@
<template> <template>
<view> <view id="codeView" :style="{ display: isShow }">
<view style="text-align: center; margin-top: 100px;"> <view id="user-text"><text>{{ userText }}</text></view>
<view><text>{{ id }} | {{ name }}</text></view> <view id="time-text"><text>{{ time }}</text></view>
<canvas type="2d" style="width: 70vw; height: 70vw;" id="myQrcode"></canvas> <canvas type="2d" style="width: 250px; height: 250px;" id="myQrcode"></canvas>
<view><text class="time-text">{{ time }}</text></view> <view id="show-text"><text :style="{ color: showTextColor }">{{ showText }}</text></view>
</view> <view id="small-text"><text>下拉可刷新</text></view>
</view> </view>
</template> </template>
<script> <script>
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import { eventCenter, getCurrentInstance } from '@tarojs/taro' import md5 from 'blueimp-md5'
import drawQrcode from '../../utils/qrcode/index' import drawQrcode from '../../utils/qrcode/index'
import utils from '../../utils/utils' import utils from '../../utils/utils'
@ -22,70 +22,137 @@ export default {
...Taro.getApp().globalData, ...Taro.getApp().globalData,
userInfo: null, userInfo: null,
timeInterval: null, timeInterval: null,
id: '', isShow: 'none',
name: '', userText: '',
showText: '',
showTextColor: '',
time: '', time: '',
} }
}, },
// onShow
onShow() { onShow() {
console.log('onShow') console.log('onShow')
setTimeout(() => { setTimeout(this.refershData, 100)
Taro.startPullDownRefresh();
}, 100)
}, },
// onHide
onHide() { onHide() {
console.log('onHide') console.log('onHide')
clearInterval(this.timeInterval); clearInterval(this.timeInterval);
this.isShow = 'none'
this.time = ''
}, },
// onPullDownRefresh
onPullDownRefresh() { onPullDownRefresh() {
console.log('onPullDownRefresh') console.log('onPullDownRefresh')
Taro.showNavigationBarLoading(); this.$nextTick(() => {
clearInterval(this.timeInterval); this.refershData(() => {
this.id = '' Taro.stopPullDownRefresh();
this.name = '' });
this.time = '' });
this.userInfo = Taro.getStorageSync("userInfo");
if (!this.userInfo) {
Taro.redirectTo({
url: '/pages/index/login'
})
}
this.id = this.userInfo.id
this.name = this.userInfo.realname
this.drawCode()
Taro.stopPullDownRefresh();
Taro.hideNavigationBarLoading();
}, },
methods: { methods: {
refershData(callback) {
this.debugMode && console.log('this.refershData()')
Taro.showNavigationBarLoading();
clearInterval(this.timeInterval);
this.isShow = 'none'
this.time = ''
this.userInfo = Taro.getStorageSync("userInfo");
if (!this.userInfo) {
Taro.redirectTo({
url: '/pages/index/login'
})
}
Taro.showLoading({ title: '加载中' })
var that = this;
Taro.request({
url: `${this.baseUrl}/access/getCodeInfo`,
method: "POST",
header: {
"Content-Type": "application/x-www-form-urlencoded" //post
},
data: {
id: this.userInfo.id,
},
success: function (d) {
that.debugMode && console.log("begin success")
Taro.hideLoading()
let result = d.data;
if (result.success) {
console.log("result.data", result.data);
that.userText = `${that.userInfo.id} | ${that.userInfo.realname}`
that.showText = result.data.infoText
that.showTextColor = result.data.infoTextColor
that.$nextTick(() => {
let t = Date.now();
let chksum = md5(JSON.stringify({ id: that.userInfo.id, t: t }));
that.drawCode(`https://epp.cxyxiaomo.com/access/validCode?id=${that.userInfo.id}&t=${t}&chksum=${chksum}`, result.data.qrcodeColor)
});
} else {
Taro.showToast({
title: result.msg,
icon: 'error',
duration: 2000
})
}
that.isShow = ''
that.debugMode && console.log("end success")
},
fail: function () {
that.debugMode && console.log("begin fail")
Taro.hideLoading()
Taro.showToast({
title: "请求失败",
icon: 'error',
duration: 2000
})
that.debugMode && console.log("end fail")
},
complete: function () {
that.debugMode && console.log("begin complete")
if (typeof (callback) === "function")
callback();
Taro.hideNavigationBarLoading();
that.debugMode && console.log("end complete")
}
})
},
drawCode(text = 'https://www.baidu.com/', foreground = 'red') { drawCode(text = 'https://www.baidu.com/', foreground = 'red') {
const query = wx.createSelectorQuery() this.debugMode && console.log("drawCode was called.")
var that = this;
const query = Taro.createSelectorQuery()
query.select('#myQrcode') query.select('#myQrcode')
.fields({ .fields({
node: true, node: true,
size: true size: true
}) })
.exec((res) => { .exec(async (res) => {
that.debugMode && console.log("before drawQrcode")
var canvas = res[0].node var canvas = res[0].node
if (!canvas) {
Taro.showToast({
title: "canvas获取失败",
icon: 'error',
duration: 2000
})
return
}
that.debugMode && console.log("canvas:", canvas, "res:", res)
// drawQrcode // drawQrcode
drawQrcode({ await drawQrcode(Taro, {
canvas: canvas, canvas: canvas,
canvasId: 'myQrcode', canvasId: 'myQrcode',
width: 260, width: 150,
padding: 30, padding: 0,
background: '#ffffff', background: '#ffffff',
foreground: foreground, foreground: foreground,
text: text, text: text,
}) })
that.debugMode && console.log("end drawQrcode")
this.timeInterval = setInterval(this.updateTime, 1000);
this.updateTime(); this.updateTime();
this.timeInterval = setInterval(this.updateTime, 1000);
}) })
}, },
updateTime() { updateTime() {

View File

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '体温上报',
})

View File

@ -0,0 +1,179 @@
<style>
.form {
padding: 20px 30px;
}
.row {
margin: 30px 0;
border-bottom: 2px solid grey;
}
.rowItem {
margin: 0;
padding: 0;
display: inline-block;
vertical-align: middle;
height: 1.6rem;
}
.rowLeft {
width: 30%;
}
.rowRight {
width: 70%;
}
.rowRightElement {
width: 100%;
}
.center {
text-align: center;
}
.controlBtn {
width: 250px;
margin: 0 30px;
}
</style>
<template>
<view class="form">
<view class="row">
<view class="rowItem rowLeft center">
<text>姓名</text>
</view>
<view class="rowItem rowRight center">
<input class="rowRightElement" :value="formData.userRealname" disabled="true" />
</view>
</view>
<view class="row">
<view class="rowItem rowLeft center">
<text>填报时间</text>
</view>
<view class="rowItem rowRight center">
<input class="rowRightElement" :value="formData.time" disabled="true" />
</view>
</view>
<view class="row">
<view class="rowItem rowLeft center">
<text>地址</text>
</view>
<view class="rowItem rowRight center" @tap="chooseLocation">
<input class="rowRightElement" placeholder="点击获取当前位置" v-model="formData.address" disabled="true"
maxlength="500" />
</view>
</view>
<view class="row">
<view class="rowItem rowLeft center">
<text>今日体温</text>
</view>
<view class="rowItem rowRight center">
<radio-group class="rowRightElement" @change="(e) => formData.temperature = e.detail.value">
<radio value="0" checked="true" />正常&nbsp;
<radio value="1" />异常(37.3°)
</radio-group>
</view>
</view>
<view class="tips-area">
<view class="tips" style="color: red;">
* 本人承诺以上所填报的内容全部真实并愿意承担相应责任
</view>
</view>
<view style="text-align: center;">
<button class="controlBtn" size="mini" type="none" @tap="myreport">历史填报</button>
<button class="controlBtn" size="mini" type="primary" @tap="report">提交</button>
</view>
<textarea v-if="this.debugMode" maxlength="-1" disabled="true" auto-height="true" style="width: 100%"
:value="JSON.stringify(formData, null, 8)"></textarea>
</view>
</template>
<script>
import Taro from '@tarojs/taro'
import utils from '../../utils/utils'
export default {
data() {
return {
...Taro.getApp().globalData,
userInfo: null,
timeInterval: null,
formData: {
userId: '',
userRealname: '',
address: '',
time: '',
timestamp: '',
temperature: 0,
}
}
},
onShow() {
console.log('onShow')
this.userInfo = Taro.getStorageSync("userInfo")
this.formData.userId = this.userInfo.id
this.formData.userRealname = this.userInfo.realname
this.updateTime();
this.timeInterval = setInterval(this.updateTime, 1000);
},
onHide() {
console.log('onHide')
clearInterval(this.timeInterval)
},
methods: {
updateTime() {
this.formData.timestamp = Date.now();
this.formData.time = utils.formatTime(new Date(this.formData.timestamp));
},
chooseLocation: async function () {
Taro.showLoading({ title: '正在定位' })
await new Promise((resolve) => {
Taro.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
Taro.authorize({
scope: 'scope.userLocationBackground',
success() {
resolve();
}
})
} else {
resolve();
}
}
})
});
var that = this;
Taro.chooseLocation({
success: function (res) {
that.formData.address = res.address;
},
fail: function () {
if (!that.formData.address) {
Taro.showToast({
title: "请获取当前位置",
icon: 'error'
})
}
},
})
Taro.hideLoading()
},
}
}
</script>

View File

@ -0,0 +1,29 @@
const ENUM = require('./const.js');
function getUserGroupByRole(userRole) {
const role = ENUM.user.role;
userRole = Number(userRole);
let userGroupDict = {
'visitor': [
role.VISITOR,
].includes(userRole),
'user': [
role.RESIDENTS_OWNER,
role.RESIDENTS_MEMBER,
role.RESIDENTS_TENENT,
].includes(userRole),
'admin': [
role.ADMIN,
role.STAFF,
].includes(userRole)
}
console.log("userGroupDict", userGroupDict, userRole, role)
for (let userGroup of Object.keys(userGroupDict)) {
if (userGroupDict[userGroup]) {
return userGroup;
}
}
return 'unknown';
}
module.exports = getUserGroupByRole;

View File

@ -0,0 +1,104 @@
const switchTab = "switchTab";
const navigateTo = "navigateTo";
let id = 0;
let menuItemDict = {
'login': {
for: ['unknown'],
title: "登录",
image: "code.png",
switchFunc: switchTab,
url: '/pages/index/login',
},
'code': {
for: ['visitor', 'user'],
title: "进出码",
image: "code.png",
switchFunc: switchTab,
url: '/pages/residents/code'
},
'report': {
for: ['user'],
title: "体温上报",
image: "report.png",
switchFunc: switchTab,
url: '/pages/residents/report'
},
'apply-record': {
for: ['visitor', 'user'],
title: "申请记录",
image: "apply.png",
switchFunc: switchTab,
url: ''
},
'apply-approval': {
for: ['admin'],
title: "申请审批",
image: "apply.png", // ApplyReplay
switchFunc: switchTab,
url: ''
},
'visitor-apply': {
for: ['admin'],
title: "访客审批",
image: "visitor.png",
switchFunc: switchTab,
url: ''
},
'abnormal': {
for: ['admin'],
title: "异常人员",
image: "danger.png",
switchFunc: switchTab,
url: ''
},
'feedback-submit': {
for: ['visitor', 'user'],
title: "提交反馈",
image: "fk.png",
switchFunc: switchTab,
url: ''
},
'feedback-list': {
for: ['visitor', 'user'],
title: "反馈查看",
image: "feedback.png",
switchFunc: switchTab,
url: ''
},
'feedback-reply': {
for: ['admin'],
title: "反馈回复",
image: "feedback.png",
switchFunc: switchTab,
url: ''
},
'update-password': {
for: ['user', 'admin'],
title: "密码修改",
image: "updPwd.png",
switchFunc: switchTab,
url: ''
},
'assign': {
for: ['admin'],
title: "分配账号",
image: "count.png",
switchFunc: switchTab,
url: ''
},
'unfinish': {
for: ['admin'],
title: "今日未填", // RedList
image: "_report.png",
switchFunc: switchTab,
url: ''
}
}
let keys = Object.keys(menuItemDict);
for (let key of keys) {
menuItemDict[key].id = id++;
menuItemDict[key].addDot = false;
}
module.exports = menuItemDict

View File

@ -25,16 +25,15 @@ function utf16to8(str) {
return out return out
} }
function drawQrcode(options, debug) { function drawQrcode(Taro, options) {
options = options || {} options = options || {}
options = extend(true, { options = extend(true, {
canvasId: 'myQrcode', canvasId: 'myQrcode',
// canvas: canvas, canvas: null,
text: '爱一个人就要勇敢说出来', text: '爱一个人就要勇敢说出来',
width: 260, width: 260,
height: 260,
padding: 20, padding: 20,
// paddingColor: '#ffffff', // 默认与background一致 paddingColor: null, // 默认与background一致
typeNumber: -1, typeNumber: -1,
correctLevel: QRErrorCorrectLevel.H, correctLevel: QRErrorCorrectLevel.H,
background: '#ffffff', background: '#ffffff',
@ -54,88 +53,73 @@ function drawQrcode(options, debug) {
if (!options.paddingColor) options.paddingColor = options.background if (!options.paddingColor) options.paddingColor = options.background
if (debug) { // createCanvas
var qrcode = new QRCode(options.typeNumber, options.correctLevel) // create the qrcode itself
qrcode.addData(utf16to8(options.text)) var qrcode = new QRCode(options.typeNumber, options.correctLevel)
qrcode.make() qrcode.addData(utf16to8(options.text))
qrcode.make()
return new Promise(function (resolve, reject) { const dpr = Taro.getSystemInfoSync().pixelRatio
resolve(qrcode); var canvas = options.canvas
}) const ctx = canvas.getContext('2d')
canvas.width = options.width * dpr
canvas.height = options.width * dpr
const width = canvas.width
console.log(`canvas, ctx, width, dpr, qrcode, options`, canvas, ctx, width, dpr, qrcode, options)
} else { // 填充背景色
ctx.fillStyle = options.paddingColor
// ctx.clearRect(0, 0, width + options.padding * 2, width + options.padding * 2) // 绘制前清空画布
ctx.fillRect(0, 0, width + options.padding * 2, width + options.padding * 2);
return new Promise(function (resolve, reject) { var tileW = (width - options.padding * 2) / qrcode.getModuleCount()
return resolve(createCanvas()); var tileH = (width - options.padding * 2) / qrcode.getModuleCount()
})
// 绘制二维码
for (var row = 0; row < qrcode.getModuleCount(); row++) {
for (var col = 0; col < qrcode.getModuleCount(); col++) {
ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background
var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW))
var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW))
ctx.fillRect(Math.round(col * tileW) + options.padding, Math.round(row * tileH) + options.padding, w, h);
}
} }
function createCanvas() { // 绘制中心图标
// create the qrcode itself if (options.image.imageResource) {
var qrcode = new QRCode(options.typeNumber, options.correctLevel) const imgW = options.image.width * dpr
qrcode.addData(utf16to8(options.text)) const imgH = options.image.height * dpr
qrcode.make() const dx = (width - imgW) / 2
const dy = (width - imgH) / 2
if (options.image.round) {
// Logo边框
const imgW2 = options.image.width * dpr + 30
const dx2 = (width - imgW2) / 2
const r2 = imgW2 / 2
const cx2 = dx2 + r2;
ctx.beginPath();
ctx.arc(cx2, cx2, r2, 0, 2 * Math.PI);
ctx.fillStyle = '#ffffff'
ctx.fill();
ctx.restore();
const dpr = wx ? wx.getSystemInfoSync().pixelRatio : 1 // 兼容支付宝小程序 // 画Logo
var canvas = options.canvas const r = imgW / 2
const ctx = canvas.getContext('2d') const cx = dx + r;
canvas.width = options.width * dpr const cy = dy + r;
canvas.height = options.width * dpr ctx.beginPath();
const width = canvas.width ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.clip();
// 背景色 ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgW);
ctx.fillStyle = options.paddingColor ctx.restore();
ctx.fillRect(0, 0, width + options.padding * 2, width + options.padding * 2); } else {
ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgH)
var tileW = (width - options.padding * 2) / qrcode.getModuleCount() ctx.restore();
var tileH = (width - options.padding * 2) / qrcode.getModuleCount()
// 开始画二维码
for (var row = 0; row < qrcode.getModuleCount(); row++) {
for (var col = 0; col < qrcode.getModuleCount(); col++) {
ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background
var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW))
var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW))
ctx.fillRect(Math.round(col * tileW) + options.padding, Math.round(row * tileH) + options.padding, w, h);
}
} }
if (options.image.imageResource) {
const imgW = options.image.width * dpr
const imgH = options.image.height * dpr
const dx = (width - imgW) / 2
const dy = (width - imgH) / 2
if (options.image.round) {
// Logo边框
const imgW2 = options.image.width * dpr + 30
const dx2 = (width - imgW2) / 2
const r2 = imgW2 / 2
const cx2 = dx2 + r2;
ctx.beginPath();
ctx.arc(cx2, cx2, r2, 0, 2 * Math.PI);
ctx.fillStyle = '#ffffff'
ctx.fill();
ctx.restore();
// 画Logo
const r = imgW / 2
const cx = dx + r;
const cy = dy + r;
ctx.beginPath();
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgW);
ctx.restore();
} else {
ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgH)
ctx.restore();
}
}
return ctx
} }
return ctx
} }
export default drawQrcode export default drawQrcode