diff --git a/wxmp/bin/pages.js b/wxmp/bin/pages.js
index fb9f0d4..9e0d82a 100644
--- a/wxmp/bin/pages.js
+++ b/wxmp/bin/pages.js
@@ -6,7 +6,7 @@ const start = () => {
easycom: {
autoscan: true,
custom: {
- "^(K|V)(.*)": "@/components/$1$2.vue",
+ "^(Ai|V)(.*)": "@/components/$1$2.vue",
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
diff --git a/wxmp/package.json b/wxmp/package.json
index aeafa31..63f1e03 100644
--- a/wxmp/package.json
+++ b/wxmp/package.json
@@ -22,6 +22,10 @@
"@dcloudio/uni-mp-weixin": "3.0.0-3061420221215001",
"@dcloudio/uni-quickapp-webview": "3.0.0-3061420221215001",
"@dcloudio/uni-ui": "^1.4.23",
+ "axios": "^1.2.2",
+ "axios-miniprogram-adapter": "^0.3.5",
+ "dayjs": "^1.11.7",
+ "query-string": "^8.1.0",
"vue": "^3.2.45",
"vue-i18n": "^9.1.9"
},
diff --git a/wxmp/src/components/AiGroup.vue b/wxmp/src/components/AiGroup.vue
new file mode 100644
index 0000000..7ccd489
--- /dev/null
+++ b/wxmp/src/components/AiGroup.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
diff --git a/wxmp/src/components/AiItem.vue b/wxmp/src/components/AiItem.vue
new file mode 100644
index 0000000..85a8e4d
--- /dev/null
+++ b/wxmp/src/components/AiItem.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
diff --git a/wxmp/src/components/AiPagePicker.vue b/wxmp/src/components/AiPagePicker.vue
new file mode 100644
index 0000000..b18ded1
--- /dev/null
+++ b/wxmp/src/components/AiPagePicker.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
diff --git a/wxmp/src/components/pages/submitEvaluation.vue b/wxmp/src/components/pages/submitEvaluation.vue
new file mode 100644
index 0000000..8c5828c
--- /dev/null
+++ b/wxmp/src/components/pages/submitEvaluation.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wxmp/src/main.js b/wxmp/src/main.js
index 3889ada..9c7a8fa 100644
--- a/wxmp/src/main.js
+++ b/wxmp/src/main.js
@@ -1,8 +1,10 @@
import {createSSRApp} from "vue";
import App from "./App.vue";
+import util from "./utils/util";
export function createApp() {
const app = createSSRApp(App);
+ Object.keys(util).map(e => app.config.globalProperties[e] = util[e])
return {
app,
};
diff --git a/wxmp/src/utils/coin.js b/wxmp/src/utils/coin.js
new file mode 100644
index 0000000..11bb11d
--- /dev/null
+++ b/wxmp/src/utils/coin.js
@@ -0,0 +1,19 @@
+export default {
+ cny(money) {
+ if (money) {
+ money.toLocaleString('zh-Hans-CN', {style: 'currency', currency: "CNY"})
+ }
+ return money
+ },
+ cn(money) {
+ let num = parseFloat(money), cnMoney = '',
+ units = '仟佰拾亿仟佰拾万仟佰拾元角分',
+ cnNum = '零壹贰叁肆伍陆柒捌玖'
+ num = num.toFixed(2).replace(/\./g, '')
+ units = units.substring(units.length - num.length)
+ Array.from(num).map((e, i) => {
+ cnMoney += cnNum.charAt(e) + units.charAt(i)
+ })
+ return cnMoney.replace(/零角零分$/, '整').replace(/零[仟佰拾]/g, '零').replace(/零{2,}/g, '零').replace(/零([亿|万])/g, '$1').replace(/零+元/, '元').replace(/亿零{0,3}万/, '亿').replace(/^元/, "零元")
+ }
+}
diff --git a/wxmp/src/utils/dict.js b/wxmp/src/utils/dict.js
new file mode 100644
index 0000000..a376716
--- /dev/null
+++ b/wxmp/src/utils/dict.js
@@ -0,0 +1,56 @@
+export default {
+ instance: null,
+ init(instance) {
+ this.instance = instance
+ },
+ dicts() {
+ return uni.getStorageSync('dicts') || [];
+ },
+ load(...code) {
+ return !!this.instance && this.instance.post('/admin/dictionary/queryValsByCodeList?codeList=' + code.join(','), null, {
+ withoutToken: true
+ }).then((res) => {
+ if (res && res.data) {
+ let cacheDicts = {},
+ meta = {};
+ this.dicts().map((e) => (cacheDicts[e.key] = e));
+ res.data.map((e) => (meta[e.key] = e));
+ let dicts = {...cacheDicts, ...meta};
+ uni.setStorageSync('dicts', Object.values(dicts));
+ }
+ });
+ },
+ getDict(key) {
+ if (this.dicts().length) {
+ let dict = this.dicts().find((e) => e.key == key);
+ return dict ? dict.values : [];
+ } else return [];
+ },
+ getValue(key, label) {
+ if (this.dicts().length) {
+ let dict = this.dicts().find((e) => e.key == key);
+ if (dict) {
+ let item = dict.values.find((v) => v.dictName == label);
+ return item ? item.dictValue : label;
+ } else return label;
+ } else return label;
+ },
+ getLabel(key, value) {
+ if (this.dicts().length) {
+ let dict = this.dicts().find((e) => e.key == key);
+ if (dict) {
+ let item = dict.values.find((v) => v.dictValue == value);
+ return item ? item.dictName : value;
+ } else return value ? value : '';
+ } else return value ? value : '';
+ },
+ getColor(key, value) {
+ if (this.dicts().length) {
+ let dict = this.dicts().find((e) => e.key == key);
+ if (dict) {
+ let item = dict.values.find((v) => v.dictValue == value);
+ return item ? item.dictColor : value;
+ } else return value;
+ } else return value;
+ }
+}
diff --git a/wxmp/src/utils/http.js b/wxmp/src/utils/http.js
new file mode 100644
index 0000000..6e85df0
--- /dev/null
+++ b/wxmp/src/utils/http.js
@@ -0,0 +1,29 @@
+import axios from 'axios'
+import adapter from 'axios-miniprogram-adapter'
+
+const instance = axios.create({
+ timeout: 600000,
+ withCredentials: true,
+ adapter
+})
+const getToken = () => {
+ let vuex = uni.getStorageSync("vuex")
+ return !!vuex ? JSON.parse(vuex).token : null
+}
+const source = axios.CancelToken.source();
+instance.interceptors.request.use(config => {
+ if (config.withoutToken) {
+ return config
+ } else if (getToken()) {
+ config.headers["Authorization"] = getToken()
+ } else {
+ config.cancelToken = source.token
+ source.cancel("用户未验证,取消请求:" + config.url)
+ }
+ return config
+}, err => {
+ console.error(err)
+ return Promise.reject(err)
+})
+
+export default instance
diff --git a/wxmp/src/utils/identity.js b/wxmp/src/utils/identity.js
new file mode 100644
index 0000000..2275168
--- /dev/null
+++ b/wxmp/src/utils/identity.js
@@ -0,0 +1,238 @@
+import dayjs from "./moment";
+
+
+const PARAMS = {
+ /* 省,直辖市代码表 */
+ provinceAndCitys: {
+ 11: '北京',
+ 12: '天津',
+ 13: '河北',
+ 14: '山西',
+ 15: '内蒙古',
+ 21: '辽宁',
+ 22: '吉林',
+ 23: '黑龙江',
+ 31: '上海',
+ 32: '江苏',
+ 33: '浙江',
+ 34: '安徽',
+ 35: '福建',
+ 36: '江西',
+ 37: '山东',
+ 41: '河南',
+ 42: '湖北',
+ 43: '湖南',
+ 44: '广东',
+ 45: '广西',
+ 46: '海南',
+ 50: '重庆',
+ 51: '四川',
+ 52: '贵州',
+ 53: '云南',
+ 54: '西藏',
+ 61: '陕西',
+ 62: '甘肃',
+ 63: '青海',
+ 64: '宁夏',
+ 65: '新疆',
+ 71: '台湾',
+ 81: '香港',
+ 82: '澳门',
+ 91: '国外'
+ },
+
+ /* 每位加权因子 */
+ powers: [
+ '7',
+ '9',
+ '10',
+ '5',
+ '8',
+ '4',
+ '2',
+ '1',
+ '6',
+ '3',
+ '7',
+ '9',
+ '10',
+ '5',
+ '8',
+ '4',
+ '2'
+ ],
+
+ /* 第18位校检码 */
+ parityBit: ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'],
+
+ /* 性别 */
+ genders: {1: '男', 0: '女'},
+}
+
+const Check = {
+ /* 校验地址码 */
+ checkAddressCode(addressCode) {
+ const check = /^[1-9]\d{5}$/.test(addressCode)
+ if (!check) return false
+ return !!PARAMS.provinceAndCitys[parseInt(addressCode.substring(0, 2))]
+ },
+ /* 校验日期码 */
+ checkBirthDayCode(birDayCode) {
+ const check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(
+ birDayCode
+ )
+ if (!check) return false
+ const yyyy = parseInt(birDayCode.substring(0, 4), 10)
+ const mm = parseInt(birDayCode.substring(4, 6), 10)
+ const dd = parseInt(birDayCode.substring(6), 10)
+ const xdata = new Date(yyyy, mm - 1, dd)
+ if (xdata > new Date()) {
+ return false // 生日不能大于当前日期
+ } else {
+ return (
+ xdata.getFullYear() == yyyy &&
+ xdata.getMonth() == mm - 1 &&
+ xdata.getDate() == dd
+ )
+ }
+ },
+ /* 验证校检码 */
+ checkParityBit(idCardNo) {
+ const parityBit = idCardNo.charAt(17).toUpperCase()
+ return this.getParityBit(idCardNo) == parityBit
+ },
+// 校验15位的身份证号码
+ check15IdCardNo(idCardNo) {
+ // 15位身份证号码的基本校验
+ let check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(
+ idCardNo
+ )
+ if (!check) return false
+ // 校验地址码
+ const addressCode = idCardNo.substring(0, 6)
+ check = this.checkAddressCode(addressCode)
+ if (!check) return false
+ const birDayCode = '19' + idCardNo.substring(6, 12)
+ // 校验日期码
+ return this.checkBirthDayCode(birDayCode)
+ },
+
+// 校验18位的身份证号码
+ check18IdCardNo(idCardNo) {
+ // 18位身份证号码的基本格式校验
+ let check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(
+ idCardNo
+ )
+ if (!check) return false
+ // 校验地址码
+ const addressCode = idCardNo.substring(0, 6)
+ check = this.checkAddressCode(addressCode)
+ if (!check) return false
+ // 校验日期码
+ const birDayCode = idCardNo.substring(6, 14)
+ check = this.checkBirthDayCode(birDayCode)
+ if (!check) return false
+ // 验证校检码
+ return this.checkParityBit(idCardNo)
+ },
+ /* 计算校检码 */
+ getParityBit(idCardNo) {
+ const id17 = idCardNo.substring(0, 17)
+ /* 加权 */
+ let power = 0
+ for (let i = 0; i < 17; i++) {
+ power += parseInt(id17.charAt(i), 10) * parseInt(PARAMS.powers[i])
+ }
+ /* 取模 */
+ const mod = power % 11
+ return PARAMS.parityBit[mod]
+ }
+}
+
+export default class Identity {
+ constructor(code) {
+ this.code = this.getId18(code)
+ this.init()
+ }
+
+ init() {
+ const {code} = this
+ if (!!code) {
+ this.hideCode = Identity.hideId(code)
+ this.getIdCardInfo(code)
+ }
+ }
+
+ static hideId(code) {
+ return code?.replace(/^(\d{10})\d{4}(.{4}$)/g, `$1${Array(5).join('*')}$2`)
+ }
+
+ getId18(code) {
+ if (code.length == 15) {
+ const id17 = code.substring(0, 6) + '19' + code.substring(6)
+ const parityBit = Check.getParityBit(id17)
+ return id17 + parityBit
+ } else if (code.length == 18) {
+ return code
+ } else {
+ return null
+ }
+ }
+
+ getIdCardInfo(idCardNo) {
+ this.birthday = Identity.getBirthday(idCardNo)
+ this.sex = Identity.getSex(idCardNo)
+ this.gender = PARAMS.genders[this.sex]
+ this.age = Identity.getAge(idCardNo)
+ this.areaId = Identity.getArea(idCardNo)
+ }
+
+ /**
+ * 获取性别
+ * @param code
+ * @returns {string}
+ */
+ static getSex(code) {
+ return (Number(code.substring(16, 17)) % 2).toString()
+ }
+
+ /**
+ * 获取年龄
+ * @param code
+ * @returns {number}
+ */
+ static getAge(code) {
+ const birthday = dayjs(code.substring(6, 14), 'YYYYMMDD')
+ return Math.ceil(dayjs.duration(dayjs().unix() - dayjs(birthday).unix(), 's').asYears())
+ }
+
+ /**
+ * 获取地区编码
+ * @param code
+ */
+ static getArea(code) {
+ return code.substring(0, 6) + new Array(7).join(0)
+ }
+
+ /**
+ * 获取生日
+ */
+ static getBirthday(code) {
+ return dayjs(code.substring(6, 14), 'YYYYMMDD').format("YYYY-MM-DD").replace('Invalid Date', '')
+ }
+
+ /* 校验15位或18位的身份证号码 */
+ static check(idCardNo) {
+ // 15位和18位身份证号码的基本校验
+ const check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo)
+ if (!check) return false
+ // 判断长度为15位或18位
+ if (idCardNo.length == 15) {
+ return Check.check15IdCardNo(idCardNo)
+ } else if (idCardNo.length == 18) {
+ return Check.check18IdCardNo(idCardNo)
+ } else {
+ return false
+ }
+ }
+}
diff --git a/wxmp/src/utils/moment.js b/wxmp/src/utils/moment.js
new file mode 100644
index 0000000..a157d57
--- /dev/null
+++ b/wxmp/src/utils/moment.js
@@ -0,0 +1,35 @@
+import moment from 'dayjs'
+import duration from 'dayjs/plugin/duration'
+import updateLocale from 'dayjs/plugin/updateLocale'
+import customParseFormat from 'dayjs/plugin/customParseFormat'
+import 'dayjs/locale/zh-cn'
+
+moment.locale('zh-cn')
+moment.extend(updateLocale)
+moment.extend(customParseFormat)
+moment.extend(duration)
+moment.updateLocale('zh-cn', {
+ weekdays: "星期日|星期一|星期二|星期三|星期四|星期五|星期六".split("|"),
+ meridiem(hour) {
+ let word = ""
+ if (hour < 6) {
+ word = "凌晨"
+ } else if (hour < 9) {
+ word = "早上"
+ } else if (hour < 12) {
+ word = "上午"
+ } else if (hour < 14) {
+ word = "中午"
+ } else if (hour < 17) {
+ word = "下午"
+ } else if (hour < 19) {
+ word = "傍晚"
+ } else if (hour < 22) {
+ word = "晚上"
+ } else {
+ word = "夜里"
+ }
+ return word;
+ }
+})
+export default moment
diff --git a/wxmp/src/utils/regular.js b/wxmp/src/utils/regular.js
new file mode 100644
index 0000000..b85a693
--- /dev/null
+++ b/wxmp/src/utils/regular.js
@@ -0,0 +1,15 @@
+export default {
+ phone: /^((0\d{2,3}-\d{7,8})|((13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}))$/,
+ password: /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^&*,.?_-])[\da-zA-Z~!@#$%^&*,.?_-]{8,16}$/,
+ money: /^([1-9]\d*|0)(\.\d{1,2})?$/,
+ area: {
+ village: /^\d{9}[^0]0{0,2}$/,
+ town: /^\d{6}[^0]0{0,2}000$/,
+ country: /^\d{4}[^0]0?0{6}$/,
+ city: /^\d{2}[^0]0?0{8}$/,
+ province: /^[^0]0?0{10}$/,
+ },
+ zh: /^[\u4e00-\u9fa5]+$/,
+ email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
+ ip: /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/
+}
diff --git a/wxmp/src/utils/util.js b/wxmp/src/utils/util.js
new file mode 100644
index 0000000..22a14ce
--- /dev/null
+++ b/wxmp/src/utils/util.js
@@ -0,0 +1,140 @@
+import $dayjs from './moment'
+import $dict from './dict'
+import $qs from 'query-string'
+import $coin from './coin'
+import $reg from "./regular"
+import identity from "./identity"
+
+const $toast = (obj) => {
+ let params = {title: '', duration: 2000, icon: 'none'};
+ if (typeof obj == 'string') {
+ params.title = obj;
+ } else {
+ Object.assign(params, obj);
+ }
+ uni.showToast(params);
+};
+
+const $loading = (title = "加载中") => {
+ uni.showLoading({
+ title: title || '加载中',
+ mask: true
+ });
+};
+
+const $hideLoading = () => {
+ uni.hideLoading();
+};
+
+const $dialog = {
+ alert: (params) => {
+ return new Promise((resolve) => {
+ uni.showModal({
+ title: '温馨提示',
+ showCancel: false,
+ confirmColor: '#197DF0',
+ confirmText: params?.confirmButtonText || '确定',
+ ...params,
+ success: (res) => {
+ if (res.confirm) {
+ resolve();
+ }
+ }
+ });
+ });
+ },
+
+ confirm: (params) => {
+ return new Promise((resolve, reject) => {
+ uni.showModal({
+ title: '温馨提示',
+ showCancel: true,
+ confirmColor: '#197DF0',
+ cancelText: params.cancelButtonText ? params.cancelButtonText : '取消',
+ confirmText: params.confirmButtonText ? params.confirmButtonText : '确定',
+ ...params,
+ success: (res) => {
+ if (res.confirm) {
+ resolve();
+ } else if (res.cancel) {
+ reject();
+ }
+ }
+ });
+ });
+ }
+};
+
+const $linkTo = (url) => {
+ uni.navigateTo({
+ url
+ });
+};
+
+const $formatName = (name) => {
+ if (name === undefined) {
+ return;
+ }
+ return name.substr(name.length - 2, name.length > 2 ? name.length - 1 : name.length);
+};
+
+const $previewImage = (list, index, urlName) => {
+ uni.previewImage({
+ current: list[index][urlName],
+ urls: list.map((v) => v[urlName])
+ });
+};
+
+
+const $getUserProfile = () => {
+ return new Promise(function (resolve) {
+ wx.getUserProfile({
+ desc: '用于完善会员资料',
+ lang: 'zh_CN',
+ success: (data) => {
+ resolve(data);
+ },
+ fail: (err) => {
+ console.log(err);
+ }
+ });
+ });
+};
+/**
+ * 获取code
+ * @returns {Promise}
+ */
+const $getLoginCode = () => {
+ return new Promise(function (resolve, reject) {
+ uni.login({
+ success: function (res) {
+ if (res.code) {
+ resolve(res);
+ } else {
+ reject(res);
+ }
+ },
+ fail: function () {
+ reject(false);
+ }
+ });
+ });
+};
+
+export default {
+ $toast,
+ $loading,
+ $hideLoading,
+ $dialog,
+ $linkTo,
+ $formatName,
+ $previewImage,
+ $getUserProfile,
+ $dayjs,
+ $dict,
+ $getLoginCode,
+ $qs,
+ $coin,
+ $reg,
+ $ChID: identity
+};