vue-cli init

This commit is contained in:
郭鸿轩 2025-08-15 16:25:44 +08:00
parent e81805b4c0
commit 8e22afd798
590 changed files with 103286 additions and 213 deletions

View File

@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"Bash(find:*)",
"Bash(ls:*)",
"Bash(find:*)"
],
"deny": []
}
}

62
.gitignore vendored
View File

@ -1,23 +1,55 @@
# System files
.DS_Store
node_modules/
Thumbs.db
# IDE and editor files
.idea/
.vscode/
.hbuilderx/
.project
.settings/
# Uni-app specific
unpackage/
dist/
.hybrid/
uni_modules/.git/
src/uni_modules/.git/
# local env files
.env.local
.env.*.local
# Log files
# Node.js related
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-lock.yaml
# Editor directories and files
.project
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
# Environment variables
.env.local
.env.*.local
# Build output and cache
/.hbuilderx/
/unpackage/dist/
/unpackage/cache/
/unpackage/release/
# Log files
*.log
# OS generated files
*.swp
*.swo
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Deployment scripts
deploy.sh
# Temporary files
*.tmp
*.temp

3
.kilocode/mcp.json Normal file
View File

@ -0,0 +1,3 @@
{
"mcpServers": {}
}

Binary file not shown.

50
h5.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="PoweredByAidex"/>
<meta name="description" content="PoweredByAidex"/>
<link rel="shortcut icon" type="image/x-icon" href="<%= BASE_URL %>static/aidex/favicon.png">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
<script>
window.onresize = function () {
if (document.documentElement.clientWidth >= 768) {
window.location.href = '<%= BASE_URL %>static/#/';
}
};
window.onresize();
</script>
<!-- 正式发布的时候使用,开发期间不启用。↓ -->
<script src="<%= BASE_URL %>static/common/js/touch-emulator.js"></script>
<script>
TouchEmulator();
</script>
<style>
::-webkit-scrollbar{
display: none;
}
</style>
<!-- 正式发布的时候使用,开发期间不启用。↑ -->
<script>
document.addEventListener('DOMContentLoaded', function() {
document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
})
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.css" />
</head>
<body>
<!-- 该文件为 H5 平台的模板 HTML并非应用入口。 -->
<!-- 请勿在此文件编写页面代码或直接运行此文件。 -->
<!-- 详见文档https://uniapp.dcloud.io/collocation/manifest?id=h5-template -->
<noscript>
<strong>本站点必须要开启JavaScript才能运行</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script>
/*BAIDU_STAT*/
</script>
</body>
</html>

View File

@ -0,0 +1,637 @@
// 判断类型集合
export const checkStr = (str, type) => {
switch (type) {
case 'phone': //手机号码
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
case 'tel': //座机
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'card': //身份证
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
case 'pwd': //密码以字母开头长度在6~18之间只能包含字母、数字和下划线
return /^[a-zA-Z]\w{5,17}$/.test(str)
case 'postal': //邮政编码
return /[1-9]\d{5}(?!\d)/.test(str);
case 'QQ': //QQ号
return /^[1-9][0-9]{4,9}$/.test(str);
case 'email': //邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': //金额(小数点2位)
return /^\d*(?:\.\d{0,2})?$/.test(str);
case 'URL': //网址
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str)
case 'IP': //IP
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
case 'date': //日期时间
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/
.test(str)
case 'number': //数字
return /^[0-9]$/.test(str);
case 'english': //英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': //中文
return /^[\\u4E00-\\u9FA5]+$/.test(str);
case 'lower': //小写
return /^[a-z]+$/.test(str);
case 'upper': //大写
return /^[A-Z]+$/.test(str);
case 'HTML': //HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
return true;
}
}
// 格式化时间-小于10补0
function formatDigit(n) {
return n.toString().replace(/^(\d)$/, '0$1');
}
// 格式化时间,通用
export const formatDate = (timestamp, formats) => {
/* formats:
1. Y-M-D
2. Y-M-D h:m:s
3. Y年M月D日
4. Y年M月D日 h时m分
5. Y年M月D日 h时m分s秒
示例console.log(formatDate(1500305226034, 'Y年M月D日 h:m:s')) ==> 2017年07月17日 23:27:06
*/
formats = formats || 'Y-M-D';
var myDate = undefined;
if (timestamp) {
if (typeof(timestamp) != 'string') {
myDate = timestamp;
} else {
myDate = new Date(timestamp);
}
} else {
myDate = new Date();
}
var year = myDate.getFullYear();
var month = formatDigit(myDate.getMonth() + 1);
var day = formatDigit(myDate.getDate());
var hour = formatDigit(myDate.getHours());
var minute = formatDigit(myDate.getMinutes());
var second = formatDigit(myDate.getSeconds());
return formats.replace(/Y|M|D|h|m|s/g, (matches) => {
return {
Y: year,
M: month,
D: day,
h: hour,
m: minute,
s: second
} [matches];
});
}
// 验证邮箱
export const isEmail = (s) => {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
}
// 验证手机号码
export const isMobile = (s) => {
return /^1[0-9]{10}$/.test(s)
}
// 验证电话号码
export const isPhone = (s) => {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
}
// 验证是否url地址
export const isURL = (s) => {
return /^http[s]?:\/\/.*/.test(s)
}
// 验证是否字符串
export const isString = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'String'
}
// 验证是否是否数字
export const isNumber = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Number'
}
// 验证是否是Boolean
export const isBoolean = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
}
// 验证是否是函数
export const isFunction = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Function'
}
//是否为null
export const isNull = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
}
//是否undefined
export const isUndefined = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
}
//是否对象
export const isObj = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Object'
}
//是否数组
export const isArray = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Array'
}
// 是否时间对象
export const isDate = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Date'
}
//是否正则
export const isRegExp = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
}
// 是否错误对象
export const isError = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Error'
}
//是否Symbol函数
export const isSymbol = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
}
// 是否Promise对象
export const isPromise = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
}
// 是否Set对象
export const isSet = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
}
//判断数据是不是引用类型的数据
export function isObject(value) {
let type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
// 字符串超出多少字显示省略号
export function strOut(str, len=0,type) {
type=type||'star';
var restr = '';
if (str) {
if (str.length >= len) {
restr = str.substring(0, len) + (type=='star'?'***':'...');
} else {
restr = str;
}
}
return restr;
}
//浮点数加法运算--解决精度丢失传入Number返回Number
export function FloatAdd(arg1, arg2) {
var r1, r2, m;
try {
r1 = arg1.toString().split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split('.')[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return (arg1 * m + arg2 * m) / m;
}
//浮点数乘法运算--解决精度丢失传入Number返回Number
export function FloatMul(arg1, arg2) {
var m = 0,
s1 = arg1.toString(),
s2 = arg2.toString();
try {
m += s1.split('.')[1].length;
} catch (e) {}
try {
m += s2.split('.')[1].length;
} catch (e) {}
return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m);
}
//随机数时间戳 (返回数字符串)
export function uniqueId() {
var a = Math.random,
b = parseInt;
return Number(new Date()).toString() + b(10 * a()) + b(10 * a()) + b(10 * a());
}
// 数组随机洗牌算法
export const shuffle = (arr) => {
var result = [],
random;
while (arr.length > 0) {
random = Math.floor(Math.random() * arr.length);
result.push(arr[random])
arr.splice(random, 1)
}
return result;
}
// 严格的身份证号码校验
export const isCardID = (sId) => {
if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(sId)) {
console.log('你输入的身份证长度或格式错误')
return false
}
//身份证城市
var aCity = {
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: "国外"
};
if (!aCity[parseInt(sId.substr(0, 2))]) {
console.log('你的身份证地区非法')
return false
}
// 出生日期验证
var sBirthday = (sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2))).replace(/-/g,
"/"),
d = new Date(sBirthday)
if (sBirthday != (d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate())) {
console.log('身份证上的出生日期非法')
return false
}
// 身份证号码校验
var sum = 0,
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
codes = "10X98765432"
for (var i = 0; i < sId.length - 1; i++) {
sum += sId[i] * weights[i];
}
var last = codes[sum % 11]; //计算出来的最后一位身份证号码
if (sId[sId.length - 1] != last) {
console.log('你输入的身份证号非法')
return false
}
return true
}
// 随机整数范围
export const random = (min, max) => {
if (arguments.length === 2) {
return Math.floor(min + Math.random() * ((max + 1) - min))
} else {
return null;
}
}
// 将阿拉伯数字翻译成中文的大写数字
export const numberToChinese = (num) => {
var AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
var BB = new Array("", "十", "百", "仟", "萬", "億", "点", "");
var a = ("" + num).replace(/(^0*)/g, "").split("."),
k = 0,
re = "";
for (var i = a[0].length - 1; i >= 0; i--) {
switch (k) {
case 0:
re = BB[7] + re;
break;
case 4:
if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
.test(a[0]))
re = BB[4] + re;
break;
case 8:
re = BB[5] + re;
BB[7] = BB[5];
k = 0;
break;
}
if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
re = AA[0] + re;
if (a[0].charAt(i) != 0)
re = AA[a[0].charAt(i)] + BB[k % 4] + re;
k++;
}
if (a.length > 1) // 加上小数部分(如果有小数部分)
{
re += BB[6];
for (var i = 0; i < a[1].length; i++)
re += AA[a[1].charAt(i)];
}
if (re == '一十')
re = "十";
if (re.match(/^一/) && re.length == 3)
re = re.replace("一", "");
return re;
}
// 将数字转换为大写金额
export const changeToChinese = (Num) => {
//判断如果传递进来的不是字符的话转换为字符
if (typeof Num == "number") {
Num = new String(Num);
};
Num = Num.replace(/,/g, "") //替换tomoney()中的“,”
Num = Num.replace(/ /g, "") //替换tomoney()中的空格
Num = Num.replace(/¥/g, "") //替换掉可能出现的¥字符
if (isNaN(Num)) { //验证输入的字符是否为数字
//alert("请检查小写金额是否正确");
return "";
};
//字符处理完毕后开始转换,采用前后两部分分别转换
var part = String(Num).split(".");
var newchar = "";
//小数点前进行转化
for (var i = part[0].length - 1; i >= 0; i--) {
if (part[0].length > 10) {
return "";
//若数量超过拾亿单位,提示
}
var tmpnewchar = ""
var perchar = part[0].charAt(i);
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
switch (part[0].length - i - 1) {
case 0:
tmpnewchar = tmpnewchar + "元";
break;
case 1:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 2:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 3:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 4:
tmpnewchar = tmpnewchar + "万";
break;
case 5:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 6:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 7:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 8:
tmpnewchar = tmpnewchar + "亿";
break;
case 9:
tmpnewchar = tmpnewchar + "拾";
break;
}
var newchar = tmpnewchar + newchar;
}
//小数点之后进行转化
if (Num.indexOf(".") != -1) {
if (part[1].length > 2) {
// alert("小数点之后只能保留两位,系统将自动截断");
part[1] = part[1].substr(0, 2)
}
for (i = 0; i < part[1].length; i++) {
tmpnewchar = ""
perchar = part[1].charAt(i)
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
if (i == 0) tmpnewchar = tmpnewchar + "角";
if (i == 1) tmpnewchar = tmpnewchar + "分";
newchar = newchar + tmpnewchar;
}
}
//替换所有无用汉字
while (newchar.search("零零") != -1)
newchar = newchar.replace("零零", "零");
newchar = newchar.replace("零亿", "亿");
newchar = newchar.replace("亿万", "亿");
newchar = newchar.replace("零万", "万");
newchar = newchar.replace("零元", "元");
newchar = newchar.replace("零角", "");
newchar = newchar.replace("零分", "");
if (newchar.charAt(newchar.length - 1) == "元") {
newchar = newchar + "整"
}
return newchar;
}
// 判断一个元素是否在数组中
export const arrContains = (arr, val) => {
return arr.indexOf(val) != -1 ? true : false;
}
// 数组去重
export const unique = (arr) => {
if (Array.hasOwnProperty('from')) {
return Array.from(new Set(arr));
} else {
var n = {},
r = [];
for (var i = 0; i < arr.length; i++) {
if (!n[arr[i]]) {
n[arr[i]] = true;
r.push(arr[i]);
}
}
return r;
}
}
// 数组删除其中一个元素
export const arrRemove = (arr, ele) => {
var index = arr.indexOf(ele);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
// 求数组中的最大值
export const arrMax = (arr) => {
return Math.max.apply(null, arr);
}
// 求数组中的最小值
export const arrMin = (arr) => {
return Math.min.apply(null, arr);
}
// 数组中的值求和
export const arrSum = (arr) => {
return arr.reduce((pre, cur) => {
return pre + cur
})
}
// 去除空格,type: 1-所有空格 2-前后空格 3-前空格 4-后空格
export const strTrim = (str, type) => {
type = type || 2
switch (type) {
case 1:
return str.replace(/\s+/g, "");
case 2:
return str.replace(/(^\s*)|(\s*$)/g, "");
case 3:
return str.replace(/(^\s*)/g, "");
case 4:
return str.replace(/(\s*$)/g, "");
default:
return str;
}
}
// 字符转换type: 1:首字母大写 2首字母小写 3大小写转换 4全部大写 5全部小写
export const changeCase = (str, type) => {
type = type || 4
switch (type) {
case 1:
return str.replace(/\b\w+\b/g, (word) => {
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
});
case 2:
return str.replace(/\b\w+\b/g, (word) => {
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
});
case 3:
return str.split('').map((word) => {
if (/[a-z]/.test(word)) {
return word.toUpperCase();
} else {
return word.toLowerCase()
}
}).join('')
case 4:
return str.toUpperCase();
case 5:
return str.toLowerCase();
default:
return str;
}
}
// 检测密码强度 等级1-5
export const checkPwd = (str) => {
var Lv = 1;
if (str.length < 6) {
return Lv
}
if (/[0-9]/.test(str)) {
Lv++
}
if (/[a-z]/.test(str)) {
Lv++
}
if (/[A-Z]/.test(str)) {
Lv++
}
if (/[\.|-|_]/.test(str)) {
Lv++
}
return Lv;
}
// 在字符串中插入新字符串
export const insertStr = (soure, index, newStr) => {
var str = soure.slice(0, index) + newStr + soure.slice(index);
return str;
}
// 16进制颜色值转RGBA字符串
export const colorToRGB = (val, opa) => {
var pattern = /^(#?)[a-fA-F0-9]{6}$/; //16进制颜色值校验规则
var isOpa = typeof opa == 'number'; //判断是否有设置不透明度
if (!pattern.test(val)) { //如果值不符合规则返回空字符
return '';
}
var v = val.replace(/#/, ''); //如果有#号先去除#号
var rgbArr = [];
var rgbStr = '';
for (var i = 0; i < 3; i++) {
var item = v.substring(i * 2, i * 2 + 2);
var num = parseInt(item, 16);
rgbArr.push(num);
}
rgbStr = rgbArr.join();
rgbStr = 'rgb' + (isOpa ? 'a' : '') + '(' + rgbStr + (isOpa ? ',' + opa : '') + ')';
return rgbStr;
}

92
nameCard/card.vue Normal file
View File

@ -0,0 +1,92 @@
<template>
<view>
<view class="nameCard">
<view>
<image class="bgImg" :src="bjImg" mode="aspectFill"></image>
<view class="cardInfo">
<view class="clientName">暂未填写公司</view>
<view class="nameZhiwei">
<text>暂未填写姓名</text>
<text>暂未填写职位</text>
</view>
<view class="cardText">暂未填写联系方式</view>
<view class="cardText">暂未填写邮箱</view>
<view class="cardText">暂未填写地址</view>
</view>
<view class="cardShadow"></view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
bjImg: {
type: String,
default: 'https://7863-xcx-684a14-1302189669.tcb.qcloud.la/image/nameCard/bj/20210521007.jpg'
}
},
data() {
return {
AppLogo: '/static/img/logo.png'
}
},
methods: {
}
}
</script>
<style>
.nameCard {
width: 100%;
height: 390rpx;
background-color: #DDDDDD;
border-radius: 16rpx;
position: relative;
overflow: hidden;
}
.bgImg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.cardInfo {
position: absolute;
top: 40rpx;
left: 40rpx;
color: #FFFFFF;
z-index: 10;
}
.clientName {
font-size: 15px;
}
.nameZhiwei {
margin: 36rpx 0;
}
.nameZhiwei>text:first-child {
font-size: 20px;
font-weight: bold;
padding-right: 16rpx;
}
.cardText {
margin-top: 8rpx;
}
.cardShadow {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: linear-gradient(to right, rgba(0,0,0, 0.2), rgba(0,0,0, 0.06));
z-index: 8;
}
</style>

125
nameCard/cardImg.vue Normal file
View File

@ -0,0 +1,125 @@
<template>
<view>
<view class="nameCard">
<view class="flexRow">
<view class="leftImg">
<image
:src="item.avatar || AppLogo"
mode="aspectFill"></image>
</view>
<view class="cardInfo">
<view class="nameZhiwei">
<text>{{item.name || '姓名'}}</text>
<text>{{item.zhiWei || '暂未填写职位'}}</text>
</view>
<view class="clientName">{{item.clientName || '暂未填写公司'}}</view>
<view class="cardText">{{item.phone || '暂未填写联系方式'}}</view>
<view class="cardText">{{item.email || '暂未填写邮箱'}}</view>
<view class="cardText">{{item.address || '暂未填写地址'}}</view>
</view>
</view>
<view class="cardShadow"></view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
bjImg: {
type: String,
default: ''
}
},
data() {
return {
AppLogo: '/static/img/logo.png'
}
},
methods: {
}
}
</script>
<style>
.nameCard {
width: 100%;
height: 390rpx;
background-color: #515151;
border-radius: 16rpx;
position: relative;
overflow: hidden;
}
.bgImg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.cardInfo {
/* position: absolute;
top: 50rpx;
left: 50rpx; */
width: 406rpx;
margin-top: 40rpx;
color: #FFFFFF;
z-index: 10;
padding-left: 16rpx;
}
.clientName {
font-size: 14px;
margin-bottom: 32rpx;
}
.nameZhiwei {
margin-bottom: 26rpx;
}
.nameZhiwei>text:first-child {
font-size: 20px;
font-weight: bold;
padding-right: 16rpx;
}
.cardText {
margin-top: 8rpx;
}
.cardShadow {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.06));
z-index: 8;
}
.leftImg {
width: 280rpx;
height: 100%;
overflow: hidden;
}
.flexRow {
display: flex;
position: relative;
z-index: 100;
width: 100%;
height: 100%;
}
.leftImg>image {
width: 100%;
height: 100%;
}
</style>

123
nameCard/cardLeftImg.vue Normal file
View File

@ -0,0 +1,123 @@
<template>
<view>
<view class="nameCard">
<image class="bgImg" :src="bjImg" mode="aspectFill"></image>
<view class="cardInfo">
<view class="leftRightView">
<view class="leftView">
<image :src="item.avatar || AppLogo" mode="aspectFill"></image>
</view>
<view class="rightView">
<view class="nameZhiwei">
<text>{{item.name || '姓名'}}</text>
<text>{{item.zhiWei || '暂未填写职位'}}</text>
</view>
<view class="clientName">{{item.clientName || '暂未填写公司'}}</view>
</view>
</view>
<view class="cardText">{{item.phone || '暂未填写联系方式'}}</view>
<view class="cardText">{{item.email || '暂未填写邮箱'}}</view>
<view class="cardText">{{item.address || '暂未填写地址'}}</view>
<!-- <image class="codeImg" :src="item.xcxImg" mode="aspectFill"></image> -->
</view>
<view class="cardShadow"></view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
bjImg: {
type: String,
default: ''
},
xcxImg: {
type: String,
default: ''
}
},
data() {
return {
AppLogo: '/static/img/logo.png'
}
},
methods: {
}
}
</script>
<style>
.nameCard {
width: 100%;
height: 390rpx;
background-color: #DDDDDD;
border-radius: 16rpx;
position: relative;
overflow: hidden;
}
.bgImg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.cardInfo {
position: absolute;
top: 40rpx;
left: 40rpx;
color: #FFFFFF;
z-index: 10;
}
.clientName {
font-size: 14px;
}
.nameZhiwei {
margin-bottom: 18rpx;
}
.nameZhiwei>text:first-child {
font-size: 20px;
font-weight: bold;
padding-right: 16rpx;
}
.cardText {
margin-top: 8rpx;
}
.cardShadow {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: linear-gradient(to right, rgba(0,0,0, 0.2), rgba(0,0,0, 0.06));
z-index: 8;
}
.leftRightView {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.leftView {
width: 128rpx;
height: 128rpx;
background-color: #D8D8D8;
border-radius: 50%;
margin-right: 26rpx;
overflow: hidden;
}
.leftView>image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.rightView {
width: 440rpx;
}
</style>

130
nameCard/cardLeftImg1.vue Normal file
View File

@ -0,0 +1,130 @@
<template>
<view>
<view class="nameCard">
<image class="bgImg" :src="bjImg" mode="aspectFill"></image>
<view class="cardInfo">
<view class="leftRightView">
<view class="leftView">
<image :src="item.avatar || AppLogo" mode="aspectFill"></image>
</view>
<view class="rightView">
<view class="nameZhiwei">
<text>{{item.name || '姓名'}}</text>
<text>{{item.zhiWei || '暂未填写职位'}}</text>
</view>
<view class="clientName">{{item.clientName || '暂未填写公司'}}</view>
</view>
</view>
<view class="cardText">{{item.phone || '暂未填写联系方式'}}</view>
<view class="cardText">{{item.email || '暂未填写邮箱'}}</view>
<view class="cardText">{{item.address || '暂未填写地址'}}</view>
<!-- <image class="codeImg" :src="item.xcxImg" mode="aspectFill"></image> -->
</view>
<view class="cardShadow"></view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
bjImg: {
type: String,
default: ''
},
xcxImg: {
type: String,
default: ''
}
},
data() {
return {
AppLogo: '/static/img/logo.png'
}
},
methods: {
}
}
</script>
<style>
.nameCard {
width: 100%;
height: 390rpx;
background-color: #DDDDDD;
border-radius: 16rpx;
position: relative;
overflow: hidden;
}
.bgImg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.cardInfo {
position: absolute;
top: 40rpx;
left: 40rpx;
color: #FFFFFF;
z-index: 10;
}
.clientName {
font-size: 14px;
}
.nameZhiwei {
margin-bottom: 18rpx;
}
.nameZhiwei>text:first-child {
font-size: 20px;
font-weight: bold;
padding-right: 16rpx;
}
.cardText {
margin-top: 8rpx;
}
.cardShadow {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: linear-gradient(to right, rgba(0,0,0, 0.2), rgba(0,0,0, 0.06));
z-index: 8;
}
.leftRightView {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.leftView {
width: 128rpx;
height: 128rpx;
background-color: #D8D8D8;
border-radius: 26rpx;
margin-right: 26rpx;
overflow: hidden;
}
.leftView>image {
width: 100%;
height: 100%;
}
.rightView {
width: 440rpx;
}
.codeImg {
width: 150rpx;
height: 150rpx;
border-radius: 50%;
position: absolute;
bottom: 6rpx;
right: -20rpx;
}
</style>

123
nameCard/cardRightImg.vue Normal file
View File

@ -0,0 +1,123 @@
<template>
<view>
<view class="nameCard">
<image class="bgImg" :src="bjImg" mode="aspectFill"></image>
<view class="cardInfo">
<view class="leftRightView">
<view class="leftView">
<view class="nameZhiwei">
<text>{{item.name || '姓名'}}</text>
<text>{{item.zhiWei || '暂未填写职位'}}</text>
</view>
<view class="clientName">{{item.clientName || '暂未填写公司'}}</view>
</view>
<view class="rightView">
<image :src="item.avatar || AppLogo" mode="aspectFill"></image>
</view>
</view>
<view class="cardText">{{item.phone || '暂未填写联系方式'}}</view>
<view class="cardText">{{item.email || '暂未填写邮箱'}}</view>
<view class="cardText">{{item.address || '暂未填写地址'}}</view>
<!-- <image class="codeImg" :src="item.xcxImg" mode="aspectFill"></image> -->
</view>
<view class="cardShadow"></view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
bjImg: {
type: String,
default: ''
},
xcxImg: {
type: String,
default: ''
}
},
data() {
return {
AppLogo: '/static/img/logo.png'
}
},
methods: {
}
}
</script>
<style>
.nameCard {
width: 100%;
height: 390rpx;
background-color: #DDDDDD;
border-radius: 16rpx;
position: relative;
overflow: hidden;
}
.bgImg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.cardInfo {
position: absolute;
top: 40rpx;
left: 40rpx;
color: #FFFFFF;
z-index: 10;
}
.clientName {
font-size: 14px;
}
.nameZhiwei {
margin-bottom: 18rpx;
}
.nameZhiwei>text:first-child {
font-size: 20px;
font-weight: bold;
padding-right: 16rpx;
}
.cardText {
margin-top: 8rpx;
}
.cardShadow {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: linear-gradient(to right, rgba(0,0,0, 0.2), rgba(0,0,0, 0.06));
z-index: 8;
}
.leftRightView {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.rightView {
width: 128rpx;
height: 128rpx;
background-color: #D8D8D8;
border-radius: 50%;
overflow: hidden;
}
.rightView>image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.leftView {
width: 440rpx;
margin-right: 26rpx;
}
</style>

View File

@ -1,6 +1,7 @@
{
"name": "pda-cli",
"name": "HAOTOP",
"version": "0.1.0",
"description": "HAOTOP移动端",
"private": true,
"scripts": {
"serve": "npm run dev:h5",
@ -49,6 +50,10 @@
"test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
},
"keywords": [
"HAOTOP",
"浩拓移动端"
],
"dependencies": {
"@dcloudio/uni-app": "^2.0.2-4070520250711001",
"@dcloudio/uni-app-plus": "^2.0.2-4070520250711001",
@ -74,7 +79,10 @@
"core-js": "^3.8.3",
"flyio": "^0.6.2",
"vue": ">= 2.6.14 < 2.7",
"vuex": "^3.2.0"
"vuex": "^3.2.0",
"@icon-park/vue": "^1.3.5",
"dayjs": "^1.11.13",
"vue-i18n": "^8.20.0"
},
"devDependencies": {
"@dcloudio/types": "^3.3.2",

View File

@ -1,17 +1,362 @@
<script>
import { audioManager } from '@/utils/audioManager'
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
import util from '@/common/util.js';
import md5 from '@/common/md5.js';
export default {
onLaunch: function() {
console.log('App Launch')
globalData: {
AppName: '',
LoginID: 0,
EmployeeID: 0,
LoginName: '',
UserName: '',
PlanDepartmentID: 0,
PlanDepartmentName: '',
StoreNameID: 0,
StoreName: '',
StoreTypeNo: '',
IsSaleUserStatus: 0,
Token: '',
app_secret: '',
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
onLaunch() {
console.log('App Launch');
//
audioManager.init();
//
this.$store.dispatch('initNotification');
}
}
</script>
<style>
/*每个页面公共css */
@import url("~@/static/iconfont/iconfont.css");
</style>
<style lang="scss">
@import "uview-ui/index.scss";
@import "pages/common/aidex.scss";
.slot-wrap {
display: flex;
align-items: center;
flex: 1;
padding: 0 16rpx;
}
.right-item {
margin: 0 12rpx;
position: absolute;
right: 18rpx;
color: #ffffff;
display: flex;
}
.textCenter {
width: 100%;
text-align: center;
font-size: 15px;
color: #808080;
margin-top: 88rpx;
}
.h200 {
height: 200px;
}
.h100 {
height: 100px;
}
.mt32 {
margin-top: 32rpx;
}
.bgWhite {
background-color: #FFFFFF;
}
.p26 {
padding: 26rpx !important;
}
.ptb20 {
padding-top: 20rpx;
padding-bottom: 20rpx;
}
.ptb10 {
padding-top: 10rpx;
padding-bottom: 10rpx;
}
.plr0 {
padding-left: 0 !important;
padding-right: 0 !important;
}
.flex-white-plr26 {
background-color: #FFFFFF;
padding-left: 26rpx;
padding-right: 26rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 15px;
}
.flex-white-plr26-column {
background-color: #FFFFFF;
padding-left: 26rpx;
padding-right: 26rpx;
display: flex;
flex-direction: column;
font-size: 15px;
}
.bdb_f5 {
border-bottom: 1rpx solid #f5f5f5;
}
.mr16 {
margin-right: 16rpx;
}
.mr26 {
margin-right: 26rpx;
}
.mlr26 {
margin: 0 26rpx;
}
.mtb32 {
margin: 32rpx 0;
}
.mr32 {
margin-right: 32rpx;
}
.ml26 {
margin-left: 26rpx;
}
.mb0 {
margin-bottom: 0 !important;
}
.pb0 {
padding-bottom: 0 !important;
}
.redXingh {
color: #FF0000;
font-size: 14px;
}
.bluecolor {
color: #0000FF;
font-size: 16px;
}
.udropdown {
background-color: #FFFFFF;
position: fixed !important;
top: 44px;
left: 0;
// z-index: 666;
}
.width276 {
width: 546rpx;
color: #c5c5c5;
font-size: 14px;
}
.cBlack {
color: #c5c5c5;
}
.btName {
margin-bottom: -10rpx;
margin-top: 16rpx;
padding-left: 26rpx;
font-size: 30rpx;
color: #555555;
font-weight: bold;
}
.width242 {
width: 484rpx;
color: #c5c5c5;
font-size: 14px;
}
.myCard {
width: 698rpx;
padding: 24rpx 24rpx 10rpx;
margin: 32rpx 26rpx;
margin-top: 5px;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 14rpx;
position: relative;
background-color: #FFFFFF;
}
.cardRow {
display: flex;
align-items: center;
font-size: 14px;
margin-bottom: 8rpx;
}
.cardRow>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.cardRow>view:last-child {
width: 466rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.cardTopName {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
border-bottom: 1rpx solid #DDDDDD;
padding-bottom: 8rpx;
}
.submitView {
width: 100%;
padding: 16rpx 0 26rpx;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
border-top: 1rpx solid #f1f1f1;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
}
.submitBtn {
width: 666rpx;
}
.lookDetail {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
font-size: 15px;
color: #007AFF;
margin-top: 12rpx;
margin-bottom: 16rpx;
}
.lookDetail>text {
margin-right: 6rpx;
}
.fzrAbsolute {
position: absolute;
right: 26rpx;
bottom: 80rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
.statesRight {
position: absolute;
top: 26rpx;
right: 16rpx;
color: #19BE6B;
font-weight: bold;
}
.blackColor {
color: #333333;
}
.liangHang {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.yellowColor {
color: #ffaa00 !important;
font-weight: bold;
}
.greenColor {
color: #3bb607 !important;
font-weight: bold;
}
.redColor {
color: #ff0000 !important;
font-weight: bold;
}
.blueColor {
color: #007AFF;
}
.colorGray {
color: #888888;
}
.disFlexJ {
display: flex;
justify-content: space-between;
}
.width686 {
width: 686rpx;
margin: 32rpx;
}
.mt26Bt {
border-top: 26rpx solid #EEEEEE;
}
.bgeee {
background-color: #EEEEEE;
margin: 0;
padding: 16rpx 26rpx;
}
.gray32 {
width: 100%;
height: 32rpx;
background-color: #EEEEEE;
}
</style>

36
src/README.en.md Normal file
View File

@ -0,0 +1,36 @@
# ruoyi-uniapp
#### Description
若依-Ruoyi APP 移动解决方案,基于 uniapp+uView 封装的一套基础模版开箱即用一份代码多终端适配支持H5+支付宝小程序+微信小程序+APP实现了与ruoyi-vue后台完美对接的移动解决方案可直接开始快速开发业务需求全新UI设计更多交互细节我们将为您提供极致的交互体验体验持续推出高质量的交互产品
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

170
src/README.md Normal file
View File

@ -0,0 +1,170 @@
# RuoYi-Uniapp若依-手机端)开源啦
#### 介绍
&nbsp; &nbsp; 若依-Ruoyi APP 移动解决方案,基于 uniapp+uView 封装的一套基础模版开箱即用一份代码多终端适配支持H5+支付宝小程序+微信小程序+APP实现了与ruoyi-vue后台完美对接的移动解决方案可直接开始快速开发业务需求全新UI设计更多交互细节我们将为您提供极致的交互体验体验持续推出高质量的交互产品。
如果对您有帮助,您可以点右上角 “Star” 收藏一下 获取第一时间更新谢谢刚刚开源BUG修复中
* 感谢jeesite项目参考自[JeeSite Mobile Uni-App](https://gitee.com/thinkgem/jeesite4-uniapp)
* 感谢[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)
* 适配ruoyi-vue后端将doc下的java类放进去即可
#### 请大家支持一下我
开源中国发起年度开源软件评选为了让我们的Ruoyi aidex Sharp平台走的更久更远请大家为我投个票感谢[点我投票](https://www.oschina.net/project/top_cn_2021?id=590)
微信扫码投票:
<img src="%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20211208202901.jpg" width="220" height="220" >&nbsp; &nbsp; &nbsp;&nbsp;
#### 快速体验
2、微信小程序端扫码访问目前只能用用户名密码方式登录用户名admin 密码admin123<br><br>
<img src="https://images.gitee.com/uploads/images/2021/1115/214722_20aaf4c8_9700683.jpeg" width="220" height="220" >
#### 我的另一个项目:
**AiDex Sharp 快速开发平台** 基于著名的开源项目“ **若依-RuoYi-Vue** ”改造而成,追求 **极致的UI交互体验****快速开发** ,一切向 **效率** 看齐, **重构优化** 后端的代码,对前端页面进行了 **美化****我们将持续升级,持续完善,欢迎友友们收藏和点赞**
* [打开Aidex Sharp](https://gitee.com/big-hedgehog/aidex-sharp)
<table>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0923/234748_170e4ee7_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184210_ffa2880b_9700683.png"/></td>
</tr>
</table>
#### 如何使用uni-app端
##### 一、导入uniapp项目
1. 首先下载HBuilderX并安装地址https://www.dcloud.io/hbuilderx.html
2. 打开HBuilderX -> 顶部菜单栏 -> 文件 -> 导入 -> 从本地目录导入 -> 选择uniapp端项目目录
3. 找到common/config.js文件找到里面的apiUrl项填入已搭建的后端url地址
4. 打开manifest.json文件选择微信小程序配置填写小程序的appid
##### 二、本地调试
1. 打开HBuilderX -> 顶部菜单栏 -> 运行 -> 运行到浏览器 -> Chrome
2. 如果请求后端api时 提示跨域错误可安装Chrome插件【Allow CORS: Access-Control-Allow-Origin】地址https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf
##### 三、打包发行H5
1. 打开HBuilderX -> 顶部菜单栏 -> 发行 -> 网站H5-手机版
2. 打包后的文件路径:/unpackage/dist/build/h5
3. 将打包完成的所有文件 复制到商城后端/pulic目录下全部替换
##### 四、打包发行(微信小程序)
1. 下载微信开发者工具并安装地址https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
2. 打开HBuilderX -> 顶部菜单栏 -> 发行 -> 小程序-微信
3. 打包后的文件路径:/unpackage/dist/build/mp-weixin
5. 打开微信开发者工具 导入 打包完成的项目
6. 检查没有运行错误,在右上方上传小程序
##### 5、后端代码适配ruoyi-vue
1. 可以启动后端直接访问http://aidex.vip的公共服务如果要自己适配请将doc目录下的代码放到项目中即可。
#### 界面截图
<table>
<tr>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/184344_b519b98b_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223144_43bc09a8_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223205_fd09aab2_9700683.png" width="300" height="480"/></td>
</tr>
<tr>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223528_bd934103_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223553_5d4f27a1_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223612_8ca07db6_9700683.png" width="300" height="480"/></td>
</tr>
<tr>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223248_7d40c45c_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223306_a6be218d_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223324_a3415319_9700683.png" width="300" height="480"/></td>
</tr>
<tr>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223405_a7fd6593_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223424_398ebcde_9700683.png" width="300" height="480"/></td>
<td style="border:5px"><img src="https://images.gitee.com/uploads/images/2021/1112/223501_db695cd4_9700683.png" width="300" height="480"/></td>
</tr>
</table>
## 我的另一个项目:
**AiDex Sharp 快速开发平台** 基于著名的开源项目“ **若依-RuoYi-Vue** ”改造而成,追求 **极致的UI交互体验****快速开发** ,一切向 **效率** 看齐, **重构优化** 后端的代码,对前端页面进行了 **美化****我们将持续升级,持续完善,欢迎友友们收藏和点赞**
* [打开Aidex Sharp](https://gitee.com/big-hedgehog/aidex-sharp)
官方QQ群
Aidex Sharp快速开发平台3群 208511180 使用问题请入群由专人负责简答
## 后台系统截图
<table>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0923/234823_7d05456a_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0923/234748_170e4ee7_9700683.png"/></td>
</tr>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184041_c4d1f1aa_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184055_0cf08e45_9700683.png"/></td>
</tr>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184110_2e6df64f_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184125_3d5bdddf_9700683.png"/></td>
</tr>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184139_092a8f07_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0922/225255_f8710fb3_9700683.png"/></td>
</tr>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184210_ffa2880b_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184223_8f57f5f0_9700683.png"/></td>
</tr>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184238_5cb3e09e_9700683.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2021/0911/184256_5bc77bff_9700683.png"/></td>
</tr>
</table>
更多功能请访问系统体验
## 在线体验
演示地址http://aidex.vip 帐号admin 密码admin123
#### uniapp知识
1. <a href="https://uniapp.dcloud.io/README" target="blank">uni-app介绍</a>
2. <a href="https://ke.qq.com/course/3169971" target="blank">uni-app 官方视频教程</a>
3. <a href="https://www.dcloud.io/hbuilderx.html" target="blank">uni-app开发工具 HBuilderX 下载及使用说明</a>
4. <a href="http://ask.dcloud.net.cn/article/35657" target="blank">uni-app是什么能解决什么问题</a>
5. <a href="https://uniapp.dcloud.io/vue-basics" target="blank">Vue.js相关文档、视频教程</a>
#### 技术手册
* <a href="https://uniapp.dcloud.io/collocation/pages" target="blank">uni-app 框架文档</a>
* <a href="https://uniapp.dcloud.io/component/README" target="blank">uni-app 组件文档</a>
* <a href="https://uviewui.com/components/intro.html" target="blank">uView 组件文档</a>
* <a href="https://uviewui.com/js/intro.html" target="blank">uView JS 文档</a>
#### 授权许可协议条款
1. Ruoyi-Uniapp采用MIT开源协议协议。
2. 代码可用于个人项目等接私活或企业项目脚手架使用Ruoyi-Uniapp开源版完全免费。
3. 允许进行商用,但是不允许二次开源出来并进行收费,否则将追究侵权者法律责任。
4. 请不要删除和修改Ruoyi-Uniapp源码头部的版权与作者声明及出处。
5. 不得进行简单修改包装声称是自己的项目。
6. 我们已经申请了相关的软件开发著作权和相关登记
7. 需要在您的软件介绍明显位置说明出处举例本软件基于Ruoyi-Uniapp手机端
#### 关于我们
&nbsp; &nbsp; 我们擅长UI、前端开发、后端架构有一颗热爱开源的心致力于打造企业级的通用产品设计UI体系让项目
或者更直观更高效、更简单未来将持续关注UI交互持续推出高质量的交互产品。
######
<img src="https://images.gitee.com/uploads/images/2021/1112/114326_5eb079c2_9700683.jpeg" width="220" height="220" >&nbsp; &nbsp; &nbsp;&nbsp;
<img src="https://images.gitee.com/uploads/images/2021/1112/114207_bb1bac92_9700683.jpeg" width="220" height="220" >&nbsp; &nbsp; &nbsp;&nbsp;
<img src="https://images.gitee.com/uploads/images/2021/1115/164243_d4e0d61d_9700683.png" width="220" height="220" >&nbsp; &nbsp; &nbsp;&nbsp;
版权所有Copyright © 2017-2021 By AiDex (http://www.aidex.vip) All rights reserved。

475
src/chanpin/view/addCp.vue Normal file
View File

@ -0,0 +1,475 @@
<template>
<view>
<view class="flex-white-plr26 ptb10 mt32 bdb_f5">
<text class="mr26">产品名称
<text class="redXingh">*</text>
</text>
<u-input v-model="pName" placeholder="请在此输入产品名称" />
</view>
<view @click="pickerSelectFun('产品单位')" class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">产品单位
<text class="redXingh">*</text>
</text>
<u-input v-model="unit" placeholder="请在此输入产品单位" />
</view>
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">产品价格
<text class="redXingh">*</text>
</text>
<u-input v-model="price" type="number" placeholder="请在此输入产品价格" />
</view>
<view @click="pickerSelectFun('产品类型')" class="flex-white-plr26 ptb20 bdb_f5">
<text class="mr26">产品类型
<text class="redXingh">*</text>
</text>
<view :class="flName ? '' : 'cBlack'">
{{flName ? flName : '请选择'}}
<u-icon class="ml26" name="arrow-right" size="40" color="#888888"></u-icon>
</view>
</view>
<view @click="pickerSelectFun('上下架')" class="flex-white-plr26 ptb20 bdb_f5">
<text class="mr26">是否上下架
<text class="redXingh">*</text>
</text>
<view :class="isSxJ ? '' : 'cBlack'">
{{isSxJ ? isSxJ : '请选择'}}
<u-icon class="ml26" name="arrow-right" size="40" color="#888888"></u-icon>
</view>
</view>
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">产品销量</text>
<u-input v-model="salesNum" type="number" placeholder="请在此输入产品销量" />
</view>
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">产品库存</text>
<u-input v-model="stock" type="number" placeholder="请在此输入产品库存" />
</view>
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">产品编码</text>
<u-input v-model="code" placeholder="请在此输入产品编码" />
<u-icon @click="scanFun" class="ml26" name="scan" size="44" color="#007aff"></u-icon>
</view>
<view class="flex-white-plr26-column ptb20 mt32 bdb_f5">
<view style="margin-bottom: 8rpx;">
<text>产品简述</text>
</view>
<u-input v-model="describe" type="textarea" :border="true" :height="100" :auto-height="true" />
</view>
<view class="flex-white-plr26-column ptb20 mt32 bdb_f5">
<view style="margin-bottom: 8rpx; display: flex; align-items: center;">
<text>产品参数</text>
<u-icon @click="addCsFun" name="plus-circle-fill" color="#007aff" size="50" style="margin-left: 16rpx;">
</u-icon>
</view>
<view class="canshuInputRow" v-for="(item, index) in cpCsList" :key="index">
<view class="csInput1">
<u-input v-model="item.csName" :border="true" placeholder="参数名称" />
</view>
<view class="csInput2">
<u-input v-model="item.csJieShao" :border="true" placeholder="请在此输入参数介绍" />
</view>
<u-icon @click="deleteCpCsFun(index)" name="close-circle-fill" size="50" color="#ff0000"></u-icon>
</view>
</view>
<view class="flex-white-plr26-column ptb20 mt32">
<view style="margin-bottom: 8rpx;">产品封面图1</view>
<u-upload @on-choose-complete="uploadFmChangeFun" @on-remove="fmtRemoeFun" :size-type="siziType" :show-progress="false"
:file-list="cpFmtList" :max-size="5 * 1024 * 1024" max-count="1" :auto-upload="false"></u-upload>
</view>
<view class="flex-white-plr26-column ptb20 mt32">
<view style="margin-bottom: 8rpx;">产品轮播图最多上传5张</view>
<u-upload @on-choose-complete="uploadLbtChangeFun" @on-list-change="fileChangeFun" @on-remove="lbtRemoeFun" :size-type="siziType" :show-progress="false"
:file-list="cpLbtList" :max-size="5 * 1024 * 1024" max-count="5" :auto-upload="false"></u-upload>
</view>
<view class="flex-white-plr26-column ptb20 mt32">
<view style="margin-bottom: 8rpx;">产品详情图最多上传9张</view>
<u-upload @on-choose-complete="uploadXqChangeFun" @on-remove="xqtRemoeFun" :size-type="siziType" :show-progress="false"
:file-list="cpXqtList" :max-size="5 * 1024 * 1024" max-count="9" :auto-upload="false"></u-upload>
</view>
<!--提交按钮-->
<view class="submitView">
<u-button v-if="!pageType" type="primary" class="submitBtn" :ripple="true" ripple-bg-color="#909399"
@click="addXgFun">提交</u-button>
<u-button v-if="pageType == 'update'" type="primary" class="submitBtn" :ripple="true"
ripple-bg-color="#909399" @click="addXgFun">保存</u-button>
</view>
<!--组件-->
<u-select v-model="selectShow" :list="selectList" @confirm="selectConfirmFun"></u-select>
<!--图片上传方法组件-->
<uploadImg v-if="ppImgShow" :ppList="ppList" :ppUrls="ppUrls" @confirmPopupFun="confirmPopupFun"></uploadImg>
</view>
</template>
<script>
let that = '';
import {
getNowDate
} from '@/static/utils/date.js'
import {
uploadImgFun
} from '@/static/utils/upload.js'
import uploadImg from '@/components/upload/uploadImg'
import { crmChanpinApi, crmCpClassifyApi, fileApi } from '@/static/utils/api.js'
export default {
components: {
uploadImg
},
data() {
return {
selectShow: false,
selectList: [],
selectType: '',
pName: '',
price: '',
salesNum: '',
stock: '',
code: '',
flName: '',
cpFlId: '',
unit: '',
isSxJ: '上架',
describe: '',
action: 'http://www.example.com/upload',
fileList: [],
classify: [],
cpLbt: [],
cpXqt: [],
cpFmt: [],
cpLbtList: [],
cpXqtList: [],
cpFmtList: [],
cpCsList: [],
pageType: '',
siziType: ['compressed'],
ppImgShow: false,
uploadType: '',
ppList: [],
ppUrls: [],
xgCpInfo: {}
}
},
onLoad(e) {
that = this;
if (e.type == 'update') {
uni.setNavigationBarTitle({
title: '修改产品信息'
})
that.pageType = e.type;
that.setDataFun();
}
that.getClassifyFun();
},
methods: {
//
getClassifyFun: function() {
uni.showLoading({
title: '加载中...',
mask: true
})
let reqData = {
action: 'getFlList',
params: {
matchObj: {
isShow: true
}
}
}
crmCpClassifyApi(reqData)
.then(res => {
let data = res.result.data;
if (data && data.length > 0) {
if(that.pageType != 'update') {
that.flName = data[0].flName;
that.cpFlId = data[0]._id;
}
that.classify = data;
} else {
uni.showModal({
title: '提示',
content: '当前暂未设置产品分类,请先添加产品分类!',
success(res) {
if (res.confirm) {
uni.redirectTo({
url: './classify?pageType=add'
})
}
}
})
}
})
},
//
chooseAddrFun: function() {
uni.chooseLocation({
success: function(res) {
that.gjAddr = res.address;
}
});
},
//
pickerSelectFun: function(str) {
if (str == '产品类型') {
let classify = that.classify;
let arr = [];
for (var i = 0; i < classify.length; i++) {
arr.push({
value: classify[i]._id,
_id: classify[i]._id,
label: classify[i].flName
})
}
that.selectList = arr;
} else if (str == '上下架') {
that.selectList = [{
value: 0,
b: true,
label: '上架'
},
{
value: 1,
b: false,
label: '下架'
}
]
}
that.selectShow = true;
that.selectType = str;
},
//
selectConfirmFun: function(e) {
if (that.selectType == '产品类型') {
that.flName = e[0].label;
that.cpFlId = e[0]._id || e[0].value;
} else if (that.selectType == '上下架') {
that.isSxJ = e[0].label;
}
},
// clear
uploadFmChangeFun: function(list) {
that.uploadType = 'fmt';
that.ppList = list;
that.ppUrls = that.cpFmt;
that.ppImgShow = true;
},
//
fmtRemoeFun: function(e) {
let arr = that.cpFmt.splice(e, 1);
that.deleteFun(arr)
},
fileChangeFun: function(e) {
},
//
uploadLbtChangeFun: function(list) {
that.uploadType = 'lbt';
that.ppList = list;
that.ppUrls = that.cpLbt;
that.ppImgShow = true;
},
//
lbtRemoeFun: function(e) {
let arr = that.cpLbt.splice(e, 1);
that.deleteFun(arr)
},
//
uploadXqChangeFun: function(list) {
that.uploadType = 'xqt';
that.ppList = list;
that.ppUrls = that.cpXqt;
that.ppImgShow = true;
},
//
xqtRemoeFun: function(e) {
let arr = that.cpXqt.splice(e, 1);
that.deleteFun(arr)
},
// popup
confirmPopupFun: function(e) {
that.ppImgShow = false;
if (that.uploadType == 'lbt') {
that.cpLbt = e;
} else if (that.uploadType == 'xqt') {
that.cpXqt = e;
} else {
that.cpFmt = e;
}
},
//
deleteFun: function(list) {
let reqData = {
action: 'delete',
params: {
fileList: [list[0].fileId]
}
}
fileApi(reqData)
.then(res => {
})
},
scanFun: function() {
uni.scanCode({
success(res) {
that.code = res.result;
}
})
},
//
addXgFun: function() {
let reqObj = {
req: {
pName: that.pName,
price: that.price,
unit: that.unit,
cpFlId: that.cpFlId,
isSxJ: that.isSxJ == '上架' ? true : false,
code: that.code,
describe: that.describe,
cpCsList: that.cpCsList,
cpLbtList: that.cpLbt,
cpXqtList: that.cpXqt,
cpFmtList: that.cpFmt,
salesNum: that.salesNum,
stock: that.stock
}
}
if (!that.pName) {
uni.$myModalFun('产品名称不能为空,请输入!')
return
}
if (!that.price) {
uni.$myModalFun('产品价格不能为空,请输入!')
return
}
if (!that.unit) {
uni.$myModalFun('产品单位不能为空,请输入!')
return
}
let action = 'add';
let time = new Date().getTime();
if (that.pageType == 'update') {
action = 'update'
reqObj._id = that.xgCpInfo._id;
reqObj.req.update_date = time;
reqObj.req.updateUid = uni.$userInfo._id;
uni.showLoading({
title: '修改中...'
})
} else {
reqObj.req.create_date = time;
reqObj.req.update_date = time;
reqObj.req.cjRenId = uni.$userInfo._id;
reqObj.req.updateUid = uni.$userInfo._id;
uni.showLoading({
title: '提交中...'
})
}
let reqData = {
action: action,
params: reqObj
}
crmChanpinApi(reqData)
.then(res => {
if (action == 'update') {
uni.showToast({
title: '产品修改成功',
icon: 'none',
duration: 1000
})
} else {
that.pageType = 'update';
that.xgCpInfo._id = res.result.id;
let item = reqObj.req;
item._id = res.result.id;
uni.$cpDetail = item;
uni.showToast({
mask: true,
title: '产品新增成功',
duration: 1000
})
setTimeout(() => {
uni.redirectTo({
url: './cpDetail'
})
}, 1000)
}
})
},
//
addCsFun: function() {
that.cpCsList = that.cpCsList.concat({
csName: '',
csJieShao: ''
})
},
//
deleteCpCsFun: function(iii) {
that.cpCsList.splice(iii, 1)
},
//
setDataFun: function() {
let obj = uni.$cpDetail;
that.xgCpInfo = obj;
that.pName = obj.pName
that.price = obj.price;
that.unit = obj.unit;
that.flName = obj.flName;
that.cpFlId = obj.cpFlId;
that.isSxJ = obj.isSxJ ? '上架' : '下架';
that.code = obj.code;
that.describe = obj.describe;
that.cpCsList = obj.cpCsList;
that.cpLbtList = obj.cpLbtList || [];
that.cpXqtList = obj.cpXqtList || [];
that.cpFmtList = obj.cpFmtList || [];
that.cpLbt = obj.cpLbtList || [];
that.cpXqt = obj.cpXqtList || [];
that.cpFmt = obj.cpFmtList || [];
that.salesNum = obj.salesNum || '';
that.stock = obj.stock || '';
}
}
}
</script>
<style>
page {
background-color: #F8F8F8;
padding-bottom: 260rpx;
}
.u-radio {
width: 200rpx !important;
}
.submitView {
width: 100%;
padding: 16rpx 0 26rpx;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
border-top: 1rpx solid #f1f1f1;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
}
.submitBtn {
width: 666rpx;
}
.canshuInputRow {
display: flex;
justify-content: space-between;
margin-top: 16rpx;
}
.canshuInputRow>.csInput1 {
width: 36%;
}
.canshuInputRow>.csInput2 {
width: 50%;
}
</style>

View File

@ -0,0 +1,512 @@
<template>
<view>
<topDropdown :isSxShow="true" :dropdown1="dropdown1" dropdown2="上架中" :options1="options1" :options2="isSjList" :optionsSx="sxList" searchUrl="./searchAdmin" @dropDownFun1="dropDownFun1" @dropDownFun2="dropDownFun2" @optionSxFun="optionSxFun">
</topDropdown>
<dataNull v-if="list.length == 0" src="/static/img/chahua/dataNullXz.png" title="暂无相关产品"
title1="请添加或者更换查询条件"></dataNull>
<scroll-view v-else scroll-y="true" :style="{height: scrollHeight}" @scrolltolower="getChanPinFun"
refresher-enabled :refresher-threshold="200" :refresher-triggered="triggered" refresher-background="gray"
@refresherrefresh="onRefresh" @refresherrestore="onRestore">
<view v-for="(item, index) in list" :key="index" @click="cardClick(item)">
<view v-if="item.cpFmtList && item.cpFmtList.length > 0" class="myCard2">
<view class="leftImg">
<u-image height="160" width="160" border-radius="26" :src="item.cpFmtList[0].url"></u-image>
</view>
<view class="rightView">
<view class="cardTopName1">{{item.pName}}</view>
<view v-if="item.salesNum || item.stock" class="xlKcClass">
<text v-if="item.salesNum">销量: {{item.salesNum}}</text>
<text v-if="item.stock">库存: {{item.stock}}</text>
</view>
<view class="cardRow1">
<text class="redColor">{{item.price}}</text>/{{item.unit}}
</view>
<view class="rowBtn">
<u-button type="primary" :plain="true" class="cpBtn" size="mini" @tap.stop="setCpFun(item)">
编辑产品
</u-button>
<u-button type="warning" :plain="true" class="cpBtn" size="mini"
@click="cpsxjFun(item, index)">{{item.isSxJ == true ? '下架' : '上架'}}</u-button>
<u-button type="error" :plain="true" class="cpBtn" size="mini"
@tap.stop="deleteCpFun(item, index)">
删除</u-button>
</view>
</view>
</view>
<view v-else class="myCard">
<view class="cardTopName">产品名称{{item.pName}}</view>
<view class="cardRow">
<view>产品状态</view>
<view>{{item.isSxJ ? '上架中' : '下架'}}</view>
</view>
<view class="cardRow">
<view>产品价格</view>
<view><text class="redColor">{{item.price}}</text>/{{item.unit}}</view>
</view>
<view class="cardRow">
<view>产品类型</view>
<view>{{item.flName}}</view>
</view>
<view class="cardRow" v-if="item.salesNum">
<view>产品销量</view>
<view>{{item.salesNum}}</view>
</view>
<view class="cardRow" v-if="item.stock">
<view>产品库存</view>
<view>{{item.stock}}</view>
</view>
<view class="cardRow" v-if="item.describe">
<view>产品简述</view>
<view>{{item.describe}}</view>
</view>
<view class="rowBtn">
<u-button type="primary" :plain="true" class="cpBtn" size="mini" @tap.stop="setCpFun(item)">编辑产品
</u-button>
<u-button type="warning" :plain="true" class="cpBtn" size="mini" @click="cpsxjFun(item, index)">
{{item.isSxJ == true ? '下架' : '上架'}}</u-button>
<u-button type="error" :plain="true" class="cpBtn" size="mini"
@tap.stop="deleteCpFun(item, index)">
删除</u-button>
</view>
</view>
</view>
<getMore :isMore="isMore" class="h200"></getMore>
</scroll-view>
<addBtn url="./addCp"></addBtn>
</view>
</template>
<script>
let that = '';
import dataNull from '@/components/dataNull/dataNull.vue'
import addBtn from '@/components/addBtn/addBtn.vue'
import getMore from '@/components/getMore/getMore.vue'
import topDropdown from '@/components/topDropdown/topDropdown.vue'
import { crmChanpinApi, crmCpClassifyApi, fileApi } from '@/static/utils/api.js'
export default {
components: {
dataNull,
addBtn,
getMore,
topDropdown
},
data() {
return {
triggered: false,
pageIndex: 1,
list: [],
classify: [],
dropdown1: '产品分类',
cpClassify: '',
cpFlId: '',
isMore: true,
scrollHeight: '667px',
sjType: '上架中',
options1: [],
isSjList: [{
value: 0,
label: '上架中'
},
{
value: 1,
label: '下架'
},
],
isSxJ: true,
sxList: [{
title: '创建时间排序',
field: 'create_date',
current: '',
arr: [
'降序',
'升序'
]
},
{
title: '修改时间排序',
field: 'update_date',
current: '',
arr: [
'降序',
'升序'
]
},
{
title: '销量排序',
field: 'salesNum',
current: '',
arr: [
'降序',
'升序'
]
},
{
title: '库存排序',
field: 'stock',
current: '',
arr: [
'降序',
'升序'
]
},
],
sortObj: {
update_date: -1
}
}
},
onLoad() {
that = this;
uni.getSystemInfo({
success(res) {
that.scrollHeight = res.windowHeight - 40 + 'px';
}
})
that.getClassifyFun();
},
methods: {
//
getClassifyFun: function() {
uni.showLoading({
title: '加载中...',
mask: true
})
let reqData = {
action: 'get',
params: {
isShow: true
}
}
crmCpClassifyApi(reqData)
.then(res => {
let data = res.result.data;
if (data && data.length > 0) {
that.classify = data;
that.cpClassify = data[0].flName;
that.cpFlId = data[0]._id;
that.setDropDownFun();
that.getChanPinFun();
} else {
uni.showModal({
title: '提示',
content: '当前暂未设置产品分类,请先添加产品分类!',
success(res) {
if (res.confirm) {
uni.redirectTo({
url: './classify?pageType=add'
})
}
}
})
}
})
},
//
getChanPinFun: function() {
if (!that.isMore) {
return
}
uni.showLoading({
title: '加载中...',
mask: true
})
let reqObj = {
matchObj: {
cpFlId: that.cpFlId,
isSxJ: that.isSxJ,
},
pageIndex: that.pageIndex,
sortObj: that.sortObj
}
let reqData = {
action: 'getCpList',
params: reqObj
}
console.log(reqData)
crmChanpinApi(reqData)
.then(res => {
let data = res.result.data
if (that.pageIndex == 1) {
that.list = [];
}
if (data.length == 20) {
that.pageIndex += 1;
that.isMore = true;
} else {
that.isMore = false;
}
that.triggered = false;
that.list = that.list.concat(data);
})
},
//
setDropDownFun: function() {
let list = that.classify;
let arr = [];
for (var i = 0; i < list.length; i++) {
arr.push({
value: i,
_id: list[i]._id,
label: list[i].flName
})
}
that.options1 = arr;
that.dropdown1 = arr[0].label;
},
// 1
dropDownFun1: function(e) {
that.cpClassify = e.label;
that.cpFlId = e._id;
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
// 2
dropDownFun2: function(e) {
if (e.label == '上架中') {
that.isSxJ = true
} else {
that.isSxJ = false
}
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
//
optionSxFun: function(arr) {
let sortObj = {
update_date: -1
}
for (var i = 0; i < arr.length; i++) {
if (arr[i].current !== '') {
if (arr[i].field == 'create_date') {
sortObj.create_date = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'update_date') {
sortObj.update_date = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'salesNum') {
sortObj.salesNum = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'stock') {
sortObj.stock = arr[i].current == 1 ? 1 : -1
}
that.sortObj = sortObj;
break;
}
}
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
//
cardClick: function(item) {
uni.$cpDetail = item;
uni.navigateTo({
url: './cpDetail'
})
},
//
setCpFun: function(item) {
uni.$cpDetail = item;
uni.navigateTo({
url: './addCp?type=update'
})
},
//
deleteCpFun: function(item, index) {
uni.showModal({
title: '提示',
content: '是否确认删除产品:' + item.pName,
success(rrr) {
if (rrr.confirm) {
uni.showLoading({
title: '删除中...'
})
let arr = item.cpFmtList;
arr = arr.concat(item.cpLbtList);
arr = arr.concat(item.cpXqtList);
if (arr.length > 0) {
that.deleteCpFileFun(item._id, index, arr)
} else {
that.deleteCpApiFun(item._id, index);
}
}
}
})
},
// api
deleteCpApiFun: function(_id, index) {
let reqData = {
action: 'deleteById',
params: {
_id
}
}
crmChanpinApi(reqData)
.then(res => {
uni.showToast({
title: '删除成功!',
icon: 'none',
duration: 1000
})
that.list.splice(index, 1);
})
},
// api
deleteCpFileFun: function(_id, index, arr) {
let fileList = [];
for (var i = 0; i < arr.length; i++) {
fileList.push(arr[i].fileId);
}
let reqData = {
action: 'delete',
params: {
fileList
}
}
fileApi(reqData)
.then(res => {
that.deleteCpApiFun(_id, index);
})
},
//
cpsxjFun: function(item, index) {
let str = '上架中...';
let sxj = true
if (item.isSxJ) {
sxj = false;
str = '下架中...'
}
uni.showLoading({
title: str,
mask: true
})
let reqObj = {
_id: item._id,
req: {
isSxJ: sxj
}
}
let reqData = {
action: 'update',
params: reqObj
}
crmChanpinApi(reqData)
.then(res => {
let showTitle = '上架成功'
if (sxj == false) {
showTitle = '下架成功!'
}
uni.showToast({
title: showTitle,
icon: 'none',
duration: 2000
})
that.list.splice(index, 1);
})
},
onRefresh: function() {
if(that.triggered) return
that.triggered = true;
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
onRestore: function(e) {
that.triggered = false; //
}
}
}
</script>
<style>
page {
background-color: #F8F8F8;
}
.rowBtn {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 26rpx 16rpx 16rpx 0;
justify-content: flex-end;
}
.cpBtn {
margin: 0 0 0 26rpx;
font-size: 15px !important;
height: 60rpx !important;
line-height: 60rpx !important;
}
.gdCz {
width: 60rpx;
height: 60rpx;
padding: 6rpx 12rpx;
}
.myCard2 {
width: 698rpx;
padding: 26rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
display: flex;
}
.cardTopName1 {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-weight: bold;
padding-bottom: 8rpx;
}
.cardRow1 {
display: flex;
align-items: center;
font-size: 16px;
margin-bottom: 8rpx;
}
.cardRow1>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.cardRow1>view:last-child {
color: #000000;
}
.leftImg {
width: 160rpx;
height: 160rpx;
margin-right: 26rpx;
border-radius: 26rpx;
overflow: hidden;
border: 1rpx solid #DDDDDD;
}
.rightView {
width: 460rpx;
}
.xlKcClass {
font-size: 14px;
color: #888888;
margin-bottom: 8rpx;
}
.xlKcClass>text {
margin-right: 26rpx;
}
</style>

View File

@ -0,0 +1,366 @@
<template>
<view>
<dataNull v-if="list.length == 0" src="/static/img/chahua/dataNullXz.png" title="暂无相关分类"
title1="点击添加按钮添加相关分类"></dataNull>
<view v-else class="content">
<view class="row" v-for="(row, index) in list" :key="index">
<text class="text">{{row.flName}}</text>
<view class="rightMenuRow">
<u-switch v-model="row.isShow" inactive-color="#f00" @change="changeClassFun(row)">
</u-switch>
<view class="menuBtn primaryBtn" @click="updateNameFun(row)">修改</view>
<view class="menuBtn errorBtn" @click="deleteFun(row)">删除</view>
</view>
</view>
</view>
<view @click="popupShow = true">
<addBtn></addBtn>
</view>
<!--新增分类-->
<u-popup v-model="popupShow" mode="center" border-radius="14" width="500rpx">
<view class="popupTitle">新增分类</view>
<view class="popupInput">
<text>分类名称</text>
<input v-model="flName" class="uInput" type="text" placeholder="请输入分类名称" style="font-size: 16px;">
</view>
<view class="popupInput">
<text>分类排序</text>
<input v-model="sort" class="uInput" type="number" placeholder="数值越小越靠前" style="font-size: 16px;">
</view>
<view class="btnRow">
<view class="popupBtn errorBtn" @click="popupShow = false">取消</view>
<view class="popupBtn primaryBtn" @click="addClassifyFun">确认</view>
</view>
</u-popup>
<!--修改分类名称-->
<u-popup v-model="popupXgShow" mode="center" border-radius="14" width="500rpx">
<view class="popupTitle">修改名称</view>
<view class="popupInput">
<text>分类名称</text>
<input v-model="flName" class="uInput" type="text" placeholder="请输入分类名称" style="font-size: 16px;">
</view>
<view class="popupInput">
<text>分类排序</text>
<input v-model="sort" class="uInput" type="number" placeholder="数值越小越靠前" style="font-size: 16px;">
</view>
<view class="btnRow">
<view class="popupBtn errorBtn" @click="popupXgShow = false">取消</view>
<view class="popupBtn primaryBtn" @click="updateConfirmFun">确认</view>
</view>
</u-popup>
</view>
</template>
<script>
let that = '';
import dataNull from '@/components/dataNull/dataNull.vue'
import addBtn from '@/components/addBtn/addBtn.vue'
import {
crmCpClassifyApi
} from '@/static/utils/api.js'
export default {
components: {
dataNull,
addBtn
},
data() {
return {
popupShow: false,
popupXgShow: false,
addName: '',
flName: '',
sort: '',
flData: {},
list: [],
xgObj: {},
ispush: false,
pageType: ''
}
},
onLoad(e) {
that = this;
if (e.pageType) {
that.pageType = e.pageType;
that.popupShow = true;
}
that.getClassifyFun();
},
methods: {
//
getClassifyFun: function() {
uni.showLoading({
title: '加载中...',
mask: true
})
let reqData = {
action: 'getFlList',
params: {}
}
crmCpClassifyApi(reqData)
.then(res => {
let data = res.result.data;
console.log(data)
that.list = data;
// if (data) {
// that.list = data.list;
// uni.setStorageSync('classifyList', data.list);
// }
})
},
//
addClassifyFun: function() {
if (!that.flName) {
uni.showToast({
title: '请输入分类名称!',
icon: 'none'
})
return
}
if (!that.sort) {
uni.showToast({
title: '请输入分类排序数值!',
icon: 'none'
})
return
}
uni.showLoading({
title: '提交中...',
mask: true
})
let obj = {
flName: that.flName,
sort: parseFloat(that.sort),
isShow: true
}
let time = new Date().getTime()
obj.create_date = time;
obj.update_date = time;
obj.cjRenId = uni.$userInfo._id;
obj.updateUid = uni.$userInfo._id;
let reqData = {
action: 'add',
params: {
req: obj
}
}
crmCpClassifyApi(reqData)
.then(res => {
that.flName = '';
that.sort = '';
that.popupShow = false;
uni.showToast({
title: '新增成功!',
icon: 'none',
duration: 2000
})
that.getClassifyFun()
})
},
//
updateNameFun: function(item) {
that.popupXgShow = true;
that.xgObj = item;
that.sort = item.sort;
that.flName = item.flName;
},
//
updateConfirmFun: function() {
if (!that.flName) {
uni.showToast({
title: '请输入分类名称!',
icon: 'none'
})
return
}
if (!that.sort) {
uni.showToast({
title: '请输入分类排序数值!',
icon: 'none'
})
return
}
uni.showLoading({
title: '更新中...',
mask: true
})
let obj = {
flName: that.flName,
sort: parseFloat(that.sort)
};
let time = new Date().getTime()
obj.update_date = time;
obj.updateUid = uni.$userInfo._id;
let reqData = {
action: 'updateFl',
params: {
_id: that.xgObj._id,
updateObj: obj
}
}
crmCpClassifyApi(reqData)
.then(res => {
that.flName = '';
that.sort = '';
that.popupXgShow = false;
uni.showToast({
title: '修改成功!',
icon: 'none',
duration: 2000
})
that.getClassifyFun()
})
},
//
changeClassFun: function(e) {
let reqData = {
action: 'updateFl',
params: {
_id: e._id,
updateObj: {
isShow: e.isShow
}
}
}
crmCpClassifyApi(reqData)
.then(res => {
that.getClassifyFun();
})
},
//
deleteFun: function(item) {
uni.showModal({
title: '提示',
content: '是否确认要删除该产品分类:' + item.flName + '?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中,请稍等...',
mask: true
})
let reqData = {
action: 'deleteFlById',
params: {
_id: item._id
}
}
crmCpClassifyApi(reqData)
.then(res => {
that.getClassifyFun();
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #efeff4 !important;
}
.content {
background-color: #FFFFFF;
padding: 26rpx;
.row {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
height: 100rpx;
border-bottom: 1rpx solid #CDCDCD;
.icon {
width: 30px;
height: 30px;
border-radius: 6px;
margin-right: 13px;
}
.text {
font-size: 16px;
font-weight: bold;
}
}
}
.popupTitle {
font-size: 16px;
font-weight: bold;
width: 100%;
text-align: center;
margin: 16rpx 0;
}
.popupInput {
font-size: 16px !important;
display: flex;
align-items: center;
margin-left: 26rpx;
margin: 32rpx 0 26rpx 26rpx;
}
.popupInput .uInput {
width: 280rpx !important;
border-bottom: 1rpx solid #AAAAAA;
padding-bottom: 8rpx;
font-size: 16px;
}
.btnRow {
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
padding: 26rpx;
}
.btnRow>.btn {
width: 160rpx;
height: 60rpx;
margin: 0;
}
.rightMenuRow {
display: flex;
align-items: center;
position: absolute;
right: 26rpx;
}
.rightMenuRow .menuBtn {
border-radius: 12rpx;
color: #FFFFFF;
margin: 0 0 0 26rpx;
width: 100rpx;
height: 50rpx;
text-align: center;
line-height: 50rpx;
}
.popupBtn {
border-radius: 12rpx;
color: #FFFFFF;
width: 150rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
}
.primaryBtn {
background-color: #007AFF;
}
.primaryBtn:active {
background-color: #55aaff;
}
.errorBtn {
background-color: #ff0000;
}
.errorBtn:active {
background-color: #ff6e0e;
}
.uni-input-input {
font-size: 16px !important;
}
.arrowIcon {
margin-right: 26rpx;
}
</style>

View File

@ -0,0 +1,323 @@
<template>
<view>
<u-navbar back-icon-color="#FFFFFF" title="成品库存资料" title-color="#FFFFFF" :title-bold="true"
:background="background">
</u-navbar>
<view class="top-box">
<view class="myCard">
<view class="cardTopName">编号{{this.item.FabricGoodsNo}} 名称{{this.item.FabricGoodsName}}</view>
<view class="cardRow1" v-if="this.item.GoodsWeight">
<view>规格{{this.item.GoodsWidth}}*{{this.item.GoodsWeight}}</view>
</view>
<view class="cardRow1">
<view>仓库{{this.item.StoreName}} 所属{{this.item.OwnerName}}</view>
</view>
<view class="cardRow1">
<view>等级{{this.item.GoodsGradeName}}</view>
</view>
<view class="cardRow1">
<view>备注{{this.item.GoodsRemark}}</view>
</view>
</view>
</View>
<scroll-view scroll-y="true" :style="{height: scrollHeight}"
refresher-enabled :refresher-threshold="200" :refresher-triggered="triggered" refresher-background="gray"
@refresherrefresh="onRefresh" @refresherrestore="onRestore">
<view v-if="list.length > 0">
<view v-for="(item, index) in list" :key="index" @click="StoreGoodsCodeCardClickFun(item)">
<view class="myCard">
<view class="cardRow1">
<view>颜色{{item.GoodsCodeNo}} {{item.GoodsCodeName}}</view>
</view>
<view class="cardRow1">
<view class="mr26">匹数{{item.Roll}}</view>
<view class="mr26">数量{{item.Qty}}{{item.UnitName}}</view>
</view>
<view class="cardRow1">
<view class="mr26">预约{{item.AllocatedRoll}}</view>
<view class="mr26">可用{{item.UseRoll}}</view>
</view>
<view class="cardRow1" v-if="item.Price > 0">
<view class="mr26">单价{{item.Price}}/{{item.UnitName}}</view>
</view>
</view>
</view>
<getMore :isMore="isMore" nullMsg="已加载全部~"></getMore>
<view class="h200"></view>
</view>
</scroll-view>
</view>
</template>
<script>
let that = '';
//import { crmChanpinApi } from '@/static/utils/api.js'
import dataNull from '@/components/dataNull/dataNull.vue';
import util, {
playSuccessAudio,
playErrorAudio
} from '../../common/util.js';
export default {
components: {
dataNull
},
data() {
return {
triggered: false,
scrollHeight: '667px',
customerID: 0,
GoodsCodeNo: '',
GoodsCodeName: '',
tabBars: [],
list: [],
detail: {},
background: {
'background-image': 'linear-gradient(45deg, #007aff, rgb(12, 168, 234))'
},
customStyle: {
backgroundColor: 'rgb(13, 159, 224)',
color: '#FFFFFF',
border: '0',
fontSize: '32',
outline: 'none'
},
lbt: [],
pageType: ''
}
},
onLoad(e) {
that = this;
that.detail = uni.$cpDetail;
console.log("------" + that.detail.FabricGoodsName);
this.customerID = e.customerid;
this.item = JSON.parse(decodeURIComponent(e.obj));
this.getStoreGoodsCodeData(e);
},
methods: {
getStoreGoodsCodeData: function(e) {
let iii = that.leftA;
console.log("this.item.StoreNameID===" + this.item.StoreNameID);
console.log("this.item.OwnerID===" + this.item.OwnerID);
console.log("this.item.CustomerID===" + this.customerID);
console.log("this.item.FabricGoodsID===" + this.item.FabricGoodsID);
console.log("this.item.GoodsGradeName===" + this.item.GoodsGradeName);
console.log("this.item.GoodsRemark===" + this.item.GoodsRemark);
uni.request({
url: util.apiurl + 'rest/db/opensql',
data: {
token: getApp().globalData.Token,
format: 'json',
data: {
db_name: getApp().globalData.AppDBName,
sql_command_id: 'APP.StoreGoods.GetStoreGoodsMasterGoodsCode',
params: [{
name: 'SID',
value: this.item.StoreNameID
}, {
name: 'OID',
value: this.item.OwnerID
}, {
name: 'CID',
value: this.customerID
}, {
name: 'FGID',
value: this.item.FabricGoodsID
}, {
name: 'GradeName',
value: this.item.GoodsGradeName
}, {
name: 'GoodsRemark',
value: this.item.GoodsRemark
}, {
name: 'GCNo',
value: '%' + this.GoodsCodeNo + '%'
}, {
name: 'GCName',
value: '%' + this.GoodsCodeName + '%'
}]
},
},
success: (res) => {
this.triggered = false;
let data = res.data.data;
if (that.pageIndex == 1) {
that.list = [];
}
if (res.data == 20) {
that.pageIndex += 1;
that.isMore = true;
} else {
that.isMore = false;
}
that.list = that.list.concat(data);
console.log("----->>" + JSON.stringify(that.list));
},
})
},
//
StoreGoodsCodeCardClickFun: function(item) {
uni.$emit('bjdKehuBindFun', {
CustomerID: item.CustomerID,
CustomerName: item.CustomerName,
PlanDepartmentID: item.PlanDepartmentID,
PlanDepartmentName: item.PlanDepartmentName,
SaleUserID: item.SaleUserID,
SaleUserName: item.SaleUserName,
Remark: item.Remark,
CustomerAddress: item.CustomerAddress,
CustomerPhone: item.CustomerPhone,
CustomerLinkName: item.CustomerLinkName,
/*
clientName: item.clientName,
clientId: item._id
*/
})
uni.navigateBack()
},
}
}
</script>
<style lang='scss'>
page {
background-color: #F8F8F8;
padding-bottom: 100rpx;
}
.swiperClass {
margin-top: 16rpx;
}
.xiangqing {
text-align: center;
font-size: 32rpx;
font-weight: bold;
margin: 16rpx 0;
}
.spXQBox {
width: 698rpx;
margin: 0 26rpx;
background-color: #FFFFFF;
padding: 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
}
.table {
width: 100%;
border: 1rpx solid #E7E7E7;
margin: 32rpx 0;
}
.row {
display: flex;
align-items: center;
width: 100%;
border-bottom: 1rpx solid #E7E7E7;
}
.row>view:first-child {
width: 180rpx;
height: 100%;
font-size: 28rpx;
padding: 0 16rpx;
box-sizing: border-box;
}
.row>view:last-child {
width: 506rpx;
height: 100%;
font-size: 28rpx;
padding: 16rpx;
box-sizing: border-box;
border-left: 1rpx solid #E7E7E7;
}
.imgXQ {
width: 100%;
background-color: #FFFFFF;
margin-top: 32rpx;
}
.imgXqtp {
width: 100%;
}
.flexRow {
display: flex;
}
.xqTitle {
font-size: 16px;
font-weight: bold;
margin: 26rpx;
}
.addBtn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background-image: linear-gradient(45deg, #007aff, #00aaff);
display: flex;
align-items: center;
justify-content: center;
position: fixed;
bottom: 80rpx;
right: 26rpx;
z-index: 100;
}
.addBtn:active {
background-image: linear-gradient(45deg, #00aaff, #007aff);
}
.shopBtn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background-image: linear-gradient(45deg, #007aff, #00aaff);
display: flex;
align-items: center;
font-size: 26rpx;
padding: 0;
color: #FFFFFF;
font-weight: bold;
justify-content: center;
position: fixed;
bottom: 190rpx;
right: 26rpx;
z-index: 100;
}
.shopBtn:active {
background-image: linear-gradient(45deg, #00aaff, #007aff);
}
.nameCardBtn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background-image: linear-gradient(45deg, #007aff, #00aaff);
display: flex;
align-items: center;
font-size: 26rpx;
padding: 0;
color: #FFFFFF;
font-weight: bold;
justify-content: center;
position: fixed;
bottom: 300rpx;
right: 26rpx;
z-index: 100;
}
.nameCardBtn:active {
background-image: linear-gradient(45deg, #00aaff, #007aff);
}
</style>

248
src/chanpin/view/search.vue Normal file
View File

@ -0,0 +1,248 @@
<template>
<view>
<searchView placeholderStr="请输入产品名称" @searchViewClickFun="searchEventsFun($event)"></searchView>
<dataNull v-if="list.length == 0" src="/static/img/chahua/dataNullXz.png" title="暂无相关产品"
title1="请更换查询条件"></dataNull>
<scroll-view v-else scroll-y="true" :style="{height: scrollHeight}" @scrolltolower="getChanPinFun"
refresher-enabled :refresher-threshold="200" :refresher-triggered="triggered" refresher-background="gray"
@refresherrefresh="onRefresh" @refresherrestore="onRestore">
<view v-for="(item, index) in list" :key="index" @click="cardClick(item)">
<view v-if="item.cpFmtList && item.cpFmtList.length > 0" class="myCard2">
<view class="leftImg">
<u-image height="160" width="160" border-radius="26" :src="item.cpFmtList[0].url"></u-image>
</view>
<view class="rightView">
<view class="cardTopName1">{{item.pName}}</view>
<view v-if="item.salesNum || item.stock" class="xlKcClass">
<text v-if="item.salesNum">销量: {{item.salesNum}}</text>
<text v-if="item.stock">库存: {{item.stock}}</text>
</view>
<view class="cardRow1">
<text class="redColor">{{item.price}}</text>/{{item.unit}}
</view>
</view>
</view>
<view v-else class="myCard">
<view class="cardTopName">产品名称{{item.pName}}</view>
<view class="cardRow">
<view>产品状态</view>
<view>{{item.isSxJ}}</view>
</view>
<view class="cardRow">
<view>产品价格</view>
<view><text class="redColor">{{item.price}}</text>/{{item.unit}}</view>
</view>
<view class="cardRow">
<view>产品类型</view>
<view>{{item.cpClassify}}</view>
</view>
<view class="cardRow" v-if="item.salesNum">
<view>产品销量</view>
<view>{{item.salesNum}}</view>
</view>
<view class="cardRow" v-if="item.stock">
<view>产品库存</view>
<view>{{item.stock}}</view>
</view>
<view class="cardRow" v-if="item.describe">
<view>产品简述</view>
<view>{{item.describe}}</view>
</view>
</view>
</view>
<getMore :isMore="isMore" class="h100"></getMore>
</scroll-view>
</view>
</template>
<script>
let that = '';
import dataNull from '@/components/dataNull/dataNull.vue'
import addBtn from '@/components/addBtn/addBtn.vue'
import getMore from '@/components/getMore/getMore.vue'
import searchView from '@/components/searchView/searchView.vue'
import { crmChanpinApi } from '@/static/utils/api.js'
export default {
components: {
searchView,
dataNull,
getMore,
addBtn
},
data() {
return {
pageIndex: 1,
searchValue: '',
list: [],
scrollHeight: '667px',
triggered: false,
isMore: true,
sortObj: {
update_date: -1
}
}
},
onLoad(e) {
that = this;
uni.getSystemInfo({
success(res) {
that.scrollHeight = res.windowHeight - 40 + 'px';
}
})
},
methods: {
//
getChanPinFun: function() {
if (!that.isMore) {
return
}
uni.showLoading({
title: '加载中...',
mask: true
})
let reqObj = {
matchObj: {
isSxJ: true
},
pageIndex: that.pageIndex,
searchValue: that.searchValue,
sortObj: that.sortObj,
}
let reqData = {
action: 'getCpList',
params: reqObj
}
crmChanpinApi(reqData)
.then(res => {
let data = res.result.data
if (that.pageIndex == 1) {
that.list = [];
}
if (data.length == 20) {
that.pageIndex += 1;
that.isMore = true;
} else {
that.isMore = false;
}
that.triggered = false;
that.list = that.list.concat(data);
})
},
//
cardClick: function(item) {
uni.$cpDetail = item;
uni.navigateTo({
url: './cpDetail?type=client'
})
},
//
searchEventsFun: function(e) {
that.searchValue = e;
that.isMore = true;
that.pageIndex = 1;
that.getChanPinFun();
},
//
onRefresh: function() {
if(that.triggered) return
that.triggered = true;
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
onRestore: function(e) {
that.triggered = false; //
}
}
}
</script>
<style>
page {
background-color: #F8F8F8;
}
.rowBtn {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 26rpx 16rpx 16rpx 0;
justify-content: flex-end;
}
.cpBtn {
margin: 0 0 0 26rpx;
font-size: 15px !important;
height: 60rpx !important;
line-height: 60rpx !important;
}
.gdCz {
width: 60rpx;
height: 60rpx;
padding: 6rpx 12rpx;
}
.myCard2 {
width: 698rpx;
padding: 26rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
display: flex;
}
.cardTopName1 {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-weight: bold;
padding-bottom: 8rpx;
}
.cardRow1 {
display: flex;
align-items: center;
font-size: 16px;
margin-bottom: 8rpx;
}
.cardRow1>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.cardRow1>view:last-child {
color: #000000;
}
.leftImg {
width: 160rpx;
height: 160rpx;
margin-right: 26rpx;
border-radius: 26rpx;
overflow: hidden;
border: 1rpx solid #DDDDDD;
}
.rightView {
width: 480rpx;
}
.xlKcClass {
font-size: 14px;
color: #888888;
margin-bottom: 8rpx;
}
.xlKcClass>text {
margin-right: 26rpx;
}
</style>

View File

@ -0,0 +1,264 @@
<template>
<view>
<searchView placeholderStr="请输入产品名称" @searchViewClickFun="searchEventsFun($event)"></searchView>
<dataNull v-if="list.length == 0" src="/static/img/chahua/dataNullXz.png" title="暂无相关产品"
title1="请添加或者更换查询条件"></dataNull>
<scroll-view v-else scroll-y="true" :style="{height: scrollHeight}" @scrolltolower="getChanPinFun"
refresher-enabled :refresher-threshold="200" :refresher-triggered="triggered" refresher-background="gray"
@refresherrefresh="onRefresh" @refresherrestore="onRestore">
<view v-for="(item, index) in list" :key="index" @click="cardClick(item)">
<view v-if="item.cpFmtList && item.cpFmtList.length > 0" class="myCard2">
<view class="leftImg">
<u-image height="160" width="160" border-radius="26" :src="item.cpFmtList[0].url"></u-image>
</view>
<view class="rightView">
<view class="cardTopName1">{{item.pName}}</view>
<view v-if="item.salesNum || item.stock" class="xlKcClass">
<text v-if="item.salesNum">销量: {{item.salesNum}}</text>
<text v-if="item.stock">库存: {{item.stock}}</text>
</view>
<view class="cardRow1">
<text class="redColor">{{item.price}}</text>/{{item.unit}}
</view>
<view class="rowBtn">
<u-button type="primary" :plain="true" class="cpBtn" size="mini" @tap.stop="setCpFun(item)">
编辑产品
</u-button>
<u-button type="warning" :plain="true" class="cpBtn" size="mini"
@click="cpsxjFun(item, index)">{{item.isSxJ == '上架' ? '下架' : '上架'}}</u-button>
<u-button type="error" :plain="true" class="cpBtn" size="mini"
@tap.stop="deleteCpFun(item, index)">
删除</u-button>
</view>
</view>
</view>
<view v-else class="myCard">
<view class="cardTopName">产品名称{{item.pName}}</view>
<view class="cardRow">
<view>产品状态</view>
<view>{{item.isSxJ}}</view>
</view>
<view class="cardRow">
<view>产品价格</view>
<view><text class="redColor">{{item.price}}</text>/{{item.unit}}</view>
</view>
<view class="cardRow">
<view>产品类型</view>
<view>{{item.cpClassify}}</view>
</view>
<view class="cardRow" v-if="item.salesNum">
<view>产品销量</view>
<view>{{item.salesNum}}</view>
</view>
<view class="cardRow" v-if="item.stock">
<view>产品库存</view>
<view>{{item.stock}}</view>
</view>
<view class="cardRow" v-if="item.describe">
<view>产品简述</view>
<view>{{item.describe}}</view>
</view>
<view class="rowBtn">
<u-button type="primary" :plain="true" class="cpBtn" size="mini" @tap.stop="setCpFun(item)">编辑产品
</u-button>
<u-button type="warning" :plain="true" class="cpBtn" size="mini" @click="cpsxjFun(item, index)">
{{item.isSxJ == '上架' ? '下架' : '上架'}}</u-button>
<u-button type="error" :plain="true" class="cpBtn" size="mini"
@tap.stop="deleteCpFun(item, index)">
删除</u-button>
</view>
</view>
</view>
<getMore :isMore="isMore" class="h100"></getMore>
</scroll-view>
</view>
</template>
<script>
let that = '';
import dataNull from '@/components/dataNull/dataNull.vue'
import addBtn from '@/components/addBtn/addBtn.vue'
import getMore from '@/components/getMore/getMore.vue'
import searchView from '@/components/searchView/searchView.vue'
import { crmChanpinApi } from '@/static/utils/api.js'
export default {
components: {
searchView,
dataNull,
getMore,
addBtn
},
data() {
return {
pageIndex: 1,
searchValue: '',
list: [],
scrollHeight: '667px',
triggered: false,
isMore: true,
sortObj: {
update_date: -1
}
}
},
onLoad() {
that = this;
uni.getSystemInfo({
success(res) {
that.scrollHeight = res.windowHeight - 40 + 'px';
}
})
},
methods: {
//
getChanPinFun: function() {
if (!that.isMore) {
return
}
uni.showLoading({
title: '加载中...',
mask: true
})
let reqObj = {
pageIndex: that.pageIndex,
searchValue: that.searchValue,
sortObj: that.sortObj
}
let reqData = {
action: 'get',
params: reqObj
}
crmChanpinApi(reqData)
.then(res => {
let data = res.result.data
if (that.pageIndex == 1) {
that.list = [];
}
if (data.length == 10) {
that.pageIndex += 1;
that.isMore = true;
} else {
that.isMore = false;
}
that.triggered = false;
that.list = that.list.concat(data);
})
},
//
cardClick: function(item) {
uni.$cpDetail = item;
uni.navigateTo({
url: './cpDetail'
})
},
//
searchEventsFun: function(e) {
that.searchValue = e;
that.isMore = true;
that.pageIndex = 1;
that.getChanPinFun();
},
//
onRefresh: function() {
if(that.triggered) return
that.triggered = true;
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
},
onRestore: function(e) {
that.triggered = false; //
}
}
}
</script>
<style>
page {
background-color: #F8F8F8;
}
.rowBtn {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 26rpx 16rpx 16rpx 0;
justify-content: flex-end;
}
.cpBtn {
margin: 0 0 0 26rpx;
font-size: 15px !important;
height: 60rpx !important;
line-height: 60rpx !important;
}
.gdCz {
width: 60rpx;
height: 60rpx;
padding: 6rpx 12rpx;
}
.myCard2 {
width: 698rpx;
padding: 26rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
display: flex;
}
.cardTopName1 {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-weight: bold;
padding-bottom: 8rpx;
}
.cardRow1 {
display: flex;
align-items: center;
font-size: 16px;
margin-bottom: 8rpx;
}
.cardRow1>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.cardRow1>view:last-child {
color: #000000;
}
.leftImg {
width: 160rpx;
height: 160rpx;
margin-right: 26rpx;
border-radius: 26rpx;
overflow: hidden;
border: 1rpx solid #DDDDDD;
}
.rightView {
width: 460rpx;
}
.xlKcClass {
font-size: 14px;
color: #888888;
margin-bottom: 8rpx;
}
.xlKcClass>text {
margin-right: 26rpx;
}
</style>

765
src/chanpin/view/shop.vue Normal file
View File

@ -0,0 +1,765 @@
<template>
<view>
<view class="top-box">
<!--
<view style="margin-left: 26rpx;" @click="popupShow = true">
<text>排序</text>
<u-icon name="list-dot"></u-icon>
</view>
<navigator url="./search" class="top" :class="pageNum == 0 ? 'duanwidth' : ''">
<view class="search">
<u-icon class="searchIcon" name="search"></u-icon>
<text>搜索您要找的商品</text>
</view>
</navigator>-->
<u-search placeholder="请输入查询编号或名称" v-model="searchFabricGoods"
@search="getChanPinFun" @custom="getChanPinFun"></u-search>
</view>
<view class="scrollF" :style="{ height: (wHeight - 50) + 'px' }">
<scroll-view scroll-y="true" class="leftScrollV">
<view v-for="(item, index) in tabBars" :key="index" class="leftCardView">
<view class="leftCard" :class="{ leftActive: leftA == index }"
@click="selectLeftFl(index)">{{item.FabricTypeName}}</view>
</view>
</scroll-view>
<view class="rightSv">
<view style="height: 100%; width: 100%;" v-if="tabBars.length > 0">
<scroll-view v-for="(tabItem, iii) in tabBars" :key="iii" v-show="leftA == iii" scroll-y="true"
style="height: 100%; width: 100%;" @scrolltolower="loadMore" refresher-enabled
:refresher-triggered="tabItem.triggered" :refresher-threshold="200" refresher-background="gray" @refresherrefresh="onRefresh" @refresherrestore="onRestore" >
<skeleton SkelttionType="classify" v-if="!tabItem.isjz"></skeleton>
<view v-else>
<view v-if="tabItem.arr.length > 0">
<view v-for="(item, index) in tabItem.arr" :key="index" @click="cardClick(item)">
<view v-if="item.cpFmtList && item.cpFmtList.length > 0" class="myCard2">
<view class="leftImg">
<u-image height="160" width="160" :src="item.cpFmtList[0].url"></u-image>
</view>
<view class="rightView">
<view class="cardTopName1">{{item.pName}}</view>
<view v-if="item.salesNum || item.stock" class="xlKcClass">
<text v-if="item.salesNum">销量: {{item.salesNum}}</text>
<text v-if="item.stock">库存: {{item.stock}}</text>
</view>
<view class="cardRow1">
<text class="redColor">{{item.price}}</text>/{{item.unit}}
</view>
</view>
</view>
<view v-else class="myCard1">
<view class="cardTopName">编号{{item.FabricGoodsNo}}</view>
<view class="cardTopName">名称{{item.FabricGoodsName}}</view>
<view class="cardRow1">
<view>规格{{item.GoodsWidth}}</view>
<view v-if="item.GoodsWeight">*</view>
<view>{{item.GoodsWeight}}</view>
</view>
<view class="cardRow1">
<view>仓库{{item.StoreName}}</view>
</view>
<view class="cardRow1">
<view>所属{{item.OwnerName}}</view>
</view>
<view class="cardRow1">
<view>等级{{item.GoodsGradeName}}</view>
</view>
<view class="cardRow1">
<view>备注{{item.GoodsRemark}}</view>
</view>
<view class="cardRow1">
<view class="mr26">匹数{{item.Roll}}</view>
<view class="mr26">数量{{item.Qty}}{{item.UnitName}}</view>
</view>
<view class="cardRow1">
<view class="mr26">预约{{item.AllocatedRoll}}</view>
<view class="mr26">可用{{item.UseRoll}}</view>
</view>
</view>
</view>
<getMore :isMore="tabBars[tabCurrentIndex].isMore" style="margin-bottom: 16px;"></getMore>
<view style="height: 36rpx;"></view>
</view>
<dataNull v-else src="/static/img/chahua/dataNullXz.png" title="暂无相关产品" title1="请先添加">
</dataNull>
</view>
</scroll-view>
</view>
<dataNull v-else src="/static/img/chahua/dataNullXz.png" title="暂无相关产品">
</dataNull>
</view>
</view>
<!--排序-->
<!--
<u-popup v-model="popupShow" width="568rpx" mode="right" border-radius="14" :safe-area-inset-bottom="true">
<view class="popupCard" v-for="(obj, index) in sxArr" :key="index">
<view class="popupTitle">{{obj.title}}</view>
<view class="popupItem">
<view v-for="(item, iii) in obj.arr" :key="iii" :class="obj.current === iii ? 'activeClass' : ''" @click="sxItemClickFun(index, iii)">{{item}}</view>
</view>
<view class="flexJs" v-if="obj.judge">
<text>等于</text>
<u-icon name="arrow-right"></u-icon>
</view>
</view>
<view class="h200"></view>
<view class="popupBottomBtn">
<view class="popupBtn warning" @click="resetFun">重置</view>
<view class="popupBtn primary" @click="confirmFun">确定</view>
</view>
</u-popup>
-->
</view>
</template>
<script>
let that = '';
let windowWidth = 0;
import dataNull from '@/components/dataNull/dataNull.vue'
import getMore from '@/components/getMore/getMore.vue'
import skeleton from '@/components/skeleton/skeleton'
//import { crmChanpinApi, crmCpClassifyApi, crmMyAppUserApi } from '@/static/utils/api.js'
import util, {playSuccessAudio,playErrorAudio} from '../../common/util.js';
export default {
components: {
skeleton,
getMore,
dataNull
},
data() {
return {
customerID:'0',
searchFabricGoods:'',
cpClassify: '',
cpFlId: '',
list: [],
pageNum: 0,
scrollLeft: 0, //
enableScroll: true,
tabCurrentIndex: 0,
tabBars: [],
wHeight: 623,
leftA: 0,
triggered: false,
freshing: false,
sortObj: {
update_date: -1,
salesNum: -1,
stock: 1,
create_date: -1
},
popupShow: false,
sxArr: [],
tabList: [{
iconPath: "photo-fill",
selectedIconPath: "photo-fill",
text: '名片',
customIcon: false,
},
{
iconPath: "shopping-cart-fill",
selectedIconPath: "shopping-cart-fill",
text: '商城',
customIcon: false,
}
],
current: 1
}
},
onLoad(e) {
that = this;
that.pageType = e.type ? e.type : '';
that.customerID = e.customerid;
console.log("---->>>>" + that.customerID);
windowWidth = uni.getSystemInfoSync().windowWidth;
that.wHeight = uni.getSystemInfoSync().windowHeight;
that.getClassifyFun();
},
onShow() {
//uni.$userInfo = uni.getStorageSync('userInfo') || {};
//that.getClassifyFun();
},
onShareAppMessage(res) {
if (res.from === 'button') { //
console.log(res.target)
}
return {
title: '您好,这是我的微信小商城,快来查看吧!',
path: '/chanpin/view/shop?id=' + that.cardInfo.u_id
}
},
onShareTimeline() {
return {
title: '您好,这是我的微信小商城,快来查看吧!',
imageUrl: '', // URL
query: 'id=' + that.cardInfo.u_id
}
},
methods: {
tabbarChangeFun: function(e) {
if(e == 0) {
uni.redirectTo({
url: '../../nameCard/view/previewCard?id=' + that.userId
})
}
},
// crmUser
getuserInfoFun: function(id) {
let reqData = {
action: 'getUserCrmUid',
params: {
uid: id
}
}
console.log(reqData)
uni.showLoading({
title: '加载中...'
})
crmMyAppUserApi(reqData)
.then(res => {
that.getClassifyFun();
})
},
//
getClassifyFun: function() {
/*
uni.showLoading({
title: '加载中...',
mask: true
})
*/
uni.request({
url: util.apiurl + 'rest/db/opensql',
data: {
token: getApp().globalData.Token,
format: 'json',
data: {
db_name: getApp().globalData.AppDBName,
sql_command_id: 'APP.BaseData.GetFabricTypeData',
params: []
},
},
success: (res) => {
this.triggered = false;
let list = res.data.data;
if (list) {
for (var i = 0; i < list.length; i++) {
list[i].pageIndex = 1;
list[i].arr = [];
list[i].isMore = false;
list[i].triggered = false;
}
list[0].loaded = true;
that.tabBars = list;
that.cpClassify = list[0].FabricTypeName;
that.cpFlId = list[0].FabricTypeID;
//uni.setStorageSync('classifyList', data.list);
that.getChanPinFun();
}
},
})
/*
crmCpClassifyApi(reqData)
.then(res => {
console.log(res)
let list = res.result.data;
console.log(list)
if (list) {
for (var i = 0; i < list.length; i++) {
list[i].pageIndex = 1;
list[i].arr = [];
list[i].isMore = false;
list[i].triggered = false;
}
list[0].loaded = true;
that.tabBars = list;
that.cpClassify = list[0].flName;
that.cpFlId = list[0]._id;
// uni.setStorageSync('classifyList', data.list);
that.getChanPinFun();
}
})*/
},
//
getChanPinFun: function() {
/*
uni.showLoading({
title: '加载中...',
mask: true
})
*/
let iii = that.leftA;
let loadPi = 1;
let aOTypeID = -1;
let asearchFabricGoods = this.searchFabricGoods;
if (asearchFabricGoods != "")
{
aOTypeID=0
}
console.log("----->>>" + aOTypeID+'<<<>>' + this.searchFabricGoods);
uni.request({
url: util.apiurl + 'rest/db/opensql',
data: {
token: getApp().globalData.Token,
format: 'json',
data: {
db_name: getApp().globalData.AppDBName,
sql_command_id: 'APP.StoreGoods.GetStoreGoodsMasterFabricGoods',
params: [{
name: 'FTypeID',
value: that.tabBars[iii].FabricTypeID
},{
name: 'OTypeID',
value: aOTypeID
},{
name: 'FGNo',
value: '%'+this.searchFabricGoods+'%'
},{
name: 'FGName',
value: '%'+this.searchFabricGoods+'%'
}]
},
},
success: (res) => {
//this.triggered = false;
let list = res.data.data;
let item = that.tabBars[iii];
let arr = that.tabBars[iii].arr;
if (item.triggered) {
item.triggered = false;
that.freshing = false;
}
if (list.length == 20) {
item.isMore = true;
item.pageIndex += 1;
} else {
item.isMore = false;
}
if (loadPi == 1) {
item.arr = list;
} else {
arr = arr.concat(list);
item.arr = arr;
}
item.isjz = true;
that.$set(that.tabBars, iii, item);
}
})
},
/*
let reqObj = {
matchObj: {
cpFlId: that.tabBars[iii].FabricTypeID,
isSxJ: true,
},
pageIndex: that.tabBars[iii].pageIndex,
sortObj: that.sortObj
}
let loadPi = reqObj.pageIndex;
let reqData = {
action: 'getCpList',
params: reqObj
}
console.log(reqData)
crmChanpinApi(reqData)
.then(res => {
let list = res.result.data;
let item = that.tabBars[iii];
let arr = that.tabBars[iii].arr;
if (item.triggered) {
item.triggered = false;
that.freshing = false;
}
if (list.length == 20) {
item.isMore = true;
item.pageIndex += 1;
} else {
item.isMore = false;
}
if (loadPi == 1) {
item.arr = list;
} else {
arr = arr.concat(list);
item.arr = arr;
}
item.isjz = true;
that.$set(that.tabBars, iii, item);
})
},
*/
selectLeftFl: function(i) {
this.leftA = i;
this.tabCurrentIndex = i;
let tabItem = this.tabBars[i];
if (tabItem.loaded !== true) {
/*
uni.showLoading({
title: '加载中...',
mask: true
})
*/
console.log("----------->" + this.tabCurrentIndex);
this.getChanPinFun();
tabItem.loaded = true;
}
},
//
loadMore: function(e) {
if (this.tabBars[this.leftA].isMore) {
this.getChanPinFun();
}
},
onRefresh() {
let item = this.tabBars[this.leftA];
if (this.freshing) return;
this.freshing = true;
if (!item.triggered) //triggeredtruetrue
item.triggered = true;
item.isMore = true;
item.pageIndex = 1;
this.$set(this.tabBars, this.leftA, item);
this.getChanPinFun();
},
onRestore() {
let item = this.tabBars[this.leftA];
item.triggered = false; //
this.$set(this.tabBars, this.leftA, item);
},
//
cardClick: function(item) {
if(that.pageType !== '') {
uni.$emit('chanpinBindFun', item)
uni.navigateBack()
} else {
console.log(">>>>>" + this.customerID +"<<<<<<<<<");
uni.$cpDetail = item;
uni.navigateTo({
url: './cpDetail?customerid='+ this.customerID +'&obj='+ encodeURIComponent(JSON.stringify(item))
})
}
},
sxItemClickFun: function(index, iii) {
let item = that.sxArr[index];
let list = that.sxArr;
for(var i = 0; i < list.length; i++) {
if(list[i].isPx) {
list[i].current = '';
}
}
item.current = iii;
that.$set(that.sxArr, index, item)
},
//
resetFun: function() {
let list = that.sxArr;
for(var i = 0; i < list.length; i++) {
list[i].current = '';
}
that.sxArr = list;
},
//
confirmFun: function() {
that.popupShow = false;
let arr = that.sxArr;
for (var i = 0; i < arr.length; i++) {
if (arr[i].isPx && arr[i].current !== '') {
console.log(arr[i])
let sortObj = {}
if (arr[i].field == 'create_date') {
sortObj.create_date = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'update_date') {
sortObj.update_date = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'salesNum') {
sortObj.salesNum = arr[i].current == 1 ? 1 : -1
}
if (arr[i].field == 'stock') {
sortObj.stock = arr[i].current == 1 ? 1 : -1
}
that.sortObj = sortObj;
break;
}
}
that.pageIndex = 1;
that.isMore = true;
that.getChanPinFun();
// that.$emit('optionSxFun', that.sxArr);
}
}
}
</script>
<style>
.top-box {
width: 100%;
height: 50px;
display: flex;
align-items: center;
background-color: #FFFFFF;
border-bottom: 1rpx solid #EBEEF5;
}
.chuangjian {
color: #007AFF;
}
.chuangjian>text:first-child {
font-size: 36rpx;
font-weight: bold;
}
.chuangjian>text:last-child {
font-size: 30rpx;
}
.top {
height: 80rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin: 0 20rpx;
width: 580rpx;
}
.duanwidth {
width: 600rpx !important;
}
.searchIcon {
width: 40rpx;
height: 40rpx;
margin: 0 18rpx 0 12rpx;
}
.search {
flex: 1;
height: 60rpx;
background-color: #f5f5f5;
border-radius: 40rpx;
padding: 0 20rpx;
font-size: 28rpx;
display: flex;
align-items: center;
}
.rightBtn image {
width: 56rpx;
height: 56rpx;
}
.scrollF {
display: flex;
}
.leftScrollV {
width: 250rpx;
height: 100%;
background-color: #f8f8f8;
}
.rightSv {
width: 590rpx;
padding: 0 16rpx;
box-sizing: border-box;
height: 100%;
background-color: #FFFFFF;
}
.leftCard {
width: 100%;
height: 88rpx;
line-height: 88rpx;
font-size: 30rpx;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin:2rpx 10rpx;
}
.leftCardView:last-child {
margin-bottom: 100rpx;
}
.leftActive {
background-color: #FFFFFF;
color: #007AFF;
font-weight: bold;
}
.tishi {
width: 590rpx;
}
.centerF26 {
font-size: 28rpx;
width: 100%;
text-align: center;
margin-bottom: 100rpx;
color: #696969;
}
.myCard1 {
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 16rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.myCard2 {
padding: 26rpx;
margin: 32rpx 16rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
display: flex;
}
.cardTopName1 {
font-size: 12px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-weight: bold;
padding-bottom: 8rpx;
}
.cardRow1 {
display: flex;
align-items: center;
font-size: 15px;
margin-bottom: 8rpx;
}
.cardRow1>view:first-child {
--width: max;
--color: #ADADAD;
color: #000000;
}
.cardRow1>view:last-child {
color: #000000;
}
.leftImg {
width: 160rpx;
height: 160rpx;
margin-right: 26rpx;
border-radius: 26rpx;
overflow: hidden;
border: 1rpx solid #DDDDDD;
}
.rightView {
width: 288rpx;
}
.xlKcClass {
font-size: 14px;
color: #888888;
display: flex;
justify-content: space-between;
margin-bottom: 8rpx;
}
/*************************弹窗层******************************/
.popupCard {
width: 100%;
padding: 26rpx 16rpx;
border-bottom: 1rpx solid #efefef;
}
.popupTitle {
font-size: 14px;
font-weight: bold;
margin-bottom: 26rpx;
}
.popupItem {
font-size: 14px;
color: #666666;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.popupItem>view {
width: 160rpx;
text-align: center;
padding: 12rpx 20rpx;
background-color: #e6e6e6;
margin-bottom: 26rpx;
border-radius: 16rpx;
margin-right: 28rpx;
}
.mr0 {
margin-right: 0 !important;
}
.flexJs {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.popupBottomBtn {
width: 100%;
height: 100rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
position: fixed;
bottom: 0;
font-size: 15px;
}
.settingView {
width: 128rpx;
height: 100% !important;
display: flex;
align-items: center;
justify-content: center;
}
.popupBtn {
width: 50%;
height: 100% !important;
line-height: 100rpx;
text-align: center;
color: #FFFFFF;
border-radius: 0 !important;
}
.activeClass {
background-image: linear-gradient(45deg, #007AFF, #00aaff);
color: #FFFFFF;
}
.warning {
background-color: #ff9900;
}
.warning:active {
background-color: #ffaa00;
}
.primary {
background-color: #2979ff;
}
.primary:active {
background-color: #55aaff;
}
</style>

74
src/common/base64.js Normal file
View File

@ -0,0 +1,74 @@
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function() {factory(root);});
} else factory(root);
// node.js has always supported base64 conversions, while browsers that support
// web workers support base64 too, but you may never know.
})(typeof exports !== "undefined" ? exports : this, function(root) {
if (root.atob) {
// Some browsers' implementation of atob doesn't support whitespaces
// in the encoded string (notably, IE). This wraps the native atob
// in a function that strips the whitespaces.
// The original function can be retrieved in atob.original
try {
root.atob(" ");
} catch(e) {
root.atob = (function(atob) {
var func = function(string) {
return atob(String(string).replace(/[\t\n\f\r ]+/g, ""));
};
func.original = atob;
return func;
})(root.atob);
}
return;
}
// base64 character set, plus padding character (=)
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// Regular expression to check formal correctness of base64 encoded strings
b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
root.btoa = function(string) {
string = String(string);
var bitmap, a, b, c,
result = "", i = 0,
rest = string.length % 3; // To determine the final padding
for (; i < string.length;) {
if ((a = string.charCodeAt(i++)) > 255
|| (b = string.charCodeAt(i++)) > 255
|| (c = string.charCodeAt(i++)) > 255)
throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
bitmap = (a << 16) | (b << 8) | c;
result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63)
+ b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
}
// If there's need of padding, replace the last 'A's with equal signs
return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
};
root.atob = function(string) {
// atob can work with strings with whitespaces, even inside the encoded part,
// but only \t, \n, \f, \r and ' ', which can be stripped.
string = String(string).replace(/[\t\n\f\r ]+/g, "");
if (!b64re.test(string))
throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
// Adding the padding if missing, for semplicity
string += "==".slice(2 - (string.length & 3));
var bitmap, result = "", r1, r2, i = 0;
for (; i < string.length;) {
bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12
| (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result;
};
});

15
src/common/common.js Normal file
View File

@ -0,0 +1,15 @@
/**
* 通用js方法封装处理
* Copyright (c) 2019 aidex
*/
export function replaceAll (text,stringToFind,stringToReplace) {
if ( stringToFind == stringToReplace) return this;
var temp = text;
var index = temp.indexOf(stringToFind);
while (index != -1) {
temp = temp.replace(stringToFind, stringToReplace);
index = temp.indexOf(stringToFind);
}
return temp;
}

44
src/common/config.js Normal file
View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
// 判断是否为开发环境
export const isDevelopment = process.env.NODE_ENV === 'development'
const config = {
upgradeName: 'erp_pda_pre',
// 产品名称
productName: '浩拓技术',
// 公司名称
companyName: '浩拓科技',
// 版本检查标识
appCode: 'android',
// 内部版本号码
appVersion: 1,
// 管理基础路径
adminPath: 'https://hcscmpre.zzfzyc.com/hcscm/pda/v1',
// 环境判断
isDevelopment: isDevelopment,
// 生产环境API URL
productionApiUrl: 'https://hcscmpre.zzfzyc.com/hcscm/pda/v1',
// 开发环境API URL选项
devApiUrlOptions: [
{ label: '测试环境', value: 'https://hcscmtest.zzfzyc.com/hcscm/pda/v1' },
{ label: '正式环境', value: 'https://hcscmpre.zzfzyc.com/hcscm/pda/v1' },
{ label: '自定义', value: 'custom' }
]
}
// 设置后台接口服务的基础地址 - 使用动态API URL
// config.baseUrl = 'https://aidex.vip/api'; // 注释掉固定的baseUrl
export default config;

87
src/common/http.api.js Normal file
View File

@ -0,0 +1,87 @@
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
// 此处第二个参数vm就是我们在页面使用的this你可以通过vm获取vuex等操作
const install = (Vue, vm) => {
// 参数配置对象
const config = vm.vuex_config;
console.log('install u',config)
// 将各个定义的接口名称统一放进对象挂载到vm.$u.api(因为vm就是this也即this.$u.api)下
vm.$u.api = {
// 基础服务:登录登出、身份信息、菜单授权、切换系统、字典数据等
lang: (params = {}) => vm.$u.get('/lang/'+params.lang),
index: (params = {}) => vm.$u.get(config.adminPath+'/mobile/index', params),
getUserInfo: (params = {}) => vm.$u.get(config.adminPath+'/mobile/user/getUserInfo', params),
login: (params = {}) => vm.$u.post(config.adminPath+'/mobile/login/loginByPassword', params),
// PDA登录接口
pdaLogin: (params = {}) => vm.$u.postJson('/login', params),
pdaLogout: (params = {}) => vm.$u.postJson('/logout', params),
// 获取配布单列表
getFpmArrangeOrderList: (params = {}) => vm.$u.get('/product/fpmArrangeOrder/getFpmArrangeOrderList', params),
// 获取成品配布单详情
getFpmArrangeOrder: (params = {}) => vm.$u.get('/product/fpmArrangeOrder/getFpmArrangeOrder', params),
// 生成出仓单
outFpmArrangeOrder: (params = {}) => vm.$u.put('/product/fpmArrangeOrder/outFpmArrangeOrder', params),
sendCode: (params = {}) => vm.$u.post(config.adminPath+'/mobile/login/sendCode', params),
registerUser: (params = {}) => vm.$u.post(config.adminPath+'/mobile/user/registerUser', params),
//首页相关api
getIndexCardInfo: (params = {}) => vm.$u.get(config.adminPath+'/mobile/index/getIndexCardInfo', params),
getM2mOrderFlowList: (params = {}) => vm.$u.get(config.adminPath+'/mobile/index/getM2mOrderFlowList', params),
//获取卡可购买套餐包
getM2mOrderPackageList: (params = {}) => vm.$u.get(config.adminPath+'/mobile/index/getM2mOrderPackageList', params),
logout: (params = {}) => vm.$u.get(config.adminPath+'/mobile/login/logout', params),
authInfo: (params = {}) => vm.$u.get(config.adminPath+'/authInfo', params),
menuTree: (params = {}) => vm.$u.get(config.adminPath+'/menuTree', params),
switchSys: (params = {}) => vm.$u.get(config.adminPath+'/switch/'+params.sysCode),
dictData: (params = {}) => vm.$u.get(config.a取dminPath+'/system/dict/data/type/'+params.dictType),
// 账号服务:验证码接口、忘记密码接口、注册账号接口等
validCode: (params = {}) => vm.$u.getText('/validCode', params),
getFpValidCode: (params = {}) => vm.$u.post('/account/getFpValidCode', params),
savePwdByValidCode: (params = {}) => vm.$u.post('/account/savePwdByValidCode', params),
getRegValidCode: (params = {}) => vm.$u.post('/account/getRegValidCode', params),
saveRegByValidCode: (params = {}) => vm.$u.post('/account/saveRegByValidCode', params),
// APP公共服务
upgradeCheck: (params = {}) => vm.$u.put(vm.$u.http.config.baseUrl.replace('/pda/v1', '') + '/version/check', params, {
'content-type': 'application/json'
}),
commentSave: (params = {}) => vm.$u.post('/app/comment/save', params),
// 个人信息修改
user: {
saveUserInfo: (params = {}) => vm.$u.post(config.adminPath+'/mobile/user/saveUserInfo', params),
infoSavePwd: (params = {}) => vm.$u.put(config.adminPath+'/system/user/profile/updatePwd', params),
infoSavePqa: (params = {}) => vm.$u.post(config.adminPath+'/sys/user/infoSavePqa', params),
},
// 员工用户查询
empUser: {
listData: (params = {}) => vm.$u.get(config.adminPath+'/sys/empUser/listData', params),
},
// 组织机构查询
office: {
treeData: (params = {}) => vm.$u.get(config.adminPath+'/sys/office/treeData', params),
},
// 增删改查例子
testData: {
form: (params = {}) => vm.$u.post(config.adminPath+'/test/testData/form', params),
list: (params = {}) => vm.$u.post(config.adminPath+'/test/testData/listData', params),
save: (params = {}) => vm.$u.postJson(config.adminPath+'/test/testData/save', params),
disable: (params = {}) => vm.$u.post(config.adminPath+'/test/testData/disable', params),
enable: (params = {}) => vm.$u.post(config.adminPath+'/test/testData/enable', params),
delete: (params = {}) => vm.$u.post(config.adminPath+'/test/testData/delete', params),
},
};
}
export default {
install
}

View File

@ -0,0 +1,142 @@
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
// 此处第二个参数vm就是我们在页面使用的this你可以通过vm获取vuex等操作
const install = (Vue, vm) => {
// 通用请求头设定
const ajaxHeader = 'x-ajax';
const sessionIdHeader = 'Authorization';
const rememberMeHeader = 'x-remember';
// 请求参数默认配置
Vue.prototype.$u.http.setConfig({
baseUrl: vm.$store.state.apiurl,
originalData: true,
// 默认头部http2约定header名称统一小写 aidex
header: {
'Platform': 2,
'content-type': 'application/x-www-form-urlencoded',
'x-requested-with': 'XMLHttpRequest'
}
});
// 请求拦截配置Token等参数
Vue.prototype.$u.http.interceptor.request = (req) => {
if (!req.header){
req.header = [];
}
req.header["source"] = "app";
// 默认指定返回 JSON 数据
if (!req.header[ajaxHeader]){
req.header[ajaxHeader] = 'json';
}
// 设定传递 Token 认证参数 aidex
if (!req.header[sessionIdHeader] && vm.vuex_token){
req.header[sessionIdHeader] = vm.vuex_token;
}
// 为节省流量,记住我数据不是每次都发送的,当会话失效后,尝试重试登录 aidex
if (!req.header[rememberMeHeader] && vm.vuex_remember && req.remember){
req.header[rememberMeHeader] = vm.vuex_remember;
req.remember = false;
}
console.log('request', req);
return req;
}
// 响应拦截,判断状态码是否通过
Vue.prototype.$u.http.interceptor.response = async (res, req) => {
console.log('response', res);
// 处理401未授权状态码
if (res.statusCode === 401) {
vm.$u.toast('登录已过期,请重新登录');
// 清除token和用户信息
uni.removeStorageSync('token');
vm.$u.vuex('vuex_token', '');
vm.$u.vuex('vuex_user', {});
// 跳转到登录页面
uni.reLaunch({
url: '/pages/sys/login/index'
});
return false;
}
if (!(res.data)){
vm.$u.toast('未连接到服务器')
return Promise.reject(new Error('未连接到服务器'));
}
if(res.data.code !== 0) {
vm.$u.toast(res.data.msg)
return Promise.reject(new Error(res.data.msg))
}
let data = res.data.data;
console.log('data',data)
if (typeof data === 'object' && !(data instanceof Array)){
if (data.token){
console.log('token',data.token)
vm.$u.vuex('vuex_token', data.token);
if (data.user){
vm.$u.vuex('vuex_user', data.user);
}
vm.$u.vuex('vuex_isAgent', data.isAgent);
}
if (data.result === 'login'){
vm.$u.vuex('vuex_user', {});
if (req.tryagain == undefined || req.tryagain){
req.tryagain = false; req.remember = true;
await vm.$u.http.request(req).then(res => {
data = res;
});
}
if (data.result === 'login'){
if (!req.data.loginCheck){
vm.$u.toast(data.msg);
}
req.tryagain = true;
}
}
}
if (res.header && res.header[rememberMeHeader]){
let remember = res.header[rememberMeHeader];
if (remember && remember != 'deleteMe'){
vm.$u.vuex('vuex_remember', remember);
}else{
vm.$u.vuex('vuex_remember', '');
}
}
return data;
}
// 封装 get text 请求
vm.$u.getText = (url, data = {}, header = {}) => {
return vm.$u.http.request({
dataType: 'text',
method: 'GET',
url,
header,
data
})
}
// 封装 post json 请求
vm.$u.postJson = (url, data = {}, header = {}) => {
console.log('header', header, url, vm.$u)
header['content-type'] = 'application/json';
return vm.$u.http.request({
url,
method: 'POST',
header,
data
})
}
}
export default {
install
}

34
src/common/locales/en.js Normal file
View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
export default {
common: {
title: 'Aidex',
},
nav: {
home: 'Home',
user: 'User',
msg: 'Msg'
},
login: {
title: 'Login',
placeholderAccount: 'Enter Account',
placeholderPassword: 'Enter Password',
autoLogin: 'Auto Login',
loginButton: 'Login',
logoutButton: 'Logout',
forget: 'Forget Password',
reg: 'Resister Account',
noLogin: 'No Login'
},
home: {
title: 'Home'
},
user: {
title: 'User'
},
msg: {
title: 'Message'
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
*/
export default {
common: {
title: 'Aidex',
},
nav: {
home: '消息',
workbench: '工作台',
user: '我的',
book: '通讯录',
msg: '消息',
},
login: {
title: '登录',
placeholderAccount: '请输入账号',
placeholderPassword: '请输入密码',
autoLogin: '记住密码',
loginButton: '登录',
logoutButton: '退出登录',
forget: '忘记密码',
reg: '注册账号',
noLogin: '未登录'
},
home: {
title: '消息'
},
workbench: {
title: '工作台'
},
user: {
title: '用户中心'
},
msg: {
title: '消息'
},
book: {
title: '通讯录'
}
}

685
src/common/md5.js Normal file
View File

@ -0,0 +1,685 @@
/**
* [js-md5]{@link https://github.com/emn178/js-md5}
*
* @namespace md5
* @version 0.7.3
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2014-2017
* @license MIT
*/
(function () {
'use strict';
var ERROR = 'input is invalid type';
var WINDOW = typeof window === 'object';
var root = WINDOW ? window : {};
if (root.JS_MD5_NO_WINDOW) {
WINDOW = false;
}
var WEB_WORKER = !WINDOW && typeof self === 'object';
var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
if (NODE_JS) {
root = global;
} else if (WEB_WORKER) {
root = self;
}
var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;
var AMD = typeof define === 'function' && define.amd;
var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
var HEX_CHARS = '0123456789abcdef'.split('');
var EXTRA = [128, 32768, 8388608, -2147483648];
var SHIFT = [0, 8, 16, 24];
var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];
var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
var blocks = [], buffer8;
if (ARRAY_BUFFER) {
var buffer = new ArrayBuffer(68);
buffer8 = new Uint8Array(buffer);
blocks = new Uint32Array(buffer);
}
if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {
Array.isArray = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
}
if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
ArrayBuffer.isView = function (obj) {
return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
};
}
/**
* @method hex
* @memberof md5
* @description Output hash as hex string
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {String} Hex string
* @example
* md5.hex('The quick brown fox jumps over the lazy dog');
* // equal to
* md5('The quick brown fox jumps over the lazy dog');
*/
/**
* @method digest
* @memberof md5
* @description Output hash as bytes array
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {Array} Bytes array
* @example
* md5.digest('The quick brown fox jumps over the lazy dog');
*/
/**
* @method array
* @memberof md5
* @description Output hash as bytes array
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {Array} Bytes array
* @example
* md5.array('The quick brown fox jumps over the lazy dog');
*/
/**
* @method arrayBuffer
* @memberof md5
* @description Output hash as ArrayBuffer
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {ArrayBuffer} ArrayBuffer
* @example
* md5.arrayBuffer('The quick brown fox jumps over the lazy dog');
*/
/**
* @method buffer
* @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
* @memberof md5
* @description Output hash as ArrayBuffer
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {ArrayBuffer} ArrayBuffer
* @example
* md5.buffer('The quick brown fox jumps over the lazy dog');
*/
/**
* @method base64
* @memberof md5
* @description Output hash as base64 string
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {String} base64 string
* @example
* md5.base64('The quick brown fox jumps over the lazy dog');
*/
var createOutputMethod = function (outputType) {
return function (message) {
return new Md5(true).update(message)[outputType]();
};
};
/**
* @method create
* @memberof md5
* @description Create Md5 object
* @returns {Md5} Md5 object.
* @example
* var hash = md5.create();
*/
/**
* @method update
* @memberof md5
* @description Create and update Md5 object
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {Md5} Md5 object.
* @example
* var hash = md5.update('The quick brown fox jumps over the lazy dog');
* // equal to
* var hash = md5.create();
* hash.update('The quick brown fox jumps over the lazy dog');
*/
var createMethod = function () {
var method = createOutputMethod('hex');
if (NODE_JS) {
method = nodeWrap(method);
}
method.create = function () {
return new Md5();
};
method.update = function (message) {
return method.create().update(message);
};
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
var type = OUTPUT_TYPES[i];
method[type] = createOutputMethod(type);
}
return method;
};
var nodeWrap = function (method) {
var crypto = eval("require('crypto')");
var Buffer = eval("require('buffer').Buffer");
var nodeMethod = function (message) {
if (typeof message === 'string') {
return crypto.createHash('md5').update(message, 'utf8').digest('hex');
} else {
if (message === null || message === undefined) {
throw ERROR;
} else if (message.constructor === ArrayBuffer) {
message = new Uint8Array(message);
}
}
if (Array.isArray(message) || ArrayBuffer.isView(message) ||
message.constructor === Buffer) {
return crypto.createHash('md5').update(new Buffer(message)).digest('hex');
} else {
return method(message);
}
};
return nodeMethod;
};
/**
* Md5 class
* @class Md5
* @description This is internal class.
* @see {@link md5.create}
*/
function Md5(sharedMemory) {
if (sharedMemory) {
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
this.blocks = blocks;
this.buffer8 = buffer8;
} else {
if (ARRAY_BUFFER) {
var buffer = new ArrayBuffer(68);
this.buffer8 = new Uint8Array(buffer);
this.blocks = new Uint32Array(buffer);
} else {
this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
}
this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;
this.finalized = this.hashed = false;
this.first = true;
}
/**
* @method update
* @memberof Md5
* @instance
* @description Update hash
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {Md5} Md5 object.
* @see {@link md5.update}
*/
Md5.prototype.update = function (message) {
if (this.finalized) {
return;
}
var notString, type = typeof message;
if (type !== 'string') {
if (type === 'object') {
if (message === null) {
throw ERROR;
} else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
message = new Uint8Array(message);
} else if (!Array.isArray(message)) {
if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
throw ERROR;
}
}
} else {
throw ERROR;
}
notString = true;
}
var code, index = 0, i, length = message.length, blocks = this.blocks;
var buffer8 = this.buffer8;
while (index < length) {
if (this.hashed) {
this.hashed = false;
blocks[0] = blocks[16];
blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
}
if (notString) {
if (ARRAY_BUFFER) {
for (i = this.start; index < length && i < 64; ++index) {
buffer8[i++] = message[index];
}
} else {
for (i = this.start; index < length && i < 64; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
}
}
} else {
if (ARRAY_BUFFER) {
for (i = this.start; index < length && i < 64; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
buffer8[i++] = code;
} else if (code < 0x800) {
buffer8[i++] = 0xc0 | (code >> 6);
buffer8[i++] = 0x80 | (code & 0x3f);
} else if (code < 0xd800 || code >= 0xe000) {
buffer8[i++] = 0xe0 | (code >> 12);
buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
buffer8[i++] = 0x80 | (code & 0x3f);
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
buffer8[i++] = 0xf0 | (code >> 18);
buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);
buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
buffer8[i++] = 0x80 | (code & 0x3f);
}
}
} else {
for (i = this.start; index < length && i < 64; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
} else if (code < 0x800) {
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else if (code < 0xd800 || code >= 0xe000) {
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
}
}
}
}
this.lastByteIndex = i;
this.bytes += i - this.start;
if (i >= 64) {
this.start = i - 64;
this.hash();
this.hashed = true;
} else {
this.start = i;
}
}
if (this.bytes > 4294967295) {
this.hBytes += this.bytes / 4294967296 << 0;
this.bytes = this.bytes % 4294967296;
}
return this;
};
Md5.prototype.finalize = function () {
if (this.finalized) {
return;
}
this.finalized = true;
var blocks = this.blocks, i = this.lastByteIndex;
blocks[i >> 2] |= EXTRA[i & 3];
if (i >= 56) {
if (!this.hashed) {
this.hash();
}
blocks[0] = blocks[16];
blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
}
blocks[14] = this.bytes << 3;
blocks[15] = this.hBytes << 3 | this.bytes >>> 29;
this.hash();
};
Md5.prototype.hash = function () {
var a, b, c, d, bc, da, blocks = this.blocks;
if (this.first) {
a = blocks[0] - 680876937;
a = (a << 7 | a >>> 25) - 271733879 << 0;
d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;
d = (d << 12 | d >>> 20) + a << 0;
c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;
c = (c << 17 | c >>> 15) + d << 0;
b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;
b = (b << 22 | b >>> 10) + c << 0;
} else {
a = this.h0;
b = this.h1;
c = this.h2;
d = this.h3;
a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;
a = (a << 7 | a >>> 25) + b << 0;
d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;
d = (d << 12 | d >>> 20) + a << 0;
c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;
c = (c << 17 | c >>> 15) + d << 0;
b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;
b = (b << 22 | b >>> 10) + c << 0;
}
a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;
a = (a << 7 | a >>> 25) + b << 0;
d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;
d = (d << 12 | d >>> 20) + a << 0;
c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;
c = (c << 17 | c >>> 15) + d << 0;
b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;
b = (b << 22 | b >>> 10) + c << 0;
a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;
a = (a << 7 | a >>> 25) + b << 0;
d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;
d = (d << 12 | d >>> 20) + a << 0;
c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;
c = (c << 17 | c >>> 15) + d << 0;
b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;
b = (b << 22 | b >>> 10) + c << 0;
a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;
a = (a << 7 | a >>> 25) + b << 0;
d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;
d = (d << 12 | d >>> 20) + a << 0;
c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;
c = (c << 17 | c >>> 15) + d << 0;
b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;
b = (b << 22 | b >>> 10) + c << 0;
a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;
a = (a << 5 | a >>> 27) + b << 0;
d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;
d = (d << 9 | d >>> 23) + a << 0;
c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;
c = (c << 14 | c >>> 18) + d << 0;
b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;
b = (b << 20 | b >>> 12) + c << 0;
a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;
a = (a << 5 | a >>> 27) + b << 0;
d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;
d = (d << 9 | d >>> 23) + a << 0;
c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;
c = (c << 14 | c >>> 18) + d << 0;
b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;
b = (b << 20 | b >>> 12) + c << 0;
a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;
a = (a << 5 | a >>> 27) + b << 0;
d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;
d = (d << 9 | d >>> 23) + a << 0;
c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;
c = (c << 14 | c >>> 18) + d << 0;
b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;
b = (b << 20 | b >>> 12) + c << 0;
a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;
a = (a << 5 | a >>> 27) + b << 0;
d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;
d = (d << 9 | d >>> 23) + a << 0;
c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;
c = (c << 14 | c >>> 18) + d << 0;
b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;
b = (b << 20 | b >>> 12) + c << 0;
bc = b ^ c;
a += (bc ^ d) + blocks[5] - 378558;
a = (a << 4 | a >>> 28) + b << 0;
d += (bc ^ a) + blocks[8] - 2022574463;
d = (d << 11 | d >>> 21) + a << 0;
da = d ^ a;
c += (da ^ b) + blocks[11] + 1839030562;
c = (c << 16 | c >>> 16) + d << 0;
b += (da ^ c) + blocks[14] - 35309556;
b = (b << 23 | b >>> 9) + c << 0;
bc = b ^ c;
a += (bc ^ d) + blocks[1] - 1530992060;
a = (a << 4 | a >>> 28) + b << 0;
d += (bc ^ a) + blocks[4] + 1272893353;
d = (d << 11 | d >>> 21) + a << 0;
da = d ^ a;
c += (da ^ b) + blocks[7] - 155497632;
c = (c << 16 | c >>> 16) + d << 0;
b += (da ^ c) + blocks[10] - 1094730640;
b = (b << 23 | b >>> 9) + c << 0;
bc = b ^ c;
a += (bc ^ d) + blocks[13] + 681279174;
a = (a << 4 | a >>> 28) + b << 0;
d += (bc ^ a) + blocks[0] - 358537222;
d = (d << 11 | d >>> 21) + a << 0;
da = d ^ a;
c += (da ^ b) + blocks[3] - 722521979;
c = (c << 16 | c >>> 16) + d << 0;
b += (da ^ c) + blocks[6] + 76029189;
b = (b << 23 | b >>> 9) + c << 0;
bc = b ^ c;
a += (bc ^ d) + blocks[9] - 640364487;
a = (a << 4 | a >>> 28) + b << 0;
d += (bc ^ a) + blocks[12] - 421815835;
d = (d << 11 | d >>> 21) + a << 0;
da = d ^ a;
c += (da ^ b) + blocks[15] + 530742520;
c = (c << 16 | c >>> 16) + d << 0;
b += (da ^ c) + blocks[2] - 995338651;
b = (b << 23 | b >>> 9) + c << 0;
a += (c ^ (b | ~d)) + blocks[0] - 198630844;
a = (a << 6 | a >>> 26) + b << 0;
d += (b ^ (a | ~c)) + blocks[7] + 1126891415;
d = (d << 10 | d >>> 22) + a << 0;
c += (a ^ (d | ~b)) + blocks[14] - 1416354905;
c = (c << 15 | c >>> 17) + d << 0;
b += (d ^ (c | ~a)) + blocks[5] - 57434055;
b = (b << 21 | b >>> 11) + c << 0;
a += (c ^ (b | ~d)) + blocks[12] + 1700485571;
a = (a << 6 | a >>> 26) + b << 0;
d += (b ^ (a | ~c)) + blocks[3] - 1894986606;
d = (d << 10 | d >>> 22) + a << 0;
c += (a ^ (d | ~b)) + blocks[10] - 1051523;
c = (c << 15 | c >>> 17) + d << 0;
b += (d ^ (c | ~a)) + blocks[1] - 2054922799;
b = (b << 21 | b >>> 11) + c << 0;
a += (c ^ (b | ~d)) + blocks[8] + 1873313359;
a = (a << 6 | a >>> 26) + b << 0;
d += (b ^ (a | ~c)) + blocks[15] - 30611744;
d = (d << 10 | d >>> 22) + a << 0;
c += (a ^ (d | ~b)) + blocks[6] - 1560198380;
c = (c << 15 | c >>> 17) + d << 0;
b += (d ^ (c | ~a)) + blocks[13] + 1309151649;
b = (b << 21 | b >>> 11) + c << 0;
a += (c ^ (b | ~d)) + blocks[4] - 145523070;
a = (a << 6 | a >>> 26) + b << 0;
d += (b ^ (a | ~c)) + blocks[11] - 1120210379;
d = (d << 10 | d >>> 22) + a << 0;
c += (a ^ (d | ~b)) + blocks[2] + 718787259;
c = (c << 15 | c >>> 17) + d << 0;
b += (d ^ (c | ~a)) + blocks[9] - 343485551;
b = (b << 21 | b >>> 11) + c << 0;
if (this.first) {
this.h0 = a + 1732584193 << 0;
this.h1 = b - 271733879 << 0;
this.h2 = c - 1732584194 << 0;
this.h3 = d + 271733878 << 0;
this.first = false;
} else {
this.h0 = this.h0 + a << 0;
this.h1 = this.h1 + b << 0;
this.h2 = this.h2 + c << 0;
this.h3 = this.h3 + d << 0;
}
};
/**
* @method hex
* @memberof Md5
* @instance
* @description Output hash as hex string
* @returns {String} Hex string
* @see {@link md5.hex}
* @example
* hash.hex();
*/
Md5.prototype.hex = function () {
this.finalize();
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];
};
/**
* @method toString
* @memberof Md5
* @instance
* @description Output hash as hex string
* @returns {String} Hex string
* @see {@link md5.hex}
* @example
* hash.toString();
*/
Md5.prototype.toString = Md5.prototype.hex;
/**
* @method digest
* @memberof Md5
* @instance
* @description Output hash as bytes array
* @returns {Array} Bytes array
* @see {@link md5.digest}
* @example
* hash.digest();
*/
Md5.prototype.digest = function () {
this.finalize();
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
return [
h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,
h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,
h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,
h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF
];
};
/**
* @method array
* @memberof Md5
* @instance
* @description Output hash as bytes array
* @returns {Array} Bytes array
* @see {@link md5.array}
* @example
* hash.array();
*/
Md5.prototype.array = Md5.prototype.digest;
/**
* @method arrayBuffer
* @memberof Md5
* @instance
* @description Output hash as ArrayBuffer
* @returns {ArrayBuffer} ArrayBuffer
* @see {@link md5.arrayBuffer}
* @example
* hash.arrayBuffer();
*/
Md5.prototype.arrayBuffer = function () {
this.finalize();
var buffer = new ArrayBuffer(16);
var blocks = new Uint32Array(buffer);
blocks[0] = this.h0;
blocks[1] = this.h1;
blocks[2] = this.h2;
blocks[3] = this.h3;
return buffer;
};
/**
* @method buffer
* @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
* @memberof Md5
* @instance
* @description Output hash as ArrayBuffer
* @returns {ArrayBuffer} ArrayBuffer
* @see {@link md5.buffer}
* @example
* hash.buffer();
*/
Md5.prototype.buffer = Md5.prototype.arrayBuffer;
/**
* @method base64
* @memberof Md5
* @instance
* @description Output hash as base64 string
* @returns {String} base64 string
* @see {@link md5.base64}
* @example
* hash.base64();
*/
Md5.prototype.base64 = function () {
var v1, v2, v3, base64Str = '', bytes = this.array();
for (var i = 0; i < 15;) {
v1 = bytes[i++];
v2 = bytes[i++];
v3 = bytes[i++];
base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +
BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +
BASE64_ENCODE_CHAR[v3 & 63];
}
v1 = bytes[i];
base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
BASE64_ENCODE_CHAR[(v1 << 4) & 63] +
'==';
return base64Str;
};
var exports = createMethod();
if (COMMON_JS) {
module.exports = exports;
} else {
/**
* @method md5
* @description Md5 hash function, export to global in browsers.
* @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
* @returns {String} md5 hashes
* @example
* md5(''); // d41d8cd98f00b204e9800998ecf8427e
* md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
* md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
*
* // It also supports UTF-8 encoding
* md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
*
* // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
* md5([]); // d41d8cd98f00b204e9800998ecf8427e
* md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
*/
root.md5 = exports;
if (AMD) {
define(function () {
return exports;
});
}
}
})();

207
src/common/scanMixin.js Normal file
View File

@ -0,0 +1,207 @@
// common/scanMixin.js
export default {
data() {
return {
scanReceiver: null,
isPageActive: false
}
},
methods: {
// 注册扫码广播(兼容多种设备)
registerScanBroadcast(scanCallback) {
try {
// 先尝试注册商米扫码头
this.registerSunmiBroadcast(scanCallback)
.then(() => {
console.log('商米扫码头注册成功');
})
.catch((error) => {
console.log('商米扫码头注册失败,尝试新大陆扫码头:', error);
// 如果商米扫码头注册失败,尝试新大陆扫码头
this.registerNewlandBroadcast(scanCallback);
});
} catch (error) {
console.error("注册扫码广播失败:", error);
return false;
}
},
// 注册商米扫码头广播接收器
registerSunmiBroadcast(scanCallback) {
return new Promise((resolve, reject) => {
try {
const main = plus.android.runtimeMainActivity();
const IntentFilter = plus.android.importClass("android.content.IntentFilter");
const filter = new IntentFilter();
filter.addAction("com.sunmi.scanner.ACTION_DATA_CODE_RECEIVED");
const self = this;
const receiver = plus.android.implements(
"io.dcloud.feature.internal.reflect.BroadcastReceiver",
{
onReceive: (context, intent) => {
console.log('商米扫码广播接收isPageActive:', self.isPageActive);
// 只有当页面活动时才处理广播
if (!self.isPageActive) return;
try {
// 导入 Intent 类以使用其方法
const Intent = plus.android.importClass("android.content.Intent");
const scanResult = intent.getStringExtra("data");
const sourceBytes = intent.getByteArrayExtra("source_byte");
console.log('商米扫码结果:', scanResult, sourceBytes);
if (scanResult) {
self.handleScanResult(scanResult, scanCallback);
}
} catch (error) {
console.error('处理商米广播数据时出错:', error);
}
}
}
);
// 注册广播接收器
main.registerReceiver(receiver, filter);
this.scanReceiver = receiver;
console.log('商米扫码广播接收器注册成功');
resolve();
} catch (error) {
console.error('注册商米广播接收器失败:', error);
reject(error);
}
});
},
// 注册新大陆扫码头广播接收器
registerNewlandBroadcast(scanCallback) {
try {
const main = plus.android.runtimeMainActivity();
// 先配置扫码枪广播设置
try {
const Intent = plus.android.importClass("android.content.Intent");
const intent = new Intent("com.android.scanner.service_settings");
intent.putExtra(
"action_barcode_broadcast",
"com.android.server.scannerservice.broadcast"
);
intent.putExtra("key_barcode_broadcast", "scannerdata");
main.sendBroadcast(intent);
console.log('新大陆扫码枪广播配置完成');
} catch (error) {
console.error("配置新大陆扫码枪广播失败:", error);
}
// 注册广播接收器
const IntentFilter = plus.android.importClass(
"android.content.IntentFilter"
);
const filter = new IntentFilter();
filter.addAction("com.android.server.scannerservice.broadcast");
console.log("添加新大陆广播action完成");
const self = this;
const receiver = plus.android.implements(
"io.dcloud.feature.internal.reflect.BroadcastReceiver",
{
onReceive: (context, intent) => {
console.log('新大陆扫码广播接收isPageActive:', self.isPageActive);
// 只有当页面活动时才处理广播
if (!self.isPageActive) return;
try {
// 导入 Intent 类以使用其方法
const Intent = plus.android.importClass("android.content.Intent");
const scanResult = intent.getStringExtra("scannerdata");
console.log("新大陆扫码结果:", scanResult);
if (scanResult) {
self.handleScanResult(scanResult, scanCallback);
}
} catch (error) {
console.error("处理新大陆广播数据时出错:", error);
}
},
}
);
// 注册广播接收器
main.registerReceiver(receiver, filter);
this.scanReceiver = receiver;
console.log("新大陆扫码广播注册成功,等待扫码...");
} catch (error) {
console.error("注册新大陆扫码广播失败:", error);
throw error;
}
},
// 处理扫码结果的统一方法
handleScanResult(scanResult, scanCallback) {
try {
// 数据清理:去除空格、换行符等
let cleanCode = scanResult.replace(/\s+/g, '').replace(/[\r\n]/g, '');
console.log("扫码结果:", cleanCode);
if (scanCallback) {
scanCallback(cleanCode);
}
} catch (error) {
console.error("处理扫码结果时出错:", error);
}
},
// 取消扫码广播监听
unregisterScanBroadcast() {
if (this.scanReceiver) {
try {
const main = plus.android.runtimeMainActivity();
main.unregisterReceiver(this.scanReceiver);
this.scanReceiver = null;
console.log("扫码广播注销成功");
} catch (err) {
console.error("注销扫码广播失败:", err);
}
}
},
// 通用的商品扫描处理方法
handleGoodsScan(scanCode, successCallback, errorCallback) {
const trimmedCode = scanCode ? scanCode.toString().trim() : "";
if (!trimmedCode) {
this.playError && this.playError();
errorCallback && errorCallback("无效的二维码!");
return;
}
// 根据业务类型处理不同的扫码逻辑
if (this.processScanCode) {
this.processScanCode(trimmedCode, successCallback, errorCallback);
} else {
// 默认处理方式
successCallback && successCallback(trimmedCode);
}
}
},
// 页面激活状态管理
onShow() {
this.isPageActive = true;
console.log('页面显示,设置 isPageActive 为 true');
},
onHide() {
this.isPageActive = false;
},
onUnload() {
this.isPageActive = false;
this.unregisterScanBroadcast();
}
}

751
src/common/spark-md5.js Normal file
View File

@ -0,0 +1,751 @@
(function (factory) {
if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
// AMD
define(factory);
} else {
// Browser globals (with support for web workers)
var glob;
try {
glob = window;
} catch (e) {
glob = self;
}
glob.SparkMD5 = factory();
}
}(function (undefined) {
'use strict';
/*
* Fastest md5 implementation around (JKM md5).
* Credits: Joseph Myers
*
* @see http://www.myersdaily.org/joseph/javascript/md5-text.html
* @see http://jsperf.com/md5-shootout/7
*/
/* this function is much faster,
so if possible we use it. Some IEs
are the only ones I know of that
need the idiotic second function,
generated by an if clause. */
var add32 = function (a, b) {
return (a + b) & 0xFFFFFFFF;
},
hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
}
function md5cycle(x, k) {
var a = x[0],
b = x[1],
c = x[2],
d = x[3];
a += (b & c | ~b & d) + k[0] - 680876936 | 0;
a = (a << 7 | a >>> 25) + b | 0;
d += (a & b | ~a & c) + k[1] - 389564586 | 0;
d = (d << 12 | d >>> 20) + a | 0;
c += (d & a | ~d & b) + k[2] + 606105819 | 0;
c = (c << 17 | c >>> 15) + d | 0;
b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
b = (b << 22 | b >>> 10) + c | 0;
a += (b & c | ~b & d) + k[4] - 176418897 | 0;
a = (a << 7 | a >>> 25) + b | 0;
d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
d = (d << 12 | d >>> 20) + a | 0;
c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
c = (c << 17 | c >>> 15) + d | 0;
b += (c & d | ~c & a) + k[7] - 45705983 | 0;
b = (b << 22 | b >>> 10) + c | 0;
a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
a = (a << 7 | a >>> 25) + b | 0;
d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
d = (d << 12 | d >>> 20) + a | 0;
c += (d & a | ~d & b) + k[10] - 42063 | 0;
c = (c << 17 | c >>> 15) + d | 0;
b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
b = (b << 22 | b >>> 10) + c | 0;
a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
a = (a << 7 | a >>> 25) + b | 0;
d += (a & b | ~a & c) + k[13] - 40341101 | 0;
d = (d << 12 | d >>> 20) + a | 0;
c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
c = (c << 17 | c >>> 15) + d | 0;
b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
b = (b << 22 | b >>> 10) + c | 0;
a += (b & d | c & ~d) + k[1] - 165796510 | 0;
a = (a << 5 | a >>> 27) + b | 0;
d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
d = (d << 9 | d >>> 23) + a | 0;
c += (d & b | a & ~b) + k[11] + 643717713 | 0;
c = (c << 14 | c >>> 18) + d | 0;
b += (c & a | d & ~a) + k[0] - 373897302 | 0;
b = (b << 20 | b >>> 12) + c | 0;
a += (b & d | c & ~d) + k[5] - 701558691 | 0;
a = (a << 5 | a >>> 27) + b | 0;
d += (a & c | b & ~c) + k[10] + 38016083 | 0;
d = (d << 9 | d >>> 23) + a | 0;
c += (d & b | a & ~b) + k[15] - 660478335 | 0;
c = (c << 14 | c >>> 18) + d | 0;
b += (c & a | d & ~a) + k[4] - 405537848 | 0;
b = (b << 20 | b >>> 12) + c | 0;
a += (b & d | c & ~d) + k[9] + 568446438 | 0;
a = (a << 5 | a >>> 27) + b | 0;
d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
d = (d << 9 | d >>> 23) + a | 0;
c += (d & b | a & ~b) + k[3] - 187363961 | 0;
c = (c << 14 | c >>> 18) + d | 0;
b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
b = (b << 20 | b >>> 12) + c | 0;
a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
a = (a << 5 | a >>> 27) + b | 0;
d += (a & c | b & ~c) + k[2] - 51403784 | 0;
d = (d << 9 | d >>> 23) + a | 0;
c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
c = (c << 14 | c >>> 18) + d | 0;
b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
b = (b << 20 | b >>> 12) + c | 0;
a += (b ^ c ^ d) + k[5] - 378558 | 0;
a = (a << 4 | a >>> 28) + b | 0;
d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
d = (d << 11 | d >>> 21) + a | 0;
c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
c = (c << 16 | c >>> 16) + d | 0;
b += (c ^ d ^ a) + k[14] - 35309556 | 0;
b = (b << 23 | b >>> 9) + c | 0;
a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
a = (a << 4 | a >>> 28) + b | 0;
d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
d = (d << 11 | d >>> 21) + a | 0;
c += (d ^ a ^ b) + k[7] - 155497632 | 0;
c = (c << 16 | c >>> 16) + d | 0;
b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
b = (b << 23 | b >>> 9) + c | 0;
a += (b ^ c ^ d) + k[13] + 681279174 | 0;
a = (a << 4 | a >>> 28) + b | 0;
d += (a ^ b ^ c) + k[0] - 358537222 | 0;
d = (d << 11 | d >>> 21) + a | 0;
c += (d ^ a ^ b) + k[3] - 722521979 | 0;
c = (c << 16 | c >>> 16) + d | 0;
b += (c ^ d ^ a) + k[6] + 76029189 | 0;
b = (b << 23 | b >>> 9) + c | 0;
a += (b ^ c ^ d) + k[9] - 640364487 | 0;
a = (a << 4 | a >>> 28) + b | 0;
d += (a ^ b ^ c) + k[12] - 421815835 | 0;
d = (d << 11 | d >>> 21) + a | 0;
c += (d ^ a ^ b) + k[15] + 530742520 | 0;
c = (c << 16 | c >>> 16) + d | 0;
b += (c ^ d ^ a) + k[2] - 995338651 | 0;
b = (b << 23 | b >>> 9) + c | 0;
a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
a = (a << 6 | a >>> 26) + b | 0;
d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
d = (d << 10 | d >>> 22) + a | 0;
c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
c = (c << 15 | c >>> 17) + d | 0;
b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
b = (b << 21 |b >>> 11) + c | 0;
a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
a = (a << 6 | a >>> 26) + b | 0;
d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
d = (d << 10 | d >>> 22) + a | 0;
c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
c = (c << 15 | c >>> 17) + d | 0;
b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
b = (b << 21 |b >>> 11) + c | 0;
a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
a = (a << 6 | a >>> 26) + b | 0;
d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
d = (d << 10 | d >>> 22) + a | 0;
c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
c = (c << 15 | c >>> 17) + d | 0;
b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
b = (b << 21 |b >>> 11) + c | 0;
a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
a = (a << 6 | a >>> 26) + b | 0;
d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
d = (d << 10 | d >>> 22) + a | 0;
c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
c = (c << 15 | c >>> 17) + d | 0;
b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
b = (b << 21 | b >>> 11) + c | 0;
x[0] = a + x[0] | 0;
x[1] = b + x[1] | 0;
x[2] = c + x[2] | 0;
x[3] = d + x[3] | 0;
}
function md5blk(s) {
var md5blks = [],
i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
}
return md5blks;
}
function md5blk_array(a) {
var md5blks = [],
i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
}
return md5blks;
}
function md51(s) {
var n = s.length,
state = [1732584193, -271733879, -1732584194, 271733878],
i,
length,
tail,
tmp,
lo,
hi;
for (i = 64; i <= n; i += 64) {
md5cycle(state, md5blk(s.substring(i - 64, i)));
}
s = s.substring(i - 64);
length = s.length;
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
}
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Beware that the final length might not fit in 32 bits so we take care of that
tmp = n * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(state, tail);
return state;
}
function md51_array(a) {
var n = a.length,
state = [1732584193, -271733879, -1732584194, 271733878],
i,
length,
tail,
tmp,
lo,
hi;
for (i = 64; i <= n; i += 64) {
md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
}
// Not sure if it is a bug, however IE10 will always produce a sub array of length 1
// containing the last element of the parent array if the sub array specified starts
// beyond the length of the parent array - weird.
// https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
length = a.length;
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= a[i] << ((i % 4) << 3);
}
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Beware that the final length might not fit in 32 bits so we take care of that
tmp = n * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(state, tail);
return state;
}
function rhex(n) {
var s = '',
j;
for (j = 0; j < 4; j += 1) {
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
}
return s;
}
function hex(x) {
var i;
for (i = 0; i < x.length; i += 1) {
x[i] = rhex(x[i]);
}
return x.join('');
}
// In some cases the fast add32 function cannot be used..
if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {
add32 = function (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
};
}
// ---------------------------------------------------
/**
* ArrayBuffer slice polyfill.
*
* @see https://github.com/ttaubert/node-arraybuffer-slice
*/
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
(function () {
function clamp(val, length) {
val = (val | 0) || 0;
if (val < 0) {
return Math.max(val + length, 0);
}
return Math.min(val, length);
}
ArrayBuffer.prototype.slice = function (from, to) {
var length = this.byteLength,
begin = clamp(from, length),
end = length,
num,
target,
targetArray,
sourceArray;
if (to !== undefined) {
end = clamp(to, length);
}
if (begin > end) {
return new ArrayBuffer(0);
}
num = end - begin;
target = new ArrayBuffer(num);
targetArray = new Uint8Array(target);
sourceArray = new Uint8Array(this, begin, num);
targetArray.set(sourceArray);
return target;
};
})();
}
// ---------------------------------------------------
/**
* Helpers.
*/
function toUtf8(str) {
if (/[\u0080-\uFFFF]/.test(str)) {
str = unescape(encodeURIComponent(str));
}
return str;
}
function utf8Str2ArrayBuffer(str, returnUInt8Array) {
var length = str.length,
buff = new ArrayBuffer(length),
arr = new Uint8Array(buff),
i;
for (i = 0; i < length; i += 1) {
arr[i] = str.charCodeAt(i);
}
return returnUInt8Array ? arr : buff;
}
function arrayBuffer2Utf8Str(buff) {
return String.fromCharCode.apply(null, new Uint8Array(buff));
}
function concatenateArrayBuffers(first, second, returnUInt8Array) {
var result = new Uint8Array(first.byteLength + second.byteLength);
result.set(new Uint8Array(first));
result.set(new Uint8Array(second), first.byteLength);
return returnUInt8Array ? result : result.buffer;
}
function hexToBinaryString(hex) {
var bytes = [],
length = hex.length,
x;
for (x = 0; x < length - 1; x += 2) {
bytes.push(parseInt(hex.substr(x, 2), 16));
}
return String.fromCharCode.apply(String, bytes);
}
// ---------------------------------------------------
/**
* SparkMD5 OOP implementation.
*
* Use this class to perform an incremental md5, otherwise use the
* static methods instead.
*/
function SparkMD5() {
// call reset to init the instance
this.reset();
}
/**
* Appends a string.
* A conversion will be applied if an utf8 string is detected.
*
* @param {String} str The string to be appended
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.append = function (str) {
// Converts the string to utf8 bytes if necessary
// Then append as binary
this.appendBinary(toUtf8(str));
return this;
};
/**
* Appends a binary string.
*
* @param {String} contents The binary string to be appended
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.appendBinary = function (contents) {
this._buff += contents;
this._length += contents.length;
var length = this._buff.length,
i;
for (i = 64; i <= length; i += 64) {
md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
}
this._buff = this._buff.substring(i - 64);
return this;
};
/**
* Finishes the incremental computation, reseting the internal state and
* returning the result.
*
* @param {Boolean} raw True to get the raw string, false to get the hex string
*
* @return {String} The result
*/
SparkMD5.prototype.end = function (raw) {
var buff = this._buff,
length = buff.length,
i,
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
ret;
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
}
this._finish(tail, length);
ret = hex(this._hash);
if (raw) {
ret = hexToBinaryString(ret);
}
this.reset();
return ret;
};
/**
* Resets the internal state of the computation.
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.reset = function () {
this._buff = '';
this._length = 0;
this._hash = [1732584193, -271733879, -1732584194, 271733878];
return this;
};
/**
* Gets the internal state of the computation.
*
* @return {Object} The state
*/
SparkMD5.prototype.getState = function () {
return {
buff: this._buff,
length: this._length,
hash: this._hash.slice()
};
};
/**
* Gets the internal state of the computation.
*
* @param {Object} state The state
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.setState = function (state) {
this._buff = state.buff;
this._length = state.length;
this._hash = state.hash;
return this;
};
/**
* Releases memory used by the incremental buffer and other additional
* resources. If you plan to use the instance again, use reset instead.
*/
SparkMD5.prototype.destroy = function () {
delete this._hash;
delete this._buff;
delete this._length;
};
/**
* Finish the final calculation based on the tail.
*
* @param {Array} tail The tail (will be modified)
* @param {Number} length The length of the remaining buffer
*/
SparkMD5.prototype._finish = function (tail, length) {
var i = length,
tmp,
lo,
hi;
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(this._hash, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Do the final computation based on the tail and length
// Beware that the final length may not fit in 32 bits so we take care of that
tmp = this._length * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(this._hash, tail);
};
/**
* Performs the md5 hash on a string.
* A conversion will be applied if utf8 string is detected.
*
* @param {String} str The string
* @param {Boolean} [raw] True to get the raw string, false to get the hex string
*
* @return {String} The result
*/
SparkMD5.hash = function (str, raw) {
// Converts the string to utf8 bytes if necessary
// Then compute it using the binary function
return SparkMD5.hashBinary(toUtf8(str), raw);
};
/**
* Performs the md5 hash on a binary string.
*
* @param {String} content The binary string
* @param {Boolean} [raw] True to get the raw string, false to get the hex string
*
* @return {String} The result
*/
SparkMD5.hashBinary = function (content, raw) {
var hash = md51(content),
ret = hex(hash);
return raw ? hexToBinaryString(ret) : ret;
};
// ---------------------------------------------------
/**
* SparkMD5 OOP implementation for array buffers.
*
* Use this class to perform an incremental md5 ONLY for array buffers.
*/
SparkMD5.ArrayBuffer = function () {
// call reset to init the instance
this.reset();
};
/**
* Appends an array buffer.
*
* @param {ArrayBuffer} arr The array to be appended
*
* @return {SparkMD5.ArrayBuffer} The instance itself
*/
SparkMD5.ArrayBuffer.prototype.append = function (arr) {
var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
length = buff.length,
i;
this._length += arr.byteLength;
for (i = 64; i <= length; i += 64) {
md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
}
this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
return this;
};
/**
* Finishes the incremental computation, reseting the internal state and
* returning the result.
*
* @param {Boolean} raw True to get the raw string, false to get the hex string
*
* @return {String} The result
*/
SparkMD5.ArrayBuffer.prototype.end = function (raw) {
var buff = this._buff,
length = buff.length,
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
i,
ret;
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= buff[i] << ((i % 4) << 3);
}
this._finish(tail, length);
ret = hex(this._hash);
if (raw) {
ret = hexToBinaryString(ret);
}
this.reset();
return ret;
};
/**
* Resets the internal state of the computation.
*
* @return {SparkMD5.ArrayBuffer} The instance itself
*/
SparkMD5.ArrayBuffer.prototype.reset = function () {
this._buff = new Uint8Array(0);
this._length = 0;
this._hash = [1732584193, -271733879, -1732584194, 271733878];
return this;
};
/**
* Gets the internal state of the computation.
*
* @return {Object} The state
*/
SparkMD5.ArrayBuffer.prototype.getState = function () {
var state = SparkMD5.prototype.getState.call(this);
// Convert buffer to a string
state.buff = arrayBuffer2Utf8Str(state.buff);
return state;
};
/**
* Gets the internal state of the computation.
*
* @param {Object} state The state
*
* @return {SparkMD5.ArrayBuffer} The instance itself
*/
SparkMD5.ArrayBuffer.prototype.setState = function (state) {
// Convert string to buffer
state.buff = utf8Str2ArrayBuffer(state.buff, true);
return SparkMD5.prototype.setState.call(this, state);
};
SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
/**
* Performs the md5 hash on an array buffer.
*
* @param {ArrayBuffer} arr The array buffer
* @param {Boolean} [raw] True to get the raw string, false to get the hex one
*
* @return {String} The result
*/
SparkMD5.ArrayBuffer.hash = function (arr, raw) {
var hash = md51_array(new Uint8Array(arr)),
ret = hex(hash);
return raw ? hexToBinaryString(ret) : ret;
};
return SparkMD5;
}));

858
src/common/tool.js Normal file
View File

@ -0,0 +1,858 @@
// 判断类型集合
export const checkStr = (str, type) => {
switch (type) {
case 'phone': //手机号码
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
case 'tel': //座机
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'card': //身份证
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
case 'pwd': //密码以字母开头长度在6~18之间只能包含字母、数字和下划线
return /^[a-zA-Z]\w{5,17}$/.test(str)
case 'postal': //邮政编码
return /[1-9]\d{5}(?!\d)/.test(str);
case 'QQ': //QQ号
return /^[1-9][0-9]{4,9}$/.test(str);
case 'email': //邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': //金额(小数点2位)
return /^\d*(?:\.\d{0,2})?$/.test(str);
case 'URL': //网址
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str)
case 'IP': //IP
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
case 'date': //日期时间
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/
.test(str)
case 'number': //数字
return /^[0-9]$/.test(str);
case 'english': //英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': //中文
return /^[\\u4E00-\\u9FA5]+$/.test(str);
case 'lower': //小写
return /^[a-z]+$/.test(str);
case 'upper': //大写
return /^[A-Z]+$/.test(str);
case 'HTML': //HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
return true;
}
}
// 格式化时间-小于10补0
function formatDigit(n) {
return n.toString().replace(/^(\d)$/, '0$1');
}
// 格式化时间,通用
export const formatDate = (timestamp, formats) => {
/* formats:
1. Y-M-D
2. Y-M-D h:m:s
3. Y年M月D日
4. Y年M月D日 h时m分
5. Y年M月D日 h时m分s秒
示例console.log(formatDate(1500305226034, 'Y年M月D日 h:m:s')) ==> 2017年07月17日 23:27:06
*/
formats = formats || 'Y-M-D';
var myDate = undefined;
if (timestamp) {
if (typeof(timestamp) != 'string') {
myDate = timestamp;
} else {
myDate = new Date(timestamp);
}
} else {
myDate = new Date();
}
var year = myDate.getFullYear();
var month = formatDigit(myDate.getMonth() + 1);
var day = formatDigit(myDate.getDate());
var hour = formatDigit(myDate.getHours());
var minute = formatDigit(myDate.getMinutes());
var second = formatDigit(myDate.getSeconds());
return formats.replace(/Y|M|D|h|m|s/g, (matches) => {
return {
Y: year,
M: month,
D: day,
h: hour,
m: minute,
s: second
} [matches];
});
}
// 验证邮箱
export const isEmail = (s) => {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
}
// 验证手机号码
export const isMobile = (s) => {
return /^1[0-9]{10}$/.test(s)
}
// 验证电话号码
export const isPhone = (s) => {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
}
// 验证是否url地址
export const isURL = (s) => {
return /^http[s]?:\/\/.*/.test(s)
}
// 验证是否字符串
export const isString = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'String'
}
// 验证是否是否数字
export const isNumber = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Number'
}
// 验证是否是Boolean
export const isBoolean = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
}
// 验证是否是函数
export const isFunction = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Function'
}
//是否为null
export const isNull = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
}
//是否undefined
export const isUndefined = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
}
//是否对象
export const isObj = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Object'
}
//是否数组
export const isArray = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Array'
}
// 是否时间对象
export const isDate = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Date'
}
//是否正则
export const isRegExp = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
}
// 是否错误对象
export const isError = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Error'
}
//是否Symbol函数
export const isSymbol = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
}
// 是否Promise对象
export const isPromise = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
}
// 是否Set对象
export const isSet = (o) => {
return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
}
//判断数据是不是引用类型的数据
export function isObject(value) {
let type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
// 字符串超出多少字显示省略号
export function strOut(str, len=0,type) {
type=type||'star';
var restr = '';
if (str) {
if (str.length >= len) {
restr = str.substring(0, len) + (type=='star'?'***':'...');
} else {
restr = str;
}
}
return restr;
}
//浮点数加法运算--解决精度丢失传入Number返回Number
export function FloatAdd(arg1, arg2) {
var r1, r2, m;
try {
r1 = arg1.toString().split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split('.')[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return (arg1 * m + arg2 * m) / m;
}
//浮点数乘法运算--解决精度丢失传入Number返回Number
export function FloatMul(arg1, arg2) {
var m = 0,
s1 = arg1.toString(),
s2 = arg2.toString();
try {
m += s1.split('.')[1].length;
} catch (e) {}
try {
m += s2.split('.')[1].length;
} catch (e) {}
return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m);
}
//随机数时间戳 (返回数字符串)
export function uniqueId() {
var a = Math.random,
b = parseInt;
return Number(new Date()).toString() + b(10 * a()) + b(10 * a()) + b(10 * a());
}
// 数组随机洗牌算法
export const shuffle = (arr) => {
var result = [],
random;
while (arr.length > 0) {
random = Math.floor(Math.random() * arr.length);
result.push(arr[random])
arr.splice(random, 1)
}
return result;
}
// 严格的身份证号码校验
export const isCardID = (sId) => {
if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(sId)) {
console.log('你输入的身份证长度或格式错误')
return false
}
//身份证城市
var aCity = {
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: "国外"
};
if (!aCity[parseInt(sId.substr(0, 2))]) {
console.log('你的身份证地区非法')
return false
}
// 出生日期验证
var sBirthday = (sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2))).replace(/-/g,
"/"),
d = new Date(sBirthday)
if (sBirthday != (d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate())) {
console.log('身份证上的出生日期非法')
return false
}
// 身份证号码校验
var sum = 0,
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
codes = "10X98765432"
for (var i = 0; i < sId.length - 1; i++) {
sum += sId[i] * weights[i];
}
var last = codes[sum % 11]; //计算出来的最后一位身份证号码
if (sId[sId.length - 1] != last) {
console.log('你输入的身份证号非法')
return false
}
return true
}
// 随机整数范围
export const random = (min, max) => {
if (arguments.length === 2) {
return Math.floor(min + Math.random() * ((max + 1) - min))
} else {
return null;
}
}
// 将阿拉伯数字翻译成中文的大写数字
export const numberToChinese = (num) => {
var AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
var BB = new Array("", "十", "百", "仟", "萬", "億", "点", "");
var a = ("" + num).replace(/(^0*)/g, "").split("."),
k = 0,
re = "";
for (var i = a[0].length - 1; i >= 0; i--) {
switch (k) {
case 0:
re = BB[7] + re;
break;
case 4:
if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
.test(a[0]))
re = BB[4] + re;
break;
case 8:
re = BB[5] + re;
BB[7] = BB[5];
k = 0;
break;
}
if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
re = AA[0] + re;
if (a[0].charAt(i) != 0)
re = AA[a[0].charAt(i)] + BB[k % 4] + re;
k++;
}
if (a.length > 1) // 加上小数部分(如果有小数部分)
{
re += BB[6];
for (var i = 0; i < a[1].length; i++)
re += AA[a[1].charAt(i)];
}
if (re == '一十')
re = "十";
if (re.match(/^一/) && re.length == 3)
re = re.replace("一", "");
return re;
}
// 将数字转换为大写金额
export const changeToChinese = (Num) => {
//判断如果传递进来的不是字符的话转换为字符
if (typeof Num == "number") {
Num = new String(Num);
};
Num = Num.replace(/,/g, "") //替换tomoney()中的“,”
Num = Num.replace(/ /g, "") //替换tomoney()中的空格
Num = Num.replace(/¥/g, "") //替换掉可能出现的¥字符
if (isNaN(Num)) { //验证输入的字符是否为数字
//alert("请检查小写金额是否正确");
return "";
};
//字符处理完毕后开始转换,采用前后两部分分别转换
var part = String(Num).split(".");
var newchar = "";
//小数点前进行转化
for (var i = part[0].length - 1; i >= 0; i--) {
if (part[0].length > 10) {
return "";
//若数量超过拾亿单位,提示
}
var tmpnewchar = ""
var perchar = part[0].charAt(i);
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
switch (part[0].length - i - 1) {
case 0:
tmpnewchar = tmpnewchar + "元";
break;
case 1:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 2:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 3:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 4:
tmpnewchar = tmpnewchar + "万";
break;
case 5:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 6:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 7:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 8:
tmpnewchar = tmpnewchar + "亿";
break;
case 9:
tmpnewchar = tmpnewchar + "拾";
break;
}
var newchar = tmpnewchar + newchar;
}
//小数点之后进行转化
if (Num.indexOf(".") != -1) {
if (part[1].length > 2) {
// alert("小数点之后只能保留两位,系统将自动截断");
part[1] = part[1].substr(0, 2)
}
for (i = 0; i < part[1].length; i++) {
tmpnewchar = ""
perchar = part[1].charAt(i)
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
if (i == 0) tmpnewchar = tmpnewchar + "角";
if (i == 1) tmpnewchar = tmpnewchar + "分";
newchar = newchar + tmpnewchar;
}
}
//替换所有无用汉字
while (newchar.search("零零") != -1)
newchar = newchar.replace("零零", "零");
newchar = newchar.replace("零亿", "亿");
newchar = newchar.replace("亿万", "亿");
newchar = newchar.replace("零万", "万");
newchar = newchar.replace("零元", "元");
newchar = newchar.replace("零角", "");
newchar = newchar.replace("零分", "");
if (newchar.charAt(newchar.length - 1) == "元") {
newchar = newchar + "整"
}
return newchar;
}
// 判断一个元素是否在数组中
export const arrContains = (arr, val) => {
return arr.indexOf(val) != -1 ? true : false;
}
// 数组去重
export const unique = (arr) => {
if (Array.hasOwnProperty('from')) {
return Array.from(new Set(arr));
} else {
var n = {},
r = [];
for (var i = 0; i < arr.length; i++) {
if (!n[arr[i]]) {
n[arr[i]] = true;
r.push(arr[i]);
}
}
return r;
}
}
// 数组删除其中一个元素
export const arrRemove = (arr, ele) => {
var index = arr.indexOf(ele);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
// 求数组中的最大值
export const arrMax = (arr) => {
return Math.max.apply(null, arr);
}
// 求数组中的最小值
export const arrMin = (arr) => {
return Math.min.apply(null, arr);
}
// 数组中的值求和
export const arrSum = (arr) => {
return arr.reduce((pre, cur) => {
return pre + cur
})
}
// 去除空格,type: 1-所有空格 2-前后空格 3-前空格 4-后空格
export const strTrim = (str, type) => {
type = type || 2
switch (type) {
case 1:
return str.replace(/\s+/g, "");
case 2:
return str.replace(/(^\s*)|(\s*$)/g, "");
case 3:
return str.replace(/(^\s*)/g, "");
case 4:
return str.replace(/(\s*$)/g, "");
default:
return str;
}
}
// 字符转换type: 1:首字母大写 2首字母小写 3大小写转换 4全部大写 5全部小写
export const changeCase = (str, type) => {
type = type || 4
switch (type) {
case 1:
return str.replace(/\b\w+\b/g, (word) => {
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
});
case 2:
return str.replace(/\b\w+\b/g, (word) => {
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
});
case 3:
return str.split('').map((word) => {
if (/[a-z]/.test(word)) {
return word.toUpperCase();
} else {
return word.toLowerCase()
}
}).join('')
case 4:
return str.toUpperCase();
case 5:
return str.toLowerCase();
default:
return str;
}
}
// 检测密码强度 等级1-5
export const checkPwd = (str) => {
var Lv = 1;
if (str.length < 6) {
return Lv
}
if (/[0-9]/.test(str)) {
Lv++
}
if (/[a-z]/.test(str)) {
Lv++
}
if (/[A-Z]/.test(str)) {
Lv++
}
if (/[\.|-|_]/.test(str)) {
Lv++
}
return Lv;
}
// 在字符串中插入新字符串
export const insertStr = (soure, index, newStr) => {
var str = soure.slice(0, index) + newStr + soure.slice(index);
return str;
}
// 16进制颜色值转RGBA字符串
export const colorToRGB = (val, opa) => {
var pattern = /^(#?)[a-fA-F0-9]{6}$/; //16进制颜色值校验规则
var isOpa = typeof opa == 'number'; //判断是否有设置不透明度
if (!pattern.test(val)) { //如果值不符合规则返回空字符
return '';
}
var v = val.replace(/#/, ''); //如果有#号先去除#号
var rgbArr = [];
var rgbStr = '';
for (var i = 0; i < 3; i++) {
var item = v.substring(i * 2, i * 2 + 2);
var num = parseInt(item, 16);
rgbArr.push(num);
}
rgbStr = rgbArr.join();
rgbStr = 'rgb' + (isOpa ? 'a' : '') + '(' + rgbStr + (isOpa ? ',' + opa : '') + ')';
return rgbStr;
}
export const dateFormat = (fmt, date) => {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
//uni-app request请求封装
//使用方法 供新手参考 :
// 在vue文件中 import { uniAjax } from '@/js_sdk/common.js'
//uniAjax("api/userInfo",{name:"admin"},"POST",(res)=>{
//成功回调函数
// },(err)=>{
//失败回调函数
// },(data)=>{
//完成回调函数
// })
export const uniAjax = (url, dataPost, type, successCallBack, errorCallBack, completeCallBack) => {
let obj = {};
obj.url = url || "";
obj.data = dataPost || {};
obj.methods = type || "POST";
obj.success = successCallBack || function(data) {};
obj.error = errorCallBack || function(data) {};
obj.complete = completeCallBack || function(data) {};
uni.request({
url: obj.url,
data: obj.data,
method: obj.methods,
header: "",
dataType: "json",
success: obj.success,
fail: obj.error,
complete: obj.complete
});
}
// 数据深拷贝
//使用方法 供新手参考 :
// 在vue文件中 import { cloneObj } from '@/js_sdk/common.js'
// let dataList = cloneObj(data)
export const cloneObj = (obj) => {
let newobj = obj.constructor === Array ? [] : {};
if (typeof obj !== 'object') {
return;
}
for (let i in obj) {
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
}
return newobj
};
// 常用正则判断
//使用方法 供新手参考 :
// 在vue文件中 import { regExpObj } from '@/js_sdk/common.js'
// let valueReg = regExpObj.regExpZh(value)
export const regExpObj = {
//匹配有没有中文
regExpZh: (str) => {
return RegExp(/[\u4e00-\u9fa5]+/).test(str)
},
//只允许中文
onlyregExpZh: (str) => {
return RegExp(/^[\u4e00-\u9fa5]+$/).test(str)
},
//只允许中文,英文字母,数字
regExpZhEnNum: (str) => {
return RegExp(/^[\u4e00-\u9fa5A-Za-z0-9]+$/).test(str)
},
//匹配身份证
regExpIDCard: (str) => {
return RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(str);
},
//匹配手机号
regExpPhone: (str) => {
return RegExp(/^1[3456789]\d{9}$/).test(str);
},
//匹配邮箱格式
regExpEmail: (str) => {
return RegExp(/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/).test(str);
},
//匹配域名
regExpRealmName: (str) => {
return RegExp(/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\/.?/).test(str)
},
//匹配InternetURL
regExpInternetURL: (str) => {
return RegExp(/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/).test(str)
},
//匹配密码(密码(以字母开头长度在6~18之间只能包含字母、数字和下划线)
regExpPwd: (str) => {
return RegExp(/^[a-zA-Z]\w{5,17}$/).test(str)
},
//日期格式 2019-01-12
regExpDate: (str) => {
return RegExp(/^\d{4}-\d{1,2}-\d{1,2}/).test(str)
},
//匹配空白行
regExpWhiteLine: (str) => {
return RegExp(/\n\s*\r/).test(str)
},
//匹配正数、负数、和小数
regExpNumberFloat: (str) => {
return RegExp(/^(\-|\+)?\d+(\.\d+)?$/).test(str)
},
//匹配零和非零开头的数字
regExpZeroNumber: (str) => {
return RegExp(/^(0|[1-9][0-9]*)$/).test(str)
},
//匹配数字
regExpNumber: (str) => {
return RegExp(/^[0-9]*$/).test(str)
},
//长度为8-20的所有字符
regExpAllByte: (str) => {
return RegExp(/^.{8,20}$/).test(str)
}
}
//判断枚举对象取值
// 在vue文件中 import { enumeration } from '@/js_sdk/common.js'
// let valueStatus = enumeration(enumObj,0);
export const enumeration = (enumObj, index) => {
//enumObj ====> 枚举对象 例如:{0:"不通过",1:"通过",2:"待审批"};
//index ====> 查询属性值或属性名
for (let i in enumObj) {
if (i == index) {
return enumObj[i];
} else if (enumObj[i] == index) {
return i;
}
}
}
//本地缓存
export const dataStroage = {
//设置离线缓存
setStroage: (key, data) => {
uni.setStorageSync(key, data);
},
//获取离线缓存
getStroage: (key) => {
let data = uni.getStorageSync(key);
return data;
},
//移除某个离线缓存
removeStroage: (key) => {
uni.removeStorageSync(key);
},
//移除所有离线缓存
closeAllStroage: () => {
uni.clearStorageSync();
}
}
// 原生Js获取URL传递的参数
export const getUrlParam = (name) => {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
let r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
//大于固定字符串显示省略号
export const handleStr = (str,length) => {
let handle_str;
str.length <= length ? handle_str = str : handle_str = str.slice(0, length) + "...";
return handle_str
}
/*
endtime 结束时间
nowtime 开始时间 默认值时当前时间
*/
export const countDown = (endtime,nowtime) => {
let day = 0,
hour = 0,
minute = 0,
second = 0, //时间默认值
newtime = nowtime || new Date().valueOf()/1000,
times = endtime - newtime;
if (times > 0) {
day = Math.floor(times / (60 * 60 * 24));
hour = Math.floor(times / (60 * 60)) - (day * 24);
minute = Math.floor(times / 60) - (day * 24 * 60) - (hour * 60);
second = Math.floor(times) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60);
}
day <= 9 ? day = '0' + day : null;
hour <= 9 ? hour = '0' + hour : null;
minute <= 9 ? minute = '0' + minute : null;
second <= 9 ? second = '0' + second : null;
return {day,hour,minute,second}
}
/* 判断数据类型 */
export const isDataType = {
isArray:(obj) => {
return (typeof obj == 'object') && obj.constructor == Array;
},
isObject:(obj) => {
return Object.prototype.toString.call(obj) === "[object Object]";
},
isEmptyObject:(obj) => {
let t;
for (t in obj) return !1;
return !0
}
}

1459
src/common/uni.css Normal file

File diff suppressed because it is too large Load Diff

378
src/common/util.js Normal file
View File

@ -0,0 +1,378 @@
/**
* 通用公共js库主要定义api接口auth apikey 常量值和通用函数
*/
import store from '@/store/index.js';
// var apiurl = 'http://192.168.1.66:50002/hcscm/pda/v1/'; //开发环境 添
// var apiurl = 'http://192.168.1.55:50002/hcscm/pda/v1/'; //开发环境 添
//var apiurl ='http://192.168.1.127:50003/hcscm/pda/v1/'; //开发环境 添
// var apiurl = 'https://hcscmpre.zzfzyc.com/hcscm/pda/v1/'; //预发布环境
// var apiurl = 'https://hcscmtest.zzfzyc.com/hcscm/pda/v1/'; //测试环境
//var apiurl = 'https://hcscmtest.zzfzyc.com/hcscm/'; //ERP测试环境
export const getApiUrl = () => store.state.apiurl
export function updateApiUrl(newUrl) {
store.dispatch('updateApiUrl', newUrl);
}
// 添加统一请求方法
export function request(options) {
const token = uni.getStorageSync('RemoteTokenData')?.token;
const apiurl = getApiUrl()
return uni.request({
url: apiurl + options.url,
method: options.method || 'GET',
data: options.data,
header: {
'Platform': 2,
'Authorization': token,
...(options.header || {})
},
success: options.success,
fail: options.fail,
complete: options.complete
});
}
// 设置标识 app wx
var shebei = '';
//#ifdef APP-PLUS
shebei = 'app';
//#endif
//#ifdef MP-WEIXIN
shebei = 'wx';
//#endif
const S4 = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
export function guid() {
return (S4() + S4() +'-' +S4() +'-' +S4() +'-' +S4() +'-' +S4() +S4() +S4()
);
}
// store 解析字符串或对象
export function parGetData(v) {
if (v.indexOf('obj-') === 0) {
v = v.slice(4);
return JSON.parse(v);
} else {
if (v.indexOf('str-') === 0) {
return v.slice(4);
}
}
}
// localstore 存储字符串或对象
export function parSetData(v) {
if (typeof v == 'object') {
v = JSON.stringify(v);
v = 'obj-' + v;
} else {
v = 'str-' + v;
}
return v;
}
function getPrefixNumber(maybeNumStr) {
const numReg = /^[0-9]*[!0-9]*/;
if (numReg.test(maybeNumStr)) {
return maybeNumStr.match(numReg)[0];
}
}
export function parFabricGoodsBarCode2D(aSourceBarCode) {
let aOjbectBarCode = aSourceBarCode.toString();
console.log(aOjbectBarCode);
var aCrockNo = '';
var aGoodsBillNo = '';
var aFabricGoodsNo = '';
var aGoodsCodeNo = '';
var aGoodsCodeName = '';
var aQty = '';
var aBarCodeDig = '';
console.log("****************");
if (aOjbectBarCode.indexOf('|') > 0) {
console.log("aOjbectBarCode--&8888888888->");
var aBarCodeList = aOjbectBarCode.split('|');
aCrockNo = aBarCodeList[3];
aGoodsBillNo = aBarCodeList[5];
aFabricGoodsNo = aBarCodeList[1];
aGoodsCodeNo = aBarCodeList[2];
aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
if (aGoodsCodeNo.length == 1) {
aGoodsCodeNo = '00' + aGoodsCodeNo;
} else if (aGoodsCodeNo.length == 2) {
aGoodsCodeNo = '0' + aGoodsCodeNo;
};
aQty = aBarCodeList[6];
aBarCodeDig = aBarCodeList[0];
} else if (aOjbectBarCode.indexOf('$') > 0) {
console.log("aOjbectBarCode--&6555555->");
aOjbectBarCode = aOjbectBarCode.replace('¥', '$');
aOjbectBarCode = aOjbectBarCode.replace('', '#');
aOjbectBarCode = aOjbectBarCode.replace('##', '#');
aOjbectBarCode = aOjbectBarCode.replace('^', '$');
var aBarCodeList = aOjbectBarCode.split('$');
console.log("aBarCodeList.length---->" + aBarCodeList.length);
if (aBarCodeList.length <= 5) {
aCrockNo = aBarCodeList[0];
aGoodsBillNo = aBarCodeList[1];
aFabricGoodsNo = aBarCodeList[2];
aGoodsCodeNo = aBarCodeList[3];
console.log("aGoodsCodeNo---->" + aGoodsCodeNo);
//aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
if (aGoodsCodeNo == '') {
aGoodsCodeNo = aBarCodeList[3];
}
aGoodsCodeName = "";
aQty = aBarCodeList[4];
aBarCodeDig = aBarCodeList[1];
} else {
aCrockNo = aBarCodeList[0];
aGoodsBillNo = aBarCodeList[1];
aFabricGoodsNo = aBarCodeList[2];
aGoodsCodeNo = aBarCodeList[4];
console.log("aGoodsCodeNo1111---->" + aGoodsCodeNo);
//aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
console.log("aGoodsCodeNo222---->" + aGoodsCodeNo);
if (aGoodsCodeNo == '') {
aGoodsCodeNo = aBarCodeList[4];
}
console.log("aGoodsCodeNo33333333333---->" + aGoodsCodeNo);
aGoodsCodeName = aBarCodeList[5];
aQty = aBarCodeList[6];
aBarCodeDig = aBarCodeList[7];
}
} else if (aOjbectBarCode.indexOf('^') > 0) {
var aBarCodeList = aOjbectBarCode.split('^');
console.log(">>>aBarCodeList.length>>>>" + aBarCodeList.length.toString());
if (aBarCodeList.length > 7) {
if (aBarCodeList[0] == '99' || aBarCodeList[0] == '96') {
aCrockNo = aBarCodeList[3];
aGoodsBillNo = aBarCodeList[4];
aFabricGoodsNo = aBarCodeList[5];
aGoodsCodeNo = aBarCodeList[6];
aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
aGoodsCodeName = aBarCodeList[6];
aQty = aBarCodeList[7];
aBarCodeDig = aBarCodeList[4];
} else {
aCrockNo = aBarCodeList[1];
aGoodsBillNo = aBarCodeList[3];
aFabricGoodsNo = aBarCodeList[5].replace("ZH", "");
aGoodsCodeNo = aBarCodeList[7];
aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
aGoodsCodeName = aBarCodeList[7];
aQty = aBarCodeList[8];
aBarCodeDig = aBarCodeList[4];
}
} else {
aCrockNo = aBarCodeList[0];
aGoodsBillNo = aBarCodeList[1];
aFabricGoodsNo = aBarCodeList[2];
aGoodsCodeNo = aBarCodeList[4];
aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
aGoodsCodeName = aBarCodeList[5];
aQty = aBarCodeList[6];
aBarCodeDig = aBarCodeList[7];
}
} else if (aOjbectBarCode.indexOf('^') == 0) {
var aBarCodeList = aOjbectBarCode.split('^');
aCrockNo = aBarCodeList[1];
aGoodsBillNo = aBarCodeList[2];
aFabricGoodsNo = aBarCodeList[3];
aGoodsCodeNo = '';
//aGoodsCodeNo = getPrefixNumber(aGoodsCodeNo);
//aGoodsCodeName = aBarCodeList[5];
aQty = aBarCodeList[5];
console.log(">>>>>>>>" + aCrockNo + ">>>" + aGoodsBillNo.toString() + ">>>>" + aQty.toString());
aBarCodeDig = 0;
} else if (aOjbectBarCode.indexOf('http') > 0) {
console.log("aOjbectBarCode--&&&->");
return '';
} else {
aCrockNo = '';
aGoodsBillNo = '';
aFabricGoodsNo = '';
aGoodsCodeNo = '';
aGoodsCodeNo = '';
aGoodsCodeName = '';
aQty = 0;
aBarCodeDig = aSourceBarCode;
console.log("aOjbectBarCode--&66666->"+aBarCodeDig) ;
//return '';
}
/*
if (aGoodsCodeNo.length == 1) {
aGoodsCodeNo = '00' + aGoodsCodeNo;
} else if (aGoodsCodeNo.length == 2) {
aGoodsCodeNo = '0' + aGoodsCodeNo;
};
*/
return aCrockNo + ',' + aGoodsBillNo + ',' + aBarCodeDig + ',' + aFabricGoodsNo + ',' + aGoodsCodeNo + ',' + aQty;
}
export function GetGoodsQRBarCode(aSourceQRBarCode) {
let aQRBarCode = aSourceQRBarCode.toString().trimRight().trimLeft();
aQRBarCode = aQRBarCode.replace('¥', '$');
aQRBarCode = aQRBarCode.replace('', '#');
aQRBarCode = aQRBarCode.replace('##', '#');
aQRBarCode = aQRBarCode.replace('^', '$');
if (aQRBarCode.indexOf('$') > 0)
{
var aQRBarCodeList = aQRBarCode.split('$');
var aCrockNo = aQRBarCodeList[0];
var aGoodsBillNo = aQRBarCodeList[1];
var aFabricGoodsNo = aQRBarCodeList[2];
var aSaleOrderNo = aQRBarCodeList[3];
var aFabricGoodsName = '';
var aGoodsCodeNo = aQRBarCodeList[4].split('#')[0];
var aGoodsCodeName = aQRBarCodeList[4].split('#')[1];
var aQty = aQRBarCodeList[5];
var aBarCodeDig= '';
return aCrockNo + '^' + aGoodsBillNo + '^' + aBarCodeDig + '^'
+ aFabricGoodsNo + '^' + aFabricGoodsName + '^' + aGoodsCodeNo
+ '^' + aGoodsCodeName +'^' + aSaleOrderNo +'^'+ aQty+'^';
} else if (aQRBarCode.indexOf('http') > 0) {
return '';
} else {
return '';
}
}
export function parYarnGoodsBarCode2D(aSourceBarCode) {
aSourceBarCode = aSourceBarCode.replace('\n','');
aSourceBarCode = aSourceBarCode.replace('\t','');
aSourceBarCode = aSourceBarCode.replace('\s','');
aSourceBarCode = aSourceBarCode.replace('\r','');
let aOjbectBarCode = aSourceBarCode.toString();
var aDyeWorksDigCode = '';
var aCustomerPO = '';
var aYarnGoodsCodeNo = '';
var aYarnGoodsColorNo = '';
var aYarnDyeOrderDate = '';
var aYarnCrockNo = '';
var aYarnBoxBillNo = '';
var aYarnBoxRoll = '';
var aYarnGrossQty = 0;
var aYarnNetQty = 0;
if (aOjbectBarCode.indexOf('^') >= 0) {
var aBarCodeList = aOjbectBarCode.split('^');
aDyeWorksDigCode = aBarCodeList[1];
aCustomerPO = aBarCodeList[2];
aYarnGoodsCodeNo = aBarCodeList[3];
aYarnGoodsColorNo = aBarCodeList[4];
aYarnDyeOrderDate = aBarCodeList[5];
aYarnCrockNo = aBarCodeList[6];
aYarnBoxBillNo = aBarCodeList[7];
aYarnBoxRoll = aBarCodeList[8];
aYarnGrossQty = aBarCodeList[9];
aYarnNetQty = aBarCodeList[10];
} else if (aOjbectBarCode.indexOf('http') > 0) {
console.log("aOjbectBarCode-CCCC-&&&->");
return '';
} else {
aDyeWorksDigCode = '';
aCustomerPO = '';
aYarnGoodsCodeNo = '';
aYarnGoodsColorNo = '';
aYarnDyeOrderDate = '';
aYarnCrockNo = '';
aYarnBoxBillNo = '';
aYarnBoxRoll = '';
aYarnGrossQty = '';
aYarnNetQty = '';
//return '';
}
return aDyeWorksDigCode + ',' + aCustomerPO + ',' + aYarnGoodsCodeNo + ','
+ aYarnGoodsColorNo + ',' + aYarnDyeOrderDate + ',' + aYarnCrockNo + ','
+ aYarnBoxBillNo + ',' + aYarnBoxRoll + ',' + aYarnGrossQty + ',' + aYarnNetQty;
}
// 将对象中项目存到数组arr中
function concat(arr, obj) {
Object.keys(obj).forEach(function(key) {
arr.push(obj[key])
});
return arr;
}
// 新建一个audio实例
function createAudio(src) {
//console.log("createInnerAudioContext");
let innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
innerAudioContext.src = src;
innerAudioContext.onPlay(() => {
console.log("开始播放");
});
innerAudioContext.onEnded(() => {
//console.log('i am onEnded')
//播放结束,销毁该实例
//innerAudioContext.destroy();
console.log('已执行destory()')
});
innerAudioContext.onError(res => {
//console.log(res.errMsg);
//console.log(res.errCode);
innerAudioContext.stop();
});
return innerAudioContext;
}
let successAudio = undefined;
let errorAudio = undefined;
function playSuccessAudio() {
if (!successAudio) {
//console.log("create success");
successAudio = createAudio('/static/audio/appright.wav');
successAudio.onError(res => {
console.log(res.errMsg);
console.log(res.errCode);
console.log(res);
successAudio.destroy();
successAudio = undefined; //createAudio('/static/audio/appright.wav');
});
}
successAudio.stop();
successAudio.play();
}
function playErrorAudio() {
if (!errorAudio) {
//console.log("create error");
errorAudio = createAudio('/static/audio/apperror.wav');
errorAudio.onError(res => {
console.log(res.errMsg);
console.log(res.errCode);
console.log(res);
errorAudio.destroy();
errorAudio = undefined; //createAudio('/static/audio/apperror.wav');
})
}
console.log("create error");
errorAudio.stop();
errorAudio.play();
}
export default {
get apiurl() {
return getApiUrl()
},
request,
shebei,
updateApiUrl,
parSetData,
parGetData,
playSuccessAudio,
playErrorAudio,
};

6
src/common/vue-i18n.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,50 @@
<template>
<view>
<view @click="gotoAdd" class="addBtn">
<u-icon name="plus" color="#ffffff" size="40"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
url: {
type: String
}
},
data() {
return {
};
},
methods: {
gotoAdd: function() {
if(this.url) {
uni.navigateTo({
url: this.url
})
}
}
}
}
</script>
<style>
.addBtn {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background-image: linear-gradient(45deg, #007aff, #00aaff);
display: flex;
align-items: center;
justify-content: center;
position: fixed;
bottom: 200rpx;
right: 26rpx;
z-index: 100;
}
.addBtn:active {
background-image: linear-gradient(45deg, #00aaff, #007aff);
}
</style>

View File

@ -0,0 +1,89 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">排产单号{{item.ProductWeaveNo}} {{item.WeaveFactoryName}}</view>
<view class="cardRow">
<view>排产日期</view>
<view>{{item.ProductWeaveDate}}</view>
</view>
<view class="cardRow">
<view>营销部门</view>
<view>{{item.PlanDepartmentName}}</view>
</view>
<view class="cardRow">
<view>客户名称</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.SaleUserName}}</view>
</view>
<view class="cardRow">
<text class="fzrLeft">单据状态</text>
<text class="fzrRight">{{item.BillStatusName}} {{item.BillStatusTime}}</text>
</view>
<view class="cardRow">
<view>物流公司</view>
<view>{{item.ShipCompanyName}}</view>
</view>
<view class="cardRow">
<view>发货地址</view>
<view>{{item.SaleCustomerAddress}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,148 @@
<template>
<view>
<view class="card">
<view class="topRow1" @click="">
<view class="name">
<text class="mr26"> {{item.BillTypeName}}</text>
</view>
<view>
<text class="colorGray">单据仓库</text>
<text>{{item.BillClassName}}</text>
</view>
<view>
<text class="colorGray">单据类型</text>
<text>{{item.BillBusinessTypeName}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
isSelect: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
data() {
return {
moreShow: false,
allotShow: false,
}
},
methods: {
}
}
</script>
<style>
.card {
width: 698rpx;
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.genjinBtn {
position: absolute;
right: 26rpx;
top: 26rpx;
background-color: #007AFF;
color: #FFFFFF;
text-align: center;
padding: 6rpx 16rpx;
border-radius: 6rpx;
font-size: 14px;
}
.genjinBtn:active {
background-color: #13B8FF;
}
.topRow1 {
margin-bottom: 16rpx;
font-size: 15px;
color: #000;
position: relative;
}
.name {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
}
.bottomRow {
width: 100%;
padding-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
font-size: 15px;
color: #007AFF;
}
.lxRow {
display: flex;
align-items: center;
}
.lxRow>image {
width: 52rpx;
height: 52rpx;
margin-right: 26rpx;
}
.bqRow {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.bqRow>text {
font-size: 14px;
color: #888888;
}
.bqRow>view {
padding: 6rpx 16rpx;
font-size: 14px;
background-color: rgba(255, 85, 127, 0.1);
color: #ff5500;
border-radius: 10rpx;
margin: 6rpx 26rpx 20rpx 0;
}
.khJieDuan {
position: absolute;
right: 0;
top: 50rpx;
font-weight: bold;
}
.khType {
position: absolute;
right: 0;
top: 72rpx;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<view class="myCard">
<view class="cardTopName">产品名称{{item.pName}}</view>
<view class="cardRow">
<view>产品价格</view>
<view>{{item.price}}/{{item.unit}}</view>
</view>
<view class="flexRow">
<view>
<text>售价</text>
<text>{{item.sellingPrice}}</text>
</view>
<view>
<text>折扣</text>
<text>{{item.discount}}%</text>
</view>
</view>
<view class="cardRow">
<view>产品数量</view>
<view>{{item.num}}</view>
</view>
<view class="cardRow">
<view>价格合计</view>
<view>{{item.totalPrice}}</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
}
},
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.flexRow {
display: flex;
font-size: 32rpx;
color: #ADADAD;
margin-bottom: 8rpx;
}
.flexRow>view {
width: 50%;
display: flex;
}
.flexRow>view>text:last-child {
color: #000000;
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">进仓单号{{item.BillNo}}</view>
<view class="cardRow">
<view>进仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>染整厂名</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,66 @@
<template>
<view class="myCard">
<view class="statesRight">已完成</view>
<view class="cardTopName">发票编号FP20210326-0001</view>
<view class="cardRow">
<view>合同名称</view>
<view>行云办公CRM</view>
</view>
<view class="cardRow">
<view>开票金额</view>
<view>3650000</view>
</view>
<view class="cardRow">
<view>开票日期</view>
<view>2021-07-01</view>
</view>
<view class="fzrAbsolute">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">曹国防</text>
</view>
<view class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
}
},
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.progress {
width: 200rpx !important;
margin-left: 26rpx;
}
.fzr {
position: absolute;
right: 26rpx;
bottom: 74rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<view class="myCard">
<view class="cardTopName">表单名称满意度问卷调查</view>
<!-- <view class="cardRow">
<view>表单描述</view>
<view>软件服务满意度问卷调查表</view>
</view> -->
<view class="cardRow">
<view>表单类型</view>
<view>市场调查</view>
</view>
<view class="flexJb">
<view class="cardRow1">
<view>阅读人数</view>
<view>888</view>
</view>
<view class="cardRow1">
<view>提交人数</view>
<view>666</view>
</view>
</view>
<view class="cardRow">
<view>创建日期</view>
<view>{{$u.timeFormat(item.date, 'yyyy-mm-dd')}}</view>
</view>
<view v-if="!isDetail" class="fzrAbsolute">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">{{item.fuZeRen}}</text>
</view>
<view v-else class="cardRow">
<view>负责人</view>
<view>{{item.fuZeRen}}</view>
</view>
<view v-if="!isDetail" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.progress {
width: 200rpx !important;
margin-left: 26rpx;
}
.fzr {
position: absolute;
right: 26rpx;
bottom: 74rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
.flexJb {
display: flex;
align-items: center;
}
.flexJb>.cardRow1 {
width: 50%;
}
.cardRow1 {
display: flex;
font-size: 16px;
margin-bottom: 4px;
}
.cardRow1>view:first-child {
width: 88px;
color: #ADADAD;
}
.cardRow1>view:last-child {
color: #000000;
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<view class="card" @click="gotoDetailFun">
<view class="khName">客户名称{{item.clientName}}</view>
<view class="lrView">
<view>跟进类型</view>
<view>{{item.type}}</view>
</view>
<view class="lrView" v-if="item.orderType">
<view>单据类型</view>
<view>{{item.orderType}}</view>
<!-- <view v-if="item.states == '有需求跟进'" class="yellowColor">{{item.states}}</view>
<view v-if="item.states == '促单'" class="greenColor">{{item.states}}</view>
<view v-if="item.states == '放弃'" class="redColor">{{item.states}}</view> -->
</view>
<view class="lrView">
<view>跟进内容</view>
<view class="liangHang">{{item.gjContent}}</view>
</view>
<view v-if="item.gjAddr" class="lrView">
<view>跟进地址</view>
<view>{{item.gjAddr}}</view>
</view>
<view v-if="item.next_gjDate" class="lrView">
<view>下次跟进</view>
<view>{{$u.timeFormat(item.next_gjDate, 'yyyy-mm-dd hh:MM:ss')}}</view>
</view>
<view v-if="item.genjin_date" class="lrView">
<view>跟进时间</view>
<view>{{$u.timeFormat(item.genjin_date, 'yyyy-mm-dd hh:MM:ss')}}</view>
</view>
<view class="lrView">
<view>创建人</view>
<view class="liangHang">{{item.cjRenName}}</view>
</view>
<view class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
uni.$gjInfo = this.item;
uni.navigateTo({
url: '/pages/crm/genJin/detail?index=' + this.index
})
}
}
}
</script>
<style>
.card {
width: 686rpx;
margin: 32rpx;
background-color: #FFFFFF;
padding: 16rpx;
border-radius: 26rpx;
box-sizing: border-box;
box-shadow: #dddddd 0px 0px 32rpx;
}
.bottomRow {
display: flex;
justify-content: space-between;
border-top: 1rpx solid #dddddd;
padding-top: 16rpx;
margin-top: 16rpx;
}
.khName {
font-size: 16px;
font-weight: bold;
margin-bottom: 16rpx;
padding-bottom: 10rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.lrView {
display: flex;
font-size: 16px;
}
.lrView>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.lrView>view:last-child {
width: 466rpx;
color: #000000;
}
</style>

View File

@ -0,0 +1,73 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">合同名称{{item.htName}}</view>
<view class="cardRow">
<view>客户名称</view>
<view>{{item.clientName}}</view>
</view>
<view class="cardRow" v-if="item.htCode">
<view>合同编号</view>
<view>{{item.htCode}}</view>
</view>
<view class="cardRow">
<view>合同金额</view>
<view>{{item.htPrice}}</view>
</view>
<view class="cardRow">
<view>签约日期</view>
<view>{{$u.timeFormat(item.qianYueDateTime, 'yyyy-mm-dd')}}</view>
</view>
<view class="fzrAbsolute" v-if="item.fuZeRenId && !isDetail">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">{{item.fuZeRenName}}</text>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$htInfo = this.item;
uni.navigateTo({
url: '/pages/crm/hetong/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,85 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">计划编号{{item.hkjhCode}}</view>
<view class="cardRow">
<view>合同名称</view>
<view>{{item.htName}}</view>
</view>
<view class="cardRow">
<view>回款金额</view>
<view>{{item.hkPrice}}</view>
</view>
<view class="cardRow">
<view>回款日期</view>
<view>{{$u.timeFormat(item.date, 'yyyy-mm-dd')}}</view>
</view>
<view class="fzrAbsolute" v-if="item.fuZeRenId && !isDetail">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">{{item.fuZeRenName}}</text>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$hkjhInfo = this.item;
uni.navigateTo({
url: '/pages/crm/huikuanJH/detail?index=' + this.index
})
}
}
}
</script>
<style>
.progress {
width: 200rpx !important;
margin-left: 26rpx;
}
.fzr {
position: absolute;
right: 26rpx;
bottom: 74rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
</style>

View File

@ -0,0 +1,456 @@
<template>
<view>
<u-action-sheet :list="sheetList" v-model="moreShow" @click="sheetFun"></u-action-sheet>
<u-select v-model="allotShow" mode="single-column" confirm-text="确认分配" cancel-text="取消分配" :list="userList" @confirm="allotConfirmFun" value-name="_id" label-name="nickname"></u-select>
<view class="card">
<view class="topRow1" @click="gotoDetailFun">
<view class="name">
<text class="mr26">{{item.CustomerNo}} {{item.CustomerName}}</text>
</view>
<view>
<text class="colorGray">联系方式</text>
<text>{{item.CustomerLinkName}} {{item.CustomerPhone}}</text>
</view>
<view>
<text class="colorGray">销售群体</text>
<text>{{item.SalesGroupNames}}</text>
<text class="colorGray">销售区域</text>
<text>{{item.SalesAreaNames}}</text>
</view>
<view>
<text class="colorGray">联系地址</text>
<text>{{item.CustomerAddress}}</text>
</view>
<view>
<text class="colorGray">信用额度</text>
<text>{{item.CreditAmount}}</text>
<text class="colorGray">信用级别</text>
<text>{{item.CreditGrade}}</text>
</view>
<view>
<text class="colorGray">结算方式</text>
<text>{{item.PaymentModeName}}</text>
<text class="colorGray">营销部门</text>
<text>{{item.PlanDepartmentName}}</text>
</view>
<view>
<text class="colorGray">销售员</text>
<text>{{item.SaleUserName}}</text>
</view>
<view>
<view>创建人{{item.OpName}} {{item.OpDate}}</view>
</view>
<view>
<view>修改人{{item.CommitName}} {{item.CommitDate}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { crmKeHuApi } from '../../static/utils/api.js'
import { uidUserApi } from '../../static/utils/adminApi.js'
export default {
props: {
item: {
type: Object,
default: () => {}
},
isSelect: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
data() {
return {
sheetList: [{
text: '添加跟进'
},
{
text: '编辑'
},
{
text: '删除'
}
],
moreShow: false,
allotShow: false,
userList: []
}
},
methods: {
moreShowFun: function() {
let status = this.item.status;
if(status == 0) {
if(uni.$userInfo.isDepManager) {
this.sheetList = [
{
text: '领取'
},
{
text: '分配'
},
{
text: '编辑'
},
{
text: '删除'
}
];
} else {
this.sheetList = [
{
text: '领取'
}
];
}
} else {
this.sheetList = [
{
text: '添加跟进'
},
{
text: '放入客户池'
},
{
text: '编辑'
}
// {
// text: ''
// }
];
}
this.moreShow = true;
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$khInfo = this.item;
uni.navigateTo({
url: './khDetail?index=' + this.index
})
},
sheetFun: function(i) {
console.log(i)
let arr = this.sheetList;
let str = arr[i].text;
if(str == '添加跟进') {
uni.navigateTo({
url: '../genJin/add?clientName=' + this.item.clientName + '&clientId=' + this.item._id
})
} else if(str == '编辑') {
uni.$infoObj = this.item;
uni.navigateTo({
url: './addKeHu?type=update'
})
} else if(str == '删除') {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认删除客户名称为:' + that.item.clientName + '的客户吗?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
isDelete: 1,
update_date: new Date().getTime()
}
}
}
crmKeHuApi(reqData)
.then(res => {
uni.showToast({
title: '删除成功!',
duration: 1000,
icon: 'none'
})
uni.$emit('deleteKhFun', {index: that.index})
that.addCzjlFun('删除');
})
}
}
})
} else if(str == '领取') {
this.lingquFun()
} else if(str == '分配') {
if(this.userList.length > 0) {
this.allotShow = true;
} else {
this.getUserLisByDepIdtFun();
}
} else if(str == '放入客户池') {
this.putInFun()
}
},
addCzjlFun: function(type, content) {
let czjlObj = {
create_date: new Date().getTime(),
czRen: uni.$userInfo._id,
pageType: 'client',
dataId: this.item._id,
type
}
if(content && content.length > 0) {
czjlObj.content = content;
}
uni.$czjlApiAddFun(czjlObj);
},
//
lingquFun: function() {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认领取客户名称为:' + that.item.clientName + '的客户吗?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '领取中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 1, //
fuZeRenId: uni.$userInfo._id,
update_date: new Date().getTime()
}
}
}
crmKeHuApi(reqData)
.then(res => {
that.addCzjlFun('领取');
that.$emit('cxGetDataFun');
uni.showToast({
title: '领取成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
//
putInFun: function() {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认将客户名称为:' + that.item.clientName + '的客户放入客户池吗?',
success(res) {
let time = new Date().getTime();
if(res.confirm) {
uni.showLoading({
title: '更新中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 0, //
fuZeRenId: '',
next_gjDate: '',
awaitFollowUp: 0,
recycle_date: time,
update_date: time
}
}
}
crmKeHuApi(reqData)
.then(res => {
that.addCzjlFun('放入客户池');
that.$emit('cxGetDataFun');
uni.showToast({
title: '更新成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
//
allotConfirmFun: function(e) {
console.log(e)
let obj = e[0];
let that = this;
uni.showModal({
title: '提示',
content: '是否确认将客户名称为:' + that.item.clientName + '的客户分配给 - ' + obj.label + ' - 吗?',
success(res) {
let time = new Date().getTime();
if(res.confirm) {
uni.showLoading({
title: '分配中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 1, //
fuZeRenId: obj.value,
update_date: time
}
}
}
crmKeHuApi(reqData)
.then(res => {
let content = [
'修改 ' + ' 负责人为 ' + obj.label
]
that.addCzjlFun('编辑', content);
that.$emit('cxGetDataFun');
uni.showToast({
title: '更新成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
// id
getUserLisByDepIdtFun: function() {
uni.showLoading({
title: '加载中...',
mask: true
})
let reqData = {
action: 'getAllUserListByDepID',
params: {
depId: uni.$userInfo.depManager_Id,
status: 0
}
}
uidUserApi(reqData)
.then(res => {
this.userList = res.result.data;
this.allotShow = true;
})
},
}
}
</script>
<style>
.card {
width: 698rpx;
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.genjinBtn {
position: absolute;
right: 26rpx;
top: 26rpx;
background-color: #007AFF;
color: #FFFFFF;
text-align: center;
padding: 6rpx 16rpx;
border-radius: 6rpx;
font-size: 14px;
}
.genjinBtn:active {
background-color: #13B8FF;
}
.topRow1 {
margin-bottom: 16rpx;
font-size: 15px;
color: #000;
position: relative;
}
.name {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
}
.bottomRow {
width: 100%;
padding-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
font-size: 15px;
color: #007AFF;
}
.lxRow {
display: flex;
align-items: center;
}
.lxRow>image {
width: 52rpx;
height: 52rpx;
margin-right: 26rpx;
}
.bqRow {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.bqRow>text {
font-size: 14px;
color: #888888;
}
.bqRow>view {
padding: 6rpx 16rpx;
font-size: 14px;
background-color: rgba(255, 85, 127, 0.1);
color: #ff5500;
border-radius: 10rpx;
margin: 6rpx 26rpx 20rpx 0;
}
.khJieDuan {
position: absolute;
right: 0;
top: 50rpx;
font-weight: bold;
}
.khType {
position: absolute;
right: 0;
top: 72rpx;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,262 @@
<template>
<view>
<u-action-sheet :list="sheetList" v-model="moreShow" @click="sheetFun"></u-action-sheet>
<view class="card">
<view class="topRow" @click="gotoDetailFun">
<view class="txView">
<image class="txViewImg" src="/static/icon/touxiangnan.png" mode="aspectFill"></image>
</view>
<view class="info">
<view class="name">
<text>{{item.lxr_name}}</text>
<text v-if="item.company_zhiWei">{{item.company_zhiWei}}</text>
</view>
<view>{{item.clientName}}</view>
<!-- <view>来自手动添加 | 最后跟进时间</view> -->
<view v-if="item.genjin_date" class="colorGray">
<text>最后跟进时间</text>
<text>{{$u.timeFrom(item.genjin_date, 'yyyy年mm月dd日')}}</text>
</view>
<view v-else-if="item.update_date" class="colorGray">
<text>最后更新时间</text>
<text>{{$u.timeFrom(item.update_date, 'yyyy年mm月dd日')}}</text>
</view>
<view v-else class="colorGray">
<text>创建时间</text>
<text>{{$u.timeFrom(item.create_date, 'yyyy年mm月dd日')}}</text>
</view>
</view>
</view>
<!--标签-->
<!-- <view class="bqRow" @click="gotoDetailFun">
<view>吸烟</view>
<view>喝酒</view>
<view>烫头</view>
<text>共3个标签</text>
</view> -->
<view v-if="!isSelect" class="bottomRow">
<text v-if="isHideMore" style="color: #333333;">{{item.lxr_phone}}</text>
<view class="lxRow">
<lianxiRow :phone="item.lxr_phone"></lianxiRow>
</view>
<view v-if="!isHideMore" class="lxRow" @click.stop="moreShow = true">
<image src="/static/icon/gengduosz.png" mode="aspectFill"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import { crmLianXiRenApi } from '../../static/utils/api.js'
export default {
props: {
item: {
type: Object,
default: () => {}
},
isSelect: {
type: Boolean,
default: false
},
isHideMore: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
data() {
return {
sheetList: [{
text: '添加跟进'
},
{
text: '编辑'
},
{
text: '删除'
}
],
moreShow: false
}
},
mounted() {
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$lxrInfo = this.item;
uni.navigateTo({
url: '/pages/crm/lianxiren/detail?index=' + this.index
})
},
sheetFun: function(i) {
if(i == 0) {
uni.navigateTo({
url: '../genJin/add?clientName=' + this.item.clientName + '&clientId=' + this.item._id + '&glkhLxr=' + this.item.lxr_name + '&glkhLxrId=' + this.item._id
})
} else if(i == 1) {
uni.$infoObj = this.item;
uni.navigateTo({
url: './addLxr?type=update'
})
} else if(i == 2) {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认删除姓名为:' + that.item.lxr_name + '的联系人吗?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
isDelete: 1,
update_date: new Date().getTime()
}
}
}
crmLianXiRenApi(reqData)
.then(res => {
uni.showToast({
title: '删除成功!',
duration: 1000,
icon: 'none'
})
uni.$emit('deleteCardFun', {index: that.index})
that.addCzjlFun();
})
}
}
})
}
},
addCzjlFun: function() {
let czjlObj = {
create_date: new Date().getTime(),
czRen: uni.$userInfo._id,
pageType: 'contact',
dataId: this.item._id,
type: '删除'
}
uni.$czjlApiAddFun(czjlObj);
}
}
}
</script>
<style>
.card {
width: 698rpx;
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.genjinBtn {
position: absolute;
right: 26rpx;
top: 26rpx;
background-color: #007AFF;
color: #FFFFFF;
text-align: center;
padding: 6rpx 16rpx;
border-radius: 6rpx;
font-size: 14px;
}
.genjinBtn:active {
background-color: #13B8FF;
}
.topRow {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.txView {
width: 128rpx;
height: 128rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 26rpx;
}
.txViewImg {
width: 100%;
height: 100%;
}
.info {
width: 492rpx;
font-size: 15px;
color: #000;
}
.name {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
}
.bottomRow {
width: 100%;
padding-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
font-size: 15px;
color: #007AFF;
}
.lxRow {
display: flex;
align-items: center;
}
.lxRow>image {
width: 52rpx;
height: 52rpx;
margin-right: 26rpx;
}
.bqRow {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.bqRow>text {
font-size: 14px;
color: #888888;
}
.bqRow>view {
padding: 6rpx 16rpx;
font-size: 14px;
background-color: rgba(255, 85, 127, 0.1);
color: #ff5500;
border-radius: 10rpx;
margin: 6rpx 26rpx 20rpx 0;
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">排产单号{{item.ProductWeaveNo}} {{item.WeaveFactoryName}}</view>
<view class="cardRow">
<view>排产日期</view>
<view>{{item.ProductWeaveDate}}</view>
</view>
<view class="cardRow">
<view>商品编码</view>
<view>{{item.FabricEmbryoNo}}-{{item.EmbryoCodeNo}}#</view>
</view>
<view class="cardRow">
<view>商品名称</view>
<view>{{item.FabricEmbryoName}}</view>
</view>
<view class="cardRow">
<view>商品颜色</view>
<view>{{item.EmbryoCodeName}}</view>
</view>
<view class="cardRow">
<text class="fzrLeft">进度状态</text>
<text class="fzrRight">{{item.WeaveCompleteTypeName}}</text>
</view>
<view class="cardRow">
<view>生产情况</view>
<view>{{item.WeaveFactoryWeaveRemark}}</view>
</view>
<view class="cardRow">
<view>排产数量</view>
<text class="fzrRight">{{item.WeaveRoll}} {{item.WeaveQty}}Kg</text>
</view>
<view class="cardRow">
<view>已产数量</view>
<text class="fzrRight">{{item.HasProductRoll}} {{item.HasProductQty}}Kg</text>
</view>
<view class="cardRow">
<view>派纱时间</view>
<view>{{item.WeaveFactorySendYarn}}</view>
</view>
<view class="cardRow">
<view>派纱备注</view>
<view>{{item.WeaveFactorySendRemark}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,168 @@
<template>
<view>
<u-action-sheet :list="sheetList" v-model="moreShow"></u-action-sheet>
<view class="card">
<view class="topRow">
<view class="info">
<view class="cardTopName">客户名称{{item.clientName}}</view>
<view class="cardRow">
<view>客户地址</view>
<view>{{item.address}}</view>
</view>
<view class="cardRow">
<view>跟进人</view>
<view>曹国防</view>
</view>
<view class="cardRow">
<view>最后跟进</view>
<view>2021-03-23 23:01:22</view>
</view>
</view>
</view>
<view class="bottomRow">
<view class="lxRow">
距您{{item.distance}}
</view>
<view class="fujinBtn">
<view class="bottomBtn blueBtn" @click="openLocationFun">
<image src="/static/icon/daohang.png" mode="aspectFill"></image>
<text>导航</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
pageType: ''
},
data() {
return {
sheetList: [{
text: '添加跟进'
},
{
text: '添加标签'
}
],
moreShow: false
}
},
methods: {
//
openLocationFun: function() {
uni.openLocation({
latitude: this.item.latitude,
longitude: this.item.longitude,
address: this.item.address,
name: this.item.clientName,
success: function() {
console.log('success');
}
});
}
}
}
</script>
<style>
.card {
width: 698rpx;
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.genjinBtn {
position: absolute;
right: 26rpx;
top: 26rpx;
background-color: #007AFF;
color: #FFFFFF;
text-align: center;
padding: 6rpx 16rpx;
border-radius: 6rpx;
font-size: 14px;
}
.genjinBtn:active {
background-color: #13B8FF;
}
.topRow {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.txView {
width: 128rpx;
height: 128rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 26rpx;
}
.txViewImg {
width: 100%;
height: 100%;
}
.info {
width: 100%;
font-size: 15px;
color: #000;
}
.bottomRow {
width: 100%;
padding-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
font-size: 15px;
}
.fujinBtn {
display: flex;
align-items: center;
}
.bottomBtn {
display: flex;
align-items: center;
padding: 10rpx 26rpx;
border-radius: 30rpx;
margin-left: 26rpx;
font-size: 15px;
}
.blueBtn {
background-image: linear-gradient(45deg, #007aff, #00aaff);
color: #FFFFFF;
}
.blueBtn:active {
background-image: linear-gradient(45deg, #00aaff, #007aff);
}
.bottomBtn>image {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
.borderBtn {
border: 1rpx solid #888888;
color: #333333;
}
.borderBtn:active {
background-color: #F0F0F0;
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">商机名称{{item.sjName}}</view>
<view class="cardRow">
<view>客户名称</view>
<view>{{item.clientName}}</view>
</view>
<view class="cardRow">
<view>商机阶段</view>
<view>{{item.sjJieduan}}</view>
<cover-view v-if="item.percent != -1">
<u-line-progress class="progress" :striped="true" :percent="item.percent" :striped-active="true" :show-percent="false" :active-color="activeColor"></u-line-progress>
</cover-view>
</view>
<view class="cardRow">
<view>商机金额</view>
<view>{{item.sjPrice}}</view>
</view>
<view class="cardRow">
<view>预计成交</view>
<view>{{$u.timeFormat(item.chengJiao_date, 'yyyy-mm-dd')}}</view>
</view>
<view class="fzr" v-if="item.fuZeRenId && !isDetail">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">{{item.fuZeRenName}}</text>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
watch: {
item: function(val, old) {
this.setSjJieduanFun()
}
},
data() {
return {
percent: 70,
activeColor: ''
}
},
created() {
this.setSjJieduanFun()
},
methods: {
setSjJieduanFun: function() {
let str = this.item.sjJieduan;
let str1 = '';
if(str && str.indexOf('(') != -1) {
str = str.split("(")[0]
}
if(str == '初步沟通') {
str1 = '初步沟通(10%)';
this.item.percent = 10;
this.activeColor = '#ffda03'
} else if(str == '需求确定') {
str1 = '需求确定(30%)';
this.item.percent = 30;
this.activeColor = '#ffaa00'
} else if(str == '方案报价') {
str1 = '方案报价(50%)';
this.item.percent = 50;
this.activeColor = '#00ff7f'
} else if(str == '谈判协商') {
str1 = '谈判协商(80%)';
this.activeColor = '#00ff00'
this.item.percent = 80;
} else if(str == '赢单') {
str1 = '赢单(100%)';
this.activeColor = '#00aa00'
this.item.percent = 100;
} else if(str == '输单') {
str1 = '输单(0%)';
this.item.percent = 0;
this.activeColor = '#ff0000'
} else {
this.item.percent = -1;
}
this.item.sjJieduan = str1;
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$sjInfo = this.item;
uni.navigateTo({
url: '/pages/crm/shangji/detail?index=' + this.index
})
}
}
}
</script>
<style>
.progress {
width: 200rpx !important;
margin-left: 26rpx;
}
.fzr {
position: absolute;
right: 26rpx;
bottom: 80rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">回款编号{{item.hkdCode}}</view>
<view class="cardRow">
<view>合同名称</view>
<view>{{item.htName}}</view>
</view>
<view class="cardRow">
<view>客户名称</view>
<view>{{item.clientName}}</view>
</view>
<view class="cardRow">
<view>回款方式</view>
<view>{{item.hkdType}}</view>
</view>
<view class="cardRow">
<view>回款金额</view>
<view>{{item.hkdPrice}}</view>
</view>
<view class="cardRow">
<view>回款日期</view>
<view>{{$u.timeFormat(item.hkdDateTime, 'yyyy-mm-dd')}}</view>
</view>
<view class="fzrAbsolute" v-if="item.fuZeRenId && !isDetail">
<text class="fzrLeft">负责人</text>
<text class="fzrRight">{{item.fuZeRenName}}</text>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$hkdInfo = this.item;
uni.navigateTo({
url: '/pages/crm/huikuan/detail?index=' + this.index
})
}
}
}
</script>
<style>
.progress {
width: 200rpx !important;
margin-left: 26rpx;
}
.fzr {
position: absolute;
right: 26rpx;
bottom: 74rpx;
font-size: 15px;
}
.fzrLeft {
color: #ADADAD;
}
.fzrRight {
font-weight: bold;
color: #ff941a;
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">盘点单号{{item.order_no}}</view>
<view class="cardRow">
<view>盘点日期</view>
<view>{{item.check_time}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.warehouse_name}}</view>
</view>
<view class="cardRow">
<view>仓位名称</view>
<view>{{item.warehouse_bin_name}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.create_user_name}} {{item.create_time}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.update_user_name}} {{item.update_time}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,77 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">进仓单号{{item.BillNo}} {{item.SaleBillNo}}</view>
<view class="cardRow">
<view>进仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>往来单位</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,93 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">出仓单号{{item.BillNo}}</view>
<view class="cardRow">
<view>出仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>单据类型</view>
<view>{{item.BillTypeName}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>调至仓库</view>
<view>{{item.ToStoreName}}</view>
</view>
<view class="cardRow">
<view>营销部门</view>
<view>{{item.PlanDepartmentName}}</view>
</view>
<view class="cardRow">
<view>往来单位</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view>销售员</view>
<view>{{item.SaleUserName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,76 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">移仓单号{{item.BillNo}}</view>
<view class="cardRow">
<view>移仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>仓位名称</view>
<view>{{item.ScanStoreStationName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,85 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">盘点单号{{item.BillNo}}</view>
<view class="cardRow">
<view>盘点类型</view>
<view>{{item.BillTypeName}}</view>
</view>
<view class="cardRow">
<view>盘点日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>仓位名称</view>
<view>{{item.ScanStoreStationName}}</view>
</view>
<view class="cardRow">
<view>往来单位</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,81 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">进仓单号{{item.BillNo}}</view>
<view class="cardRow">
<view>进仓类型</view>
<view>{{item.BillTypeName}}</view>
</view>
<view class="cardRow">
<view>进仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>往来单位</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,81 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">出仓单号{{item.BillNo}}</view>
<view class="cardRow">
<view>出仓类型</view>
<view>{{item.BillTypeName}}</view>
</view>
<view class="cardRow">
<view>出仓日期</view>
<view>{{item.BillDate}}</view>
</view>
<view class="cardRow">
<view>仓库名称</view>
<view>{{item.StoreName}}</view>
</view>
<view class="cardRow">
<view>往来单位</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
onlaunch(e) {
console.log("---->>>" + item.OpDate);
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,89 @@
<template>
<view class="myCard" @click="gotoDetailFun">
<view class="cardTopName">预约单号{{item.AllocatedBillNo}} {{item.CustomerName}}</view>
<view class="cardRow">
<view>预约日期</view>
<view>{{item.AllocatedDate}}</view>
</view>
<view class="cardRow">
<view>营销部门</view>
<view>{{item.PlanDepartmentName}}</view>
</view>
<view class="cardRow">
<view>客户名称</view>
<view>{{item.CustomerName}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.SaleUserName}}</view>
</view>
<view class="cardRow">
<text class="fzrLeft">单据状态</text>
<text class="fzrRight">{{item.BillStatusName}} {{item.BillStatusTime}}</text>
</view>
<view class="cardRow">
<view>物流公司</view>
<view>{{item.ShipCompanyName}}</view>
</view>
<view class="cardRow">
<view>发货地址</view>
<view>{{item.SaleCustomerAddress}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.OpName}} {{item.OpDate}}</view>
</view>
<view class="cardRow">
<view> </view>
<view>{{item.CommitName}} {{item.CommitDate}}</view>
</view>
<view v-if="!isDetail && !isSelect" class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
isSelect: {
type: Boolean,
default: false
},
isDetail: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$bjInfo = this.item;
uni.navigateTo({
url: '/pages/saleship/detail?index=' + this.index
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,465 @@
<template>
<view>
<u-action-sheet :list="sheetList" v-model="moreShow" @click="sheetFun"></u-action-sheet>
<u-select v-model="allotShow" mode="single-column" confirm-text="确认分配" cancel-text="取消分配" :list="userList" @confirm="allotConfirmFun" value-name="_id" label-name="nickname"></u-select>
<view class="card">
<view class="topRow1" @click="gotoDetailFun">
<view class="name">
<text>{{item.clientName || '暂无'}}</text>
</view>
<view v-if="item.xingZhi != '个人客户'">
<text class="colorGray">联系人</text>
<text>{{item.lxRen}}</text>
<text v-if="item.company_zhiWei">{{item.lxRen}}</text>
</view>
<view v-if="item.genjin_date">
<text class="colorGray">最后跟进时间</text>
<text>{{$u.timeFrom(item.genjin_date, 'yyyy年mm月dd日')}}</text>
</view>
<view v-else-if="item.update_date">
<text class="colorGray">最后更新时间</text>
<text>{{$u.timeFrom(item.update_date, 'yyyy年mm月dd日')}}</text>
</view>
<view v-else>
<text class="colorGray">创建时间</text>
<text>{{$u.timeFrom(item.create_date, 'yyyy年mm月dd日')}}</text>
</view>
</view>
<!--标签-->
<view class="bqRow" @click="gotoDetailFun">
<view v-if="item.xingZhi">{{item.xingZhi}}</view>
<view v-if="item.fenJi">{{item.fenJi}}</view>
<view v-if="item.hangYe">{{item.hangYe}}</view>
<view v-if="item.zycdNum">
<text v-if="item.zycdNum == 1">一星</text>
<text v-if="item.zycdNum == 2">二星</text>
<text v-if="item.zycdNum == 3">三星</text>
<text v-if="item.zycdNum == 4">四星</text>
<text v-if="item.zycdNum == 5">五星</text>
</view>
</view>
<view v-if="!isSelect" class="bottomRow">
<view class="lxRow">
<lianxiRow :phone="item.phone"></lianxiRow>
</view>
<view class="lxRow" @click.stop="moreShowFun">
<image src="/static/icon/gengduosz.png" mode="aspectFill"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import { crmKeHuApi, threadApi } from '../../static/utils/api.js'
import { uidUserApi } from '../../static/utils/adminApi.js'
export default {
props: {
item: {
type: Object,
default: () => {}
},
isSelect: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
data() {
return {
sheetList: [{
text: '添加跟进'
},
{
text: '编辑'
},
{
text: '删除'
}
],
moreShow: false,
allotShow: false,
userList: []
}
},
methods: {
moreShowFun: function() {
let status = this.item.status;
if(status == 0) {
if(uni.$userInfo.isDepManager) {
this.sheetList = [
{
text: '领取'
},
{
text: '分配'
},
{
text: '编辑'
},
{
text: '删除'
}
];
} else {
this.sheetList = [
{
text: '领取'
}
];
}
} else {
this.sheetList = [
{
text: '添加跟进'
},
{
text: '转为客户'
},
{
text: '放入线索池'
},
{
text: '编辑'
}
// {
// text: ''
// }
];
}
this.moreShow = true;
},
gotoDetailFun: function() {
if(this.isSelect) {
return
}
uni.$khInfo = this.item;
uni.navigateTo({
url: './threadDetail?index=' + this.index
})
},
sheetFun: function(i) {
let arr = this.sheetList;
let str = arr[i].text;
if(str == '添加跟进') {
uni.navigateTo({
url: './addGj?clientName=' + this.item.clientName + '&clientId=' + this.item._id
})
} else if(str == '编辑') {
uni.$infoObj = this.item;
uni.navigateTo({
url: './addThread?type=update'
})
} else if(str == '删除') {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认删除客户名称为:' + that.item.clientName + '的线索吗?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
isDelete: 1,
update_date: new Date().getTime()
}
}
}
threadApi(reqData)
.then(res => {
uni.showToast({
title: '删除成功!',
duration: 1000,
icon: 'none'
})
uni.$emit('deleteKhFun', {index: that.index})
that.addCzjlFun('删除');
})
}
}
})
} else if(str == '领取') {
this.lingquFun()
} else if(str == '分配') {
if(this.userList.length > 0) {
this.allotShow = true;
} else {
this.getUserLisByDepIdtFun();
}
} else if(str == '放入线索池') {
this.putInFun()
} else if(str == '转为客户') {
uni.$infoObj = this.item;
uni.navigateTo({
url: '../kehu/addKeHu?type=zhuanClient'
})
}
},
addCzjlFun: function(type, content) {
let czjlObj = {
create_date: new Date().getTime(),
czRen: uni.$userInfo._id,
pageType: 'thread',
dataId: this.item._id,
type
}
if(content && content.length > 0) {
czjlObj.content = content;
}
uni.$czjlApiAddFun(czjlObj);
},
// 线
lingquFun: function() {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认领取客户名称为:' + that.item.clientName + '的线索吗?',
success(res) {
if(res.confirm) {
uni.showLoading({
title: '领取中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 1, //
fuZeRenId: uni.$userInfo._id,
update_date: new Date().getTime()
}
}
}
threadApi(reqData)
.then(res => {
that.addCzjlFun('领取');
that.$emit('cxGetDataFun');
uni.showToast({
title: '领取成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
// 线线
putInFun: function() {
let that = this;
uni.showModal({
title: '提示',
content: '是否确认将客户名称为:' + that.item.clientName + '的线索放入线索池吗?',
success(res) {
let time = new Date().getTime();
if(res.confirm) {
uni.showLoading({
title: '更新中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 0, // 线
fuZeRenId: '',
next_gjDate: '',
awaitFollowUp: 0,
recycle_date: time,
update_date: time
}
}
}
threadApi(reqData)
.then(res => {
that.addCzjlFun('放入线索池');
that.$emit('cxGetDataFun');
uni.showToast({
title: '更新成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
//
allotConfirmFun: function(e) {
console.log(e)
let obj = e[0];
let that = this;
uni.showModal({
title: '提示',
content: '是否确认将客户名称为:' + that.item.clientName + '的线索分配给 - ' + obj.label + ' - 吗?',
success(res) {
let time = new Date().getTime();
if(res.confirm) {
uni.showLoading({
title: '分配中...',
mask: true
})
let reqData = {
action: 'update',
params: {
_id: that.item._id,
req: {
status: 1, //
fuZeRenId: obj.value,
update_date: time
}
}
}
threadApi(reqData)
.then(res => {
let content = [
'修改 ' + ' 负责人为 ' + obj.label
]
that.addCzjlFun('编辑', content);
that.$emit('cxGetDataFun');
uni.showToast({
title: '更新成功!',
duration: 1600,
icon: 'none',
mask: true
})
})
}
}
})
},
// id
getUserLisByDepIdtFun: function() {
uni.showLoading({
title: '加载中...',
mask: true
})
let reqData = {
action: 'getAllUserListByDepID',
params: {
depId: uni.$userInfo.depManager_Id,
status: 0
}
}
uidUserApi(reqData)
.then(res => {
this.userList = res.result.data;
this.allotShow = true;
})
},
}
}
</script>
<style>
.card {
width: 698rpx;
padding: 26rpx 26rpx 10rpx;
margin: 32rpx 26rpx;
box-sizing: border-box;
border-radius: 16rpx;
box-shadow: #d8d8d8 0px 0px 16rpx;
position: relative;
background-color: #FFFFFF;
}
.genjinBtn {
position: absolute;
right: 26rpx;
top: 26rpx;
background-color: #007AFF;
color: #FFFFFF;
text-align: center;
padding: 6rpx 16rpx;
border-radius: 6rpx;
font-size: 14px;
}
.genjinBtn:active {
background-color: #13B8FF;
}
.topRow1 {
margin-bottom: 16rpx;
font-size: 15px;
color: #000;
position: relative;
}
.name {
font-size: 16px;
margin-bottom: 8rpx;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
}
.bottomRow {
width: 100%;
padding-top: 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1rpx solid #f0f0f0;
font-size: 15px;
color: #007AFF;
}
.lxRow {
display: flex;
align-items: center;
}
.lxRow>image {
width: 52rpx;
height: 52rpx;
margin-right: 26rpx;
}
.bqRow {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.bqRow>text {
font-size: 14px;
color: #888888;
}
.bqRow>view {
padding: 6rpx 16rpx;
font-size: 14px;
background-color: rgba(255, 85, 127, 0.1);
color: #ff5500;
border-radius: 10rpx;
margin: 6rpx 26rpx 20rpx 0;
}
.khJieDuan {
position: absolute;
right: 0;
top: 50rpx;
font-weight: bold;
}
.khType {
position: absolute;
right: 0;
top: 72rpx;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<view class="card" @click="gotoDetailFun">
<view class="khName">客户名称{{item.clientName}}</view>
<view class="lrView">
<view>跟进类型</view>
<view>{{item.type}}</view>
</view>
<view class="lrView" v-if="item.orderType">
<view>单据类型</view>
<view>{{item.orderType}}</view>
<!-- <view v-if="item.states == '有需求跟进'" class="yellowColor">{{item.states}}</view>
<view v-if="item.states == '促单'" class="greenColor">{{item.states}}</view>
<view v-if="item.states == '放弃'" class="redColor">{{item.states}}</view> -->
</view>
<view class="lrView">
<view>跟进内容</view>
<view class="liangHang">{{item.gjContent}}</view>
</view>
<view v-if="item.gjAddr" class="lrView">
<view>跟进地址</view>
<view>{{item.gjAddr}}</view>
</view>
<view v-if="item.next_gjDate" class="lrView">
<view>下次跟进</view>
<view>{{$u.timeFormat(item.next_gjDate, 'yyyy-mm-dd hh:MM:ss')}}</view>
</view>
<view v-if="item.genjin_date" class="lrView">
<view>跟进时间</view>
<view>{{$u.timeFormat(item.genjin_date, 'yyyy-mm-dd hh:MM:ss')}}</view>
</view>
<view class="lrView">
<view>创建人</view>
<view class="liangHang">{{item.cjRenName}}</view>
</view>
<view class="lookDetail">
<text>查看详情</text>
<u-icon name="arrow-right" size="36"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
},
index: {
type: Number,
default: 0
},
},
data() {
return {
}
},
methods: {
gotoDetailFun: function() {
uni.$gjInfo = this.item;
uni.navigateTo({
url: '/pages/crm/thread/gjDetail?index=' + this.index
})
}
}
}
</script>
<style>
.card {
width: 686rpx;
margin: 32rpx;
background-color: #FFFFFF;
padding: 16rpx;
border-radius: 26rpx;
box-sizing: border-box;
box-shadow: #dddddd 0px 0px 32rpx;
}
.bottomRow {
display: flex;
justify-content: space-between;
border-top: 1rpx solid #dddddd;
padding-top: 16rpx;
margin-top: 16rpx;
}
.khName {
font-size: 16px;
font-weight: bold;
margin-bottom: 16rpx;
padding-bottom: 10rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.lrView {
display: flex;
font-size: 16px;
}
.lrView>view:first-child {
width: 176rpx;
color: #ADADAD;
}
.lrView>view:last-child {
width: 466rpx;
color: #000000;
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<view class="navbar_container">
<view class="navbar_content" :style="navbarStyle">
<!-- 左侧返回按钮 -->
<view class="navbar_left" @click="handleLeftClick">
<slot name="left">
<text v-if="showBack" class="iconfont icon-arrow-left" :style="{ color: iconColor }">返回</text>
</slot>
</view>
<!-- 中间标题 -->
<view class="navbar_center">
<slot name="center">
<text :style="titleStyle">{{ title }}</text>
</slot>
</view>
<!-- 右侧自定义区域 -->
<view class="navbar_right" @click="handleRightClick">
<slot name="right"></slot>
</view>
</view>
<view class="safe_area" :style="safeAreaStyle"></view>
</view>
</template>
<script>
import { getStatusBarHeight } from "@/utils/safeArea";
export default {
props: {
//
title: {
type: String,
default: ''
},
//
titleColor: {
type: String,
default: '#333333'
},
//
titleSize: {
type: Number,
default: 18
},
//
titleWeight: {
type: [Number, String],
default: 600
},
//
iconColor: {
type: String,
default: '#333333'
},
//
showBack: {
type: Boolean,
default: true
},
//
customBack: {
type: Function,
default: null
},
//
backgroundColor: {
type: String,
default: '#ffffff'
},
//
showShadow: {
type: Boolean,
default: true
},
//
shadowStyle: {
type: String,
default: 'none'
}
},
data() {
return {
getStatusBarHeight: getStatusBarHeight(),
contentHeight: 0,
};
},
computed: {
navbarStyle() {
return {
backgroundColor: this.backgroundColor,
boxShadow: this.showShadow ? this.shadowStyle : 'none',
top: `${this.getStatusBarHeight}px`
}
},
titleStyle() {
return {
color: this.titleColor,
fontSize: `${this.titleSize}px`,
fontWeight: this.titleWeight
}
},
safeAreaStyle() {
const totalHeight = this.getStatusBarHeight + this.contentHeight;
return {
height: `${totalHeight}px`,
backgroundColor: this.backgroundColor
}
}
},
mounted() {
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.navbar_content').boundingClientRect(data => {
if (data) {
this.contentHeight = data.height;
}
}).exec();
});
},
methods: {
handleLeftClick() {
if (this.customBack) {
this.customBack();
} else if (this.showBack) {
const pages = getCurrentPages();
if (pages.length > 1) {
uni.navigateBack({
delta: 1
});
}
}
this.$emit('leftClick');
},
handleRightClick() {
this.$emit('rightClick');
}
}
};
</script>
<style lang="scss" scoped>
.navbar_container {
z-index: 999;
.navbar_content {
position: fixed;
left: 0;
right: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 12px;
.navbar_left {
min-width: 60px;
.icon-arrow-left {
font-size: 16px;
}
}
.navbar_center {
flex: 1;
text-align: center;
//
padding: 0 60px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navbar_right {
min-width: 60px;
text-align: right;
font-size: 16px;
}
}
.safe_area {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<view class="dataNull">
<image :src="src" mode="aspectFill"></image>
<view class="title">{{title}}</view>
<view class="title1" v-if="title1">{{title1}}</view>
</view>
</template>
<script>
export default {
props: {
src: {
type: String,
default: '/static/img/dataNull.png'
},
title: {
type: String,
default: '暂无内容哦~'
},
title1: {
type: String,
default: ''
}
},
}
</script>
<style>
.dataNull {
display: flex;
align-items: center;
flex-direction: column;
}
.dataNull>image {
max-width: 500rpx;
max-height: 400rpx;
margin: 200rpx 0 66rpx;
}
.title {
color: #555555;
font-size: 16px;
font-weight: bold;
}
.title1 {
margin-top: 16rpx;
color: #555555;
font-size: 15px;
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<view class="tishi">
<image v-if="isMore" class="loadingIcon" src="../../static/icon/loading.gif" mode="aspectFill"></image>
<text v-if="isMore">正在加载更多哦...</text>
<text v-else>{{nullMsg}}</text>
</view>
</template>
<script>
export default {
name: "getMore",
props: {
isMore:{
type: Boolean,
default: true
},
nullMsg:{
type: String,
default: '我是有底线的人~'
}
}
}
</script>
<style>
/*上拉刷新提示文字*/
.tishi {
flex-direction: row;
width: 750rpx;
justify-content: center;
text-align: center;
flex-direction: column;
align-items: center;
margin: 28rpx 0;
font-size: 26rpx;
}
.tishiT {
font-size: 26rpx;
color: #333;
}
.loadingIcon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
margin-bottom: -10rpx;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<view class="wrap wrap-home">
<u-navbar :title="title" height="44" :is-back="false">
<!-- #ifdef APP-PLUS --><!-- #endif -->
<view slot="right">
<view style="color: #22262d;font-size: 20px;" class="iconfont icon-setting-two" @click="navTo('/pages/sys/user/setting')"></view>
</view>
<u-avatar class="home-head" :src="avatarUrl" @click="show = true"></u-avatar>
</u-navbar>
</view>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
}
},
data() {
return {
src: '',
show: false,
};
},
onLoad() {
},
computed: {
avatarUrl() {
var url = this.vuex_config.baseUrl + this.vuex_user.avatar || '/static/aidex/tabbar/my_2.png';
url = this.replaceAll(url,'\\','/');
return url + '?t=' + new Date().getTime();
}
},
methods: {
showPersonalInfo() {
this.show = true
},
navTo(url) {
uni.navigateTo({
url: url
});
}
}
};
</script>
<style lang="scss">
.slot-wrap {
display: flex;
align-items: center;
/* 如果您想让slot内容占满整个导航栏的宽度 */
/* flex: 1; */
/* 如果您想让slot内容与导航栏左右有空隙 */
/* padding: 0 30rpx; */
}
page {
background-color: #ffffff;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<view>
<image class="lxIcon" @click.stop="makePhoneCallFun" src="/static/icon/dianhua.png" mode="aspectFill">
</image>
<image class="lxIcon" @click.stop="sendMsgFun" src="/static/icon/duanxin.png" mode="aspectFill"></image>
<!-- <image class="lxIcon" @click="sendEmailFun" src="/static/icon/youjian.png" mode="aspectFill"></image> -->
</view>
</template>
<script>
export default {
props: {
phone: ''
},
methods: {
sendMsgFun: function() {
if(!this.phone) {
uni.$myModalFun('该客户暂未设置联系方式!')
return
}
// #ifdef APP-PLUS
var msg = plus.messaging.createMessage(plus.messaging.TYPE_SMS);
msg.to = [this.phone];
msg.body = '';
plus.messaging.sendMessage(msg);
// #endif
},
sendEmailFun: function() {
// #ifdef APP-PLUS
var msg = plus.messaging.createMessage(plus.messaging.TYPE_EMAIL);
msg.to = ['test@163.com', 'test@173.com'];
msg.cc = ['test@163.com', 'test@173.com'];
msg.bcc = ['test@163.com', 'test@173.com'];
msg.subject = '测试邮件';
msg.body = 'This is Pandora example test message';
plus.messaging.sendMessage(msg, function() {
alert("Send success!");
}, function() {
alert("Send failed!");
});
// #endif
},
makePhoneCallFun: function() {
if(!this.phone) {
uni.$myModalFun('该客户暂未设置联系方式!')
return
}
// #ifdef APP-PLUS
uni.makePhoneCall({
phoneNumber: this.phone
})
// #endif
}
}
}
</script>
<style>
.lxIcon {
width: 52rpx;
height: 52rpx;
margin-right: 26rpx;
}
</style>

View File

@ -0,0 +1,819 @@
<template>
<view v-if="isShow" class="picker">
<!-- 日期选择器 -->
<view v-if="type!='time'" class="picker-modal">
<view class="picker-modal-header">
<view class="picker-icon picker-icon-zuozuo" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('-1')"></view>
<view class="picker-icon picker-icon-zuo" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('-1')"></view>
<text class="picker-modal-header-title">{{title}}</text>
<view class="picker-icon picker-icon-you" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('+1')"></view>
<view class="picker-icon picker-icon-youyou" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('+1')"></view>
</view>
<swiper class="picker-modal-body" :circular="true" :duration="200" :skip-hidden-item-layout="true" :current="calendarIndex" @change="onSwiperChange">
<swiper-item class="picker-calendar" v-for="(calendar,calendarIndex2) in calendars" :key="calendarIndex2">
<view class="picker-calendar-view" v-for="(week,index) in weeks" :key="index - 7">
<view class="picker-calendar-view-item">{{week}}</view>
</view>
<view class="picker-calendar-view" v-for="(date,dateIndex) in calendar" :key="dateIndex" @click="onSelectDate(date)">
<!-- 背景样式 -->
<view v-show="date.bgStyle.type" :class="'picker-calendar-view-'+date.bgStyle.type" :style="{background: date.bgStyle.background}"></view>
<!-- 正常和选中样式 -->
<view class="picker-calendar-view-item" :style="{opacity: date.statusStyle.opacity, color: date.statusStyle.color, background: date.statusStyle.background}">
<text>{{date.title}}</text>
</view>
<!-- 小圆点样式 -->
<view class="picker-calendar-view-dot" :style="{opacity: date.dotStyle.opacity, background: date.dotStyle.background}"></view>
<!-- 信息样式 -->
<view v-show="date.tips" class="picker-calendar-view-tips">{{date.tips}}</view>
</view>
</swiper-item>
</swiper>
<view class="picker-modal-footer">
<view class="picker-modal-footer-info">
<block v-if="isMultiSelect">
<view class="picker-display">
<text>{{beginText}}日期</text>
<text class="picker-display-text">{{BeginTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
</view>
<view class="picker-display">
<text>{{endText}}日期</text>
<text class="picker-display-text">{{EndTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click="onShowTimePicker('end')">{{EndTimeTitle}}</view>
</view>
</block>
<block v-else>
<view class="picker-display">
<text>当前选择</text>
<text class="picker-display-text">{{BeginTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
</view>
</block>
</view>
<view class="picker-modal-footer-btn">
<view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click="onCancel">取消</view>
<view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click="onConfirm">确定</view>
</view>
</view>
</view>
<!-- 时间选择器 -->
<view v-if="showTimePicker" class="picker">
<view class="picker-modal picker-time">
<view class="picker-modal-header">
<text class="picker-modal-header-title">选择日期</text>
</view>
<picker-view class="picker-modal-time" indicator-class="picker-modal-time-item" :value="timeValue" @change="onTimeChange">
<picker-view-column>
<view v-for="(v,i) in 24" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
<picker-view-column>
<view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
<picker-view-column v-if="showSeconds">
<view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
</picker-view>
<view class="picker-modal-footer">
<view class="picker-modal-footer-info">
<view class="picker-display">
<text>当前选择</text>
<text class="picker-display-text">{{PickerTimeTitle}}</text>
</view>
</view>
<view class="picker-modal-footer-btn">
<view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click="onCancelTime">取消</view>
<view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click="onConfirmTime">确定</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* 工具函数库
*/
const DateTools = {
/**
* 获取公历节日
* @param date Date对象
*/
getHoliday(date) {
let holidays = {
'0101': '元旦',
'0214': '情人',
'0308': '妇女',
'0312': '植树',
'0401': '愚人',
'0501': '劳动',
'0504': '青年',
'0601': '儿童',
'0701': '建党',
'0801': '建军',
'0903': '抗日',
'0910': '教师',
'1001': '国庆',
'1031': '万圣',
'1224': '平安',
'1225': '圣诞'
};
let value = this.format(date, 'mmdd');
if (holidays[value]) return holidays[value];
return false;
},
/**
* 解析标准日期格式
* @param s 日期字符串
* @return 返回Date对象
*/
parse: s => new Date(s.replace(/(年|月|-)/g, '/').replace(/(日)/g, '')),
/**
* 比较日期是否为同一天
* @param a Date对象
* @param b Date对象
* @return Boolean
*/
isSameDay: (a, b) => a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear() && a.getDate() == b.getDate(),
/**
* 格式化Date对象
* @param d 日期对象
* @param f 格式字符串
* @return 返回格式化后的字符串
*/
format(d, f) {
var o = {
"m+": d.getMonth() + 1,
"d+": d.getDate(),
"h+": d.getHours(),
"i+": d.getMinutes(),
"s+": d.getSeconds(),
"q+": Math.floor((d.getMonth() + 3) / 3),
};
if (/(y+)/.test(f))
f = f.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(f))
f = f.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return f;
},
/**
* 用于format格式化后的反解析
* @param s 日期字符串
* @param f 格式字符串
* @return 返回Date对象
*/
inverse(s, f) {
var o = {
"y": '',
"m": '',
"d": '',
"h": '',
"i": '',
"s": '',
};
let d = new Date();
if (s.length != f.length) return d;
for (let i in f)
if (o[f[i]] != undefined) o[f[i]] += s[i];
if (o.y) d.setFullYear(o.y.length < 4 ? (d.getFullYear() + '').substr(0, 4 - o.y.length) + o.y : o.y);
o.m && d.setMonth(o.m - 1, 1);
o.d && d.setDate(o.d - 0);
o.h && d.setHours(o.h - 0);
o.i && d.setMinutes(o.i - 0);
o.s && d.setSeconds(o.s - 0);
return d;
},
/**
* 获取日历数组42
* @param date 日期对象或日期字符串
* @param proc 处理日历(和forEach类似)传递一个数组中的item
* @return Array
*/
getCalendar(date, proc) {
let it = new Date(date),
calendars = [];
it.setDate(1);
it.setDate(it.getDate() - ((it.getDay() == 0 ? 7 : it.getDay()) - 1)); //
for (let i = 0; i < 42; i++) {
let tmp = {
dateObj: new Date(it),
title: it.getDate(),
isOtherMonth: it.getMonth() < date.getMonth() || it.getMonth() > date.getMonth()
};
calendars.push(Object.assign(tmp, proc ? proc(tmp) : {}));
it.setDate(it.getDate() + 1);
}
return calendars;
},
/**
* 获取日期到指定的月份1号(不改变原来的date对象)
* @param d Date对象
* @param v 指定的月份
* @return Date对象
*/
getDateToMonth(d, v) {
let n = new Date(d);
n.setMonth(v, 1);
return n;
},
/**
* 把时间数组转为时间字符串
* @param t Array[,,]
* @param showSecinds 是否显示秒
* @return 字符串 :[:]
*/
formatTimeArray(t, s) {
let r = [...t];
if (!s) r.length = 2;
r.forEach((v, k) => r[k] = ('0' + v).slice(-2));
return r.join(':');
}
};
export default {
props: {
//
color: {
type: String,
default: '#409eff'
},
// typedatetimetime
showSeconds: {
type: Boolean,
default: false
},
//
value: [String, Array],
//date time datetime range rangetime
type: {
type: String,
default: 'range'
},
//
show: {
type: Boolean,
default: false
},
//
format: {
type: String,
default: ''
},
//
showHoliday: {
type: Boolean,
default: true
},
//
showTips: {
type: Boolean,
default: false
},
// type
beginText: {
type: String,
default: '开始'
},
// type
endText: {
type: String,
default: '结束'
}
},
data() {
return {
isShow: false, //
isMultiSelect: false, //
isContainTime: false, //
date: {}, //
weeks: ["一", "二", "三", "四", "五", "六", "日"],
title: '初始化', //
calendars: [[],[],[]], //
calendarIndex: 1, //
checkeds: [], //
showTimePicker: false, //
timeValue: [0, 0, 0], //
timeType: 'begin', //
beginTime: [0, 0, 0], //
endTime: [0, 0, 0], //
};
},
methods: {
//
setValue(value) {
this.date = new Date();
this.checkeds = [];
this.isMultiSelect = this.type.indexOf('range') >= 0;
this.isContainTime = this.type.indexOf('time') >= 0;
//Date
let parseDateStr = (str) => (this.format ? DateTools.inverse(str, this.format) : DateTools.parse(str));
if (value) {
if (this.isMultiSelect) {
Array.isArray(value) && value.forEach((dateStr, index) => {
let date = parseDateStr(dateStr);
let time = [date.getHours(), date.getMinutes(), date.getSeconds()];
if (index == 0) this.beginTime = time;
else this.endTime = time;
this.checkeds.push(date);
});
} else {
if (this.type == 'time') {
let date = parseDateStr('2019/1/1 ' + value);
this.beginTime = [date.getHours(), date.getMinutes(), date.getSeconds()];
this.onShowTimePicker('begin');
} else {
this.checkeds.push(parseDateStr(value));
if (this.isContainTime) this.beginTime = [
this.checkeds[0].getHours(),
this.checkeds[0].getMinutes(),
this.checkeds[0].getSeconds()
];
}
}
if (this.checkeds.length) this.date = new Date(this.checkeds[0]);
} else {
if (this.isContainTime) {
this.beginTime = [this.date.getHours(), this.date.getMinutes(), this.date.getSeconds()];
if (this.isMultiSelect) this.endTime = [...this.beginTime];
}
this.checkeds.push(new Date(this.date));
}
if (this.type != 'time') this.refreshCalendars(true);
else this.onShowTimePicker('begin');
},
//
onSetYear(value) {
this.date.setFullYear(this.date.getFullYear() + parseInt(value));
this.refreshCalendars(true);
},
//
onSetMonth(value) {
this.date.setMonth(this.date.getMonth() + parseInt(value));
this.refreshCalendars(true);
},
//
onTimeChange(e) {
this.timeValue = e.detail.value;
},
//
onShowTimePicker(type) {
this.showTimePicker = true;
this.timeType = type;
this.timeValue = type == 'begin' ? [...this.beginTime] : [...this.endTime];
},
//
procCalendar(item) {
//
item.statusStyle = {
opacity: 1,
color: item.isOtherMonth ? '#ddd' : '#000',
background: 'transparent'
};
item.bgStyle = {
type: '',
background: 'transparent'
};
item.dotStyle = {
opacity: 1,
background: 'transparent'
};
item.tips = "";
//
if (DateTools.isSameDay(new Date(), item.dateObj)) {
item.statusStyle.color = this.color;
if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
}
//
this.checkeds.forEach(date => {
if (DateTools.isSameDay(date, item.dateObj)) {
item.statusStyle.background = this.color;
item.statusStyle.color = '#fff';
item.statusStyle.opacity = 1;
if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
}
});
//
if (item.statusStyle.background != this.color) {
let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
item.title = holiday || item.title;
item.dotStyle.background = this.color;
if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
}
} else {
item.title = item.dateObj.getDate();
}
//
if (this.checkeds.length == 2) {
if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) { //
item.bgStyle.type = 'bgbegin';
}
if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) { //
if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' + this.endText : this.endText;
if (!item.bgStyle.type) { //
item.bgStyle.type = 'bgend';
} else {
item.bgStyle.type = '';
}
}
if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[1])) { //
item.bgStyle.type = 'bg';
item.statusStyle.color = this.color;
}
if (item.bgStyle.type) {
item.bgStyle.background = this.color;
item.dotStyle.opacity = 1;
item.statusStyle.opacity = 1;
}
}
},
//
refreshCalendars(refresh = false) {
let date = new Date(this.date);
let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
if (this.calendarIndex == 0) {
if(refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
} else if (this.calendarIndex == 1) {
this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
if(refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
} else if (this.calendarIndex == 2) {
this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
if(refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
}
this.title = DateTools.format(this.date, 'yyyy年mm月');
},
//
onSwiperChange(e) {
this.calendarIndex = e.detail.current;
let calendar = this.calendars[this.calendarIndex];
this.date = new Date(calendar[22].dateObj); //
this.refreshCalendars();
},
//
onSelectDate(date) {
if (~this.type.indexOf('range') && this.checkeds.length == 2) this.checkeds = [];
else if (!(~this.type.indexOf('range')) && this.checkeds.length) this.checkeds = [];
this.checkeds.push(new Date(date.dateObj));
this.checkeds.sort((a, b) => a - b); //
this.calendars.forEach(calendar => {
calendar.forEach(this.procCalendar); //
});
},
//
onCancelTime() {
this.showTimePicker = false;
this.type == 'time' && this.onCancel();
},
//
onConfirmTime() {
if (this.timeType == 'begin') this.beginTime = this.timeValue;
else this.endTime = this.timeValue;
this.showTimePicker = false;
this.type == 'time' && this.onConfirm();
},
//
onCancel() {
this.$emit('cancel', false);
},
//
onConfirm() {
let result = {
value: null,
date: null
};
//
let defaultFormat = {
'date': 'yyyy/mm/dd',
'time': 'hh:ii' + (this.showSeconds ? ':ss' : ''),
'datetime': ''
};
defaultFormat['datetime'] = defaultFormat.date + ' ' + defaultFormat.time;
let fillTime = (date, timeArr) => {
date.setHours(timeArr[0], timeArr[1]);
if (this.showSeconds) date.setSeconds(timeArr[2]);
};
if (this.type == 'time') {
let date = new Date();
fillTime(date, this.beginTime);
result.value = DateTools.format(date, this.format ? this.format : defaultFormat.time);
result.date = date;
} else {
if (this.isMultiSelect) {
let values = [],
dates = [];
if (this.checkeds.length < 2) return uni.showToast({
icon: 'none',
title: '请选择两个日期'
});
this.checkeds.forEach((date, index) => {
let newDate = new Date(date);
if (this.isContainTime) {
let time = [this.beginTime, this.endTime];
fillTime(newDate, time[index]);
}
values.push(DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
'datetime' : 'date']));
dates.push(newDate);
});
result.value = values;
result.date = dates;
} else {
let newDate = new Date(this.checkeds[0]);
if (this.isContainTime) {
newDate.setHours(this.beginTime[0], this.beginTime[1]);
if (this.showSeconds) newDate.setSeconds(this.beginTime[2]);
}
result.value = DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
'datetime' : 'date']);
result.date = newDate;
}
}
this.$emit('confirm', result);
}
},
computed: {
BeginTitle() {
let value = '未选择';
if (this.checkeds.length) value = DateTools.format(this.checkeds[0], 'yy/mm/dd');
return value;
},
EndTitle() {
let value = '未选择';
if (this.checkeds.length == 2) value = DateTools.format(this.checkeds[1], 'yy/mm/dd');
return value;
},
PickerTimeTitle() {
return DateTools.formatTimeArray(this.timeValue, this.showSeconds);
},
BeginTimeTitle() {
return this.BeginTitle != '未选择' ? DateTools.formatTimeArray(this.beginTime, this.showSeconds) : '';
},
EndTimeTitle() {
return this.EndTitle != '未选择' ? DateTools.formatTimeArray(this.endTime, this.showSeconds) : '';
}
},
watch: {
show(newValue, oldValue) {
newValue && this.setValue(this.value);
this.isShow = newValue;
},
value(newValue, oldValue) {
setTimeout(()=>{
this.setValue(newValue);
}, 0);
}
}
}
</script>
<style lang="scss" scoped>
$z-index: 100;
$cell-spacing: 20upx;
$calendar-size: 630upx;
$calendar-item-size: 90upx;
.picker {
position: fixed;
z-index: $z-index;
background: rgba(255, 255, 255, 0);
left: 0;
top: 0;
width: 100%;
height: 100%;
font-size: 28upx;
&-btn {
padding: $cell-spacing*0.5 $cell-spacing;
border-radius: 12upx;
color: #666;
&-active {
background: rgba(0, 0, 0, .1);
}
}
&-display {
color: #666;
&-text {
color: #000;
margin: 0 $cell-spacing*0.5;
}
&-link {
display: inline-block;
&-active {
background: rgba(0, 0, 0, .1);
}
}
}
&-time {
width: $calendar-size - 80upx !important;
left: ((750upx - $calendar-size) / 2 + 40upx) !important;
}
&-modal {
background: #fff;
position: absolute;
top: 50%;
left: (750upx - $calendar-size) / 2;
width: $calendar-size;
transform: translateY(-50%);
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.1);
border-radius: 12upx;
&-header {
text-align: center;
line-height: 80upx;
font-size: 32upx;
&-title {
display: inline-block;
width: 40%;
}
.picker-icon {
display: inline-block;
line-height: 50upx;
width: 50upx;
height: 50upx;
border-radius: 50upx;
text-align: center;
margin: 10upx;
background: #fff;
font-size: 36upx;
&-active {
background: rgba(0, 0, 0, .1);
}
}
}
&-body {
width: $calendar-size !important;
height: $calendar-size !important;
position: relative;
}
&-time {
width: 100%;
height: 180upx;
text-align: center;
line-height: 60upx;
}
&-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: $cell-spacing;
&-info {
flex-grow: 1;
}
&-btn {
flex-shrink: 0;
display: flex;
}
}
}
&-calendar {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
&-view {
position: relative;
width: $calendar-item-size;
height: $calendar-item-size;
text-align: center;
&-bgbegin,
&-bg,
&-bgend,
&-item,
&-dot,
&-tips {
position: absolute;
transition: .2s;
}
&-bgbegin,
&-bg,
&-bgend {
opacity: .15;
height: 80%;
}
&-bg {
left: 0;
top: 10%;
width: 100%;
}
&-bgbegin {
border-radius: $calendar-item-size 0 0 $calendar-item-size;
top: 10%;
left: 10%;
width: 90%;
}
&-bgend {
border-radius: 0 $calendar-item-size $calendar-item-size 0;
top: 10%;
left: 0%;
width: 90%;
}
&-item {
left: 5%;
top: 5%;
width: 90%;
height: 90%;
border-radius: $calendar-item-size;
display: flex;
align-items: center;
justify-content: center;
}
&-dot {
right: 10%;
top: 10%;
width: 12upx;
height: 12upx;
border-radius: 12upx;
}
&-tips {
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #4E4B46;
color: #fff;
border-radius: 12upx;
padding: 10upx 20upx;
font-size: 24upx;
width: max-content;
margin-bottom: 5px;
pointer-events: none;
&:after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-style: solid;
border-width: 5px 5px 0 5px;
border-color: #4E4B46 transparent transparent transparent;
}
}
}
}
}
@font-face {
font-family: "mxdatepickericon";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMYAAsAAAAACBgAAALMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDIgqDRIJiATYCJAMUCwwABCAFhG0HSRvfBsg+QCa3noNAyAQ9w6GDvbwpNp2vloCyn8bD/x+y+/5qDhtj+T4eRVEcbsCoKMFASzCgLdDkmqYDwgxkWQ6YH5L/YnppOlLEjlnter43YRjU7M6vJ3iGADVAgJn5kqjv/wEii23T86UsAQT+04fV+o97VTMx4PPZt4DlorLXwIQiGMA5uhaVrBWqGHfQXcTEiE+PE+g2SUlxWlLVBHwUYFMgrgwSB3wstTKSGzqF1nOyiGeeOtNjV4An/vvxR58PSc3AzrMViyDvPo/7dVEUzn5GROfIWAcU4rLXfMFdhte56y4We9gGNEVIezkBOOaQXUrbTf/hJVkhGpDdCw7dSOEzByMEn3kIic98hMxnAfeFPKWCbjRcA148/HxhCEkaA94eGWFaGolsblpaWz8/Po2WVuNHh1fmBpZHIpqal9fOjizhTteY+RZ9rv02I/pq0W6QVH3pSncBz3m55r9ZIPycHfmenvxe4uyutIgfT5u4bgkDusl9gcF0rnfnz+b2NpSaQWBFeu8GIL1xQj5AH/6FAsEr/50F28e/gA9ny6KjLrxIp0TE+UucmQOl5AFNLXkzZufWamWHYEI39PEP2If97CMdm51N6DSmIekwAVmneXTBr0PVYx+aTgfQbU3p+R4jKHdRurBq0oEw6AKSfm+QDbpGF/w3VOP+oBnMHbqdx409FjP4RRHHkAj5IWgQiBUjHfMTuQ1Icpg5avI4sQVRu8EHdWptM1aKrIjuscfeL+kZwxBTYoElztOQ2UygjRIjEphaZsyWodHgvm9SC8QC/JygEA6DiCDeEMhAQFhhOpvxa/18A0TiYMahIy0L2hYIZWeYH9JR085Al4qts1re5St2/SR6DINBGEVYQCWOETHDMAHZ+pcZIQJGTV4RtMmg8UbhuWL1+VLLA2RFHYC71kiRo0SNpjwQh8pj2EFU3oTNmS1WqgIA') format('woff2');
}
.picker-icon {
font-family: "mxdatepickericon" !important;
}
.picker-icon-you:before {
content: "\e63e";
}
.picker-icon-zuo:before {
content: "\e640";
}
.picker-icon-zuozuo:before {
content: "\e641";
}
.picker-icon-youyou:before {
content: "\e642";
}
</style>

View File

@ -0,0 +1,166 @@
<template>
<view>
<u-popup :show="show" @close="cancel">
<view class="title">{{popupTitle}}</view>
<view style="padding: 20rpx;">
<u-search v-if="showSearch" @custom="search" @search="search" :placeholder="placeholder"
v-model="keyword"></u-search>
<u-gap v-if="showSearch" height="15"></u-gap>
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltolower="$emit('lower')">
<!--单选-->
<u-radio-group v-if="type == 'radio'" :borderBottom="true" iconPlacement="right" placement="column"
@change="groupChange" v-model="radioValue">
<u-radio :customStyle="{marginBottom: '12px'}" v-for="(item, index) in dataLists" :key="index"
:label="item[name]" :name="index">
</u-radio>
</u-radio-group>
<!--多选-->
<u-checkbox-group v-if="type == 'checkbox'" :borderBottom="true" placement="column"
iconPlacement="right" @change="checkboxChange" v-model="checkboxValue">
<u-checkbox :customStyle="{marginBottom: '12px',paddingBottom:'12px'}"
v-for="(item, index) in dataLists" :key="index" :label="item[name]" :name="index">
</u-checkbox>
</u-checkbox-group>
</scroll-view>
<u-gap height="45"></u-gap>
<view class="bottons">
<u-row>
<u-col customStyle="padding:0 10rpx 20rpx 20rpx" span="6">
<u-button @click="cancel">取消</u-button>
</u-col>
<u-col customStyle="padding:0 20rpx 20rpx 10rpx" span="6">
<u-button @click="submit" type="primary" throttleTime="1000" :disabled="(JSON.stringify(radioData) === '{}') && (checkboxData.length === 0)">确认</u-button>
</u-col>
</u-row>
</view>
</view>
</u-popup>
</view>
</template>
<script>
/**
* 公共选择下拉框基于uview支持下拉加载列表搜索单选多选
* @author qianziyu
* @description 弹出层选择器基于uview中u-popup实现
* @property {Array} dataLists 数据列表
* @property {String} name 列表显示的字段名
* @property {Boolean} show 是否展示弹窗 (默认 false )
* @property {String} type 选择类型 单选多选 (默认 单选 )
* @property {Boolean} showSearch 是否显示搜索框 (默认 true )
* @property {String} popupTitle 列表标题
* @property {String} placeholder 搜索框placeholder
* @event {Function} search 搜索事件返回keyword
* @event {Function} lower 滑动到底部触发用于下拉加载新数据
* @event {Function} cancel 组件关闭事件
* @event {Function} submit 提交按钮,返回选中的列表数据
* @example <common-select :show="show" :popupTitle="popupTitle" @cancel="show=false" @search="selectSearch" name="cworkStationName" @submit="onsubmit"
:dataLists="dataLists" placeholder="输入工站名称搜索"></common-select>
*/
export default {
name: "qianziyu-select",
props: {
dataLists: {
default: {},
type: Array
},
name: {
default: 'name',
},
show: {
default: false,
type: Boolean
},
type: {
default: 'radio',
type: String
},
showSearch: {
default: true,
type: Boolean
},
popupTitle: {
default: '列表选择',
type: String
},
placeholder: {
default: '请输入搜索内容'
}
},
data() {
return {
keyword: '',
scrollTop: 0,
checkboxData: [],
checkboxValue:[],
radioData: {},
radioValue: ''
};
},
methods: {
checkboxChange(n) {
this.checkboxData=[]
n.forEach(key=>{
this.checkboxData.push(this.dataLists[key])
})
},
//
groupChange(n) {
this.radioData = this.dataLists[n]
},
//
search() {
this.$emit('search', this.keyword)
},
//
cancel() {
this.$emit('cancel')
},
//
submit() {
if (this.type == 'radio') {
if (JSON.stringify(this.radioData) == '{}') {
uni.$u.toast('请选择数据')
return;
}
this.$emit('submit', this.radioData)
} else if (this.type == 'checkbox') {
if (this.checkboxData.length == 0) {
uni.$u.toast('请选择数据')
return;
}
this.$emit('submit', this.checkboxData)
}
}
}
}
</script>
<style lang="scss" scoped>
.u-popup {
.title {
border-bottom: 1px solid #f7f7f7;
padding: 20rpx;
text-align: center;
font-weight: bold;
}
}
.scroll-Y {
height: 650rpx;
}
.bottons {
background-color: white;
position: fixed;
left: 0;
bottom: 0;
right: 0;
bottom: constant(safe-area-inset-bottom);
bottom: env(safe-area-inset-bottom);
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<view style="background-color: #FFFFFF;">
<view class="searchContent">
<view class="searchBox">
<u-icon class="uIcon" name="search"></u-icon>
<u-icon v-if="searchValue" name="close-circle-fill" @click="searchValue = ''" class="uIcon closeSearch"></u-icon>
<input :placeholder="placeholderStr" v-model="searchValue" confirm-type="search" class="searchInput" :focus="inputFocus" @confirm="searchFun"></input>
<view v-if="btnStr != 'AGV'" class="searchBtn searchBtnA" @click="searchFun">{{btnStr}}</view>
<!-- <view v-else class="searchBtn">搜索</view> -->
</view>
</view>
</view>
</template>
<script>
export default {
props: {
placeholderStr: {
type: String,
default: '请输入搜索内容'
},
btnStr: {
type: String,
default: '搜索'
},
inputFocus: {
type: Boolean,
default: false
},
svProp: {
type: String,
default: ''
}
},
data() {
return {
searchValue: ''
}
},
created() {
if(this.svProp) {
this.searchValue = this.svProp;
}
},
methods: {
searchFun: function() {
this.$emit('searchViewClickFun', this.searchValue)
if(this.btnStr == '添加') {
this.searchValue = ''
}
},
scanIconClickFun: function() {
uni.scanCode({
success: (res) => {
this.searchValue = res.result;
this.searchFun();
}
})
}
}
}
</script>
<style>
.searchContent {
display: flex;
align-items: center;
width: 686rpx;
height: 100rpx;
margin-left: 32rpx;
}
.searchBox {
width: 686rpx;
height: 66rpx;
margin: 16rpx 0;
box-sizing: border-box;
border-radius: 31rpx;
background-color: #eeeded;
display: flex;
align-items: center;
font-size: 15px;
overflow: hidden;
position: relative;
}
.closeSearch {
position: absolute;
right: 128rpx;
}
.searchInput {
width: 440rpx;
padding: 0;
height: 50rpx !important;
min-height: 50rpx !important;
line-height: 50rpx !important;
font-size: 14px;
margin-left: 16rpx;
}
.searchBox>.uIcon {
width: 50rpx;
height: 50rpx;
padding: 16rpx;
}
.searchBtn {
position: absolute;
right: 0;
width: 108rpx;
height: 100%;
line-height: 66rpx;
text-align: center;
color: #fff;
background-image: linear-gradient(to right, #a0b1c0, #858891);
}
.searchBtn:active {
background-image: linear-gradient(to right, #858891, #a0b1c0);
}
.searchBtnA {
background-image: linear-gradient(to right, #3b9dec, #4471ed);
}
.searchBtnA:active {
background-image: linear-gradient(to right, #4471ed, #3b9dec);
}
</style>

View File

@ -0,0 +1,231 @@
<template>
<view class="SkelttionBox">
<!-- 首页的骨架屏 start -->
<view v-if="SkelttionType=='index'" class="SkelttionIndexBox">
<view v-for="(item, index) in 2" :key="index" class="cardList">
<view class="grxinxi">
<view class="tx"></view>
<view class="grms">
<view></view>
<view></view>
</view>
</view>
<view class="wenben"></view>
<view class="wenben"></view>
<view class="imgList">
<view class="imgView" :class="index == 1 ? 'imgView1' : ''" v-for="(ooo, iii) in 4 * (index + 1)" :key="iii"></view>
</view>
<view class="bbList">
<view class="bbbtn" v-for="(item, index) in 4" :key="index"></view>
</view>
</view>
</view>
<!-- 分类 start -->
<view v-else-if="SkelttionType=='classify'" class="SkelttionClassify">
<view class="ClassifyRight">
<view class="htCard" v-for="(items,indexs) in 10" :key="indexs">
<view class="imgCard"></view>
<view class="contentBox">
<view></view>
<view></view>
</view>
<view class="btn"></view>
</view>
</view>
</view>
<!-- 分类 end -->
<!--msg-->
<view v-else-if="SkelttionType == 'msg'" class="SkelttionIndexBox">
<view v-for="(item, index) in 12" :key="index" class="cardList" style="border-width: 0;">
<view class="grxinxi">
<view class="tx"></view>
<view class="grms">
<view></view>
<view></view>
</view>
</view>
<view class="wenben"></view>
<view class="itemWenben"></view>
<view style="border-bottom: 4rpx solid #f2f2f2; margin-top: 12rpx;width: 96%;"></view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
SkelttionType: {
type: String,
default: 'index'
}
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
// #f3f4f6
.SkelttionBox,
.SkelttionProuctBox,
.SkelttionMember {
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
}
// start
.SkelttionIndexBox {
width: 100%;
.cardList {
width: 100%;
padding: 20rpx 26rpx;
box-sizing: border-box;
border-bottom: 16px solid #f2f2f2;
}
.grxinxi {
display: flex;
align-items: center;
margin-bottom: 8px;
position: relative;
}
.tx {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
margin-right: 8px;
background-color: #f2f2f2;
}
.grms {
width: 320rpx;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
view {
background-color: #F2F2F2;
height: 28rpx;
}
view:last-child {
margin-top: 16rpx;
}
}
.wenben {
width: 96%;
height: 26rpx;
background-color: #F2F2F2;
margin-bottom: 12rpx;
}
.itemWenben {
width: 96%;
height: 88rpx;
background-color: #F2F2F2;
}
.imgList {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.imgView {
width: 224rpx;
height: 224rpx;
margin-right: 10rpx;
border-radius: 10rpx;
background-color: #F2F2F2;
margin-bottom: 10rpx;
}
.imgView1 {
width: 220rpx;
}
.bbList {
margin-top: 20rpx;
display: flex;
justify-content: space-between;
.bbbtn {
width: 81rpx;
height: 44rpx;
border-radius: 4rpx;
background-color: #F2F2F2;
}
}
}
// end
// start
.SkelttionClassify {
width: 100vw;
height: 100vh;
display: flex;
justify-content: space-between;
.ClassifyRight {
width: 590rpx;
height: 100%;
background: rgba(244, 244, 245, 0.4);
box-sizing: border-box;
padding: 40rpx 20rpx;
.htCard {
width: 100%;
display: flex;
align-items: center;
border-bottom: 1rpx solid #ececec;
padding: 20rpx 0;
position: relative;
background-color: #FFFFFF;
.imgCard {
width: 100rpx;
height: 100rpx;
overflow: hidden;
border-radius: 12rpx;
background-color: #F2F2F2;
margin-right: 26rpx;
}
.contentBox {
width: 280rpx;
height: 100%;
}
.contentBox>view {
background-color: #F2F2F2;
height: 30rpx;
}
.contentBox>view:last-child {
margin-top: 16rpx;
}
.btn {
width: 100rpx;
height: 56rpx;
background-color: #F2F2F2;
border-radius: 28rpx;
position: absolute;
right: 14rpx;
bottom: 40rpx;
}
}
}
}
// end
</style>

View File

@ -0,0 +1,626 @@
<template>
<view>
<view class="topSxRow">
<u-dropdown ref="uDropdown" class="bgWhite" duration="200" @open="dropdownOpenFun"
@close="dropdownCloseFun">
<u-dropdown-item v-model="value1" :title="label1" :options="options1"
@change="dropdownChange"></u-dropdown-item>
<u-dropdown-item v-if="dropdown2" v-model="value2" :title="label2" :options="options2" height="666"
@change="dropdownChange" class="whiteNoWrap"></u-dropdown-item>
<u-dropdown-item v-if="isPaiXu" title="排序"></u-dropdown-item>
<u-dropdown-item v-if="isSxShow" title="筛选"></u-dropdown-item>
</u-dropdown>
<navigator v-if="searchUrl" :url="searchUrl" class="topSearchView">
<u-icon name="search" size="36" color="#666666"></u-icon>
</navigator>
<view v-else class="topSearchView" @click="searchShow = true">
<u-icon name="search" size="36" color="#666666"></u-icon>
</view>
</view>
<!--侧边栏弹窗-->
<u-popup v-model="popupShow" width="568rpx" mode="right" border-radius="14" :safe-area-inset-bottom="true"
@close="popupCloseFun">
<view v-if="isKhShow && dropdownNum == 2" class="popupCard">
<view class="popupTitle">客户名称</view>
<view v-if="selectKhList.length == 0" class="kehuRow" @click="selectKhShowFun">选择客户</view>
<view v-else class="kehuRow" @click="selectKhShowFun">已选<text class="greenColor">{{selectKhList.length}}</text>条数据</view>
</view>
<view class="popupCard" v-for="(obj, index) in sxArr" :key="index">
<view class="popupTitle">{{obj.title}}</view>
<view class="popupItem">
<view v-for="(item, iii) in obj.arr" :key="iii"
:class="{activeClass: obj.current === iii, mr0: (iii+1) % 3 == 0 }" class="itemCard"
@click="sxItemClickFun(index, iii)">
<view v-if="item == '自定义'">{{item}}</view>
<view v-else>{{item}}</view>
</view>
</view>
<view v-if="obj.current === obj.arr.length - 1 && obj.isDate" class="dateRow">
<picker mode="date" :value="obj.startDate" start="1999-01-01" end="2199-12-30"
@change="bindStartDateChange" @click="startIndex = index">
<view class="DateInput">{{obj.startDate}}</view>
</picker>
<view class="marLR16">~</view>
<picker mode="date" :value="obj.endDate" start="1999-01-01" end="2199-12-30"
@change="bindEndDateChange" @click="endIndex = index">
<view class="DateInput">{{obj.endDate}}</view>
</picker>
</view>
<view class="flexJs" v-if="obj.judge">
<text>等于</text>
<u-icon name="arrow-right"></u-icon>
</view>
</view>
<view class="h200"></view>
<view class="popupBottomBtn">
<view class="popupBtn warning" @click="resetFun">重置</view>
<view class="popupBtn primary" @click="confirmFun">确定</view>
</view>
</u-popup>
<!--搜索弹窗-->
<u-popup v-model="searchShow" mode="center" width="666rpx" border-radius="14" :closeable="false">
<view class="searchBox">
<view class="searchTitle">搜索</view>
<u-field v-if="searchLabel1" v-model="searchValue1" :label="searchLabel1" :placeholder="searchPh1"
clear-size="40"></u-field>
<u-field v-if="searchLabel2" v-model="searchValue2" :label="searchLabel2" :placeholder="searchPh2"
clear-size="40"></u-field>
<view class="searchBtnRow">
<u-button type="warning" class="searchBtn" :ripple="true" ripple-bg-color="#909399" :plain="true" size="medium" @click="searchShow = false">取消</u-button>
<u-button type="primary" class="searchBtn" :ripple="true" ripple-bg-color="#909399" :plain="true" size="medium" @click="searchBoxFun">确认</u-button>
</view>
</view>
</u-popup>
<!--客户查询弹窗-->
<u-popup v-model="khPopupShow" width="568rpx" mode="right" border-radius="14" :safe-area-inset-bottom="true"
@close="khPopupShow = false">
<view class="popupCard">
<view class="popupTitle">选择客户(已选
<text v-if="selectKhList.length == 0">0</text>
<text v-else class="greenColor">{{selectKhList.length}}</text>
)</view>
<u-search placeholder="请输入客户名称搜索" v-model="keyword" :animation="true" @search="searchKhBtnFun" @custom="searchKhBtnFun"></u-search>
</view>
<scroll-view scroll-y="true" class="khScrollView" @scrolltolower="searchKhFun">
<u-checkbox-group @change="checkboxGroupChange" :wrap="true" class="checkBoxGroup">
<u-checkbox class="popupCard" v-model="item.checked" v-for="(item, index) in khList" :key="item._id" :name="item._id">{{item.clientName}}</u-checkbox>
</u-checkbox-group>
</scroll-view>
<view class="popupBottomBtn">
<view class="popupBtn warning" @click="resetKehuFun">重置</view>
<view class="popupBtn primary" @click="khPopupShow = false">确定</view>
</view>
</u-popup>
</view>
</template>
<script>
let that = '';
import {
getDayByNumFun,
getWeekFun,
getDayFun,
getMonthFun,
getSZDateFun,
lastMonthFun
} from '../../static/utils/date.js'
import { crmKeHuApi } from '../../static/utils/api.js'
export default {
props: {
pageType: {
type: String,
default: ''
},
options1: {
type: Array,
default: () => []
},
options2: {
type: Array,
default: () => []
},
optionsSx: {
type: Array,
default: () => []
},
optionsPx: {
type: Array,
default: () => []
},
dropdown1: '',
dropdown2: '',
searchUrl: '',
isSxShow: { //
type: Boolean,
default: false
},
isPaiXu: { //
type: Boolean,
default: false
},
isDuoXuan: { //
type: Boolean,
default: false
},
isKhShow: { //
type: Boolean,
default: false
},
searchLabel1: '',
searchLabel2: '',
searchPh1: '',
searchPh2: '',
isDbDate: false
},
watch: {
dropdown1: function(val, oldVal) {
that.label1 = val;
},
dropdown2: function(val, oldVal) {
that.label2 = val;
},
optionsSx: function(val, oldVal) {
this.sxArr = val;
},
optionsPx: function(val, oldVal) {
this.sxArr = val;
},
isDbDate: function(val, oldVal) {
console.log(val, oldVal)
}
},
data() {
return {
label1: '',
label2: '',
value1: 0,
value2: 0,
sxArr: [],
popupShow: false,
searchShow: false,
khPopupShow: false,
dropdownNum: 0,
startIndex: '',
endIndex: '',
myStartDate: '',
myEndDate: '',
mySTime: '',
myETime: '',
searchValue1: '',
searchValue2: '',
clientName: '',
clientId: '',
keyword: '',
khPageIndex: 1,
khList: [],
khIsMore: true,
selectKhList: []
}
},
created() {
that = this;
},
mounted() {
that.label1 = that.dropdown1;
that.label2 = that.dropdown2;
},
methods: {
//
dropdownOpenFun: function(e) {
that.dropdownNum = e;
if (e == 2 && that.isSxShow) {
that.popupShow = true;
that.sxArr = that.optionsSx;
}
if (e == 1 && that.isPaiXu) {
that.popupShow = true;
that.sxArr = that.optionsPx;
}
if (this.pageType == 'fujin') {
this.$emit('clickDropDownFun');
}
},
dropdownCloseFun: function(e) {
if (this.pageType == 'fujin') {
this.$emit('closeDropDownFun');
}
},
//
popupCloseFun: function() {
that.$refs.uDropdown.close();
},
//
dropdownChange: function(e) {
console.log(e)
if (that.dropdownNum == 0) {
that.label1 = that.options1[e].label;
that.value1 = e;
that.$emit('dropDownFun1', that.options1[e]);
} else if (that.dropdownNum == 1) {
that.label2 = that.options2[e].label;
that.value2 = e;
that.$emit('dropDownFun2', that.options2[e]);
}
},
//
sxItemClickFun: function(index, iii) {
let item = that.sxArr[index];
let list = that.sxArr;
if (that.dropdownNum == 2 && that.isDuoXuan) {
} else {
for (var i = 0; i < list.length; i++) {
if (i != index) {
list[i].current = '';
}
}
}
if (item.current === iii) {
item.current = '';
} else {
item.current = iii;
if (item.isDate == 1) {
if (item.current == item.arr.length - 1) {
let dateArr = getDayByNumFun(30, true);
item.sTime = dateArr[0];
item.eTime = dateArr[1];
item.startDate = dateArr[2];
item.endDate = dateArr[3];
} else {
let dateArr = that.setDateFun(iii);
item.sTime = dateArr[0];
item.eTime = dateArr[1];
}
} else if(item.isDate == 2) {
if (item.current == item.arr.length - 1) {
let dateArr = getDayByNumFun(-10, true);
item.sTime = dateArr[1];
item.eTime = dateArr[0];
item.startDate = dateArr[3];
item.endDate = dateArr[2];
} else {
let dateArr = that.setDateFun1(iii);
item.sTime = dateArr[1];
item.eTime = dateArr[0];
}
}
}
that.$set(that.sxArr, index, item)
},
//
resetFun: function() {
let list = that.sxArr;
for (var i = 0; i < list.length; i++) {
list[i].current = '';
}
that.sxArr = list;
},
//
confirmFun: function() {
that.popupShow = false;
that.$refs.uDropdown.close();
if (that.dropdownNum == 2) {
if(that.isKhShow) {
that.$emit('optionSxFun', {
arr: that.sxArr,
selectKhList: that.selectKhList
});
} else {
that.$emit('optionSxFun', that.sxArr);
}
} else {
that.$emit('optionPxFun', that.sxArr);
}
},
//
bindStartDateChange: function(e) {
let item = that.sxArr[that.startIndex];
item.startDate = e.detail.value;
item.sTime = new Date(e.detail.value + ' 00:00:00').getTime();
that.$set(that.sxArr, that.startIndex, item);
},
bindEndDateChange: function(e) {
let item = that.sxArr[that.endIndex];
item.endDate = e.detail.value;
item.eTime = new Date(e.detail.value + ' 00:00:00').getTime();
that.$set(that.sxArr, that.endIndex, item);
},
//
setDateFun: function(i) {
let dateArr = [];
if (i == 0) {
dateArr = getDayFun();
} else if (i == 1) {
dateArr = getDayByNumFun(1)
} else if (i == 2) {
dateArr = getWeekFun();
} else if (i == 3) {
dateArr = getSZDateFun();
} else if (i == 4) {
dateArr = getMonthFun();
} else if (i == 5) {
dateArr = lastMonthFun();
} else if (i == 6) {
dateArr = getDayByNumFun(7);
} else if (i == 7) {
dateArr = getDayByNumFun(90);
}
return dateArr
},
//
setDateFun1: function(i) {
let dateArr = [];
if (i == 0) {
dateArr = getDayByNumFun(-1)
} else if (i == 1) {
dateArr = getDayByNumFun(-3)
} else if (i == 2) {
dateArr = getDayByNumFun(-7)
} else if (i == 3) {
dateArr = getDayByNumFun(-15)
} else if (i == 4) {
dateArr = getDayByNumFun(-30)
}
return dateArr
},
//
searchBoxFun: function() {
that.searchShow = false;
that.$emit('searchBoxEmitFun', {
searchValue1: that.searchValue1,
searchValue1: that.searchValue1
});
},
//
selectKhShowFun: function() {
that.khPopupShow = true;
if(that.khList.length == 0) {
that.searchKhFun()
}
},
//
searchKhBtnFun: function() {
that.khIsMore = true;
that.khPageIndex = 1;
that.searchKhFun();
},
//
searchKhFun: function() {
if (!that.khIsMore) {
return
}
uni.showLoading({
title: '加载中...',
mask: true
})
let reqObj = {
pageIndex: that.khPageIndex,
sortObj: {
update_date: 1
},
searchValue: that.keyword
}
let reqData = {
action: 'selectKhNameId',
params: reqObj
}
crmKeHuApi(reqData)
.then(res => {
let data = res.result.data
if (that.khPageIndex == 1) {
that.khList = [];
}
if (data.length == 20) {
that.khPageIndex += 1;
that.khIsMore = true;
} else {
that.khIsMore = false;
}
that.khList = that.khList.concat(data);
})
},
// checkboxcheckbox-group
checkboxGroupChange: function(e) {
that.selectKhList = e;
},
//
resetKehuFun: function() {
let list = that.khList;
for(var i = 0; i < list.length; i++) {
list[i].checked = false;
}
that.selectKhList = [];
that.khList = list;
},
}
}
</script>
<style>
.topSxRow {
display: flex;
align-items: center;
border-bottom: 1rpx solid #F8F8F8;
}
.topSearchView {
width: 100rpx;
background-color: #FFFFFF;
height: 80rpx;
display: flex;
align-items: center;
padding-left: 20rpx;
box-sizing: border-box;
}
/*************************弹窗层******************************/
.popupCard {
width: 100%;
padding: 26rpx 16rpx;
border-bottom: 1rpx solid #efefef;
}
.popupTitle {
font-size: 16px;
font-weight: bold;
margin-bottom: 26rpx;
}
.popupItem {
font-size: 15px;
color: #666666;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.itemCard {
width: 160rpx;
height: 66rpx;
text-align: center;
background-color: #e6e6e6;
margin-bottom: 26rpx;
border-radius: 16rpx;
margin-right: 28rpx;
overflow: hidden;
}
.itemCard>view {
height: 100%;
line-height: 66rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.itemCard:nth-child(3),
.mr0 {
margin-right: 0 !important;
}
.flexJs {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.popupBottomBtn {
width: 100%;
height: 100rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
position: fixed;
bottom: 0;
font-size: 15px;
}
.settingView {
width: 128rpx;
height: 100% !important;
display: flex;
align-items: center;
justify-content: center;
}
.popupBtn {
width: 50%;
height: 100% !important;
line-height: 100rpx;
text-align: center;
color: #FFFFFF;
border-radius: 0 !important;
}
.activeClass {
background-image: linear-gradient(45deg, #007AFF, #00aaff);
color: #FFFFFF;
}
.u-dropdown__menu__item {
white-space: nowrap !important;
}
.dateRow {
display: flex;
align-items: center;
}
.DateInput {
border: 1rpx solid #DEDEDE;
padding: 10rpx 26rpx;
border-radius: 8rpx;
}
.marLR16 {
margin: 0 16rpx;
}
.uni-picker-container .uni-picker-custom {
z-index: 888888 !important;
}
.u-drawer {
z-index: 998 !important;
}
.searchBox {
padding: 16rpx 26rpx;
}
.searchTitle {
width: 100%;
border-bottom: 1rpx solid #DDDDDD;
font-size: 16px;
font-weight: bold;
text-align: center;
padding-bottom: 16rpx;
}
.searchBtnRow {
margin: 26rpx 0 16rpx 0;
display: flex;
align-items: center;
justify-content: space-around;
}
.searchBtn {
width: 200rpx;
height: 66rpx;
}
.u-field {
font-size: 15px !important;
}
.kehuRow {
width: 100%;
height: 66rpx;
line-height: 66rpx;
text-align: center;
background-color: #e6e6e6;
margin-bottom: 16rpx;
border-radius: 16rpx;
}
.khScrollView {
width: 100%;
height: calc(100vh - 145px);
}
.checkBoxGroup {
margin-bottom: 100rpx;
}
.warning {
background-color: #ff9900;
}
.warning:active {
background-color: #ffaa00;
}
.primary {
background-color: #2979ff;
}
.primary:active {
background-color: #55aaff;
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<view class="tishi">
<u-popup v-model="show" border-radius="26" mode="center" :mask-close-able="false" length="60%">
<view class="popupClass">
<view class="popupTitle">上传进度{{percent}}%</view>
<u-image class="popupImg" width="100%" height="300rpx" :src="showImg"></u-image>
<u-line-progress class="progress" height="36" active-color="#2979ff" :percent="percent">
</u-line-progress>
</view>
</u-popup>
</view>
</template>
<script>
let _self = ''
export default {
props: {
ppList: {
type: Array,
default: () => []
},
ppUrls: {
type: Array,
default: () => []
},
imgType: {
type: String,
default: 'product'
}
},
data() {
return {
show: true,
percent: 0,
urls: [],
index: 0,
showImg: ''
}
},
async created() {
_self = this;
let ppUrls = _self.ppUrls;
let ppList = _self.ppList;
let arr = ppUrls;
for (var i = ppUrls.length; i < ppList.length; i++) {
_self.index = i;
_self.showImg = ppList[i].url;
let obj = await _self.uploadImgFun(ppList[i].url)
arr.push(obj);
}
_self.$emit('confirmPopupFun', arr);
},
methods: {
uploadImgFun: function(path) {
return new Promise(reslove => {
let date = new Date();
let typeSrc = '.png';
let xxx = path.lastIndexOf(".");
typeSrc = path.substring(xxx, path.length);
const result = uniCloud.uploadFile({
filePath: path,
cloudPath: 'image/' + _self.imgType + '/' + date.getFullYear() + '/' + (date.getMonth() + 1) + '/' +
date
.getDate() + '/' +
date.getTime() + Math.ceil(Math.random() * 100) + typeSrc,
onUploadProgress: (progressEvent) => {
_self.percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
}
})
.then(res => {
// 访
uniCloud.getTempFileURL({
fileList: [res.fileID]
})
.then(ddd => {
let obj = {
url: ddd.fileList[0].tempFileURL,
fileId: ddd.fileList[0].fileID
}
reslove(obj)
})
.catch(err => {
uni.showModal({
title: '错误提示',
content: err.toString(),
showCancel: false
})
})
})
.catch(err => {
uni.hideLoading();
uni.showModal({
title: '错误提示',
content: err.toString(),
showCancel: false
})
})
})
}
}
}
</script>
<style>
.popupClass {
position: relative;
}
.popupTitle {
width: 100%;
text-align: center;
margin-top: 16rpx;
font-weight: bold;
font-size: 30rpx;
}
.popupImg {
width: 80% !important;
margin-left: 10%;
margin: 26rpx 10%;
}
.progress {
width: 80%;
margin: 0 10% 26rpx;
}
</style>

View File

@ -0,0 +1,23 @@
@font-face {font-family: "iconfont";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMoAAsAAAAABzAAAALaAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDHAqBbIFSATYCJAMQCwoABCAFhG0HRhtCBsgOJUGS2IBhSABBPHyN/f7c3UVEk2hkSKLNE9NNSrBEgkhrJIYS7JuG/v7Pv7cbyBNUBB7u+/D8Cczd0qrAKui2UweV2+2Jz3M5bQIFMr+d5TbWojXpyo96AcZbAxpr0xYuoAS5pXYRBwav/GubCdQbFslkvbiyEawVpFcgLhUyDqx7fkWJUrVC9czEIh5YqE136RTAvf5+/IP4qCWpysjA3eMiEXJ/OnyLyVeVK52SRnqdC9E0MmaAQpzOxveZiYhjpr65uTmgVq3EVTXhP2MqFWvjw2L6l0dIMlGNkBvBrJfI/HTgBMHPcILEzxiSDAjR1faT88CGzx5UBz2+19V1ZP+Ku9i8v3xj0oPb8/DYW/HyOvCSHUz14N7Vleu2waXja7bOy1cOj1ridz1feeqBe5fDdm2dr93ynUqZbj7cXLr14cePR99QnyP4HxIbUmdfHxcc//rLnQ8Udwy/eHERdvFCLbSSeTLhHOI8cZIp+nn9/Hx4LPDc6fx1uum/+27vJ0s30CNb5dvUA0B+MVUAkD+bPkH2b3y7s5Xb45T5z7qhgFfGPmpTAdMCxqRgKWqlwJxSyom1lFzBJZWv6AX1SKhXD4SmafflCl0XOJtQq+uAr8ZQi6zWCL2wZ1ClwSyq1VpCvWkl0xt0oMxEqcOUOQeh1X0kzZ6QtTqjF/ZnVOn2F9VaI6PeXrgt2GAszmwLKHIMRcIPEYWg00rMzmxNZj3K+tQc7co1txmpUREicdGxw1QJapFeMcTYL4tnTCIS1WlIsbMdqtU6oqc6JQosWs6YPj0mRpq7UbSg04CtNRTiMEhE8IYQCgIdLUkWZmxHn6+HZPqocegKZSHaDFFGivqJONFiAfQSjRZE+ZVrjPrJxGMYCSGhdDSIYseF1DSuQ+jn2ykhARNNfiCqly7GyydBNdHP6zR/uAjqkcVLpMhRokrVgRwFla1SwWmZrm9Q6awaMwAAAA==') format('woff2')
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-check:before {
content: "\e60d";
}
.icon-arrow-down:before {
content: "\e62a";
}
.icon-arrow-up:before {
content: "\e62f";
}

View File

@ -0,0 +1,36 @@
.loader-one {
width: 50rpx;
height: 50rpx;
position: relative;
-webkit-animation: loading-one 1s infinite linear;
animation: loading-one 1s infinite linear;
}
.loader-one,
.loader-one:after {
border-radius: 50%;
}
@-webkit-keyframes loading-one {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loading-one {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}

View File

@ -0,0 +1,901 @@
/*!
author:kooboy_li@163.com
MIT licensed
*/
let base = 19968,
middle = (40896 - base) / 2;
let EMPTY = '';
let COMA = ',';
let chars = (() => {
let a = [];
for (let i = 33; i < 127; i++) {
if (i != 34 && i != 92 && i != 45) {
a.push(String.fromCharCode(i));
}
}
return a.join(EMPTY);
})();
let SDB = {
"a": {
"yi": "!]#R$!$q(3(p)[*2*g+6+d.C.q0[0w1L2<717l8B8E9?:8;V;[;e;{<)<+<S<]=9>.>4??@~A`BbC:CGC^CiDMDjDkF!H/H;JaL?M.M2MoNCN|OgO|P$P)PBPyQ~R%R.S.T;T<TBTqT|UQUXU}V[WCXgYCYDY_YdYuZ9Zs];]j]p]q^.^@^S^w^x_,_T`H`J`ga)a8aQb9budJddgoh9hqi2itj&jEjRj]jzk>k^l$l<mLmdnDoEoMoQoop3p5pWp`qSr.u'uLv]wIxXy_y~{z}`~r-$=-$X-$Y-%!-%0-%j-&^-&s-'t-(<-)2-*n-+6-+f-/M-/N-0.-2|-3u-4b-4c-4m-5E-5N-5Z-5l-6&-6+-7*-70-73-8F-8R-8g-:*-:5",
"ding": "!2%%&_&x'u=:=h@NC`H?LQNkQ3Xo^Gn?osrUsNvAwKxKy9-!T-$6-$v-%O-&b-(+-9%-9(",
"zheng": "!S#(#D/]031$456+=L?OIzYM[']I^g_.eUl}m~qJsHulwuxU-!?-,d-3D",
"kao": "<dLWr5x7-!J-,7-/Y-/s-2'",
"qiao": "#+$4&.&1'7'Y'z($(),B,{0c7y8<:H<8<YE{F0GdKYMCZP]Y_8_zd.d/d{e5fGfHfUmKmrmvp#t>t?uJv$vMyE|R}a-!}-#&-#8-#L-#b-$Q-%?-+q-,6-,8",
"yu": "#V$l%S&9&I('(7(=)))m*#*$*B+2+F+v,0,b,i.W0.1F232L2a3(384>6P8n;';i;y<1>(>)>]@iB<B?BDBEC'C*CoCpELE^HIHJHTIpJIJ`KXL&L1LxMbMqNXNqPdPsQ<RFT?U(URV7WnX:Z?ZT[6[H]!]~_7_J_``Za#eXg;h#hVhuiyj!j#k9kDkMl#lClUlmmUnFoAp(pzqnrSsSt0vJwszp{_|N}!}$}I}t~(~,~.~w-$D-$]-%^-&j-';-'k-(3-(H-(v-*1-*Z-+#-+d-+{-.1-.2-.<-.K-.[-.e-/d-0=-0P-1:-1m-39-3`-3b-3e-41-5e-5}-6/-6;-6p-7:-7Z-:(-:2-:F",
"qi": "!8%&%>&X&m&s'2'X'd'f(9(c(i(j)@)l+'+M.).+1y1{2=3K4c6&6'6)606<6B6`9`9{:a<g>`?`AgCLCuD%D2F2GyH&H1I;K~LkLuM&MYO0O3O9P8PbPcQqR5S2SCU0U~V%XYY&Z}[G^P`7cUc}dEeNgOj$j)l?m:n4p,sOuRv.y'{/|i}1~P-$B-%Y-)|-)}-*K-+G-+H-,m-.@-.M-/|-0y-2D-2c-4W-4`-4h-7a-7p-9c-9i",
"shang": ")Y6V9cJvR8UqXJXa])asbQc,s,uSvz-#+-.;",
"xia": "#Y#w&,&;'''I)1.u/j7=:[<'B[ByCtL'NmNyQOR([0`(cLh[iRkVt/t_u4uezFzM|W|{~d-&)-*4-.}-0a-5;-8S",
"han": "#,.m/h:l<P>MFrGXJqNrOUPCPqPrQ|]@`+`2h1lBlZnXp*r;rWrkz9{4{B}x-#c-#y-$;-$l-$y-%Q-%n-(i-(x-)i-/!-3*-5B-9V",
"wan": "#=$0&o.]0F4@5X5b6*628u9p<K?e?h@IChFqG!G7H2HHJzL=O5Q'RQ`;a:b<bGeHh&h)rMr^s'slu!-$E-%V",
"mo": "!`#$#&#y$%%P'e(T*N3v5$517`8R=6?XA5E6FZF~JLM;MgP+RTRcU6]'](_j`s`x`y`za+qkuDyR|G-!e-'g-($-(U-*R-+k-,(-.U-.k-.{-8/-80-8K-8L",
"zhang": "#~(#.:2o3N>k@,JhR`b$b`knmtujz'z0}<-#+-'I-*Q-16-7m",
"san": "3T3q3w3x7~uJuwzA-'n-([-,s",
"ji": "#r%''l'y)3)d)o*Z+'+9+G+M+T+Z+^+g+x._.c/R090d1S1W2;43484J4R5C5w6)6C6`7f7s878H8t8w9J9X9Z9{;8;<;B;C=(=2>6?YA$B+CHD0D8DbE:EQF2I*I|JEJnKKL)L:LkLzMdN'N5N:NiQ6QyRrUWVcVnWPWQWtX6XEXYXuY(ZAZ|[/]O]e^F^J^U^~`)b#b0c*ckc}dee!e$e9e>eyf+fXfrg)hFhriMjZlrqmr)sRt%uov3vevw|@};}N}g~!~+~F~{-!&-!u-#N-$%-&a-'u-(,-*x-+]-,W-.?-.V-._-.d-.g-/+-0$-0H-1%-1/-10-1^-1o-2/-2@-3'-4)-4o-5>-5H-5U-6,-6J-7/-7P-9e-9g-9h-9i-9j-:l",
"bu": "0$192,FKJgT=UYZ^e+hhjmm8mFoGpGp}sjw]w{-'7-'E-/m-3#-4.-6=",
"fou": "4I:L:O:Q~1-3:",
"mian": "!G!d#4$U$W$]3Y5X6A6_6o9g9w@qB/CkG!H_Q;-!L-!M-!P-/_-7y-7z-8'-8,-8q-8r",
"gai": "):5=5LD,ErI!J1Z'_/`TaYaac!lnpcw[|O}1",
"chou": "!+#n$N+0/y0}2:4e5/6#9jB*B.GNLfUmZ+^3^5_4e%e4fWkan]nbo.o6oU}u~$~*-.X-/>",
"zhuan": "%H'S'V.K0k1B1H1r2?7Z<r@RA7IDRsVk[J]Tb3b<c8gThai'mp-%+-%u-'p-(]-14",
"qie": "%>+7+f,8.#.|0K0p2O>#DNE1P.ccd]eMlpt8y>-0&",
"ju": "!Z$L$w%R*W,c,l/e1~3&3J8#:t=#=`=k@FBGC0DlD}FeGAIaIkJbMrN[OVP`RDTlU|W>Y`[$^Z`Ua*ccc{dWd]dae#e@eFeff8fSg*g<guh~l'lXmIoOq(rps%vXw_x|y;zb|m}o-#/-#:-&4-&Q-)<-)?-)d-*z-+0-/.-/:-3[-48-4S-4k-5.-9H-9K-9x-:@",
"pi": "#M%D'C(5(6)L*F*K+;.n1C4M8}:y;/;2;A<,<{>a@'@2@KA%C|DQO+O]O^PvR!REScU'UfZw]m`l`na'i[l_m;p<pYpyqCqyr*s1s;trx4{8|*|=|p}F-!!-#,-)@-,H-.p-/#-/3-2#-3>-4F-6'-63-91",
"shi": "!E!Q!e#?$p%$&+'$([(](q*^.&/5/n0[1w204z<gBNBQG)I:ISIUJ3NlN{Q>QQR9VYW2W@W^X2XNYxY{ZI[:[<[v]X^l^{^}_p`DaDbmgqi8ixjdk!kNkpl(lkntoMo^ocoeofp5ppq%q&q*q4qbr=t9x/-&^-&_-&}-'<-'@-(*-(8-)!-)H-+,-/<-0?-0d-0o-0p-2:-2O-3+-38-57-6M-9C-9E",
"qiu": "*6*7+a0r3k4D5]6j>7CaCeF`HEJXMhNgNjONP;QMQ_RfSWUUX?XUXqXrajc$d'jpjskXl]n@o.oup:r?-#5-#6-$8-/'-/k-0W-0X-1,-2Z-4v-7&-9U-:Y-:Z-:]",
"bing": "!n)F*4+/,>.75@DsOcZ7l`puqar||>-!:-!q-#,-#G-''-'C-(D-/O",
"ye": "$>$E(0,a6g=;@?HfSb[]_]lUlfn(oip=rmtDtTtevTx?-!O-!R-$5-%N-'F-'e-(T-*o-4Y-61",
"cong": "$'&Y1>8==g=l=p=vDIE=I2JUK0LsRZZk]$a}a~sKtBuKu_-*)-*V-+Y",
"dong": "&&.r0b5D?7?C@JD|G;I#KwQ([&jV~^-)T-/=-0)-4g-5/-6T-9,",
"si": "'?(b)^)g)p*+.</#40415O6i8l9~;.<|<}>+>0KxL+NLP7PiQnReS&W_`tp1pvp{qTqnr8r`tIuzyB-&6-&R-&^-&c-&s-&{-(:-)L-)q-*8-+.-0.-5j-6`-9N-:o",
"cheng": "#0$,$P&W*O*[*w+A+{,O,v/l5[7#:`?}FQOoS(UKZV_#cHcJk#m$nhrxtkuxv@vWx=xB|2-!A-$h-'w-)o-*>-+B-/u",
"diu": "r2xL-&&",
"liang": "3A3D3{6K@0CRF{Q%Up[,_Oe1h!h2hCiBiHojss-!=-)h-.J-.O",
"you": "(r)O*I7o8W;L;f=5=M>VDKFoFsFwG/KaOOOSPSQLY8ZN_;`qh%hMjWjnk6kPlYmEn3n>ncodp~r3x&x<-),-.y-/1-1p-1z-7N-8P-9D",
"yan": "##%F%L&%&F&T&v(Z,j/u1?2$5t7V;!;h?<@@AsCVCYCZD3FmGpH.JlN_PVQAT$UxV9WUX/XkXmXnY?Z3[U^1^C^E_e_~`B`C`RbDbPc;g/g7kIm#mNmsn5nHnsnyoPoVo`x+z7zkzmzn{A{`{e|}}2}b-%'-%,-%B-%v-'0-(#-)~-*$-*F-*j-*s-+C-.4-.H-.Y-0V-3$-3*-3B-3n-5#-5G-5u-7K-7r-8T-8W-8_-8`-8a-8d-8j-9L-9Q-9w-:1-:N",
"sang": "'EVNts-%2-%{",
"gun": "#<&#'U6F6z9dJ>JpTFTwUu]4h<iF-/2-/g-2<",
"jiu": "+E,*42464]8mB:BCBHBMH7cQnGz){Z-#}-#~-,l-./-01-3!-5w-6I-79-7c-:$",
"ge": "&!/30*4?8r>:?B@}AbB3BwECHxJ1NwOrP'U9UPXM[X[hhLhmq`tetlu.xSyUzTzU{W}4-!S-!s-#F-#`-#j-%f-(A-*%-+t-.3-/K-/U-1u-3T-3z-6g",
"ya": "#B%C&{'I*{,a.g=UDEKqO;T1WEWGY.^[g=i!j4lUp=s=v7x;}f-3C-3c-4U-6O-6V-9o-:;",
"pan": "!&!>!?!H!o'L'x2A76=F>R?$AIH<IrRoT{WBY[d[e{f0rvtpw=zx-#E-$J-4D",
"zhong": "#%(n*8+>+m/V2T4{6b99>j@`BnEkK*O:OBP^R2RKSzTKTNTO[@e^f>ohparHtQv5wbyF-3_-9@",
"jie": "#S%@&{(.*d+=.G0e4J5,599D;k=(@/CfD,G#G`J[LzOFP&P:PTQ=SKSQSqT/TITPTlU4U7UPVQXOXSX}Z%ZWZh]/^K^~_5ckdve=j^qGtNtXz,|1}.-!m-!u-$U-%c-&v-+i-.l-/@-2&-4{-5$",
"feng": "!@%N'40m5v7R:3C$FdHnN.PFSaWI[R^c`?b.c5k'n+n;r[u5uXxs-!$-!4-&%-&J-&L-(w-3(-3,-3F-8)",
"guan": "!'$b$j$k(W)B,Y/f0E6:9&:]:gBVFqIEWSW{X+X.a?bifMh?kmsUu>w7zOzS{,{2}{-'K-(N-0q-1N-1j-2e-2z-6D-7A",
"kuang": "!Y!z$Y%1%r%w(G+}/O/z5'538V8vZ<ZG^y_=aNbpgHgRgXg`j+lHlhn/qUrevy-4>-8>",
"chuan": ",40jA7BYB`BhBxEvale[hIkJp%wQ-5+",
"chan": "&6'W)K)q1N6D7$8*8A8[8_:6;xCODJIHKQQ2RGR_R{S1UeW!W`X3ZMZy]B^+^7_N_bfbi|n2n6o@rTr]uWw3xYz%ze{7{g-#Q-%D-%~-(%-(S-+Z",
"lin": "$B&['t0:393O5{8!<WA?B%GsKEMOaWb{fEf]fgfxhlh}iVk{lgn$utzg|9}C~[-*a-1G-2t-7_-7n",
"zhuo": "#'&Q)a+l,%,V,]102E2`8?:J;&=NE.HtJ:L|SJSsZx[+]6_Fd!nArfvLvOy|-4J-5d-:x",
"zhu": "!a$6$h%^%v'f)!)/*h,@.4.S.T.[.w/P/o0]0n141=1a4n4q5.9+:s;W<EBrD/DVDpE_EmFYHtJQKZMMO`O{QTS>S]SrU;V<YLYoZ;[S_$_B`[aCbhdVdjfRggjMjrk1ljq6q{r}vbwExIx`|x-&r-(~-)=-)]-+2-/H-0E-11-3s-6(-7T-7V-8x",
"ba": "%#.a3#:y;2;N<z>sD5E4GTO$WNYk`LdDdNgjozp?wr~~-!a-&.-.D-.`-/&-/0-1t-1v-1}-9=",
"dan": "!K%$%5)r,S0N1h4V8A=A=B=H=~>q@9ATAVH*JDOkPUTLV?VoXGX~ZK_'a|bBc3f{mHn&nKn~~t-$I-'G-'s-)*-)a-,C-3Z-8H-8b-8i",
"wei": "#o$M%}&0'#'D'M6/6p6r7+8y9f;6>n@gC+D!DOE+FCGBH)I&I(I4INJ]K$KJL7LdMDN0PwQ$QDQHR?T3T6V`WkX$Z)[#[^^*^4_I_^e;fefig@hbj>k<k[m}nvs~t4uGzz{G}&}'}7}Y~n-!#-#Z-#a-#i-#q-#v-#z-$T-&7-'J-'X-'z-+a-+b-+c-.P-/,-/F-/P-0N-0O-2(-2W-2p",
"jing": "#C*?*u,2.8.9.A.E.P.R042v3F3Q5(5q6!9@=_>g?:?k@<E;EtExFiG8HlS/Z`]ge(jTjwrhuYyi|+-!=-!@-!C-!D-!F-$N-$m-%b-*m-03-2M-4:-4a-4d-7e-7o-9I",
"li": "!!!0#A#E%7%_%m%q'|(K(L(Q(^)u)y*%*H,&.$.J.{/c1.1:2Z3$303G3b4)5}7T8Q8g:7;4@*C%DPDbEEF%FDFWF[GUI[I`JFKIM1MKN4OWOnP#PNPlQaR[S*S:STSVS_ULU_VWXhYY]&^,`9`}cPdbf`hzh{i5jDk+l7l;m6n=oBoNogokqAqururzs3tludvuxjyU}V}W}X~&~8-!+-!5-*}-+A-,^-.3-/p-/v-07-1W-1b-1k-26-29-2x-2~-3Q-4X-5I-6F-6l-7f-7k-8A-8Z",
"pie": "$2DmW]u~",
"fu": "%8%[(u(v)U)j*k*o+:.'/$///_0$0=1j3C3d4a4j4u5B5k5p6q7B8L939<:0:o:}<&>N?#@!@D@E@nA3C!CWC}D*DFE'E,E]EpFFF|GKHKHjJXKsNSODOGOXOwPIPMQEQIQWTETsTvU.V(V6ViW+WKWMXpYS[C^H`Va4a{b4bXc(c7cRd=dZegh*hPhRiAiLlIm(m*mmnQowo|pFq<q@t#t5{s{t|?-#]-#x-$`-&(-&.-(n-)F-+/-,P-.5-/)-/8-/X-0^-1|-2[-2}-3%-34-3N-4H-4}-7x-7{-8#-8*-8o-8p",
"nai": "<p<q?L@=CcH4R'VHj[o}sk-9'",
"wu": "$A%*&l)+,D,o0a2tAMB]D#D<EPFSKvMVPLQzS#Z>ZYZZ]U_6_9d9fYj6j~lWm)mep)rQrbrctvwkxc{y|U}6~?~C~`~m-!Z-*'-+R-/j-0j-3i-4/-4@-5,-5f-6j-6s-7)-9G-9W-9X",
"tuo": "%U%V&z0L2J4v?{@$F_H6MUTbT~Y'Yc^QdHdQnVq+r`x1{{|;|<-&d-(.-(z-({-)1-)J-)K-*:-*e-*p-+$-+3-.b-/%-/[-0b-3O-4,-6_-8}-9$-9?",
"zhe": "#'%+%E'P2f2|<f=VHtJ~NoP4PKR9RRRSU%VXW<Yq]*]:^%^0_ucKe`h(h0hei@iUj:j{kurAtMy!-({-/f-5W-75",
"ma": "#X%3'8(e)h;0GsK?N}R+RTRUkku/z2-(u-)N-+!-+9-,r-0n-5P-8.-80",
"me": "-8/-80",
"yao": "!T$R'T(g,3,:,=,F,I,J,e,f/C0^4<7o8Q8s<a>_@eB>CADvFAI0I>J:L]M:M~TgWHWfY/Ya[|[}^6_ngmi6k`kll*l9r!tdwhxRzv}!-!j-%=-&9-&T-'(-'=-*&-0u-1I-2f-3;-3]-5F-5Y-7+-9T-:%",
"zhi": "!7!t$s%=(J(i(k(s(y)2)I)Z*2*>*A*T*^*c+(+)+J+Y,G/k4Q4b5T5W5s6~7^7|9(98;(<0=E=Q=b=}>L>|?+?QA<AJB1B2B5B6CzD$D?E8GeM7N/O3P1P]R@RhTQTTTxTyU{W.WgXCX[XcY9ZB^l`@`A`haAb!b=bbbwdAdYdueTeWf,f_fag6glg}i1i:jDlqm6neoyqrr=r_vsxAy3|)|Z}R}[}j-)!-))-)Q-*?-*L-*Y-+O-0:-31-3S-3m-5+-5^-6a-8m-8y",
"zha": "!l%Q0>4^4g=0D{OPOZX]Yb[(]G]W^ng=o;t*xHzI{N~J-&t-/9-/a-1{-22-9]-9`",
"hu": "(1(~.j0Z1M3!3^545r757G?0AMCtCxD<E$GxI+K%K;NGNHNPNWQ^R)T2X`Xd]<]x^^``gVi3mqo)snt+tK}Z}q~B-$4-$k-'O-,j-.s-0<-0c-1`-2v-32-4?-4x-5)-52-5?-65-6n-7!-7?",
"fa": "#k%O/'/N:q;*;3EeKkLvo1oKstzV{V-,F-,J",
"le": "%f.U1_>5C_{u-$*-'1-(A-1!-1d-2i",
"yue": "$S%!(a){0^0|242S2_373H4<8sAlM{O,O.ZaZc_>cid2dCdFfZgApDqBw2whw}zczd{[-,V-6:-6B-8Y-:^-:m",
"lao": "&)'n,71s3<5>9M<b<c=&=3F'HYP3Rvg.g4hin`oDr(v/x8xa-%8-,9-/W",
"yin": "&#&j'a)Q*a,^/B2{5G6{7V?3DJEGEcF=FHIRK4K8MuO2RLRzU=Y$Y*Y2Zu[M^9cXczh'monipNp]qer/xFx^z{{||/|l|w|~}0}@}Q~W~f~p-!b-!r-$&-$2-&m-&q-(6-)^-+:-/I-5h-9p-:!-:?-:E",
"ping": "%b&'.H0W1Q:T=f>~CXE%F$H(JWMaOQP%Yg^jgrh>mAqa-$^-(w-/(-1w",
"pang": "!o'A1+=/>R?$?=A/B|QmWsd@jf~6~|-0k-2g-:K-:M",
"guai": "0,;%",
"sheng": "!D!^...t7*7q859e=[=x?*E(KM]^aMb1q2t2|#|Y|u-4_-9B",
"hao": "*:.,25<x=ZEMJ$L3L5LWLtNYO<SG[0]z`Y`ym,mhu#y]-%>-%|-0i",
"mie": "!`(D1G1dJxL>SNS~W]vt-1e-3M",
"nie": "1&294(4,=G=|B)B0E!GDMlSX^=e)e?eAezforAs$sJu*vfw9wByVyY{&|c}(-%L-%x-:#",
"xi": "!>#6$3$d%/&(&g'J's(!)P)n*l+7,,,n313z434i5j6H7?7W81878g979U;V;n<2<5<6>c>d@>A6BABBB}FUG]HeI9IbIwJ+JVKzL2NdPjQoQqRYRqSiT!U)UzW9WFWiWlX7XfXjXlZH[K[m]5]F_@`.`/`W`_a(cCcGcfcwesf)fulGlplwm&m4m_n:oIokp2p7pbqLqMqvsYu+ufv&w6wSxJy,z[{5{b}9}?}P}U~#~2~q-!%-&?-'2-'`-'r-(1-(C-*C-*O-*{-.)-/x-0_-1+-1J-2X-2q-46-6*-8I-9O",
"xiang": "!;)*+50U5Q6Y8b9u:U;E;J<4APC{HGHvL<N~RbS4T.VgVsZ(_0`PdqmGmYmZmfqiq|v(w4z&zXzt|H-$3-$9-%R-&g-'+-'{-(&-(?-(b-*w-+_-/C-/~-1<-1L-1g-23-7g",
"shu": "*V*x.0.D2B4#4K5%5^6s9/;,@[BPF(GuIBIeK7LUL`MLNePDShT*UHW'W0`=bOc+e%e0gIhOiOjQmSqIs_u[|I}!~Y-/A-1Z-1a-4G-4p-8@-98-99-:e",
"dou": "$#,[,}1E@#FEKCOI_E`5jym%mMnMpCrIwpzH{.{~|]-'9-(F-.%-.&-.*-.,-..",
"nang": "Sd-(&-()-(^-9b",
"jia": "+L/23l=!?)?u@jF+FuI.P5P>TaU4UI`]a$a]bxdRjGl{m/q#qOrXu,x$x>y`-$a-$e-%c-%d-)B-+5-3J-3q-4(-7i",
"mao": "!M#i$i*:/66e:u<eDDE/E2E3HVJOQ9QNRXT}WY`|a&aSbrgPmkn!nJq>qcsVx,y%-,B-,O-4|",
"mai": "?W?XF>K^LgS{aKaxj(l+~g~h-!'-5{-7t-7u",
"luan": ";D?dAzA{L=NDW~o{r7w@-4'-6G-6h-:y",
"ru": "/M7F8G:1>AEgIYJ6KlLhQJSHU:VGW,inlEm`oSr+x_-%E-&!-1]-3)-3K-3x",
"xue": "$?,(A=C@E@IGLKStTnXd[p_[coe,hdibig~/-!_-#M-18-2k-6%-6^",
"sha": "%4&G052u4O8F8~<<<CFaG`H+K<U]t}xPzazi~S-,[-.h-/q-/r-2=",
"na": "*0.u.x4E9#>WIYIuTJU!Zt`m`pgNlNlypHu7wcyZ~0-!d-.x",
"qian": "'K.(/~0A0t1'2*2D2R2p6+7[8J8q:G;h>b@vA~CnD(EIElF:I%IjK>KLNNO&O8P}VR[*[u]u_q`!`&gSh;i~kjk~p9pEpOq;q?r6sPtYukvqwPwgwtwvx+{x-#U-$z-*+-*/-*=-+U-,y-,z-0x-37-4M-6z-8G-8M",
"suo": "#*1Z1^4Z797U:?;cFaFbJ7P{VJcuk)tatju3u9xi-/b",
"gan": "!3%)*1*t.Y/x1*1}3%4s91>GCmE#T>Y^bJbTcAcTcti}nE-+e-.Q-1T-2w-3*-:i",
"gui": "!q#o$.$C%x%})0)s,E/?1K1T?NERJ;N%P/R*RpU<V{WVX0XPZ!_*aHbod<dng>gEi#lilxuyvlzY{P|M~#-#K-*;-.7-.:-.=-/S-1F-1U-2%-2r-34-:Y-:]",
"jue": "$Z$l$o%6,%525S8#9NA^D=KiKtNnO6RwRxU!WWWbX%X5X>XBXZXiY4Zj]N^f_}a0c[chd<fCfDfwpKv)v:wCyo-)0-,$-2r-3<-3=-5g",
"liao": "$:,A,m,x1g7n8%:@:C=OA#ADJcM(RnRv`1b8f$fJizl&mnopv,wNypz.-&@-&G-,)-5t-77",
"er": "3><m<p=8=T?HEyLoS|U8Z6aBaGbjd3gshtjJl2q_x9|L}M-'/-(=-)Y-,Q-,R-/D-2)-3j-6b",
"chu": "$e%s(/)M.%.)114y9=<~=%A_DCG=IdIoMMNOPQS'XRXe[/`E`Oa,cmf=fTfcmaq3rnxlzW|`}p}|-59-8O-9|-:)-:9",
"kui": "#f#o$C'D,Z,p0v1m22=m=o=s={?NAFI6IJKnLyN1N;NbQY[edpf*fvk;mXt;tJ{0}7-$A-$d-%6-'a-'o-(P-(`-*6-+P-.B",
"yun": "!F'N*;/`/|0y4T6z7!7<7C8z9|<y=?@_D@FLG7IAIVIyK_K|L#L0MIM`QcV@a3b)b@bYc=j1kQm!m7mVmgnRo0o8pVrO|'|d}5~7~i-#?-#g-#n-#{-$(-$/-'N-(p-)'-:'-:0",
"sui": "!q#G#J%G&f)$)t+R+h+p5m7>7h7x8D9V:4AQCyFOFPNxV}Zm]c_QazkFkHl.uqv!vF}*}/}G}H}w-#$-#r-+|-,/",
"gen": "CQEHdc",
"xie": "';(f*&3c4k5+595I5h6g6v7&8>8T92:B:M<3>l?T?V?ZA&LRLTM0Q7QKS+S@SBStTRV*V^W4XKXOXS[B[y^<_Z_mflfnl,lU-!i-!v-#1-#D-#h-$#-%c-/S-2%-9Z-9q-9t-9~-:b",
"zhai": "%X)3,92q<?a@b]q=-9c-9d-9i",
"tou": "4G6sMyjqrItA-$b-&r-+h-8;",
"wang": "!664:h:i:j:k:mFvGmO>P*Q,Znh5iGj+jM-.N",
"kang": "%<+U2v3tg1lJpgugwmz={L-17",
"da": "!W.u/(/S84;H=<EsF*LHS0VCYldzi{j0j7j;k?kZt]tqvZ-!g-!|-#R-:S-:U",
"jiao": "$y$}'~+k,A,K.`/I1o5;8?8]9O:J?E?j@hA9AKB(CaEZE[KTM5NZP!RkR|WWWbX%X5X>Xs]Q]fa`d0dhe3gvh_hfi;i?lvnkoHo]p#q]v*xW-'%-(B-*h-+;-/Q-1>-20-3|-5k-5s-78-:a",
"hai": "5L?Aj9l/lnnro<-'!-'~-)Z-)b-+>-+p",
"heng": "?J?mMZT9vc-3o-4$-6e",
"peng": "%c&'&S'+'Z+,.V1+1@5@8P>~AACgE%FdJRMkRiRjU3eSgbh:s9v{zL-$+-$0-):-*A-,X-,b-,q-4K-6y",
"mu": "!1#N%]+V7`7n:@?.C5DeF~G%O=e/qKqPx!~3~G-#9",
"ting": "/s5l<t=j=z>%>&?qC)FnI7PWQ8ZJ[El=rUxKz`~K-!~-$g-%e-9F",
"qin": "$j$k*'*Q.d5c=>>MD1DAGZG^GkMRO8Q}RJS7TVWJWrZQc]pXpkriwix{}c-!]-$~-)f-+E-/c-33-4L",
"qing": "&/&Z'i046+60:ZDaHzQ#Wr[%]%_Agph+i7m<s4vi-!;-!<-!B-$7-%P-/}-2B-8X",
"bo": "%h&^'x(B(U*L+l081c2%2,3~4m:S>;>t?fA!BuC,DrGWH=I'J{L4MmO^U+U,U6VrW5ZL[d]Rd8d_eKf@m3pxq5qFrVtow0wxw|x(yT-'4-'^-(E-(V-(d-(g-).-)[-*^-+)-+~-,$-/0-1=-1}-42-6k",
"lian": "'K+D2+2P2V6w7b8k94;s<T=Y=n=q=t=u@+AZAcG(G,HLJTKDLELOMsMtQtS=U`UaVUW#We]0f2j?k(n0oPsZsyt`u@vKxfy}-,n-0U-0}-27",
"duo": "&U5|:!BtU0Uncrdfdid~eYg!g#g5plvUx5|E|J}*}3}S-&~-(;-(z-)1-,i-4]",
"men": "#{$*+XGRNEsuwVz1z6{>{M-#!",
"ren": "(o*,*e+#4A4U5)5y8x9$>?@AD)E}FGGDTUU2Y!ZC^I^Vg&gFi&p/p;pRqp-!W-![-#[-#w-&i-'#-(2-.^-3{",
"shen": "!U![$8$r$u%j)#)9,12e2g3T3U3q3w4l96:p:~>i>m?t@BFkHwH}JGK!LCPGPHUNX)Y1YHZ*[2^)_%_L_S_VfylPqRrj-$W-)W-.m-/z-0@-0|-1)-2N-4A-8b",
"ze": "#R#}$n(+*p/,0J1I=0BsKAS?Vz[(].a@b7b]c:jO-&t-6.-9s-:,",
"jin": "!#$j$k%M)8)G.U.m/J4W4`6L70:/B6F&F;GcGkJYM!TWW%WzX<X@]9_sb&bIc#j2j<k8olomp>sTwGy2-!^-'m-(Y-)$-7D-88-::",
"pu": "$5*k+j0$8LBTBUFXGGGaH~IsIt[D]]_|bEfInprtupv=xbyqyu|[-/m",
"reng": "(_DGiu|z",
"zong": "&Y'h+?3P3]4$5z6E6Q6n6x7(7M7X7e7t9%9n<J@MI=J=QU`eePeRf1t!v_-)z-*5-+K-,`-,f-.8-09-0G",
"lun": "&n'k*|6:9&='@4D:GLPk[1^`eBhAi)s.|k-04",
"cang": "15B$BpC<DUI~M#R3b/w8-50-6P",
"zi": "!i!j%()R*/*X*b+E/)2l354F4d6I6W8O9s<u>z?!?MB'CwE5E7ENE`F4GHHuJbL;NsXHYOYP[I_caFa[bzb~cZcpd(h3hQiJmbp&pmsGtRtuy=yO-$s-$t-,I-/{-0r-2P-4e-9)-9f-9i-9u-:D",
"zai": "#^7HGHb+g|i9n^",
"ta": "(d)i2~VAZr]wdBe7etfFfOfpkdkiq+sBt]tex1{'{5{;{={R{o-!s-#*-#B-/?-0t-2d",
"xian": "!:!O#5$<&#(F(h)X*3+D/D0V2k3B4%4|5A5c5t6,6]7J7r8Z8c8q90:%;];d;h?&@oAnA~B;BvDSDwFzG,LOM'M*MpOKO_O}PJT+T0V_W:WRX,ZXZo[O]d`>awbKb^cYdgd}f;fhgBhHnfo'oPqvr#r$rFrqs<sps{uww'xJxMy4zBzC{H|K|a|e|s|v}J~v-#T-$!-$$-%.-%H-'D-(M-(o-/T-1l-21-55-5x-5y-6$-6q-7G-7h-8$-9P",
"cha": "'0*049B=C9CjD}EYEdTAYyY}_1enr't7t[vryDz!-!U-'Z-(O",
"hong": "&*&8.*.>0o334=4P4f5i8o8{;z<!<==CDyF?HoHpL*LXNtXtXy^L`'`*`,gUhNhwi+p[q[rGrYt:z?zXzrzt{I~U~e-!n-.(-.a-3v-6i-8<-8?",
"tong": "!r$@%o&>*]+m.?/Q/i345D5N5`9PA@EjJPO1T,Z,cFj|ndq:qYqjxC-')-/L-2*",
"dai": "0,1n4x7%9AC?OMQ]TdW=Yd^xa7aLbqdff'gCgLg[i%jIk4p0~z-!0-)E-/>-3I-8N-8e",
"ling": "%d)D*M++.5/+4p6@9];K;U<.=KBqD[GiJJJmL%M|OiT(TcUjYVdLgZh/n8oWpts0x)zN|q~;~O~]~a~c-!2-$L-%`-)C-/$-05-2C-3L-6Y-7E-7q-9z-9{-:A-:T",
"chao": "!k,h,r2u6?9b;5<wXDY=]?cdh`mlpSwa-7w-8v-9#",
"chang": ">J@mA+DTGMH!UlUqZfs&sWy+z'z(z0zh{1{a-#d-.0-02-1X-2H-2T-92-:d",
"sa": "8g?^HDK{LYY@fnpQuwwS}A-!c-!s-&,-&P-)&",
"fan": "%0(M/1/40i2A2d6R7i8$;o<[AIBcBfE0KNLPM>N!SOVqXva=bcf<gEg_hThkj5p'v#v?wT-&=-&Z-&n-&o-(5-1E-5r",
"miao": "!J#m*=.10s6e6u7n9z:@D`M$l3-4s-6u",
"yang": "!R#!(C)Y*R4t;E;J;P?5OxQ/YX[T_0gahGqDswt,wX{}|.|y~:~}-!p-&8-&M-&k-',-)G-0]-3a-3t-62-6X",
"ang": ">Xo:-+g",
"wo": "#l&A,R,_6}>I@OAlB!G*HQLgP[Qbe:-(p-:4-:I-:L",
"jian": "!%#9#`$<$D$I&N&b','r'}(&(<(X+D.p/9/g0#0/0Q181k262I3_5U6Z788(899v:9<F>$>S@fB4BoCICSCTETE~G<GrHiI{K5K]L!LVLwN=RGSEU5UcVjVlWAWRW}X#X,YT[.[F[c],][]}^!_Y_v`K`Racaybkc|d?dKdye8ecephvp/p;qXrMrZs(tFtHu!ubv4vDvNvovpw.w1w5xwy:zCzD{J}d-!V-#;-#>-#O-#X-'A-'S-(7-(k-,h-0Y-0`-0h-1(-28-2h-37-40-4R-5@-71-7F-7I-7J-7W",
"fen": "#|%A*9./2x3=3r4S9';M;q;~ARD4IxKmO?O@TGY,`^`ff|hjnOpUvY}K~5-'W-'}-(c-(r-.w-1M-2Q-35-85-8n-9.-9:",
"bin": "%A8I::A)AiNc`X`cahailKvjya~l-$p-%G-%k-,'-,1-,E-,_-,p-.!",
"di": "!u#/%W')'.'{)<)_*U.v/*1=2c4+6c:);X<?=b>;@WDXD_FMG9G_ICJMJrJwJ|M6Q+QVR<TtX*X8XIYW[:[A^q_f`dcee_f/gYjKjtjukLkekwldp0qNuIyj|5}#-!X-#=-$H-(y-+n-,>-0>-69",
"fang": "!I!n(l4Y9*>TBjD;O!Y;^ed@lLp@siwn|,-,?-.v-1s-3E-51",
"pei": ">Q?(JBSwUrUsauc2hyiPnBn{s5y7|%|f~M-)#",
"diao": "$#&a,C,k.B1]5FJML|NhOaXxZ8Zv_M`ro~p_r!r:s*s[vawUxExR}v~D-.c-//-0%-2L-2{-3&-4O-9>",
"dun": "!<!A%J'3(%Pxd;eZf?fKfVjikGkvpLw`-$G-%X-*c",
"wen": "+C+`+z4B4C5X7!7<839)9|=d>^?gD'G!O'O(R/RO`ahShWiNu6zlzqzw{<{D{Q{c~4-#?-#{-%(-'f-)(-)4-.r-0g-0z-2V-36-3G-9<",
"xin": "!=(F?zBID7FkLZSyVtY3Y<gBiWlOo[pIrNv1w,xtyn{w-%/-(q-(t-)$",
"ai": "$F$|%l%~&e'M(:5=CbKGL6MN[K]k]{b2g(r9tWv^yK}1}8~s-!.-!3-'U-(m-1[-3l",
"xiu": "**3h5g7u8,9T;Y?i?yB*B7DuQ{ToV0V1`ur%rBtSu=u^uvxp-&K-'l-(X-,@-,U-/Z-13-3}-6d-9^",
"xu": "!$!*!4!Z#j$l%;)W+@+H3[5K5e5x6T6X6s7)8X9[9_=X=e?4D/IeJ)JXJfKrLxM/NQNTNUO[P$Q:UDX|YBYJYs[8[Z]C^^_3_ia^lUmwnLo*qovn~E-$<-$>-%T-%U-*[-,w-.G-.W-1_",
"tang": "$f'@)f0{3V3j3o;l=)@zA4J4LJQSR$RAcMc~eef&g+m]o=tiu)uTv'wDx[yWyd{1}:-#I-']-'h-5:-96",
"huo": "!V$S$^(*)>)S*Y*_*`+|,W10=$=4AuCJG.IhMTSI[g`0a<bacnlTpesrvhwoy6yyz5}y~R-!,-#S-*0",
"hui": "#J#[$G)N*i+s1;5R8.869I9}<9<:<L<^CxEbF1K2KeL8L9MFN,NuO7OtOuPZR*RyT_V:Z$Z2Z_[L]S]n^#^X_!_<`FaXbyh4iEjUk*qouqvI{6{j}3}S-!Q-$c-%C-%l-'R-/V-1#-81",
"kuai": "/w3}?]AWIJIql|n*-)0-1P-2.",
"cui": "'g,w2z3L4[697>:4<%<@?R?U@.AEANAhG{THVmd#uQ}Y-$|",
"che": "$;%I&?&@=JFjP@g<h~jA-$M",
"chen": "#t&M&t'`*[+A+{5{>FA}EKFRFcK:LmRBTDW6Y7Zz[Q[o^;_V`$arb;c`cad>dKeagKimjHmDo@pAt(|C|o~H-5T-7]-9l-9m-:=",
"xun": "!x$Q*p,^4;8MAjEnF:KLKSL[LaMcRzS%XwY#Y)Yt^R^T_+j%jajlkclsmzoTv`-%A-(}-)U-+%-1?-1H-24-5A",
"chi": "!]!y$).X.y/A0+02133,5W<#<$<D<H<|=@>>?2?D@SE9E|GeO%OHORR;U/U0UkVMYFZ9Zq[t`8aRcBc^d+dfeGj@jBkKkfkrkyl7q7q^qusx~9-&l-(4-(|-+&-.R-3Y-4!-4r-4w-4y-5]-6Z-8(-8C-9k-9v-:<",
"xuan": "!m!x#d$['5)k0R5?7J7d7w9K<G<_HMHNJ8K#L/MQMfPEQ?S<T)U$[;[W]_^&_abRgDi$jkl!q,ratLu?x0yl-#'-&2-)U-)k-0f",
"nu": "%a/.?;-)>-+4",
"bai": "+&.;3;3M51L^W3b:b_-#k",
"gu": "!/$J'B)A*~+P.z010?0u3g75:r:v;Q>K@(AfE)G>GhJ,LSOdOjSeXFYR^h`%a]bxgdgehYi,iXk,nYprpws]wwy.}h-%@-%W-'Y-(Q-+`-/;-0'-2I-3^-5?-6S-7%-9*-9+",
"ni": "!h#P*G2m73=i>$>}@pABA{DqLpOLP.Q!XXZt`~d`h.jhmCpnx3}L~X-(e-0,-2J-7`-:+",
"ban": "*E2s5!9;>PBgBkQ*QvVKd[iciipPqEwfzx|$-!h-$F-%Z-.n-35",
"zhou": "!+#U$x&y062.2@2C3+384:777o8p9:<B>B>o?#B^F@GoI$LfY][a]y^r_4_Manc0gkg{h,i0i<k7m>nCqg~Q-);-)`-)t-*r-+[-0(-3~-6f",
"qu": "$L'o(}.2.F/@2U3?4o5#<1<U<~>u?/AxDlG:HhKbM}O[OfOpQdRDRlSkSpT'T:U&WxX!X&X=YeYjZj^tcjcld%d*fqf}g2gWw<zfzu{i|4-)3-)5-*W-+'-,S-.~-1'-1;-3W-4l-6E-6[-7}-7~-8&-8+-8U-8u-9A-:/-:H",
"ci": "'=(A)%353a5579ESEUG6L;OsQpS3Yp^saqc.c_dSiYiZiaij}m-&y-'*-+l-,%-/+-3V-5C-5D-7'-:6",
"beng": "(l5@657k9iGnO*dtf3jYk2uiygz>-#)",
"ga": "g=onsfwH-.A",
"dian": "&p'v,j1iIiKRPXdXeVewq!x%|8~@-!E-%3-%4-%z-*g-8Q-:8",
"tian": "!:#;'1'H,j4w6D>v@:BRBXGvWmX9atnTr#rFsXx%xM{%{n-!>-!G-'$-3f-5J-5S-8:",
"bi": "#L#M'!(w)L*@*C+;.n.o/E/Y0(0)1/1<2r2y4M4m6>7Q8@8};7<,=a>a>r@lA[BlC|E*F.FJG~H:J<JdKHLLPPR!TiUfVhW$W)X^Yh^v`<a!aEaUbMblc/d|e~fPfQi[kBl)l^mjmym{q1truFvQx2z8z9z:zP{B{C|V-#,-#G-#p-&u-'j-(f-)I-*X-+x-,N-.T-/*-0Z-2S-45-4}-5b-5n-8~-9S",
"zhao": "#'$K.e00:V;#;?>*>1>2GdYf^ucScxorp<q.t6wL-)8-/G-3&",
"shao": "#+*y/r4r6%9>C&CqD^FyHSK}Tjh$la-#&-$)-,Z-/`",
"zuo": "(|*S+!+n/,/p4*7{?'D{F^H`HaJ?Th[(nWp||7-&t",
"ti": "!g#e')'?)Z)|*v/8285f6|9Y9y:{DXF!KgLIUzV&V'[qd)d2eJemexf~g8jxk=kLo&rDt)xy-%$-%r-*2-+m-,0-,L-,]-,a-/^-0B-2U-4;-4w-4y-5L-5M-5i-6r",
"zhan": "$H&b.33*6=9oGQLMN2N`NaOeWyYQZ/]h]l^B`#cghUhgiSl0n|zK~V-%~-&*-&N-&e-'|-*b-*l-.Z-1S-2y-37-60-7=-8i-:h",
"he": "&c()*(0z2i3@4?8r<N<ODdFIGFGzJ1R(SMTmV2WOYGYIYw[z^i`x`yaTbtcIloovq0vgzRzU{){X{m}Z-!7-!8-!9-#7-$P-%f-'&-(@-.|-1u-5$-52-58-6?-7#-72-7v-9n-:>-:`",
"she": "'y(`BJBKBLJuNpOgP(S5Y>^dagakc'cDg~{!{^-#h-)u-7l",
"die": "!g!t&w5M9G<k<l>pB5C6D~PmQ`R@V,V]YU[7_WcbdOdXdreigojNz+-#1-0S-2R-3d",
"gou": "/01%2)3g6t:&<h<i<jD>DhO[U#VBWwX;YNY~_(`ob5bgk_pMqHwl}k-#A-#m",
"kou": "!P!Z#r$$,P.2/W1OD+K=KFp$-5K",
"ning": "$P=R>!DpLevm-,~-64",
"yong": "%p&>A]DcIPP=Yre2e]l@mJmio9rHuVyh}n}~-%*-%s-'x-/y-0w-15-2A-2o-5`",
"wa": "%K,),?,E,`=N@r@xOyTuW1lc-#W-#^-#t-8w",
"ka": "?8U@qV",
"bao": ",<.~6h?,DgGYHcK`L4MJN^OJTeUdV4V5Vf`ib*d8q/w%x.zs~>-!6-&x-&|-(9-)/-+j-,M-/7-1~-3/-3A-6Q-9r-:B",
"huai": "=7N3N8VDVSeE-:f",
"ming": "!C!w#zEDJ'R,WuZ0m^n_q}xT-3.-6L",
"hen": "Y|-!y",
"quan": "$b%u/K0B5<6$7:9mEqI3NAP|SlXLZ#_)dkeIgzi=o5qxv%xO{#-#_-%M-&$-)V-*3-,e-0L-2^-9}",
"tiao": "!~(t),,J,g/!3/4.5F=S?PCdD^H0J@JMJNPnWdZ8Zv_McqdwjCr!rdtyxR-#%-,G-/o-1&-2;-9y-:C",
"xing": "!D#Z&$0Y0g6J@YApBFEuF7FhHrP9T#XVX_[_lMluo+pBqZqwrhwZx6|D|S-'V-(/-)p-+D-/5-0D",
"kan": "!N$=$g%?'^.QG&T%h8ho{4{q-%)-.+-:R-:X",
"lai": "#8#F/X0%2/2MG'H%MSW7Zqaob,c&c4k.mBsgxd-$q-$w-)y-0*-4B-4f-8%",
"kua": "50?>B~Z=d9dlq~-+s",
"gong": "'91*44474=8o;z>[OBXQXba6bZfzg$gtrG-!z-,T-:L-:Q-:W-:u",
"mi": "!s#p$A(w)')w*C1d2b2}3p407c;>;F?bClH{J#K'K/L}N#N6PaU*WZW[WcX1Z.[j[l_g_rjXo4oXoYo_r,z/-!K-66-7X-7Y-7j-82-9&",
"an": "!(!.;)?I@XEzGlHWHgJSUxZS[N_d`k`{r1s:x]zy}+~=-!w-!x-$1-(l-/E-4I-4u-6v-8c",
"lu": "!)#Q$_%|&L&d'])E)J*}+[+o071X1v2!2#2G2H3I6S8^9q:f?9A,AtBmBzCFCMCND.G@JcJeJtKcM[N<NINVR>SYXh[~aVb|d$dseCf#gxh^h|i/i>iTk5nwpis2sascu8uMumvGw&w+yr|A|t~x-%J-%_-)+-)r-*N-,3-.q-.t-00-1i-1r-1y-3w-4E-4P-6!-6>-6U-7;-7C-7M-7b-8l",
"mou": "!|7n:@Oq[[_Ue6t=-#9-3y-8!",
"cun": ".N2nA>lS",
"lv": "$()(*r+~0`5Z5~6S7_7j9q:*@wA(A8A;HkM,NKV=VZm'rJw#xDz_{T-*u-+*-5a",
"zhen": "!X!b!c!}%Y'%)5)T)b+I.A0X264N4w5Y7D7L9,:2=I?%B9H5I5IWJ&LnTpUSWaYKZb^pa2afbWc%g^hZi4iqkOnNoxq$r~s`tOu$u%wJyS|0|_~L-)D-,o-1f-3@-6R-8d",
"ce": "/%/U/^/t0G1W36F/H3HPJA",
"chai": ")&>HCjEJNzS9T[Xz`jp4wY",
"nong": ")v*j+q8C?cAXL,V~]iioipoL-,{-9a",
"hou": "#c$t0q3Z<M<UEVHq`MjgltmWq|t@-'T-+r-/B-0C-1O-2!-2,-9Y",
"jiong": ",M4~5uB#B&MeMjVIjFjjqi-$}-%h-)6-)X",
"tui": "+y=N@tJ^MAM^P?PYQkVL^.eof7jb}D-$n-$o-$r-%m-)l-+u-.L",
"nan": "@^G$HOQe[PcEk]}_~'",
"xiao": "#+&4&:+i,N.l/q0!0O0c1(1b1u5a9R<;>@AGFyHCKyL2LtNBNMP<RPR^S!S[Y5YzZUZl[ke*jom9r@xh~I-&3-*`-+8-+q-,!-,+-.I-3X-3p-5Q-6W",
"bian": "%`&}+8,;/=0S2A2W3W6k6y:$:+B/C4DLHUL{QBV+WTW}[5^/aJbfi^idieifihikiliviwkSl4l5oatPzO-##-#<-0I-0J-2`-3R-5&",
"pian": "0l6y:$<I?K@5WX[9_haIaZdtejsq-)O-)v-*(-**-+?-+N-+w-.z-5&",
"cu": "1P3)7S?xK)XAZDcjcvd%d*eOehf%fAfBo$-%<-7O-7R-7T-7s-8t",
"e": "#3%:%B%Z%y'<(9@bDRF}HXKfO#PBQ)WpY+ZF[?]L^2^___`NgMgii(j8kRkUl%mRpJpjrrt&w*xoyCzn{f|!|3|:-$?-$R-$S-%%-%&-%t-%w-'6-'L-(G-)n-.f-0[-0v-1h-2Y-4&-4<-4=-4z-6o-7$-9[-:3",
"guang": "%w?@B#B&EWgwj}r0-89",
"ku": "%,&5*D,@,T5:9E>{DoU1UbVTdPllnm-+o-/R-:p",
"jun": "&].=/`0<0CFlGCI1O/PeTXWhaeg?m1p^qfr&t'wj|Q}^}l-$j-'8-(J-)m-+F-/]-2?-43-44-47-7U-7^-7d-:Y-:]",
"zu": "(x*J+10H4}95GqHbIkYm^kd6eLtdu2u;yk|6-!f",
"hun": "!F#O#W#]F6I8JyXT[=_2hczo{d-'>-(L-.C-9J",
"su": "';+1+3+],X1U3.324X7K7U:?>,>/@{DWFwJsM+M]MiXWYE[r^o_lcyf(k$khksnZrR-':-*_-+L-/i-1@-5p-6~",
"pai": "0'1z1|IOhBjLtV",
"biao": "'c,!1D@3A,A1AoJoM=T@UoVa[3]#b?seuZw$ycz#-&&-&+-&5-&D-&E-&F-&H-&O-&W-&X-*~-+@-+W-,;-2j-7Q",
"fei": "%[//1!6M9a<A>O>e>r>z>{@GDFGjH$KhP_PuRuUtZp_GaObsvEyP|g~T-!/-!H-!I-&Y-&[-&]-'H-(j-*!-*,-0+-2F-9;",
"bei": "&i&r)`0'3f>wA[DfJ9M8PAU'V;ZLZwa1bVgch@iDlbm5mQqWrPv[wd|=-!l-#,-#C-+k-4N-6x",
"dao": ")=)H)x+B+K005F8h<B<`B_C7GwR7T4T7Umeqg9iwkYoq|b}=}O-.]-1n",
"tan": "'/6D8A:_:eBOBSGtM@TkW(WJZ~]Z]a_R_xa.a>bdm?n~o,oJqQsMx#y8-$x",
"chui": "&U0D@8GPsFtny0|n-$u-:_",
"kong": "%.&V,/0@;gg,sA-#(-4[",
"juan": "!{#2#H5J5V7Z9S:|;=?w@7AaG[K3SfUM^&mTrZras6u0vHy5yXzt}^}l-#'-&k-'.-6m-:w",
"luo": "%T&!&='n/>0M2]5>8f9M:n;@@)@UAwF8H9HYJ5N9OrRHS6UvW~X'Z1dbf`g'kAl:uEw>y/yf}s-$f-('-)_-*P-*k-+=-+X-/K-4#-6)",
"song": "&P.@===yGOY0Z]^b_?jcu1-$@-%[-'[-)e-,c",
"leng": "#>&h++L@eD",
"ben": "/&<(DxRuaUblk/sIy&",
"cai": "#T677P8aGSK+U>a5b[dxeQob",
"ying": "!R$v&C&|(P)c+_2K2^6U7/8`9^:>:X:Y:c=?A:ASDzEAF7F9G0G1H@HAHBHZJKLqMwOmQ0QPQiR0S8SgVPWv[i]M]|adbHc@g:j/m2twv8vky?~_-##-$.-$i-%g-%o-%p-1V-3g-4q-5*-53-5o-5~-67-6C-74-7>",
"ruan": "&u(>6^<o@QgQhDi*|(",
"chun": "#_0_4L8|>U?sA7C~G3G}HRITJZQgSUb(hKn}o/sL|T-0#-0Q-4i-4~-6{",
"ruo": "0P1#DnI}mP-0e-0{-5<",
"dang": "!,#s%2'((2/[1f2&CDF3GbKuN(S)UCW&]b^A_kd&kEvWxB{9~A-8[",
"huang": "'w+e0f1q7O>=C1F#H|Q@RtSuYv[V[f_Xd,kWt3txu}yI},-$,-'P-*.-0T-1A-2]-5q-86-87",
"duan": "${'&.I1`2X6a:#<r@kI/V/fdt.tGyG",
"ou": "*$=*@VA*KPM)MG]3^Yu:-3H-5[-6N",
"zan": ")},'1A1t1x3`W?^'^?apbCc<d4d5e}n1n7n<smuaubv2v<-((-4C",
"za": "%k4^4gAvA|Vpj*q8}r}}~)-$'-.u",
"lou": "$(0x1V=+=1C>IMK(QfRI]1a*g3kxu]yN|F~x-#J-+}-,*-5a",
"sou": "#v2BC;IQJ(L_M?Qum[o3t~uAyH-&:-&<-&S-'c-(R-*<",
"yuan": "!9!f)V.i0F6f7':.;m>CD3DYE?I?I_InLGLdO5PRPzQFQXQrT&TYUiUuV3VF[xa3bYh]iQj=k@kgl8lRnPphs'u(|^-%1-)9-*G-.o-30-3U-4V-5%-54-6K-6]-6}-8s-9!-90-95",
"rong": "+Q+S5E7@9C;^>FEFEfF5J/QhQwQxSDVEghthyb-)R",
"jiang": "(43u3|5P8:9L:F<>=.A2EaH^ILK.LAQjRM[w]=^W`6ngo>oF|H-#P-%5-12-2_",
"bang": "&<'A+%5_749B@uC8IcO!O*OvPt[s_olQlVt^y^-#3-,#",
"shan": "#:'m)K)q+W.s7g7}:D;p;r?pALATBaD&DtR}S,TCWjY%[b]r^ObFc?cVd^gGlAn#p!qtvBwRz4z5z;{@|P|X-'q-*J-+V-/l-1C-1D-2s-2y",
"que": "&5&E&g'6'7(1(N:P:RI]O6c}z}{*{l{p}a-4Q-6t",
"nuo": "+<+u3e3y4&<oU/U0[Y_DelkCt<y#}_~'",
"can": "+W1A3ELBO4Q.SjSn]2uJ-&`-'3-*T-+M-8^-8f",
"lei": "$X'F'b(,(H(I)7)~2j4h5H7Y8S8Y8j:=:d;t<s>5JiKWL.M4N*N+N7N@SPZ:^(^zhxnoqls?vPvvw:yz~<-!*-$O-$_-%7-%}-1Y-6<-9R",
"zao": ",y,~1R3sC#LlMPOC]`d1f4fNk%ktoCwA",
"cao": "3m>9C=C[EwJ_R:VbV|n)uc-*D-94",
"ao": "!T'Y<Q<V<Z=wC]DBK&R=T]Vy]7]8g]kom9uBuMuNz*}>}I-*S-+S-0~-2b-5X-8{",
"cou": "@ThJiK",
"chuang": "'_,H,L,q{+{E",
"piao": "$+).1D7a:;<RF|LiRCo?{3-%9-&A-&B-&V-*U-+W-.S-1.",
"man": "#{$*$c5X7]:<JkJzN)P2R6R]SoVw]>_tmuuCuUye-#!-%;-%y-'i-(Z-,t-,u-1*-2m",
"zun": "8':^U5]Pk|qqv+-1B-2u-4n-5|",
"deng": "$7'q.M/H1pCCW|`:f9l>mxv6yx}E",
"tie": "=VH8OhaPbndXq'qzv>vRx'-&z-'Q-*i",
"seng": "-,v",
"zhuang": "3:3nF)F]UBUZ",
"min": "!B%9&`.}/<1l6O6d:,:wDiSSb'pqs7tEzEzZ{K{S-1$-2n-3P-8q-8r",
"sai": "2'@cb6c9-%#-0_-2X",
"tai": "0+27>h>yB8BeD]GeLjdIl[nSpfw^-&/-)E-+7-/6-2$",
"lan": "17212Q4/8K8i9x;+I<JCL~N$N&VVVxW*W;WDWoX(X4]K^:_{fknxw/wFytz~{h-#Y-%K",
"meng": "$/$T$`(?C.CKFgH'IZKONvPgQZRaSFn'n,rKsby<~?~k-!(-!)-%F-(!-,O-/t-08-68-7@-8q-8r-8z",
"qiong": "#@#x,+,.,d,|/:/FB{EBM%MBP,P0cWdolFqs",
"lie": "5}=]?oEOOzU?csf^j`-&0-,x-.#-/J-1c-3r",
"teng": "2>2F7I@sAHM9N?R1Z@[`l1~u-)S-*B-*v-0s-97",
"long": "!p$a%n&=(R(S,u.!.6/;1*162N=P>'?6E<MxS^S`W8`4bSffu`w)|B}%}T~y-!1-*t-6@-:J-:O-:P-:V",
"rang": ")z+t,$8bMn]s^8^Nfm-.$",
"xiong": "?F?GCrY:YiZ4^a^mb'}e",
"chong": "*86b;:;|B@CBEhNfQRS$T5V)f!ohqhxZ||",
"dui": "&k'O(m5nLb]H]vhsj_v0v9ys{v|j})-$[-3h",
"rui": "#h.h6N8+D6E(KUKVKpMWMXO)P~r<rwuqxx",
"ke": "#u%T&5&~'B'Q(*(;*<+.,U,r6[9t<7C3DdHFLFOTQ5S}TmZi_Hd:gni.o2psqds/wyxQy)zM-$Z-${-%i-%q-){-+I-+y",
"tu": "*)*.*x,6/a@dFNG+GVHsIfcbe&j,jvnjp6porIs!s}wO-(h-)j-4*-49-4T-5!-5O-5z-9M",
"nei": "?~@;lNsE-'5-(I-/e-0!",
"liu": "&B&d'>'[,A6;9l;1;;</IgJ*MERWUTe|kbs#tctzuHu{xuy[ym~%~j-&>-&@-&C-&U-'b-(W-)M-)c-*@-*d-+T-.9-0m-5=-5_-7.-76-7[",
"shou": "6.9h@yC2uA-(_-:s",
"ran": "7v>ZDZIFOEOYTST`Tz-,A-,K",
"gang": "%.&q/{639!:N:W:x>Ep+s)ttwe",
"gua": "506}:z;%>xU<V#Z5[>^|cnedr#rFxM-&'-&1-*9-3k-6c",
"zui": "#G)C+15&8d;$KjRdXHi]nInqo!s$s8",
"qia": "%{'I?1HyU4dUnU-!{-+z",
"mei": "!L!_#)#a({)]+X0h3p;I;T?S?r@PE&FfI@QGTZdMg0mOnlrKtUtZyMyQ~N-#^-.>-.F-5(-7(-8V-8h",
"zhun": "+$,56(>UT8YAZ{_Pj.",
"du": "#K#b*f.T.^1,>DCsFBR&SZSmUyWqZd^$^D_E`3b%bNc)mMo(sDs|v}yL{!{^-!Y-#V-#s-#u-*E-,,-8]-8k",
"kai": "II`7gysvtbt{vCxGxvy@z<{({U-&;",
"hua": "%;&K'B3S8/BWD9D:GgIKK[MzR#XKZ&Ze[4[>]A]o_&`0p(p)rbsdunxN-*]-+<-5m-8=",
"bie": "FTNFObRmVuf6-19-2l-8|-:[",
"pao": "%e(@(O,!?|H>M=TeTfV>dDdTgfq/x.-!N-!o-7Q-7S-7|",
"geng": "56575d6m7,9Q;j;u<v=DFVGfavc1m0-%b-+v-/h-25-4j-6|",
"shua": "<nZR",
"cuo": "#1$z'G79?nFpFtImJ2J}NR[(erk0kzn7o7rEs^t[xqy$-7H-7L",
"la": "%_'R<*@>AbArG?HYM3PfQ4Q[SRi_i`l6v|z$-#0-,k-0F",
"pou": "0$UO",
"tuan": "1H4'V8a%u<-5V-6#",
"zuan": "1B2Y808N8U8e:Kb3fjftq)vxw?w~",
"keng": "%t&3&RZOr>t1uOxg|&",
"gao": "#R#g)4)6)e*m+N+O/v0~3i7E:5;O;TA'B,GILrMHZ[_:m+ryu#xny]-#o-'_-,4-,5-5R-5v-93",
"lang": "&7*n/dC(F{IXJ.JHPOQlZEg%lzl~m.rLu&xzz^{]-)h",
"weng": "#q:b;}=rJ0L(Qstg-56-7,-9_",
"tao": ")?58617A7N9W9kG|PoUhX{Yn[{^MdwhXjPjenzs+|r-!k-!t-#@-#l-#|-&w-'d-'y-)P-)x-9/",
"nao": "%z&q'*?a@&@ZAkP6R~YZ]Ju|x@zJ{O-.'",
"zang": ";S?_AmAyB$I,K@M#abambLbUb}rC-)A-++-,.",
"suan": "(z.b/m0;1BI^nn",
"nian": "':*5*P1Y3*C/K6evf5f[h=iCiS-/4-0;-1x-2K-4%-8B",
"shuai": "7>:4RNTH",
"mang": "!5!6&<&D.ZCvEXEiG4G5M_OvRaSAlDp.rsx:-)g",
"rou": "*!2w3X>3?l@aHdQC]tekhEt$-#2-#f-*7-0R-4t",
"cen": "+W.m1A",
"shuang": "(V7;CPuh}z~b-*M-*y-+^-5c-6A-7B",
"po": "%g%i/70I3'7i<,IlK,jLn%n[o1oKotq9uswMwz|=-$K-%a-)7-,N-.E",
"a": "@@s@x}|:",
"tun": "AYAeC~OlVL`G`IgJ~Z-&h-(0-.j-1q-8J",
"hang": ".k/T5*9HBiDHOAT#UAa9j3lJ-$C-%]-.i",
"shun": "!x$&$1$9BZKo-$:-%S-,g",
"ne": "!vY6^]",
"chuo": "'j0^6?8&9bd!e'e<h6iIirisk:narfu;w!-'B-:&-:G",
"wai": ".O-%:",
"guo": "$Y1K3R68=W=c@6@LA.GJK9N]Q&Q1RVUwV!h7j'kTm=pZszvVxm-'?-(K-(a",
"qiang": "%.157p82;G;R;Z;a;g;w@HCEJjKBLDMvPhVd[ndGeuf.tkuPurx~yAyw-50",
"pen": "<XHm",
"pin": "$V%A(8+w=^LcMaSLa;be-%I-%k-&#-(s-*q",
"ha": "4_NyP'QOqdxQ",
"o": "/}",
"huan": "#.#x4!565b6l8;:(:I;b><EoH#H,I_M<^>`Q`b`va/hpj9k3l/lsn9tCvSyJy{{:{r}i}{-*|-,|-/n-0A-0K-2>-3?-4+-7<",
"ken": "&#>8>Y>fUFV$`S`wsh-:?-:E",
"chuai": "A0ACeb",
"pa": "/b<zBdDrI)Trd7wr",
"se": "+b+r,#3688CULD]Ehnr4tauuxVz[{5~2-&I",
"re": "Dn",
"sun": ".f/L0T1rF<J%L$LNt|}]-&f-&p-5A",
"hei": "-8D-8E",
"de": "OMsoy(",
"kuo": "*Y*_/GH[H]O~r#rFxMz|{k~o-#.-#H-#e-$V-,V-,}",
"ceng": ".Lf:-*f",
"ca": "(E(Ykq",
"zeng": "$~'p.L5z7H7z9n:E;9]DbAc>m|roxk-.6-1K",
"nin": "?[",
"kun": "#7&H);*s+*5oGEPpUEUJUgV.`wo%sCy*z]zj{Y-)w-,<-,=-,D-0/-2G-4^-5'-6w",
"qun": "0<;_;`UVU^e.k&-7U",
"ri": "TMp/p;pd-)%-+(",
"lve": "+4rgrlxr",
"zhui": "&U((.h66729r:'@C@|[!b>c6j_o#s>sQvdy1})}Y-)s-+J-4Z",
"sao": "$O7m8<:A:HAdR4-&<-*#-*I-+Q-,:-0l-1R-2a",
"en": "J!",
"zou": "0&6GG=[)_CcNcOlem@mcn.|h-*H-+1-/w-06-2E-83-:.-:7-:n",
"nv": "2h=TSvSxp8wW",
"nuan": "-'M",
"shuo": "$m&+'$0cIvZaZc_>qttmv~x*",
"niu": "4H9.FxpTwq-!`",
"rao": "+i8)9FF,KdVvk}}B-'v-(>",
"niang": "nuoRoZ",
"shui": "#I)7*q*z@1U[ZaZcZg_>_KzG",
"nve": "&ONJ",
"niao": "@%E>K1T^UGVO-2{-6H",
"kuan": ",s,tAqw(-,&-,2",
"cuan": ",',Q,s,t,z1)1[fLfsrZw;yv",
"te": "?vRgr{xe",
"zen": "]V_y",
"zei": "S;a_bv-0M-1Q-2+",
"zhua": "2(AU-,Y",
"shuan": "5<@]z3{?",
"zhuai": "#1dmi'",
"nou": ";v=,tfv;",
"shai": "/Z121J1e2[[K",
"sen": "Ve",
"run": "$1AOz@zQ{F",
"ei": "ZH_@",
"gei": "5C9J",
"miu": "7n:@]+_w",
"neng": "?LR'",
"fiao": "WL",
"shei": "Zg",
"zhei": "j:",
"nun": "-84"
},
"m": {
"yi": "-:~-:<-:;-:4-:3-:#-:!-9~-9T-92-8u-8R-8N-8I-8+-8(-7O-7M-74-6l-6c-6L-5z-5)-40-2U-2Q-2>-11-0o-/_-..-,o-,B-,3-+q-+[-+<-)X-(o-(5-'w-'k-'=-'#-&6-$'-!?~=}E}1|x{Zz|zzxix6x.x%wKw,v%uPs_rurorEr8r)pppdpXojoioVnxn<mLm=l1j{jvjkj/j(i^i]i6h6gYg0g)g&g%fbf2f1f0f/etepd~dpd;c~c`c@bhbbbTaE_T_>_,^g]|]{]`]/[!Z=Y5XVVTTgT_T7T1SxSsR~RyR;QwQ0Q!PDP6NbN^N,MZMSLXLIL6L$J9I}IUIIHMG?EaEHE4D!CwCFBkBTBEB9B5@2?Y?K?I>K>H>'=a=R;m:~:48c8!7,5g4q3&2}2Y1j1f1`1M1/1'0t.O.K,_,,*x*f(c'G&.&&%b%Y%G%$$b$6$/#x#T!9",
"ding": "-:}-8q-)?-%!vipfkGiydzY2Ik6u+B&^&[%_",
"zheng": "-:}-9O-7L-0#{1{,yjuvsRm*lNlIi;eheZe8e4e3d/`x_v]3[+ZSY8Y2XlVFTYT#Q1C@A!4W3w07.),]%*#C",
"kao": "-:|n{k][#TbL>>R3p/,",
"qiao": "-:|-:(-6A-5v-4=-3(-2[-.@-,2-$H-$5-!q-!=y/y$xkx4rSm+m!k]k%j:iSi(hqbvaT_wVuV6V$T%KgGaF^FKFGEpDSBCBBB;8<2b1C1>.}#e",
"yu": "-:|-:p-9^-9P-9J-9H-80-7t-75-6'-5g-5b-5H-4U-3F-2l-20-1F-+K-)O-)+-(J-%a-$p-$K-$9-!7}]}W}5{7zizNzEvyvwv9v3tytjtetcsqsos@rsq|pyp+p%oQn6m%l8kyklk8jfgvguf%eGdWbtb(aLaKa:`1_1^:]e]d]KZOZ!YmXiTDS`SUS7RpQyNvLAKsJKJJJ;IAH|HmHVDVD:D*D#D!CrC[CDC,B*@K=Q<><<<1;h;_:v9G908=7M7I7A535#2{2R1b1:1(0;/q.(.&,1+G+9+7)n)h)F))(+&*%!$M$D$=#V!A!0",
"qi": "-:{-:r-9{-9E-9;-99-82-8$-5f-5(-3D-2{-1:-0G-.j-(Y-(A-(.-'v-'C-&%-%m-%I-%F-%E-%:-$D-#N-!Z-!B}$zvyHwbw;w1u~t[tFn;n3n$m~l^kkiBg/dpdTcKb<aBa&`3`2`'_b_)^K]OYRY@X?W1TgT1SkSjS1RxQ4PbO@N]MyMCL]LZKhKOJ~JcJ]J[J>J4GyGJE<E,CyCkCjC<AEABA6@a@7@$?+>W<Y<N;5;49h9*6f4x3D,m+N+8)a)](`'4&V&1%K!C",
"shang": "-:z-:t-7k-3C-%S{p{*y:oAo@c8aA`@]}Q^G.BxBZ@P:h9>8l1T",
"xia": "-:y-:s-9u-6I-5e-3w-+T-*+-(v-'m-%n-!!}({Mwtwpm/logkeB_3YST)P~M<Jm4X3z2i.L.,,}*C)1%V%J$8",
"han": "-:x-8S-7J-3>-1A-/j-/i-*P-*J-(^-&C-&9-$k}[{Xtrrbp,n8lJl%dqbm_c_L]cZ(VLV%T]R_R^QRQQPOK9IJCH@l@^@?=k=Z=?<l8k7X6'3I3@1Z01.g,t**&{!p",
"wan": "-:w-:E-5=-/S-.f-+)-+&-&1{0z*x=wlwkv6tJt3ptpen%iGf_f?d[b.b,]1Z9Y|YmY=QOQDQ@Q,NVNNK1J%G9B2@h<m:X7}7<5:3]+&)t)Z%z!n!7",
"mo": "-:w-:5-0z-.(-#S-!l~j~b}!yQy#v!r_rMr$qno}o?iji_hR_(^d[cVzVkVjUHTyR$O4M[FrFMC$C#B~?~?o?e8m640`.8,%#m!x",
"zhang": "-:v-8k-8]-8L-3=-1byErnkDimiIh}hsfnfmfXey`Q]hYEPRNeFt<y<p8Z8Y,$(V$`#}#u",
"san": "-:u-8d-7q-5p-3c-*Q-)m-)l-)k-)j-)ix:iHg#T5AeAdAZ7s/%",
"ji": "-:r-:O-:<-9p-99-8x-8w-8'-8$-6t-4W-41-2w-1:-12-10-0*-/l-/^-/W-/#-.d-.^-.0-,9-*z-*`-*U-)d-)P-)0-)#-'6-&c-%s-%d-$V-#x-!{~z|~|f|.zxz?z(z'xlw;v^vJuZuLs$qAp=p;oJnfnEn(l$l#kRjsj0iBhYh!gEf=f<eseMdxdaczbAb*a!_K_)^k^F^C]@ZRYCXHW1V`VBV$UtU^TgT1RnRmRlP]P[PCOAO@O$N9N5K,JNI*HrHhGoGTFfF3ExEXEPE8E'D[BdB:@O@B>y>]=x<`;t;(9.9(857&6{6d5m3D/;.j+?(>(!&8%{%t%4$X$,#H#>#'!w",
"bu": "-:q-7F-,M-*w-*t-(d-'K-&D{B{?{6zPtOm#izh'gfd,bi[rY}Y{YfQHM,C>C;C:'=",
"fou": "-:q-(cvCBj4H",
"mian": "-:o-42-1d-0w-,S-,H-$`tktQsZqpq#aDNWJ^E=D~@p?|;k;,7G/o",
"gai": "-:n-9w-6e-+u-+t|'uYm@dy^AW%T`QYNaHZGNGM:M8|'{&6!,",
"chou": "-:m-:l-8m-5_-4=-2A-(m~{t/r!iKhld$b3aS_%[_Y%W~N?N=LJJkI|E?B_0h/O.s.p&3&!%l#v!m",
"zhuan": "-:k-7o-3G-3+-2y-.I-)n-%+~EzRyPreq<oXoRc0V28t5%)5(f'.",
"qie": "-:j-7Q-/`-+P-*@-#uw1u{iCcpbkaia8`fZoOZL]I~>;<`,E%g#(",
"ju": "-:j-:?-9m-7n-62-5`-5S-4x-4j-2l-19-0%-.Z-.:-,.-+n-)H-'d-$|{/ztx_uct_tNt$o{nvnqnOnMmqmil`jYj9j7g+e%d<d3d(an`}_E^j];[I[C[;Z^Z@YdY$XMUdUVR3M^M9KxJyI{IzIrHSHDF:EcDPDCC8AqAi?b?L?(>:<g<I;[:o7)4L3o3<30/4/..P.A*e)m%5",
"pi": "-:i-8@-7|-7P-2Z-.R-.9-+>-(h-(c-%5-!.-!,~|~X}2|L{2xhvCs<rwnumblFk7hWcibx_U]G[q[eXcUgS+OXN3N2HPB&B%<@8>7*6e4n2x.Q.G,n)Q'(%k%h%@$p#R!U",
"shi": "-:h-:g-9q-9l-9N-9M-8t-8_-7R-6k-6]-1X-0m-,^-,:-+_-+6-++-*>-);-()-'{-',-%.-#t-#7-!W-!>{>z|y{x<wQvqunu<r4pbpap[pVpMp*oun~ninhm;m7l0l/kQi{iuiQg!f}f|eCdodTc_c[aU^*[.ZyXYS6RXRUQ{QzQhMWLxLrLlL5HiH[H,ELBiAJ>n=}:{:s:W:5:'9v7C7?6n4=4%28.3.+.#,0)$&3$}",
"qiu": "-:f-:^-8m-6#-)u-)9-&+~*|FyTsQl4j2j1cFc&]rWkO%KIHeF8BpAn@s@b?J=o;^:l:k:j2D/T.k+D*'([!P!(",
"bing": "-:e-:W-8h-8b-6u-5B-4T-3Y-1;-0a-0[{mp1ngnZhbhah&cm[vY,W5R0QpN/MQLQLLJnJbGXE:@~4E)r%,",
"ye": "-:d-9z-9.-9&-4e-2_-0U-)7-(u-'%-$W-#,-!]{:zIxqxdwgoVm$jxjw[hZzZ!YyY;X:X6UhUcUUUSURQUPxP@P?P,OmOkMYMXIQHsHpCXBh>i<o8q7w753l3M2N1H0M0,0)).(T'b$V!a",
"cong": "-:c-8f-+r-)K}w}ptPq6eUeTeReJdZcnbUbIa3`^`.PTMxJ`HyG2FgF[D?<G9!8v8L8D8#5V3+1n0H)X(e(a",
"dong": "-:b-6R-4n-3,-0`-0P-0>-,u-,G-,/-'I|/{)y&u^tXr*mSm>lKl?eNc3_H^LZhX<QrNILfJGA8A+>L<j:n4#18.0",
"si": "-:a-9B-7T-7R-7N-6H-5f-5X-4,-3y-2+-1[-03-*#-)x-)5-'F-#m-!u-!M~)ugtdsJqDoaj.gUd%cHa2VMSDNOMeL{J~I/H!C'@X?O?8?*>^>J=,7[6?1</R",
"cheng": "-:`-:%-:$-68-4_-2z-0K-0C-(@{H{A{,zYz#ywu*pSlth%eZb^al`(_v^t^U]A[zZFYPXDWQW,VRVQVFQJQ)N}MnLtJPJ@IyF=F<F9EeETA!?0>e=_=G<8:?7f7d6/05/f*6*2)c%x!'",
"diu": "-:_-:[",
"liang": "-:]-:Y-9)-5x-5[-5>-5%-1G-0B-&J-%y-%7-$Ly2bWY7Q*KJIwG%<e:_",
"you": "-:Z-9#-7w-7=-7'-6X-4;-2*-0t-*p-)f-)c-):-'~-&u-&>~n}bvRuAq=pZo8o6m1lyh[hZh(d]d$c|cqbY`,^xXkTaS4OVM;LAKGK=H{GFD}DJ@8@(?V?>=g;C:b976B/j/i/O.b.D,?,>+Z+Q&g&d%O%!",
"yan": "-:X-9d-5]-4]-4O-3;-1u-1Z-1Y-.a-.[-+:-*O-*F-*/-*$-){-)z-'%-&=-&2-%'-$N-$G-!L~~~a~Q~5{GzAydy7xLx@wMw>vPv>uFu@titfrgr?r9qwqfqWpKmhlEl'kuktk0jUjKjJjIjGg<g*f'f&c$a7_5^~^8]w]?Y3Y'XhXPT3R8QZQ.P`P/O}OrJsJ<IFIEI5FeF'E^E.D`D3C_BhBG@,?P>M<V<&;K;D:i:H9R8y8S5O5I56544k4j3u3X3J3B3?3!2~2U1t1E140Q/U,w,g,d*Q*()V'$!3",
"sang": "-:V-$J-#}WgK{KzGV",
"gun": "-:Ub6JY9W93",
"jiu": "-:T-:8-:7-9|-9v-5A-2p-.H-+|-+e-+]-+A-*(-'U-$wvdo(gogdgc`IZ2XkXBXAW9TGRhO#NTM+LsKwFxD;BW@v@Q5$/b+:%X",
"ge": "-:S-9Q-8R-7!-6|-59-.O-+l-)(-)$-(e-(D-'4-&Y-&?-#s-#`-#J}6yhfLaO^^^R^=]_ZkX*WHULTML4GsE!CW9l9`/T.f,C+k%Y!,",
"ya": "-:R-9>-9<-9:-7m-5K-0W-.$-*H-*G-*A-*?-(s-(H-&n-&'-%;}L}@}9{j{5zbxTuBu3t%q2n,lVlUhKh?[`[ZZZY:XLN'KlIsIFA0A,<r9,8//g.^,[,E+/)}'b%h%J$x$K",
"pan": "-:Q-0S-/B-)R|Ys3i1[O[AW]U=MMGu?t>}>k:c9s84684l0$/w&C&/&,!*",
"zhong": "-:P-8A-83-7x-4Z-0j-/C-$Tz8ysx$vMvHs^o)i)eqe0dddYS`MKC2@=?G4w2k.T$F!>",
"jie": "-:N-8i-8<-5$-4~-4W-4!-3j-2]-/@-/?-/)-,r-,a-*j-*i-(e-&c-%d-%H-$m-$8-#q~zzKz7vevOuit>sasVsCs(qSpIoJnpnln*m|lCkvkbjrjqjgjbhihIeEbr^S^;]_[,YZY+X{XwX?W_UmUOUJS9RINXNJL0KxKoI~I1HqHgHfH8EOB,>j>;:z9b882?/'.6+0)H)8&K&J%g%]%M%##D!~",
"feng": "-:M-8:-5L-4N-2Y-0]-0&-0!-/{-/y-%p{Rz9z5w}w9v7odoYl}l|l5W4MkKPI.E[?m?h=S;Y;#:R8e5Z4i3V3*2g1h/1,O)u%C$B",
"guan": "-:L-58-1=-0l-*vphb@b?af`LXqW*SRJ+G*D(B2>w<v<W8G5Q0E)W(4'e$_$0#Y",
"kuang": "-:L-22-0V-,b-+V-+N-*v-&o}&xNwFm_dJcW^z^y]>RWQkP#L)?N>=0X.X.U",
"chuan": "-:K-7o-3G-2t-.K-$]}Tz3jFjDPMIRIDCbA?@i,H+<)7",
"chan": "-:J-91-2y-2R-1~-1/-/:-.k-.J-.*-*~-%$-$F-!n~P~@xBszr>q3l>kJkCkBjXh{hpgWdu^r^lXsX+W;VqVhU#S9RYJsJXDEB#=v:^967o7n71655d5B2V1I,#&v&u",
"lin": "-:I-9U-2g-0e-00-0/-)v-(l-%PxDlbk,gIgHc=bob)_=_6[MVGS?Q+PGN!FIEmED<U7j7H5h3819+u)S(I'+%o$Z#M#K",
"zhuo": "-:H-4t-.`-.<-+#-)X-%U-%T-!G}+y@v,tYeu[BZ,Y~V3UxU[StSHSESBSAS>Q>L#JuJfJ3J,IoGcDh@j=|=h<b<J7%6S5[4}4N3_3#1>.h)e)N",
"zhu": "-:G-:B-9]-7d-7G-7?-6Z-.&-,t-,n-#T-!z~4|=xpx3qVq!ploNnWnIl*i>[[[WT&StS;OqO1O0O.N>M#LzLFGWFmF,DhDbD^D0BH?&>Q;b7t7Z6s5x5>4V4A3y2^2@1+0x0?,K*K%B$J",
"ba": "-:F-8l-7`-1E-)^-)@-(b-&M-&I|_{[x>wCv0mumIj,fq]o]I]6]#[GZ)O+M'D,5?4R0+.m+@%N#/#!",
"dan": "-:D-8~-7{-7H-2r-2J-/V-,,-+G-*~-*{-'f-&2-%C-%B-$v-$F-!m-!b~[vTsjiofTfOfEb$aga>_q_P]4[VXuV@V?UjRiM/BeBSA*@)>r<?7.1I.@+#'O''%f%:$H#`#N!F",
"wei": "-:C-8{-7p-7e-7A-4s-4V-4Q-3~-2x-2$-*h-*b-*O-)O-'q-%q-%k-$s-$S-$@~.}o}m}S}7y1xJueu7u$snsUsHoqoQnxn_m9m2lHl7kskZk=jljTiniEi9gme=e:avaPaM`?_JYnYUXbX1VEV1S^PuO5L*JqIOINHkD@?g>c>C=n=$;S;N;0:N:08?837i6R6G5|4]4>4$2]2O2F1]0u02/$.r,[,P,I*~)h);'f&H%!$N#X#U",
"jing": "-:A-9C-9+-9'-5r-5%-3A-2O-1N-0K-0C-/9-.~-,y-,k-,[|i|g|cyIvQt:t8t+pojAh|fdfZeeeWb/___NUoT+S&S%Q:Q3PIP0KZJpEvBsBn@I@H>m>%=><87]6#,r,'(^(B(<%($u",
"li": "-:@-6_-5u-5k-5Z-3s-2&-1z-08-/Q-/=-.o-.G-.'-.%-,l-,&-*L-*I-*:-*.-*!-)|-)Z-)X-(z-(2-&U-&0-%g-$C~g~`~A~>|`yrxEu+tat#rjqYq,nAmkm5m.lzjag@b]bXbRbB`l^&]q]gWYU@U3TsTlSpP_P>P%O&NmN^MqMSLnLcLYLUK!JoJdJMG1ECDuDjD_D8D.C/C+?k?[?Z=Y=U=/:/8z7@6C6$5H0a0U/>/=/#.z,~,u*V*$)z(t(_'x'u'l'W%R%F$l#P#A!Y",
"pie": "-:>rVV]V[PHAD8>",
"fu": "-:=-9c-8[-8#-7z-73-5y-5m-5j-5U-46-3v-0d-/|-/J-.R-+h-(=-(6-'[-'S-&E-!s|<|!{]wvwWvVvRuru'tDt,sbr5qJq/pmp3oWmgmFi~ifi7hzh;fwfkeje?c{ct^w]l]J]&]%[Y[QZ+YfV7S}SLS)ORN+M]MGM)M'L1KWJ2IYIPHKA:>~>Y=W<w9c7T4S3d3/0.+2*t*!()&m&b&N&G&@#h!)",
"nai": "-::-6v-4iw:vhv)qxq(g6WVV{M$AC;<%`",
"wu": "-:9-:1-9D-97-8>-8%-6;-5|-4k-2k-2:-1q-.T-,|-,C-+y-+/-*V-(U-(T-(J-(?-(+-&)-%K-#v}4|^zLykxvvxv4u%tjthsurTownkn9n+lmkzk_j6hFgQfudbd`d@c'b[bZbKat_]^[]e]d]]Z4WGTTS7RoROQENvNtNoM&K#FLCVC=B3@[@Z@S?{>T>*=V;^:,874(3C322*1w/V/A+3*4*3(|(P')$h",
"tuo": "-:6-8X-77-6h-6.-'a-'G-%[-%$|Sz;v8sNrRmck'gzet]i]`[H[F[EZMYuV1NgN^MTM8ITI+GbFBF0AvA_@d?`?_?^<k.K",
"zhe": "-:6-9[-*K-&L-%9-$o-#T~h{Er^bp`6]H]'W_ViQGQFNgM=JWFwC%=m<E",
"ma": "-:5-9Q-3o-(r-&!-$%-#4-#3vUs1rWqNhR[cVzNQH2:2/&.c,4+5(x$[$Z",
"me": "-:5~t~j~UhR6I",
"yao": "-:5-:,-8;-6D-5@-4?-3_-2q-+m-)&-'7-$b-$2{}zBwUvGu_svs=pro3o,n/m,l,k#j~h^e;e.cqcRa%[oX2WrW@VdV$PkP'NGN#LuI;HBH9G5C!BA:B9J444&1|0f0(.E,;+r*D(~(l%S$%!t",
"zhi": "-:2-9Y-6f-5^-5C-4|-4d-44-3y-2,-/}-/0-.U-.+-,v-*e-*>-)C-(W-'v-'8|||{|T|:z~z{yFy@x$v%uNtsrGp&m7l0j+iridiahyh5h3ggf5eYeKe4e3dmdUcU`6`*_$^{^E]Y]F]E[u[HZtZpZ]Y{XvWpWVW2V{VvVtUKUJU>TjSMRwRgQ`Q/NOMyMcM2LqLhL6K~K7JjIuI]I*H+GHF_D|DnCAC6BiAJ@t@O@N?v?T?3>V>3<L<!9e9S9B8}8@7~6>4`1_/9,x,^(R'w'[&3%c%;%7${$z$k$E",
"zha": "-:0-48-.N-.=-*C-(w-'X-'?-&K-$j-$O-$Aw/pNd6]s[m[XZdX4WIW#O2M7M1M0LvLlI?H4Fv;X:67u5#4@2N/p&d%.!M!H",
"hu": "-:/-:'-9j-9F-5E-0Z-+U-+L-'h-'W-%n-%Z-$_-$4-$1-#>-#2~k}v|;x1x0x,uGt4sEr]r[oxm[iphxfxfgdFd*d)cGa{^V^6^4^3^/^.^,^']y]9[xWWW$SXRFR<OjN(L8I%I$GEGCCR@9@&?f?7=t<.<+;$9E99986Y5s483S2;1a.J,S)b)+']'['I",
"fa": "-:.-8!-6y-3Z-0R-)]|A{vy)uwm4fKL@FO?X?:=z5R*[)L%8#.#+",
"le": "-:,-9R-8r-,J-)2-#1d}]qH`G5@z??/b+A",
"yue": "-:,-1g-1e-1`-/P-&j-&@-%A-!DvAqrn1m^jec,bubS^]]g]8Y_U@OpOoOWN8LcH`G5FTDj?'5e0J+*",
"lao": "-:,-6~-3!-,j-,i-,>-'$-&N-%z-#p-!}uSr`ljk/cY_f_eYtVZO:L=G5F!=O='8%7a3{/^./*<$f#c",
"yin": "-:+-7}-6^-0t-0;-*c-(j-(V-%o-$d-!T-!+~l~+~$}`}$|&{w{YzXz:w_u=t0t&p:n}lnlLl<jdg^g>fya@`i`B_u_t_0SMO[L:KKEkE@E1DKCwC_BYBGA5>l>d>U<5;~:}:i9}9V6^6]4).],|,j*I(U$7#k#_#:",
"ping": "-:*-5i-0]-/z-/s-'u|Qz1u/ngnZmTi[iJi4heh&`0_zMfEU?6>6=A<D3)*v'F';&_",
"pang": "-:)-*B-#ww}r|o2h9h*ere<S2@<?y9p4i",
"guai": "-:&-)_wVcuc>[KMbLw",
"sheng": "-:%-:$-4H-.X-.Q-,?-+0-(9}=x{x7u*k}_VS[RGQJQIOeMuIyG~E{BzBF?%;k;@:q7G2u/M.N*h)i&y&s&`!'",
"hao": "-:!-65-3k-2)-)6-'j-&_-#k-!t-!Y-!#~xxRvacOblRDR'QBPePaPWP7J!A~Ao=]<Q9j9U7S6c5N5@,/,)+}!y!q!h!f!c!_",
"mie": "-9}-),-':-&Hq7hk^uWeDr9m64504!",
"nie": "-9}-%*-#e-!O~m~D~5~2}#q'q&mFkTjujLivZ&YVY5X[WCVsT|T<MVG@DW=@:Z%+",
"xi": "-9y-6&-5l-3i-3#-1B-0,-+?-+*-*n-*R-(P-'x-'>-'6-&/-%]-$X-$:-!p-![~T~8y?xWwnw'tgs;rCr@nsncn`nRnHkgk9jpj`jZiqiOeceOe9djd_dEcscgcZcKc/bqbeb8ay`r`p_s_r^V^6^4^3]_]O]HW%R:QKQ9Q6PEOzNON)MdLZKSIdIGG{GUFkFRE|EjCzCuCmCMCJA4@e>X>S=f<[;i:+9h9)8p8/8,7N3e3R3K343&2Y2+2)2%1q1P1O1N0}0P/E/?/*.{.t.#+p*r)|(#'h$1!k",
"xiang": "-9x-9,-9(-6}-3*-1}-,4-,$-*0-(x-&r-%L~Ww~uXk5j)h7gqe'abQXP5LWH^F1DH;!8:*E'g'T",
"shu": "-9s-61-5g-55-54-1|-1F-)Y-'3yNyGu[tGq4oNoCnWnIg}gxdWchcgcIbt^X].Z.Z#Y>WBU9T'S|PvPtP*OhO1O0O.N[NBMtL`JtFuFYEpBuBKAaA`?c<O8[8H7m7Z6m5q3Q1k)f(i('%h%e%d#O",
"dou": "-9r-61-1T-1P-(~-(N-&&-%|])S]SPN&J}EwAm=d;n6<.$$v",
"nang": "-9o-1s~d~;~1_QWwU{TkOwD+<n5b5;",
"jia": "-9n-8<-7Q-6w-4X-3X-2]-,}-)S-&?-&4-#F|}{MwIwDsrs,pvpImei,e[eBd^cA^J^G]L[d[Z[,ZWZ8UhSYSVM`M_K/ILHNH:G^ENAz?H>&=L/3,E,B*n*d&f%0$8",
"mao": "-9k-1,-1(-0|-0z-*dzLwksLmOkzi?a=_?^(S/QvPrN4M@I'B!AcAW?9;F/Y/#,J)E#$",
"mai": "-9i-7I-,{-,*-*}-#${Kx5",
"luan": "-9h-9Y-9V-*^}C}Bvmu0qXq:q$m)jOZ[TvOuL2D69K5J59#4#3",
"ru": "-9f-6K-2C-1K-(N-#{-!$vkv[s7qyq)jciX]kZgUTP+NzL(E0@W>7;Q9u6b+^",
"xue": "-9e-.x-(Q-!9|Bxbq>q+mmmMjzf=ckT/SlKvFc?!>u9j7>5y1&.B%L%<",
"sha": "-9b-4c-3?-2H-/,-.t-*+-%t-%^-%H-%4-$R-$0iCgkZEZDW<N{NrK`H?FlCaC3BDAl?w6{2P,v$g",
"na": "-9a-1*-*|-(R-(8-&T-#_v=tx]0[LZxZgYWWL",
"qian": "-9`-9Z-9W-8T-8B-7l-7(-5q-4w-4^-3g-31-2<-/r-/[-.u-+4-)}-&4-#u}/}.zaySy4xZvgt7seqtq`q5n'n!k{kVdObgbLaN`f`<]Z]N[J[1ZCYLY=Y!X7WSVgVbVUU,U+U)O_NwJ_IbH3GiGPF%E7DzD'C~CeCZC7@]@M>$<%81806O5S4B2Z/J/B/2+%!l",
"suo": "-9_-9=-3]-&8-%x-$&-#j-#gu&s(as^$ZEZDW:PjKaJz:E9y+|)w)v)!(]",
"gan": "-9Z-8S-7J-5&-0=-/u-'c|Ro'o%o#o!hfh_dqa5U~T]T6R_NuMDKLH6FNEd@??;<:8f7_7/55+;*w'#%?!T",
"gui": "-9X-6q-3{-/(-/&-.7-.5-+Q-+J-+I-+F-*%}3{zv2u;s?rhrIp|k$jpj`iLhLh,gmf;cMVxVVTiThRCQ2O%M9L.KeIeI`GTGAG<G;FWEQE)DXDQC*@v;;:H4t,Q*A(r(D'q#X#0!|",
"jue": "-9S-50-3f-0X-/R-.?-+@-*,-)X-(Q-!a-!R-!9~I{PxbvAqRqQnLnJlPl@k$j}fmf>_k_Z^b]7Z`Y~Y9V^V;TnSgKTF7F6D[CvAG@:?!5P2|1d1>0S0G000/+z+M+)+'*](n(G%L$3",
"liao": "-9R-2|-!rrLovomo<o5o4nKkLk+k*g]gG`/_^W9VaV9S{SZPLO~FxFA8Q8%4f1;0V0R+q(H%[#g",
"er": "-9L-6v-6T-1r-1a-1_-/1-'B-%hoHoGoFmAg$f~NiLCLBK6FaAt>[>90%*F",
"chu": "-9K-5N-3d-3R-2K-2!-0$-/m-/Y-/I-,t-*)-!o{$x!s>n5hjgXcj`g_SWxW$VoTNS=NEIjI&HoHQF|E}EsESE#DsDdCzCG?@9r9q6x4N/+*+(,&;",
"kui": "-9I-3{-/4-+I-+F-$U-$;-!xwow4s/rBo*mQjVjHb]a.a,_y^BXgQdPyI2I0E&BV:S7x2l.q!/",
"yun": "-9G-7r-3q-1p-+}-+x-(0-&^-$^}xwEvsvEqOb}aca4a)`c]2[yRNQTP}MwHWF@BmBaA&A%@0=3=!:!7W2h2:202(2$1b.Y+(&P",
"sui": "-9A-5#-&F-#U{3wytvr1nwn4kpRqEWC1C0Ab=H9[7+6z5}2C1g0~(/'p",
"gen": "-9@-9?-&pX=X'L7",
"xie": "-9=-9!-7[-4J-4A-4/-39-1{-0s-0c-,w-,+-+'-+!-*k-*Z-)7-$(-!C~e{ry_wrw8w1u)sOq]opnenVnNm$jrgJeFcT`z`p_BZ~ZWZ8X9WnWMV*UiUFT}SWRePXMZLIK@JwI,HOH?H/FlC]?K>p>A;P9h7B695{5!4Q4P3b3E2,0w0s0O,C+k+e)8",
"zhai": "-9;-6B-4f-4*-3E-*K-*C-&c~zw{p{os[u[2YxW/UwU>SiSfH#EL#t",
"tou": "-98-4'-4&{$wNv'sqs@aK]*T0SQ",
"wang": "-97-8v-87-1JvYo7o1o0o/eoeiefe[dldJa}]>RTQ(OEODO=N1JD@J6;+E",
"kang": "-96-8)-+X}|rmkKg|dG`8]f](G=8_4d.a",
"da": "-95-.N-+f-'f-'R-&m-#~-!J{hxrw[v*d'ag_q]nWZVJ@f?}:<4Y0p&@&4$#",
"jiao": "-94-6n-6D-2q-2j-2I-.B-.6-,6-)B-(<-$H-#M-#K-#?-#(-!^-!=~IuUu1r=r6qcm+m(k1k%k!e.e+cJbl_~_i_KZjZTZ5X&W9VlVCV(ToTJT?T,SwSuSgSSQbPgP2LOIpG!>!:l:k9Y8w8<7b5[5C443,2b1>1*.9+l*X(5#e!v!^!V",
"hai": "-93-'V-'0-$#-#h~ey]vOq;pL[!A3=N3[,C",
"heng": "-90-&B-%QuJcXcLbaVKL/FiF&<|42*B",
"peng": "-90-5,-3J-.F-+o-!~zgyqyYfUe|cyc+`%[tZ?Z6YkXpWvW4OTKCJLIlIWGGFn?6<R<D8e8]7Y3Z1h$a!u",
"mu": "-9/-8H-/~-,=|Ey9usuSu%m<i&i!`[`Z[TPVPUO7O'I(FrFqB1AwApAX@#4h/a/_/X/L.S&U&Q&E&:&9&(",
"ting": "-9*-68-60-4C-*M-*7-(]}>t}sxk~hVhJh)gBg?g;dzZ<K]KHH~H(@u=6;]6u453`3^*.&^&[",
"qin": "-9%-64-1^-,8-(g-(f-&#-#f-!Q|w{Fshs.p.p(o~oyogkmkVk2k)hOgbdO`C_G_F]N]5YlX,X$V/UlS@R=J|E`Cg@3:$7'6(*J)R)M#l",
"qing": "-9%-4b-3<-2(-0A-.b-,O-*S-%1}V{1wfp7hQgwgeb4`9YLUpUoQ5PsJ'G/EME/DcBnBFA7A.A(<';w;B916X&x",
"bo": "-9$-8Q-7`-73-6,-2v-2f-.e-.]-,Y-*y-*w-&M-%#-!h~oxbq*k3ibeu`s^|[3ZJWyV=V5UgUfMFM'KYHKEVEUDFBj?E?,=e;};W:L2//l.?,9*q'`'^#2#1!Y!8",
"lian": "-8}-34-.;-+E-+D-#V-!XzUwAvusMrKr/iegjd&cS`F_{^fW.T=SrJhI#GiGSE7DfCHBlBP=%;6:C8j8A777$6p5p5l4<2f1y0z)x)3(X",
"duo": "-8|-8X-02-/2-/$-.c-.V-'`-&y-&e-$O~}~S{|{{z}z]xzxywiwhwHvtvlsNo+lOh1ae_oZrZqYJTET>T8T.O)O(NfN^MrMTMSM&KuIRAh?`?^&D$i",
"men": "-8{-8G-53d8bcbCaz_9_&]VYgS^PZIh@>3=1,+((W",
"ren": "-8z-8y-8s-8U-8F-88-/d-/cx;vSu`n:n2d|dwdv]XO,NiLPLMK6J7/]",
"shen": "-8t-7V-6i-6/-5d-1Q-)l-)k-)j-)i-(V-'i-&}z^u|u>ttsys.qmp_pHorn7lui(fp`t`b]b]4WPTFR4P9P3M:J7J(IHHRA9@+=D<0</;f;e9?671?*g&~&w&q&e$G#{",
"ze": "-8p-6B-4*-/M-.{-'X-%d-%2-%.-#9rcl:iAi#hU[~[2Z$UwRKR7G)C.@q?n?A>n:(9U7C5[!e",
"jin": "-8o-8j-8d-7}-6<-35-2^-2=-01-,y-,k-,[-*X-*'-%o-!F~y{Fzkz6y<xPvFt7rfr9q~p(nyj'j!gbb+`CWfSOQaQ_N7HEG8CTB[>E=q=M:I9$6~6g3h2M0i*Y)y)K(z(d(@(*",
"pu": "-8n-3$-+k-!S}^}O}<{BzPy(]p[rY{V0UvTeTdQ;PiPPP&O*M,FZE_AS=`:17k6T614r3a+v(C$m",
"reng": "-8g]m",
"zong": "-8f-5:-4y-43-3KzFpikxkrkNeJcdaraVY^XXX(W&Q|O>MxJQIKG28L8D8#3+1n1c0{,b,R%E#w",
"fo": "-8e-8;-73|IJl",
"lun": "-8c-7i-6S-4u}l}Y{.t*lSlRb9[{YMJa?j<6:3",
"cang": "-8a-89-7h-5;-3e-07-+OkeD<?i9n6J,**{(p",
"zi": "-8`-4m-17-.h-)%-(W-'t-'r-';-%@-#r-#cupuoudu9qTqNqMqHq1q.l;k[c;NnLKK8InH=Ez?s>W<];o:Y9g9_8a7;/G+J(!&Y&7",
"zai": "-8`-3V-2G-1!-&v}8pOl.]j]>L3>f;>:.4|4{3~&Y&7",
"ta": "-8^-6E-3^-#~-!&~Kz$yyy6vep}lc[HZXW`V&HCG}EqA[?}<c:<9w8^7(6w/`.3+d+V",
"xian": "-8Z-8Y-7b-7,-30-2m-2d-2b-1i-0O-)o-'c-'E-'*-&O-&2-%6-#u-#:{`{!ycxXv`v&uKu>u.t`tZs~r~rOrNr9q`pUo;o:nBmylxlhjthhgCfhf+dI_a_X_R_'ZPYQXsWnWiVhVXVSU6U'QlQNPKNFMhGiFFEtDRC~ArA@>S=E=7:]:C7Q6*574*0l.=,s,G+f+c+U+O*|*s*T*,'3$c#b#Z",
"cha": "-8X-6Q-4D-/,-.t-)e-$A-$$~s{yvbu?o|m}kqj3]a]OZ7Z.XZX5WJW1NsM0LvK?I?GjEB@k,<%s",
"hong": "-8W-)w-).-(X-(K-(;-&{-%}-$)~i{kvXu6pqpjn=j[fvfBa*``XeVNQ[@E?y?<>@=b=S;J;B:R8J7U5(3|31+>+4'T",
"tong": "-8V-7/-6R-4Z-2h-,/-(}-&|-#Z}o|/mNm>m3h:f(c%`P`)Z1Q]P<O<K|KUG+F+AV=P7l4C4#18.~.0+s%%$s",
"dai": "-8P-6G-3W-)g-(B-(4|3{(w[m`ikiViMiFg[edd!_/^1PAMJJCC)ByB+5c,2*y)?'!",
"ling": "-8O-7X-0?-/D-)G-(#}h|>wwuqtKqdmdmVlQjhekY<R)OQMRJeJ5DND)?/<77=5'4O0v0=.I*z){'H!z",
"chao": "-8M-8D-.B-.6-,6-(S-!yjQj?j>ffd9]<VlQiOBGFG!C{9+7z4g303#22/v",
"chang": "-8L-8J-7j-5D-5+-5!-3|-2~-26-1b-*P-)~-%i-#8~v}%z=yZtWrdo=iDgReLd>bDaxT:RBQtPcIiAT<T<P2t,`+6)^)4(h'B&z&R%w",
"sa": "-8K-+2W<VPU:Dw?'>X7s5L",
"fan": "-8E-0)-0(-0'-,1-+R-)a-!hy%v_tDr;r:iwhwdi_h]l[ARvRtNpMLKXJrJAG,FD@w@g?4955t5_3n2E15.l.[(A&O&/&,!.",
"miao": "-8D-,m-)v-$?vDscrPh>gtgSX^NP<#;A+K",
"yang": "-8C-7<-6{-3[-15-,f-,@-*g-'Z|J{xwTukswmrl6l3e`d4cEaA`m^}]T[lXRU<T*RVR2PmNRMHL9I7HvG`FpB|A=A2A'>z>`8N6A4y4D4.2B+6*O)4%Q$|$@#F",
"ang": "-8C-*gn.RLQoN0!5",
"wo": "-8?-4s-4L-*l-(/-'&-%q-$atCtBsfi8^TZYYbYSXKV#SRN8I>@1=#<m<h;V;U7!6`3.,N'|",
"jian": "-8=-6J-5W-5P-4g-4:-3g-2s-2i-2L-14-0L-0<-.q-._-.W-.P-.4-.3-./-.,~6~'|bzmzaz2xovfuRuQp4oDiHhcg8fNfHeDaq^Z^Q^<^9[8Z>YqXmXjX7WmV!UGU'R{PpO_MoM(LEK3JgIfIJICI)HEG]FhFCEKE2DLC&BMBLA]>a>$<z;l;a;&;%:Q8T7P6H625k5f5a2a1l1Q/u/Q/2,g+%*W)<)6!2",
"fen": "-86-3}-2n-/a-(`|v|q|]xuw7vpv;n&ithog,dDa0_gR>OYOSN.K&J*J)F)A>@66}5i4v391=16+{+.",
"bin": "-86-3S-2EpAe}W?UNShJnImGXE:B^BO@r9I6q6Q6M6,+.(j((",
"di": "-85-7@-5a-4F-3:-*D-'}-&t-&$-%R-%&-#O-!(}0|h|d|@{Q{L{8zMyFy;x|w?tqsmrimUkIjoi`hBg:fofjeld#`7]g[g[=YFX]XGW2TLT!R[NfN(MrM3KAK:JCHiG7AI=g<};T9f9=3F/K.V+=*5'1%c##",
"fang": "-84-4}-+^|r{Qzcv5er^%TZS:S(RER6N/@<<M/Z'P",
"pei": "-81-7$-5o-'lzyvZvCuCtOs_k7iid7[eU5S5S,M'LyJUAj?u=F<@.`*=)d",
"diao": "-8/-0@-/f-/G-)1-)!w$njfzfYe~]gYHI|@m)U#p!?",
"dun": "-8.-(a-!2}}|sy!x~x}hNdPb2_mVYV.T2HnF>@'8*4c1@/!+m",
"wen": "-8,-/X-(M-(C-(&-%Jy`vNf)dfde]:X.WRSmQsKNHWH)C$B`@>;z;R:*4s+1*8(}(&$;$.",
"xin": "-8*-7f-5d-5G-!3-!0~%v<r,qFgTe$e#dHawa>SCR9N@N%D$C^4a3$",
"ai": "-8&-2W-09-)h-'!-&q-&5-%Y-$'-#]-#E-!;{SzIyfxUtgtUrxr'kaa9_7_,ZNYaT&T$QqP^P.CxClB.:%9t6U3.03(k(;#]!s!j!]",
"xiu": "-7~-5c-5V-''-$/~|p@mfmPh2N~G09~9F8I4+*P*#(N",
"xu": "-7~-7Y-6Y-6!-49-0x-,F-,E-*Y-)T-)+-'p-$e-$Q-#7-!o-!W}7{Wy,x+v&uxspsArFhHeXckcKc:b(`g^YY4XMTKT@RbRZR!QcP{O^OOLGI9GfC|CtCiCOCKBw@5@4>?=t<>;+;):P9r998W8B433W2H0m+t*N*?&;%T",
"tang": "-7y-5+-4M-3l-3U-1v-.2-&.-${-#.|XzpyukdilaA^cW^V~OsJFH%F{F<@P<T:h:G8n5D3i23100A(u",
"huo": "-7v-6r-5T-.Y-.1-(p-'W-'D-$e-!%~V~Fw^vouWf.f,b'^OZ/Y4UPU4RkO|E9@%>/:f8U6y6Y6+525127+_#@",
"hui": "-7u-7#-2u-1{-+H-+.-'/-&j-$[-#=-!f-!U-!D~p~,~&}u}Fz]xztEsgr7q]onn?n>i*gmg7g5f6f4f3e,e*cDcCc<c(bfau`H_x^sZ|ZQX>VEQSQCP|PQO]KeIOI3GRF4EiEZEQDqBVB>B=B7@n?D>h>g=y;+:S9X897x796y6:5,5)3t3q3k2h0y0q+h*9)G(=(2$~$)",
"kuai": "-7u-6@-2M-/p-&f-!8}:|ez&y'jEgMdXUkRrO]Cq=y79.*+g(2",
"cui": "-7s-5?-3N-04-%I-%>y8lYlWkhdSbE`TV|IxH*GHAg<48P6a331g)p(b%I$L!d",
"che": "-7n-5`-4I-,%-'y-&*|?vln|nGene/]QY.XcVsV>V<7`3r3b3E0C",
"chen": "-7h-4_-3e-2'-#|~ZyWyAw]pGoBdRa>[aY]THS~QAP$L[K_K'J(HUG3D]@+@*2n05)l%P$?$$",
"xun": "-7g-6O-4.-,Q-,A-,)-,(-+5-'3-!k-!P~u|y{=yixYxAw#uHqKq9o`oOmEj@j&j#g=ebe>c]`uXUTfRcP(NqL_KbF`BvB@Au@Y>5=r=l8+7y6V583O2h1{1D130j0Y0Q.5+b*H(L&T",
"chi": "-7c-7M-6b-6P-5E-3@-,W-,K-+_-*]-)<-)3-))-(:-&W-$z-$I-#l-!g-!=|@|)yLw/vBs6n|fsf$eweve6cBc9`X`7_|_2]`[f[!ZvZ/W+TxTCSNNcMPM3G1ChC6C4BX@T?Y;:8g4~4;3U1K.O'A$Y$U$E$2#G",
"xuan": "-7b-2N-/.-)o-)'-'(-$Y-$Mz)wsv&sWrqr.p]f[cobMaQaI_I^nX_SyS'RAR,QeQ$Q#PNK@HxHwEf?#;I8d4M3x2e+L*s*)*&)B(Z'~%/#E#<",
"nu": "-7a-3r-,svjq?ilfed1Wo",
"bai": "-7`-6z-(1-&:hJ[?[>ZwYeX}WAUfUCTAMFLN,n'D#*#)",
"gu": "-7_-3T-2e-0F-)I-'s-'N-&<-&;-%G-#y-#@}gzfx#uhrUq@o&lXl=j5j4d*`~]_]9TSNaM.K<JIHFGzF$D{B<@K?R?=<X6P6./P/@$Q!L!G",
"ni": "-7^-7]-7.-4v-2>-27-+8-(%|Nzsznv/v)t<rkqkq0nznbnEcvb5`{_,]0[i[<Y5UQS$QuQ7PSMPJ&E6@y?)<=9x6o.F,l%b",
"ban": "-7Z-.!-+,|z|Yutn0d2]R]M[OW]W[T[ScSbRJOSN;MM:c/x*>'Y'R$*#[",
"zhou": "-7W-6M-2X-0{-'|-'z-'Q-'5-%X-$i-!G~{v.t/pgjCiceIY%QnQLQ<I|>8<S494'*S'9%W!R!I",
"qu": "-7U-7E-7+-/H-,q-+S-+=-+7-)t-)s-)W-'e|Vt^nnm{m]k?e%`&^0[^SzSIOnOOD=D4CzAL>)<3;[5U3G2o0D(K(8#9",
"ci": "-7T-7B-6m-47-17-/+-/'-'t-'r-%@|*q}j3h<`hN|MILHD&C??56Z*p*k'E'6%=!{",
"beng": "-7S-#w-#+{R{#zgyXw!lBkYX0>v)d)[',&k&j$a",
"ga": "-7Q-'M-#A-#/-!4wIwDoEo>o.RaOM+C",
"dian": "-7K-7:-3m-18-**~M|P{lyBxfw6v~t6t!kXj]jNjMh@ao^!YOTrTWT9I_GqG_FPF5B?<a9k764?*u)s&c&`%1$W$$#L#=#6",
"tian": "-7K-56-1>-(7-%`ylybwYvit=nodgc2b:Y#WPQ?LSB{?U<A<$;2)g(q(.&}&|&h&`&L&F$W",
"bi": "-7D-78-73-5F-45-+c-(h-']-&k-%?-#Y|jzVxgwLvnv:u}twt1r3qonrlFi|huhthPgLg'fRfQfJeme!crciaJaF[YT;SqS+OXO!MUM!K;I<HPB)B(B'B$A|Af?x?C:u9Z9D7q6e2`1p.%+y+x*`(:&W&V&G&5%^%H$T$S#'!o",
"zhao": "-7C-1k-)A-%X-%T-!y|#v+j*]B[@S!Q}P8OBM{J,E*?S6S4T2G0r0:09.7(m!F",
"shao": "-7C-,p-+~-*a-)A-&Vu,oIf^Z'R|NhM?K(7v3m2s17*m",
"zuo": "-7>-72-66-4E-'L-&,-#!|lmtmsj;h0d6YTV4R%M7M&)e",
"ti": "-7;-5N-5'-4R-/!-.n-*;-%H-$y-$3~w~rw?smsPnmnYnVl2foeCe6bnbjb#b!aU^)ZHY*X]XGU>OaONL$JxJCCQB]=0;T8O*5)A'r",
"zhan": "-7:-4>-2y-*s-!IrQnamRl>l)kCkBk.j|d+b0^M^?^5W|SJSGS0RsMjLiL<KmJ?HLFCDEAyAQAO?Q:|)q!F!4!$",
"he": "-79-,_-)$-(v-(/-'o-'Y-'W-'&-&R-%<-$Y-$W-$1-#d-!c-!!|,xVuyp6mJb&[jTROiOZMNL8I@CsA^?]<i;M7R3P2m2'2&0k0e.8,C#^!W!<!:!6!1!,",
"she": "-76-*E-*9w/v|oVfP`_`;^h]'ZyZbYjX:WEWCT|EEDACJ?@=<<f;s9Q5Y,W&*&)&$",
"die": "-74-)M-'>-&t-%H-$j{szSmDl/kIi3c}cPa`^IZbX:QwP!M2HsGUBcAK?I0*/}/n'_&#%q%j%i",
"gou": "-71-3p-0y-+z-)H-'p-%W|C{uwdwcuTs0mnfM[CX%VcN6M^Gm?q:925.C*o%2",
"kou": "-71-0f-.C-,g-)J-)DpCp8fId3]^[|VpTV9@",
"ning": "-70-6>-4a-29-0.-'H-!)r%q!p2p)p'p!ot[4UMM5F/E5?17J6k.<+a&i",
"yong": "-7*-5t-3M-,U-,T-'T-$t-$+-!:{Oz!yCxcrlkUg{gAe{ceb{bzapaC`w`n`:[6XTU}M4LaGQ@}>x=9:p947:5T/{/i&p&l%)#S#8",
"wa": "-7)-/n-,e-(/-'P-'&-&x-%h-%A-#y-#nu5tbt3sGnCije[ZaWUTq>.:;8h'V'D'>&A",
"ka": "-7&-*r-'O-'M-'4-$u{g",
"bao": "-7%-5h-21-/>-.e-.]-,!-+{-+s~ozPzOz@sBqBpcpMp$ohoee&d:[w[kPPP1P&M]614J2<0_.u.h*G",
"huai": "-7#-',|mx^xIe_dC_:^oGhDX<25z",
"ming": "-6x-0g-06-(|-'guEs&`aXxR@PhOFH<>0:7,8",
"hen": "-6s-&p-!3eac6[0.:$y",
"quan": "-6p-1H-/.-.#-,5-,#-%%}X}Q{4w5u:t;q[m?jRf`c0b_b%['Y`WKNxJ:I[H_GLFjD>?F>F:a5841/I/H/7.o.n.m.O)2&I%'",
"tiao": "-6o-%Xr#pWmjmWh4cRZfSQRdQjOLO'NYK.Fo",
"xing": "-6j-5.-1<-/U-&g|0{auft{t5qljAh`f*cxb>aZUYR/P4Nl>Z<u9d2d.N,L)@![",
"kan": "-6g-4G-0r-/r-/]-,D|n{!zGyDlkl)k{b7^D]ELRG]E2CeCc",
"lai": "-6d-5Y-5<-%_u!t2lil_h$eSeHU2NUJiJ0DT=&<)6r5v5r,i)k%R#P#J#?",
"kua": "-6a-'.{iwJuGcGZiQcI:",
"gong": "-6`-6N-1D-1?-,~-+g-+d-)w-%}-$)yepTpQj<j8i2g4f{c1a*``[)[(T^N`L?@V7U1u*R",
"mi": "-6[-0v-0n-0b-'9-#'yzqZpmpDp9m6i:i.hrfifafAcb^dVnU_TyTON2HIG$E6E+@L?{?Z?C>G<9;H9<8o6o6l5n5G1z0B,a+T'h",
"an": "-6W-5J-4<-2D-*P-*J-')-%e-$x{b{&z_sYpwn@n8mXm:hXg~ZnXNQ.PnL'L&A1>M.g*w$V",
"lu": "-6V-33-1C-.H-,N-,<-*q-*o-!N~q~_};|G|5yVyUxMtVmChGgZgFf9f8^7XzW)V)UzUAU/O{MpLeJ#G&FyEuDvDaARAM>s<K<;;p9:9'8.7L6@6)4p1m0T+W+H)Y(Q()'m&n!%",
"mou": "-6U-,c-)x-($-&azLcVTTMEKs/a",
"cun": "-6J-/Z-(~x'qLocdn[%Nj7^!O",
"lv": "-6F-63-4#-38-23-,'-*x-(t-(F-&G|+nTnSnPl(e^`A`5ZcZ*YwS.K*HTDsDoAYA)9M6D3A0]+I",
"zhen": "-6C-67-4)},ygybuMs*p5ndiUiRi<fc[nZlZGXWWOSTR*OJN$MhLVKjK_IHHuHLHAG_FVBb=~:y:$8$72,+*_*^({(q'8&Z&<%9",
"ce": "-6B-4*-1%-1#-*=-*2wZgrc!aY_jZ}TQLl={;O&8",
"chai": "-6?-2@-$h~?j3[UL}.i$'",
"nong": "-6=-2S-0p-&b-!Eg.ZmZAElDG=s7#0o#W",
"hou": "-6:-5*-*8-({-(L-(K-'p-$l|%zQi=e]>b._,A$C",
"jiong": "-69-3'-1.-1$-0}}z|K{;]~]}?M=J7e4t4I3c2T2S1W1.",
"tui": "-6.-6(-3&y'tmo$ftfodrY(F>24",
"nan": "-6+-*|-$r~'~#v=tzstrb^e[sXfPqN*M6H}:d29&a&?",
"xiao": "-6*-5v-5R-3a-.x-,d-'j-'1-&l-&P-$}-$1-#D-#?-#&-!|-!v~c~J~CuUtHqGpPpJoKlGh/fFcJ_iX;V:TPT/SoSnQVQ'P;MiMaLOK+DOCYCLBAB4>B===8<Z8E6!5+5*4,3L2&1L,o+r+o$t$o!i!b",
"bian": "-6)-+9-*u-)UwzmKg1eAdVaX^#]=XSR#@A@@4Z26/o,@+`+,':%8",
"pian": "-6)-4P}ysI^#I=Ht/y/0,@+`(j((",
"cu": "-6%-+$-!csFegd(_YEsB},X$I#z!H",
"e": "-6$-4K-2k-+j-*T-*N-(_-(E-(*-'A-')-&X-!j-!A}s{nzhzIzCv$uzuBtotUtTtSn]n)mGm'm&l+gnc'bOata?^+]DWsWdWNUbTMM}DZCEC(>M=5;9*7)`$V$O!r",
"guang": "-5~-2}-1h-'@{~uIhXhTgOZsVKL+>28)5/4b4_4^3s.d+Y*U",
"ku": "-5}-/3-&Q-$6~R}PzrhDh+gN]dZiZ5OPMgL!I%3N.>$9",
"jun": "-5{-2T-0q-(n-(G|u{NuHollq_;Z3U5TzQPKMJH@F=l6V3G1B*1&'!Q!K!J",
"zu": "-5w-5?-+1-+$-&S-%rlYlAd(S#M1Ix0'*e",
"hun": "-5s-4o}_t9t'o9dMaz`oYDR?Q~JYJRBf=u<d<(;=:t:`9{3O36*9)G",
"su": "-5n-3x-2c-$*~9}/{3y}y|wjs#p@a(a'_lVnKKJ2H;G(F~F8DYBo?2>>=4:&9z828&+F*L(F&r",
"lia": "-5[-5>",
"pai": "-5Q-&sg9eP[NY?JU?p>+;j;8/t.w,q",
"biao": "-5O-36-2/yJtIryi%f!VfNhLjFzEG<.9C66511o0c,k#|",
"fei": "-5M-.m-+M-*4-(i-%8w%vZt@t?nXh8gpgPbH]xSdQxQ%P:OPNLLxJVH5FOF)Di?W<C;x6K.`.H,p%3$]#a",
"bei": "-5I-57-4B-4%-3b-37-,Y-+a-+%-(1-&:w|qIh#bdbGajaR`$X3RMNLNKLyK^K5JUJSIq3:/S/).R,y*/)T!@",
"dao": "-52-/g-/e-/6-)E-#K-!5xSo_oLmvlvk;k:jiiKhld{b=YoYcWqUZO'JkIaGZEIE?AA3;0g'd!+!&",
"tan": "-51-3^-3/-2R-)4-%$-#P-#I-!n-!m|o|a|U{'xxxsxaxKtAfTfOfEdtcfb$_p_W_OY/W=UDTuR5PJP=HYF5EnCUAk:w9H7|7{7.5E4K1G(3$}$^#~#7",
"chui": "-5/-(O}T|9{Va|Y[WcKtJ6ItGl4o",
"kong": "-4{{+qPlfcNb;Y)Iv<n",
"juan": "-4z-,h-,P-,0-*[-((}X}Q{Iw<w5uVtut;jpj`j%iYf`byb%`4Z%Y`OGL%K@J:I[=2<^3M.!+j'C",
"luo": "-4r-1y-.|-'4-%(~<~/o^mHZ*YbW(U@U3U/T{TlOvI^D9>q>O>N;y8^6F3{/(,T+P*M#y#5!Y",
"song": "-4q-3I-0D-)'u8pulDk^kOgydYdAb`a3a$`D_MZ#XXW0N<N:MmM>K%J`HyEF<B9!6v",
"leng": "-4p-0T-%uzdz,lQa1J5I!",
"ben": "-4l-$E|q|pwSwPw.w(YXV8O3LQKXI4?B;|8]4v/8&=",
"cai": "-4h-4,-%N{%tLp?f#]t]qY0NkJZA},Y",
"ying": "-4`-3.-%1-$>-#*-!K~Oz%x#s{sXs9s%quqqq_q%kcj[jWhCgDexdha/_AVwV_U0U&R]R.Q:PwO?MHKpK]J{HvHdFbDMDI=_;E:U:K9d9O8K8F6j6i6N6=6&5~5o5j5M5A2w2r2_1x1)0b*:)*(y(S'i'5'%#j#;!B!;",
"ruan": "-4[zJxQsiVWOUE0):'}",
"chun": "-4Y-&7sda^RPR(PlOONDIBGrFQE(=T<,:[9N8u/6)C",
"ruo": "-4S-)[sskPf]Z:YUI8;y3'0^",
"dang": "-4M-2P-1V-/k-!1}*{fx]swpkl6kdf:aAZUUsTpKiEYD5@|8:7E5D*;(J(6'?%}",
"huang": "-4@-1L-/w-$PzDz.xtw&s[pEl9jBi0e@clcQa_a#`dXTQgQfPBOEHbH7D{@9:x9i8)4:2c2.1J0X+w)((E#i!}!g!Z",
"duan": "-4+-.Uz+s`SFS<IMBIB62j)0",
"ou": "-4(-+=-+7-(q-(K-(3-#;yTd?`EDpC}CSBJB8?l8s1Y'M'0",
"zan": "-4$-2.-1x-1o-'2-$c-!e~:p>[$XOVUU8U*TwR1Q&PYKrEy6E5K't'k'c",
"za": "-4$-+Z-'b-'X-'2-$c-!c~B~:~5i}]s[$NyKr?r?a",
"lou": "-4#-38-.}-$7-#ByMu4tRo{n[kjkEg_`5X)W'HaG#:O9&8~1i'2$5#o#n",
"sou": "-3z-0J-)Q-)N-#z-#R-#QgsghZ#YvWlW>W0V:U`UBJ/DgCn:#,5#s",
"yuan": "-3u-1n-1)-0h-.z-*3-*1-)y-(0-&^-$Y-!<}{}t}Z}R}N}M}D{t{_yawlv6v(sSs:s)qhpep<f[cwbyb,`qXoX8NNJ=HxH>H0ErDk@/<m<*;{;v;r;g:e:F:D5]04,M,6)/",
"rong": "-3t-3`-0u|ts8s'qzp~pFlwkokcjj^WX#WwOyLmHGH.H&GQAsAU9|6%3T1v0b.2)#",
"jiang": "-3p-2a-,7-+Y-+Wz/xew~w+vvvru]oToSkMfrfWfVfSfCVyVeKdGDEoDeBQ@U>P>#;L9A8M.|,&&B%y%n%m",
"bang": "-3n{^ypiNi5h~hme|Z?YrWvS2KEJTJSH@=j/m++",
"shan": "-3h-3)-2R-/F-/<-.a-.E-*~-$q-$F-#H}'{Gy+y*ulubr2nDj|i(f+]zZ;Y3XuXsWaVhV?UySvQ8NrL|LlIVFSEhCI@`7|7p7O5F4B2Z211~.4*b%U%1",
"que": "-3f-*_-*W{Pyty$lgbNa+`KX!T8T.JBH$@j4e0|)O#q!N",
"nuo": "-3Q-1w-$ftxa6_#_!ZLXnWoWbWLK0HJF2Am",
"can": "-3P-2F-)l-)k-)j-)i-$D-#H~:r(q3amah`W`V`U_[XsVqVhO_BtBg;/784z1!0L(9",
"lei": "-3O-24-1t-,J-)q-#1|(z0xOx?rrU|U;G'E]DyDxD/?$>I=+<F5X'z%u$)#Q",
"zao": "-3L-/h-&(-%w-$5-!@`JRfMsLkK>JO7F5&2>1#(](7#&#%",
"cao": "-3L-#GnGk@`v`k`^_DVAUqOgOfG:8x",
"ao": "-3H-/n-*&-#X-#W|H|4xnxkv}vyvwsDs2rZmxmakAjnga`O_@]I]![DVuUeTBM*K=?>9;7M741m1^0Z,!+~(Y",
"cou": "-3D-0:Hl;1",
"chuang": "-3B-/b-/K-/5-.s-.i-.L-$T-!dhvhMd=`|W7O<F+0#/r/k%D$+",
"piao": "-36-.D-,;-#Crteze7`]RuO*Br9/.v'Z!X",
"man": "-32{KyKujtlrpn^i'bc`M`=VrOdG9Fs:V9P928b7<701V,(",
"zun": "-3%-!ix}oPk&[%YzVILEFU5k",
"deng": "-2z-/t-!VxwrHk(_v^@E$7d6/5.1A(O#,",
"tie": "-2s-'yigd+",
"seng": "-2o",
"zhuang": "-2hx9x8x2w)vWv@tphvhShE^a^`^_VDKcKBG6:`8X3H.e.Z",
"min": "-2`-0Q-/E-,X-(&|1uumYl]dfded8bJaWaG`S_`[]YhTUTIT(RSRRPzAH>|;z;+:t8(+1*c)o)j)=$R!D",
"sai": "-2V-#b-#)-!/yod%a2XaAxAb",
"tai": "-2B-0_-)=}e|Mw[wXwOvzqvqCdodQdB`e[pU]SpR]MeE>@f@D@C>{:=4G4F1$*f",
"lan": "-2?-1@-)}-%P-!'~3|hx`xXt(qgqaqUmwkwhgb)_8_'^p[5X/UXU(TmSaS_PpLbHXDDD2D1=^9L8i7K6W5`5W5=5<46121%0n0d0I0@0>($'j",
"meng": "-2;-0k-,Lwaw`qEo2hnh*_._+^qXtUaP)O9K$F;EAANAF:A6h,Z+]'/&X#B!#",
"qiong": "-28-*fr.pza]`!K}F(3(3%2L1}*))J(G's'f",
"lie": "-25-0N-/O-,z-,w-,`-'<-&G{D{CuDjaj=djZeZ_YiUEL;JMA{>_=p403f2A1$0a0[.x,h,V+k+[",
"teng": "-2%i+9]8r1e%6%&",
"long": "-2#-'J-&]~^|7|6xHxGo2n=k6j_j^g.e([9U.QmOxO8LgKDGYDU>t:g9T9%5w0N*Z'n#f",
"rang": "-1}-,$~Nx[xC^mU$5b0K+S'X",
"xiong": "-1m-1j-/q-+v-+p-&zwsdLc?Sy@;>42w2r2#2!",
"chong": "-1l-0Y-#L{*p`oflelde0dc`+_dX<W8?z=K=98X0F*@%&",
"dui": "-1g-1e-1`-%L|$zlymobo]oMcc_n_m_*TET>T2NB6[6G5|5u$P",
"rui": "-1g-1e-1`-)LxFas]0M~KVF.@G)'&t",
"ke": "-1f-/*-.w-,]-,R-+;-)>-'o-'0-$!|Dzqx4u#p^oUmomIkvknjqc4bra<a;XJWsT4M%J1G|F}CcBCBBA/;u;G:>6U4U0!/N//*j%>$O",
"tu": "-1c-1]-0H-/o-(y-&3-%?}n}c}J}I}A}?zezZyvxipvnUlskikFh.gVeVc}bsZ.YYX@W2K?EL@R=C=::r7u(i$r$>",
"nei": "-1I-1*-&TtvA<A;=H",
"liu": "-1C-/N-.8~fy^s5qik`gl^vW9S4S*R}L~LpKnKQH'FHF#>(=w::8Q7V631r1[*a)~)%(v(?&S&>&%%r$(#d",
"shou": "-13-)`-)V-%l-!o{ox)x&pxo[]v]uYITcTN<t.1+n+X$e$&",
"ran": "-1+-1&-(!-##umsKMBF'2y1Z1F*i",
"gang": "-1'-0^-/L-.gzjz4mzmplT^a^`^_]fYKWDNZJEGe;L2z2v/W/:.a%Z",
"gua": "-0~-/8-.r-.S-.A-*m-)F-(/-'s-'&-%0|Ooz[/ZuY6LSK[C`2='a",
"zui": "-0i-*6-'d-#U-!w-!*k<jmQ=O`OGLDG[F]EgEbD@6a(%",
"qia": "-0M-+;-*r-'6})m0iZc.a<[j[7YAXJUhBq>,",
"mei": "-0I~j|vz>yRv#sks]sTs4r<p/l&k|e)[bZBU%S3R&M|LoKFHzHjGgDrBfB0B/?~?o?d=I;?;7;32Q2J11,=+$*0)D$w",
"zhun": "-0E-05-%L}5zwpnnFdPRQ<,:@",
"du": "-0+-.`-+B-)p-#0z<vKv1uTqjh1SsQ4PvN_IcDlBRBNB+=(;n;Z6</s/h/5.y..+i)I'y!E",
"kai": "-/x-/v-/%-.M-,I-#J{ey~w0n3kag2dEc#aB`y`r`GXCPfHfCxCu6U4m3}",
"hua": "-/T-.>-+b-+(-(_-(.-&h-#%{@wGuWs}s|rJrDlaWTV}V+NAMvKfIgGKFX9a7c,7&]&+%~",
"bie": "-/A-/;fGe2`#M'M!$!#I",
"pao": "-/>-+i-'^~o|2w=hA]$[P?.4J4H3d06.M'^%A!S",
"geng": "-/7-&A{TzHlrh=ZIOlK4IX=X2p&M",
"shua": "-//-%j",
"cuo": "-.y-.p-*5wukWkSh!ZKY&WuV4(o$j$'",
"kei": "-.woU",
"la": "-.v-%3-$n~L|8[RXFXEWnUEU2R`MOI6DT:T0['o$A",
"pou": "-.l-'_-&[{]twtO]+]&Z+YGJS/<",
"tuan": "-.I~!}~}K}HyPy&f7`>[}XIVmGLE;;.:m8t2[,F%v%p",
"zuan": "-.)XOTt",
"keng": "-,x-([|t|kvIZCXlVgBF/C",
"gao": "-,Z-(I-(>wRlpWjNHGxGwGdG>E~E3Dm,)!y!t",
"lang": "-,V-&J-$~{Jy[r{llgiSeOIOHO;KRHHG4Cp=[3Y,z*%(s",
"weng": "-,@-#oyxv{kfU!Pd9o'N'&",
"tao": "-+m-)E-'+-%DwPwMw*r}i/fl`j[oYBWXL,JkGtE?><=)<t<H9^6_(w",
"nao": "-+`-'n{cz[wqt.rzq8l{jyjSd0b~bPad_QZVW9VOKkFJ<J,D+Z+Q),",
"zang": "-+Oynw)g(/~",
"suan": "-+C,{$n",
"nian": "-+3-&i-%b{9uOhdg3dNbTa~[SYVVHV,U7HL=;<0:C2q",
"shuai": "-*xixiWW3+I&o",
"mang": "-*<-)*-&Zx(u(o2h*dkb|OENdNSAF@c=i8`/[/D.$$q",
"rou": "-)uslpsXdMAHc;d2K)>'v",
"cen": "-)l-)k-)j-)i{Un#kH@?=1",
"shuang": "-)byOqeq^`NDB>t8R5w5^0&",
"po": "-)8-&M-#6~]|ZvztMoZmlmZg9W]TXR+O*E%?E>q>o>D;*:J8;6F3v,9*l!`",
"a": "-(s-'o-%O-$0",
"tun": "-(k-(7-%L-!`}}|snFhNdP_mRQPFOC@x=335",
"hang": "-([{dwSvIj)dGS8NML/@.",
"shun": "-(ZHnF?",
"ne": "-(R-(8-(%-&T]0%a",
"chuo": "-(Q-&@-%=~Hu!t~t.ssqVa|^2Z}UuCC<q<J",
"wai": "-(/-'&-$gwml7C95z",
"guo": "-(/-'&-%)-$e-#<~.}r}k}f}d}a}U{<zTy>lMi@i$fDf@b1`Y_4XyW6TMMzJ$I:GOD{=#<W;U9#7!,c$<",
"qiang": "-(,-%f-%M-$.-#[y=y3xmrXr0k>gKfVfSfC^P^N^>[zWQW!VySKMlIvGkFdEJ:)8{4[1s/|/z,f,.*{(p%m",
"pen": "-('-$E-$=-!6CN;'6}'Q!=",
"pin": "-&~~Yuatnrvq{[AZ{H]@_/c+!)r",
"ha": "-&wvz",
"yo": "-&`-%c-$B",
"o": "-&X-$a-!H-!%",
"n": "-&)-#a",
"huan": "-%v-$Z-$Y~G}D{_zWw@w2r.q[pYp0okm8l!h]bVaH_I^iYpXQUnU1KyK2GBD%CPCB>1=c<~;c8V7D734/3>2I.[.;,3+R*})9(1'b$d$:",
"ken": "-%V{qxjc*_CX~*I",
"chuai": "-%=XIW}Ch",
"pa": "-%/vLisihd.]oX|NC@r8608)P#!",
"se": "-%,-$,yogK_<Z}VnUrLTGJC5C3>W<x;q7h7g6|6t60)p)&(0#r",
"re": "-$fa[YU;y3g1X",
"sun": "-$DqKq9]EYsW{WzW;H1Gv.',:",
"hei": "-#h-!l7r",
"dia": "-#^",
"de": "-#5}0hBeQe5e1c)bFakR[JW<_##",
"dei": "-#5eQ",
"kuo": "-!`g`]W[:[/ZsUI8U6L",
"ceng": "-!_ntnQk4OcObF*",
"ca": "~s~B[UUWU:",
"zeng": "~7y5y._}OcObF*1R(M'*",
"nin": "~(c^bQ[*",
"kun": "}q|Wzoz`x/x*t'l[lZbwZ0RHQMJv=B8C371U,e)_(g",
"qun": "}jwxpRl~iPCT",
"ri": "}iRjA=",
"lve": "}Go^Y1&2&0",
"zhui": "|[y0w#t]aaXIIt?s'<%|",
"sao": "zus+`k_D]UYNXrWtK(AP:8$4",
"en": "wBmBc5WF20",
"zou": "w3s>Y%X`W~J/J.Hl",
"nv": "vkc7OM@!",
"nuan": "vcPo;`:m2X2W",
"shuo": "v]a'WhT'S|OKGnCn>>470W+p",
"niu": "v?q=dKd0]S]![DN?@8@!4u/e/d.W",
"rao": "u2rA]PU?KkFJ",
"niang": "t|r&qb",
"shui": "t]iTZMYuA$A#@{=.=*",
"nve": "t)%S$%",
"nen": "sirarYc^",
"niao": "s!r+qsnwFq9x",
"kuan": "pBp#ooK)CoCfCd",
"cuan": "jPV'U*T~TwDtD7BU@o6E5K1S0<",
"te": "dsdr`R/F/9",
"zen": "d5VU",
"zei": "^H",
"den": "][]C",
"zhua": "],ZYV#ER0:09",
"shuan": "[&L^GL<s",
"zhuai": "Zz",
"nou": "WoGpE0+^",
"shai": "W<TsQWOt",
"sen": "J8ISGI",
"run": "FE<{8'",
"ei": "Cl",
"chua": "Ci"
}
};
let DB = {
sToC: {},
cToS: {}
};
let sToC = DB.sToC,
cToS = DB.cToS,
ungroup = /-?.{2}/g,
rg = /^-/,
fromX = str => {
let result = 0,
temp = 1;
for (let idx = str.length; idx--;) {
result += temp * (chars.indexOf(str.charAt(idx)));
temp *= 91;
}
return result;
},
fn = (a, f) => {
let p, gs, i, ch, num;
for (p in a) {
if (a.hasOwnProperty(p)) {
gs = a[p].match(ungroup);
for (i = 0; i < gs.length; i++) {
ch = gs[i].replace(rg, '#');
num = fromX(ch);
ch = String.fromCharCode(base + middle + (f ? -num : num));
if (sToC.hasOwnProperty(p)) {
sToC[p] += ch;
} else {
sToC[p] = ch;
}
if (cToS.hasOwnProperty(ch)) {
cToS[ch] += COMA + p;
} else {
cToS[ch] = p;
}
}
}
}
};
fn(SDB.m, 1);
fn(SDB.a);
SDB = null;
export default {
getSpell(chars, polyphone, spliter) {
let cToS = DB.cToS;
let res = [],
pp = typeof (polyphone) == 'function'; //判断polyphone是否是函数
chars = String(chars).split(EMPTY);
for (let i = 0, ch, ss; i < chars.length; i++) {
ch = chars[i];
if (cToS.hasOwnProperty(ch)) {
ss = cToS[ch];
if (~ss.indexOf(COMA)) {
ss = ss.split(COMA);
ss = pp ? polyphone(ch, ss) : '[' + ss + ']';
res.push(ss);
} else {
res.push(ss);
}
} else {
res.push(ch);
}
}
return res.join(spliter || COMA);
},
getChars(spell) {
let sToC = DB.sToC;
if (sToC.hasOwnProperty(spell)) {
return sToC[spell].split(EMPTY);
}
return [];
}
};

View File

@ -0,0 +1,137 @@
/*! iNoBounce - v0.2.0
* https://github.com/lazd/iNoBounce/
* Copyright (c) 2013 Larry Davis <lazdnet@gmail.com>; Licensed BSD */
(function(global) {
// Stores the Y position where the touch started
var startY = 0;
// Store enabled status
var enabled = false;
var supportsPassiveOption = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassiveOption = true;
}
});
window.addEventListener('test', null, opts);
} catch (e) {}
var handleTouchmove = function(evt) {
// Get the element that was scrolled upon
var el = evt.target;
// Allow zooming
var zoom = window.innerWidth / window.document.documentElement.clientWidth;
if (evt.touches.length > 1 || zoom !== 1) {
return;
}
// Check all parent elements for scrollability
while (el !== document.body && el !== document) {
// Get some style properties
var style = window.getComputedStyle(el);
if (!style) {
// If we've encountered an element we can't compute the style for, get out
break;
}
// Ignore range input element
if (el.nodeName === 'INPUT' && el.getAttribute('type') === 'range') {
return;
}
var scrolling = style.getPropertyValue('-webkit-overflow-scrolling');
var overflowY = style.getPropertyValue('overflow-y');
var height = parseInt(style.getPropertyValue('height'), 10);
// Determine if the element should scroll
var isScrollable = scrolling === 'touch' && (overflowY === 'auto' || overflowY === 'scroll');
var canScroll = el.scrollHeight > el.offsetHeight;
if (isScrollable && canScroll) {
// Get the current Y position of the touch
var curY = evt.touches ? evt.touches[0].screenY : evt.screenY;
// Determine if the user is trying to scroll past the top or bottom
// In this case, the window will bounce, so we have to prevent scrolling completely
var isAtTop = (startY <= curY && el.scrollTop === 0);
var isAtBottom = (startY >= curY && el.scrollHeight - el.scrollTop === height);
// Stop a bounce bug when at the bottom or top of the scrollable element
if (isAtTop || isAtBottom) {
evt.preventDefault();
}
// No need to continue up the DOM, we've done our job
return;
}
// Test the next parent
el = el.parentNode;
}
// Stop the bouncing -- no parents are scrollable
evt.preventDefault();
};
var handleTouchstart = function(evt) {
// Store the first Y position of the touch
startY = evt.touches ? evt.touches[0].screenY : evt.screenY;
};
var enable = function() {
// Listen to a couple key touch events
window.addEventListener('touchstart', handleTouchstart, supportsPassiveOption ? { passive : false } : false);
window.addEventListener('touchmove', handleTouchmove, supportsPassiveOption ? { passive : false } : false);
enabled = true;
};
var disable = function() {
// Stop listening
window.removeEventListener('touchstart', handleTouchstart, false);
window.removeEventListener('touchmove', handleTouchmove, false);
enabled = false;
};
var isEnabled = function() {
return enabled;
};
// Enable by default if the browser supports -webkit-overflow-scrolling
// Test this by setting the property with JavaScript on an element that exists in the DOM
// Then, see if the property is reflected in the computed style
var testDiv = document.createElement('div');
document.documentElement.appendChild(testDiv);
testDiv.style.WebkitOverflowScrolling = 'touch';
var scrollSupport = 'getComputedStyle' in window && window.getComputedStyle(testDiv)['-webkit-overflow-scrolling'] === 'touch';
document.documentElement.removeChild(testDiv);
if (scrollSupport) {
enable();
}
// A module to support enabling/disabling iNoBounce
var iNoBounce = {
enable: enable,
disable: disable,
isEnabled: isEnabled
};
if (typeof module !== 'undefined' && module.exports) {
// Node.js Support
module.exports = iNoBounce;
}
if (typeof global.define === 'function') {
// AMD Support
(function(define) {
define('iNoBounce', [], function() { return iNoBounce; });
}(global.define));
}
else {
// Browser support
global.iNoBounce = iNoBounce;
}
}(this));

View File

@ -0,0 +1,40 @@
function isEqual(x, y) {
if (x === y) {
return true
}
if (!(x instanceof Object) || !(y instanceof Object)) {
return false
}
if (x.constructor !== y.constructor) {
return false
}
for (var p in x) {
if (x.hasOwnProperty(p)) {
if (!y.hasOwnProperty(p)) {
return false
}
if (x[p] === y[p]) {
continue
}
if (typeof(x[p]) !== "object") {
return false
}
if (!Object.equals(x[p], y[p])) {
return false
}
}
}
for (p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
return false
}
}
return true
}
module.exports = {
isEqual
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
import {HttpUtil} from '../../core/utils/http.util'
import {LocalStorageUtil} from '../utils/local-storage.util'
import globalVariable from "../global-variable";
export class BaseService {
httpUtil = HttpUtil
globalVariable = globalVariable
localStorageUtil = LocalStorageUtil
}

View File

@ -0,0 +1,25 @@
const globalVariable = {
key: '', // 数据签名key
localStoragePrefix: 'localStorage:demo-uview:app:', // todo 不同平台这里需要修改
// localStoragePrefix: 'localStorage:wlsh-uview:app:', // todo 不同平台这里需要修改
timestamp: new Date().getTime(),
baseUrl: 'http://xxxxxxxxxxxxxxxxxxxxxxxx:33000/demo-mobile/', // 服务端地址
systemName: 'uview商城模板',
runPlatform: "1", // 0-微信小程序版1-APP版2-h5版 todo 不同平台这里需要修改
userInfo: {},
token: null,
coordinate: "", // 手机坐标 -- > 113.41189,22.94181
orderSequenceNumber: null, // 餐饮号
tempData: {}, // 存放临时数据,例如跳转页面时获取前一个页面保存的数据。
};
export default globalVariable

View File

@ -0,0 +1,81 @@
import {LocalStorageUtil} from "../utils/local-storage.util";
import globalVariable from "../global-variable";
import {CommonUtil} from "../utils/common.util";
import {AuthUtil} from "../utils/auth.util";
// 这里的vm就是我们在vue文件里面的this所以我们能在这里获取vuex的变量比如存放在里面的token
// 同时我们也可以在此使用getApp().globalData如果你把token放在getApp().globalData的话也是可以使用的
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
// baseUrl: 'https://api.youzixy.com',
// 如果将此值设置为true拦截回调中将会返回服务端返回的所有数据response而不是response.data
// 设置为true后就需要在this.$u.http.interceptor.response进行多一次的判断请打印查看具体值
originalData: true,
// 设置自定义头部content-type
// header: {
// 'content-type': 'xxx'
// }
});
// 请求拦截配置Token等参数
Vue.prototype.$u.http.interceptor.request = (config) => {
// 添加token信息
config.header.Authorization = globalVariable.token;
config.header.timestamp = new Date().getTime();
config.header.sign = CommonUtil.generateSign(config.header.timestamp);
// 方式一存放在vuex的token假设使用了uView封装的vuex方式https://uviewui.com/components/globalVariable.html
// config.header.token = vm.token;
// 方式二如果没有使用uView封装的vuex方法那么需要使用$store.state获取
// config.header.token = vm.$store.state.token;
// 方式三如果token放在了globalData通过getApp().globalData获取
// config.header.token = getApp().globalData.username;
// 方式四如果token放在了Storage本地存储中拦截是每次请求都执行的所以哪怕您重新登录修改了Storage下一次的请求将会是最新值
// const token = uni.getStorageSync('token');
// config.header.token = token;
return config;
}
// 响应拦截,判断状态码是否通过
Vue.prototype.$u.http.interceptor.response = (res) => {
console.log("Vue.prototype.$u.http.interceptor.response", res)
if (res.header.Authorization) {
console.log('------------新的token-----------', res.header.Authorization)
globalVariable.token = res.header.Authorization
LocalStorageUtil.setItem('token', globalVariable.token)
}
// 如果把originalData设置为了true这里得到将会是服务器返回的所有的原始数据
// 判断可能变成了res.statusCode或者res.data.code之类的请打印查看结果
if (res.statusCode == 200) {
// // 这里对res.result进行返回将会在this.$u.post(url).then(res => {})的then回调中的res的到
// 如果把originalData设置为了true这里return回什么this.$u.post的then回调中就会得到什么
return res.data;
} else {
if (res.statusCode == 401) {
AuthUtil.logout();
} else {
let message = "系统异常";
if (res.data.msg) {
message = res.data.msg;
}
if (res.data.message) {
message = res.data.message;
}
CommonUtil.alert(message)
}
uni.hideLoading();
// 如果返回false则会调用Promise的reject回调
// 并将进入this.$u.post(url).then().catch(res=>{})的catch回调中res为服务端的返回值
return false;
}
}
}
export default {
install
}

View File

@ -0,0 +1,238 @@
import globalVariable from "../global-variable";
import {PaginationModel} from "../model/pagination.model";
import {CommonUtil} from "../utils/common.util";
import {UFormUtil} from "../utils/u-form.util";
import {LocalStorageUtil} from "../utils/local-storage.util";
import {TabbarUtil} from "../utils/tabbar.util";
/**
* mixin的作用是多个组件可以共享数据和方法在使用mixin的组件中引入后mixin中的方法和属性也就并入到该组件中
* 可以直接使用在已有的组件数据和方法进行了扩充引入mixin分全局引用和局部引用
* todo 可以代替基类base的功能
*
* todo Page页面生命周期函数执行顺序
* beforeCreate => onLoad => onShow => created => beforeMount => onReady => mounted
* 刷新数据后
* beforeUpdate => updated
*
* vue 父子组件的生命周期顺序加载渲染过程
* 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
*
* 子组件更新过程
* 父beforeUpdate->子beforeUpdate->子updated->父updated
*
* 父组件更新过程
* 父beforeUpdate->父updated
*
* 销毁过程
* 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
*/
const myMixin = {
data() {
return {
// _self: null, // todo 不能直接赋值否则u-view框架报错 当vue作为组件<componentName></componentName>引用时,组件模板页面<template/>中的this为null这时需要使用_self变量代替。
uni: uni, // 不这样设置template页面中不能直接使用例如@click="uni.navigateTo({url: 'xxx})"
$u: this.$u, // 不这样设置template页面中取不到值
CommonUtil: CommonUtil, // 不这样设置template页面中无法直接使用
TabbarUtil: TabbarUtil, // 不这样设置template页面中无法直接使用
UFormUtil: UFormUtil, // 不这样设置template页面中无法直接使用
globalVariable: globalVariable, // todo <template/>模板页面中可以直接使用js中可以直接使用
pagination: new PaginationModel(), // 每个组件都是一个新的对象互不影响
urlParams: {}, // 导航过来的url参数?a=1&b=2 ==> {a: 1, b: 2} <template/>可以直接获取
objParams: {}, // 导航过来的对象参数 todo 导航过来的是同一个对象,改变内容所有引用的页面将会同时受到影响。 <template/>可以直接获取
currentRouteUrl: '',
// 时间控件显示格式2020-09-22 16:57:38
pickerFormatDatetime: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
},
// 时间控件显示格式2020-09-22
pickerFormatDate: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false,
}
}
},
// options 参数为null当组件使用时不会被调用
beforeCreate(options) {
// console.log(`myMixin--------------------------------beforeCreate(${JSON.stringify(options)})--------------------------------`)
const _self = this;
// 刷新页面时重新赋值,否则页面会报错。
if (!globalVariable.token) {
let token = LocalStorageUtil.getItem("token");
let userInfo = LocalStorageUtil.getItem("userInfo");
globalVariable.orderSequenceNumber = null; // 删除已扫码的餐饮号
if (token && userInfo) {
globalVariable.token = token;
globalVariable.userInfo = userInfo;
}
}
},
// options页面导航的参数当组件使用时不会被调用
onLoad(options) {
console.log(`myMixin--------------------------------onLoad(options)--------------------------------`, options);
const _self = this;
_self.urlParams = options; // app端没有this.$root.$mp.query参数。
if (!_self.urlParams) {
_self.urlParams = {};
}
console.log("urlParams------------------------", _self.urlParams);
if (_self.urlParams && _self.urlParams.q && _self.urlParams.scancode_time) {
_self.urlParams.url = decodeURIComponent(_self.urlParams.q);
_self.urlParams = CommonUtil.getUrlParams(_self.urlParams.url);
_self.urlParams.isScan = "1"; // 是否扫码进入到该页面
console.log("微信扫码进入小程序结果urlParams------------------------", _self.urlParams);
}
// 兼容部分手机机型不能从导航事件中获取objParams问题。
if (!globalVariable.objParams) {
globalVariable.objParams = {};
}
_self.objParams = globalVariable.objParams;
console.log("globalVariable.objParams------------------------", _self.objParams);
const eventChannel = this.getOpenerEventChannel();
eventChannel.on('objParams', function (data) {
_self.objParams = data;
console.log("objParams------------------------", data);
});
if (this.validateForm) {
UFormUtil.init(this.validateForm);
console.log("validateForm表单对象初始化成功--------------------------------", this.validateForm);
}
},
// options 参数为null当组件使用时不会被调用
onShow(options) {
// console.log(`myMixin--------------------------------onShow(${JSON.stringify(options)})--------------------------------`)
},
// options 参数为null当组件使用时不会被调用
created(options) {
// console.log(`myMixin--------------------------------created(${JSON.stringify(options)})--------------------------------`)
},
// options 参数为null当组件使用时不会被调用
onReady(options) {
// console.log(`myMixin--------------------------------onReady(${JSON.stringify(options)})--------------------------------`)
if (this.validateForm && !this.validateForm.controls) { // todo 当组件使用时onLoad方法不会被调用所以需要在这里初始化。
UFormUtil.init(this.validateForm);
console.log("validateForm表单对象初始化成功--------------------------------", this.validateForm);
}
if (this.validateForm && this.validateForm.rules && this.$refs.validateFormRef) {
this.$refs.validateFormRef.setRules(this.validateForm.rules);
console.log("validateFormRef表单校验规则初始化成功--------------------------------", this.validateForm);
}
},
// options 参数为nulltodo 当组件使用时会被调用
mounted(options) {
// console.log(`myMixin--------------------------------mounted(${JSON.stringify(options)})--------------------------------`)
this._self = this; // todo 当vue作为组件<componentName></componentName>引用时,组件模板页面<template/>中的this为null这时需要使用_self变量代替。
if (this.validateForm && !this.validateForm.controls) { // todo 当组件使用时onLoad方法不会被调用所以需要在这里初始化。
UFormUtil.init(this.validateForm);
console.log("validateForm表单对象初始化成功--------------------------------", this.validateForm);
}
if (this.validateForm && this.validateForm.rules && this.$refs.validateFormRef) {
this.$refs.validateFormRef.setRules(this.validateForm.rules);
console.log("validateFormRef表单校验规则初始化成功--------------------------------", this.validateForm);
}
// 获取路由数组
let routes = getCurrentPages();
if (routes && routes.length) {
this.currentRouteUrl = routes[routes.length - 1].route;
}
},
methods: {
/**
* template页面中使用这种方式才能跳转页面
* @param url
* @param urlParams
* @param objParams 传递对象类型数据给下一个页面改变内容所有引用的页面将会同时受到影响
* 导航navigateTo(url, urlParams, objParams)跳转页面的objParams将指向同一个地址修改将同时受到影响
* 导航navigateTo(url, urlParams, {objParams objParams}) 跳转页面的objParams对象是一个全新的对象指向不同的地址对其修改不影响原对象的值
* todo <template/>中使用{tbOrder: tbOrder}的方式传值时将产生一个全新的tbOrder副本并不是只向原来的tbOrder地址所以对新的tbOrder修改不会影响原来的tbOrder
* todo <template/>中使用globalVariable.tempData.tbOrder = tbOrder赋值后globalVariable.tempData.tbOrder不是tbOrder而是一个全新属性错乱的对象
*
* 所以要传递多个对象并且每个对象始终保持是同一个地址则需要在js中实现
* 例如@click="test(url, urlParams, obj1, obj2)"
* test(url, urlParams, obj1, obj2){
* this.navigateTo(url, urlParams, {obj1, obj2});
* // 或者
* this.navigateTo(url, urlParams).then(res=>{
* res.eventChannel.emit('objParams', {obj1, obj2});
* })
* }
*/
navigateTo(url, urlParams, objParams) {
// 兼容部分手机机型不能从导航事件中获取objParams问题。
globalVariable.objParams = objParams;
return new Promise(function (resolve, reject) {
if (urlParams) {
if (url.indexOf("?") === -1) {
url = url + "?" + CommonUtil.objectToUrlParams(urlParams);
} else {
url = url + "&" + CommonUtil.objectToUrlParams(urlParams);
}
}
uni.navigateTo({
url: url,
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
});
},
/**
* 刷新数据
* @param dataList
*/
doRefresh(dataList) {
// 清空数据。
// console.log("myMixin--------------------------------doRefresh()--------------------------------")
dataList.splice(0, dataList.length);
this.pagination = new PaginationModel();
this.$forceUpdate();
this.$nextTick(() => {
this.pagination = new PaginationModel();
this.doInfinite();
});
},
/**
* 根据componentRef切换底部菜单栏选项
* @param componentRef
*/
switchTarBarByComponentRef(componentRef) {
const _self = this;
let pages = getCurrentPages();
console.log(pages);
pages.forEach((page, index) => {
if (page.route === 'pages/sub/sub1-tabs/tabs/index') {
// h5调用属性和方法可以不用page.$vm但是微信小程序必须是page.$vm.否则报错。
page.$vm.tarbar.forEach((item, index) => {
if (item.componentRef === componentRef) {
page.$vm.onChangeTabbarTab(index);
}
});
}
});
}
}
};
export default myMixin

View File

@ -0,0 +1,96 @@
export class PaginationModel {
/**
* 页码从1开始
*/
pageNum = 1;
/**
* 页面大小
*/
pageSize = 10;
size = 0;
orderBy = null;
/**
* 起始行
*/
startRow = 1;
/**
*
* 末行
*/
endRow = 0;
/**
* 总数
*/
total = 0;
/**
* 总页数
*/
pages = 0;
data = [];
firstPage = 1;
prePage = 0;
nextPage = 0;
lastPage = 1;
isFirstPage = true;
/**
* 是否是最后一页
*/
isLastPage = false;
hasPreviousPage = false
/**
* 是否有下一页
*/
hasNextPage = false;
navigatePages = 8;
navigatepageNums = [1];
isLast = false;
// <!--通过status设置组件的状态加载前值为loadmore加载中为loading没有数据为nomore-->
status = 'nomore';
refreshPage(data) {
for (let attr in data) {
this[attr] = data[attr]
}
if (this.hasNextPage) {
this.pageNum = this.pageNum + 1
this.status = 'loadmore'
} else {
this.status = 'nomore'
}
return data
}
/**
* 分页
* pagination[page]
* pagination[perpage]
* 排序
* sort[field]
* sort[sort]
*/
appendToUrl(pageNum, pageSize) {
if (pageNum) {
this.pageNum = pageNum;
}
if (pageSize) {
this.pageSize = pageSize;
}
return `pageNum=${this.pageNum}&pageSize=${this.pageSize}`
}
}

View File

@ -0,0 +1,19 @@
import globalVariable from "../global-variable";
import {LocalStorageUtil} from "./local-storage.util";
import {CommonUtil} from "./common.util";
export class AuthUtil {
/**
* 退出登录
*/
static logout(message = "会话已过期,请重新登录") {
globalVariable.token = null;
globalVariable.userInfo = {};
globalVariable.orderSequenceNumber = null;
globalVariable.coordinate = null;
LocalStorageUtil.removeItem("token");
LocalStorageUtil.removeItem("userInfo");
CommonUtil.toastReLaunch(message, "/pages/main/login/index");
}
}

View File

@ -0,0 +1,52 @@
export class BaiduMapUtil {
/**
* WGS84转GCj02
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
* @param lng
* @param lat
* @returns {*[]}
*/
static wgs84togcj02tobd09(lng, lat) {
const xPI = 3.14159265358979324 * 3000.0 / 180.0
const PI = 3.1415926535897932384626
const a = 6378245.0
const ee = 0.00669342162296594323
// WGS84转GCj02
let dlat = this.transformlat(lng - 105.0, lat - 35.0)
let dlng = this.transformlng(lng - 105.0, lat - 35.0)
let radlat = lat / 180.0 * PI
let magic = Math.sin(radlat)
magic = 1 - ee * magic * magic
let sqrtmagic = Math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
let mglat = lat + dlat
let mglng = lng + dlng
// 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
let z = Math.sqrt(mglng * mglng + mglat * mglat) + 0.00002 * Math.sin(mglat * xPI)
let theta = Math.atan2(mglat, mglng) + 0.000003 * Math.cos(mglng * xPI)
let bdlng = z * Math.cos(theta) + 0.0065
let bdlat = z * Math.sin(theta) + 0.006
// return [bdlng, bdlat]
return {lng: bdlng, lat: bdlat}
}
static transformlat(lng, lat) {
const PI = 3.1415926535897932384626
let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng))
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0
return ret
}
static transformlng(lng, lat) {
const PI = 3.1415926535897932384626
let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng))
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0
return ret
}
}

View File

@ -0,0 +1,830 @@
import Vue from 'vue'
import md5Libs from "uview-ui/libs/function/md5";
import globalVariable from "../global-variable";
export class CommonUtil {
// ----------------------------------------------原生js----------------------------------------------
/**
* 生成签名
*
* @return
*/
static generateSign(timestamp) {
return md5Libs.md5(md5Libs.md5(timestamp + globalVariable.key) + timestamp + globalVariable.key);
}
/**
* 随机生成uuid
* @returns {string}
*/
static generateUUID() {
var s = []
var hexDigits = '0123456789abcdef'
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = '-'
var uuid = s.join('')
return uuid
}
/**
* 随机生成uuid
*/
static randomUUID() {
return this.generateUUID();
}
/**
* 生成范围随机数
* @param max
* @param min
* @returns {number}
*/
static random(max, min) {
return Math.round(Math.random() * (max - min) + min);
}
/**
* 生成code编号
*
* @return
*/
static generateCode() {
let identifyingCode = parseInt((Math.random() * 9 + 1) * 100000 + '');
return this.dateFormat(new Date(), 'yyyyMMddHHmmss') + identifyingCode;
}
/**
* 获取手机端的屏幕宽度
*/
static getScreenWidth() {
// 小程序会报错
// let width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
let width = uni.getSystemInfoSync().screenWidth;
console.log(width);
return width;
}
/**
* 获取手机端的屏幕高度
*/
static getScreenHeight() {
// 微信小程序会报错
// let height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
let height = uni.getSystemInfoSync().screenHeight;
console.log(height);
return height;
}
/**
* 生成包含数字大写字母小写字母的随机数
* @param length
* @returns {string}
*/
static randomStr(length = 4) { //封装,以便日后使用。
//创建一个空字符,用于存放随机数/字母
var strData = "";
//生成随机字符库 (验证码四位随机数三种取公倍数12,所以循环4次。也可以是120次1200次。)
for (var i = 0; i < length; i++) {
var num = this.random(0, 9);//生成0-9的随机数
var az = String.fromCharCode(this.random(97, 122));//生成a-z
var AZ = String.fromCharCode(this.random(65, 90));//生成A-Z
strData = strData + num + az + AZ;//将生成的字符进行字符串拼接
}
// 开始真正的随机(从随机字符库中随机取出四个)
var str = "";
for (var i = 0; i < 4; i++) {
str += strData[this.random(0, strData.length - 1)]
}
return str;
}
/**
* 合并对象值
*/
static mergeData(_self, target, ...sources) {
for (let index in sources) {
let source = sources[index]
for (let attrName in source) {
_self.$set(target, attrName, source[attrName])
if (typeof source[attrName] === 'object') {
this.mergeData(_self, target[attrName], source[attrName])
}
}
}
_self.$forceUpdate();
return target
}
/**
* 删除左右两端的空格
* @param str
* @returns {*}
*/
static trim(str) {
let result = str
try {
result = str.replace(/(^\s*)|(\s*$)/g, '')
} catch (e) {
// 非字符串没有.replace方法
}
return result
}
/**
* 对象转url参数
* @param obj
* @param isEncodeURI
* @returns {string}
*/
static objectToUrlParams(obj, isEncodeURI) {
// 优化参数
for (let attrName in obj) {
if (obj[attrName] === undefined || obj[attrName] == null || obj[attrName] === 'undefined' || obj[attrName] === 'null' || CommonUtil.trim(obj[attrName]) === '') {
delete obj[attrName]
}
}
if (!isEncodeURI) { // 是否编码参数
return Object.keys(obj).map(function (key) {
return ''.concat(key, '=').concat(obj[key])
}).join('&')
} else {
return Object.keys(obj).map(function (key) {
return ''.concat(encodeURIComponent(key), '=').concat(encodeURIComponent(obj[key]))
}).join('&')
}
};
/**
* 时间字符串转时间戳 2020-09-27 17:06:21 --> 1601197581000
* @param datetimeStr
*/
static datetimeStrToTimestamp(datetimeStr) {
datetimeStr = datetimeStr.substring(0, 19);
datetimeStr = datetimeStr.replace(/-/g, '/'); //必须把日期'-'转为'/'
let timestamp = new Date(datetimeStr).getTime();
return timestamp;
}
/**
* 格式化日期
* @param date
* @param fmt yyyy-MM-dd HH:mm:ss
* @returns {*}
*/
static dateFormat(date, fmt = 'yyyy-MM-dd HH:mm:ss') {
// 如果是日期字符串,则转成日志类型
if (typeof date === 'string') {
date = new Date(date);
}
let ret;
const opt = {
"y+": date.getFullYear().toString(), // 年
"M+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"m+": date.getMinutes().toString(), // 分
"s+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
}
}
return fmt;
}
/**
* 获取两个时间相差的天数
* @param date1
* @param date2
* @returns {number}
*/
static getDiffDays(date1, date2) {
if (typeof date1 === 'string') {
date1 = new Date(date1);
}
if (typeof date2 === 'string') {
date2 = new Date(date2);
}
/*获取之间的天数*/
let diffDays = (date2.getTime() - date1.getTime()) / (3600 * 24 * 1000);
return parseInt(diffDays);
}
/**
* 删除对象中所有的nullundefined属性值
*/
static deleteNullAttrInObject(obj, removeEmptyStr = true) {
for (var key in obj) {
if (obj[key] === null) {
delete obj[key]
}
if (obj[key] === undefined) {
delete obj[key]
}
if (removeEmptyStr && obj[key] === '') {
delete obj[key]
}
if (Array.isArray(obj[key]) && obj[key].length === 0) { // 删除空数组[]属性
delete obj[key]
}
}
return obj
}
static urlParamsAppendToUrl(url, urlParams) {
if (urlParams) {
if (url.indexOf("?") === -1) {
url = url + "?" + this.objectToUrlParams(urlParams);
} else {
url = url + "&" + this.objectToUrlParams(urlParams);
}
}
return url;
}
/**
* 毫秒转换友好的显示格式
* 输出格式21小时前
* @param {[type]} time [description]
* @return {[type]} [description]
*/
static showTime(datetime) {
//获取js 时间戳
var time = new Date().getTime();
//去掉 js 时间戳后三位与php 时间戳保持一致
time = parseInt((time - this.datetimeStrToTimestamp(datetime)) / 1000 + '');
//存储转换值
var s;
if (time == 0) {
return '刚刚';
} else if (time < 60) {
return time + '秒前';
} else if ((time < 60 * 60) && (time >= 60)) {
//超过十分钟少于1小时
s = Math.floor(time / 60);
return s + '分钟前';
} else if ((time < 60 * 60 * 24) && (time >= 60 * 60)) {
//超过1小时少于24小时
s = Math.floor(time / 60 / 60);
return s + '小时前';
} else if ((time < 60 * 60 * 24 * 30) && (time >= 60 * 60 * 24)) {
//超过1天少于30天内
s = Math.floor(time / 60 / 60 / 24);
return s + '天前';
} else {
//超过3天
// var date = new Date(parseInt(datetime) * 1000);
// return date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate();
return this.dateFormat(datetime, 'MM-dd HH:mm');
}
}
/**
* 将字符串编码成base64
* @param str
* @returns {string}
*/
static toBase64Encode(str) {
var c1, c2, c3;
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var i = 0, len = str.length, string = '';
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
string += base64EncodeChars.charAt(c1 >> 2);
string += base64EncodeChars.charAt((c1 & 0x3) << 4);
string += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
string += base64EncodeChars.charAt(c1 >> 2);
string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
string += base64EncodeChars.charAt((c2 & 0xF) << 2);
string += "=";
break;
}
c3 = str.charCodeAt(i++);
string += base64EncodeChars.charAt(c1 >> 2);
string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
string += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
string += base64EncodeChars.charAt(c3 & 0x3F)
}
return string
}
/**
* 添加属性别名
* @param object
* @param alias
* {
* "name": "label", 给name属性取个别名label
* "code": "value" 给code属性取个别名value
* }
*/
static objectAlias(object, alias = {'name': 'label', 'code': 'value'}) {
if (!object) {
return;
}
// 数组
if (Array.isArray(object)) {
object.forEach(item => {
for (let attrName in alias) {
// 将一个属性取一个别名
if (attrName.indexOf(",") === -1) {
item[alias[attrName]] = item[attrName];
} else {// 将多个属性取同一个别名,每个属性名/值以逗号隔开
let attrNames = attrName.split(",");
let value = [];
for (let i = 0; i < attrNames.length; i++) {
value.push(item[attrNames[i]]);
}
item[alias[attrName]] = value.join(",");
}
}
if (item.children) {
this.objectAlias(item.children, alias);
}
});
} else { // 对象
for (let attrName in alias) {
if (attrName.indexOf(",") === -1) {
object[alias[attrName]] = object[attrName];
} else {
let attrNames = attrName.split(",");
let value = [];
for (let i = 0; i < attrNames.length; i++) {
value.push(item[attrNames[i]]);
}
item[alias[attrName]] = value.join(",");
}
}
if (object.children) {
this.objectAlias(object.children, alias);
}
}
return object;
}
/**
* 刷新对象值
* @param _selfVue
* @param obj
*/
static refreshObj(_selfVue, obj) {
const _self = this;
for (let key in obj) {
//排除掉原型继承而来的属性
if (!obj.hasOwnProperty(key)) {
return;
}
console.log(key, obj[key]);
if (typeof obj[key] === 'object' || typeof obj[key] === 'function') {
_self.refreshObj(_selfVue, obj[key]);
} else if (Array.isArray(obj[key])) {
obj[key].forEach((item) => {
_self.refreshObj(_selfVue, item);
})
} else {
_selfVue.$set(obj, key, obj[key]);
}
}
}
/**
* 是否是JSON字符串
* @param str
* @returns {boolean}
*/
static isJSON(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
} else {
return false;
}
} catch (e) {
console.log('error' + str + '!!!' + e);
return false;
}
}
}
/**
* 是否是数字
* @param checkVal
* @returns {boolean}
*/
static isNumber(checkVal) {
var reg = /^-?[1-9][0-9]?.?[0-9]*$/;
return reg.test(checkVal);
}
/**
* 提取url中的参数
*/
static getUrlParams(url) {
// url不存在参数
if (url.indexOf("?") === -1) {
return {};
}
// http://www.baidu.com/test?a=1&b=2
let params = url.split("?")[1]; // a=1&b=2
params = params.split("&"); // ['a=1', 'b=2']
let urlParams = {};
params.forEach(item => {
let keyValue = item.split("="); // 'a=1' --> ['a', '1']
urlParams[keyValue[0]] = keyValue[1];
});
return urlParams; // {a: 1, b: 2}
}
// ----------------------------------------------uview-ui----------------------------------------------
/**
* 深度克隆
* 当我们将一个对象(变量A)赋值给另一个变量(变量B)修改变量B因为对象引用的特性导致A也同时被修改
* 所以有时候我们需要将A克隆给B这样修改B的时候就不会 导致A也被修改
* @param object
* @returns {*}
*/
static deepClone(object = {}) {
return Vue.prototype.$u.deepClone(object)
}
/**
* 对象深度合并
* 在ES6中我们可以很方便的使用Object.assign进行对象合并但这只是浅层的合并如果对象的属性为数组或者对象的时候会导致属性内部的值丢失
* 注意 此处合并不同于Object.assign因为Object.assign(a, b)会修改a的值为最终的结果(这往往不是我们所期望的)但是deepMerge(a, b)并不会修改a的值
* @param target
* @param source
* @returns {boolean|*}
*/
static deepMerge(target = {}, source = {}) {
return Vue.prototype.$u.deepMerge(target, source)
}
/**
* md5加密
* @param value
* console.log(md5Libs.md5('uView')) // 结果为55c859b4750225eb1cdbd9e0403ee274
*/
static md5(value) {
return md5Libs.md5(value)
}
// ----------------------------------------------uni-app原生api----------------------------------------------
static navigateTo(url, urlParams, objParams) {
// 兼容部分手机机型不能从导航事件中获取objParams问题。
globalVariable.objParams = objParams;
return new Promise(function (resolve, reject) {
if (urlParams) {
if (url.indexOf("?") === -1) {
url = url + "?" + CommonUtil.objectToUrlParams(urlParams);
} else {
url = url + "&" + CommonUtil.objectToUrlParams(urlParams);
}
}
uni.navigateTo({
url: url,
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
});
}
/**
* @param title
* @param duration
* @param icon
successwarnerror 显示成功图标此时 title 文本最多显示 7 个汉字长度默认值
loading 显示加载图标此时 title 文本最多显示 7 个汉字长度 支付宝小程序不支持
none 不显示图标此时 title 文本在小程序最多可显示两行App仅支持单行显示
* @returns {Promise<any>}
*/
static toast(title, duration = 1500, icon = 'none') {
return new Promise(function (resolve, reject) {
uni.showToast({
title: title,
icon: icon,
mask: true, // 是否显示透明蒙层防止触摸穿透默认false
duration: duration, // 提示的延迟时间单位毫秒默认1500
complete: () => {
setTimeout(function () {
resolve('提示时间已完成');
}, duration);
}
});
});
}
/**
* 执行完后直接跳转页面
*/
static toastNavigateTo(title, url, urlParams, objParams) {
const _self = this;
// 兼容部分手机机型不能从导航事件中获取objParams问题。
globalVariable.objParams = objParams;
return new Promise(function (resolve, reject) {
if (title) {
this.toast(title).then(() => {
uni.navigateTo({
url: _self.urlParamsAppendToUrl(url, urlParams),
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
})
} else {
uni.navigateTo({
url: _self.urlParamsAppendToUrl(url, urlParams),
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
}
});
}
/**
* 执行完后直接返回上一个页面
*/
static toastNavigateBack(title, delta = 1) {
const _self = this;
return new Promise(function (resolve, reject) {
if (title) {
_self.toast(title).then(() => {
uni.navigateBack({
delta: delta
});
resolve();
})
} else {
uni.navigateBack({
delta: delta
});
resolve();
}
});
}
/**
* 执行完毕后关闭所有页面并打开指定页面
*/
static toastReLaunch(title, url, urlParams) {
const _self = this;
if (title) {
_self.toast(title).then(() => {
uni.reLaunch({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
})
} else {
uni.reLaunch({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
/**
* 执行完毕后跳转到 tabBar 页面并关闭其他所有非 tabBar 页面
*/
static toastSwitchTab(title, url, urlParams) {
const _self = this;
if (title) {
_self.toast(title).then(() => {
uni.switchTab({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
})
} else {
uni.switchTab({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
/**
{
title: '删除图片',
content: '确定要删除该图片?',
showCancel: true, // 是否显示取消按钮
cancelText:"否", // 默认是“取消”
cancelColor:'skyblue', // 取消文字的颜色
confirmText:"是", // 默认是“确定”
confirmColor: 'skyblue', // 确定文字的颜色
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
temp.splice(index, 1),
that.setData({
tempFilePaths: temp,
})
}
},
fail: function (res) { }, // 接口调用失败的回调函数
complete: function (res) { } // 接口调用结束的回调函数(调用成功、失败都会执行)
}
CommonUtil.alert({
title: '提示!',
content: '确认提交吗?',
showCancel: true, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
}
}
});
* @param opts
*/
static alert(opts) {
return new Promise(function (resolve, reject) {
if (typeof opts === 'string') {
uni.showModal({
title: '提示',
content: opts,
showCancel: false, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
}
resolve();
}
});
} else {
uni.showModal(opts);
resolve();
}
});
}
/**
* 执行完后直接跳转页面
*/
static alertNavigateTo(title, url, urlParams, objParams) {
const _self = this;
// 兼容部分手机机型不能从导航事件中获取objParams问题。
globalVariable.objParams = objParams;
return new Promise(function (resolve, reject) {
if (title) {
uni.showModal({
title: '提示!',
content: title,
showCancel: false, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
uni.navigateTo({
url: _self.urlParamsAppendToUrl(url, urlParams),
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
}
}
});
} else {
uni.navigateTo({
url: _self.urlParamsAppendToUrl(url, urlParams),
success: function (res) {
if (objParams) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('objParams', objParams)
}
resolve(res);
}
})
}
});
}
/**
* 执行完后直接返回上一个页面
*/
static alertNavigateBack(title, delta = 1) {
const _self = this;
return new Promise(function (resolve, reject) {
if (title) {
uni.showModal({
title: '提示!',
content: title,
showCancel: false, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
uni.navigateBack({
delta: delta
});
}
resolve();
}
});
} else {
uni.navigateBack({
delta: delta
});
resolve();
}
});
}
/**
* 执行完毕后关闭所有页面并打开指定页面
*/
static alertReLaunch(title, url, urlParams) {
const _self = this;
if (title) {
uni.showModal({
title: '提示!',
content: title,
showCancel: false, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
uni.reLaunch({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
});
} else {
uni.reLaunch({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
/**
* 执行完毕后跳转到 tabBar 页面并关闭其他所有非 tabBar 页面
*/
static alertSwitchTab(title, url, urlParams) {
const _self = this;
if (title) {
uni.showModal({
title: '提示!',
content: title,
showCancel: false, // 是否显示取消按钮
success: function (res) {
if (res.cancel) { // 点击取消,默认隐藏弹框
} else { // 点击确定
uni.switchTab({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
});
} else {
uni.switchTab({
url: _self.urlParamsAppendToUrl(url, urlParams)
});
}
}
}

View File

@ -0,0 +1,294 @@
/*
全局引入方式src/main.js
import * as filters from './app/core/utils/filters.util' // global filters
// 注册全局的过滤器,在页面上直接使用无须再显示定义过滤器
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
使用方式在页面中直接使用
<template>
{{'abc' | uppercaseFirst}}
</template>
*/
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string | null}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0 || !time) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string')) {
if ((/^[0-9]+$/.test(time))) {
// support "1548221490638"
time = parseInt(time)
} else {
// support safari
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
time = time.replace(new RegExp(/-/gm), '/')
}
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
return value.toString().padStart(2, '0')
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
/**
* Show plural label if time is plural number
* @param {number} time
* @param {string} label
* @return {string}
*/
function pluralize(time, label) {
if (time === 1) {
return time + label
}
return time + label + 's'
}
/**
* @param {number} time
*/
export function timeAgo(time) {
const between = Date.now() / 1000 - Number(time)
if (between < 3600) {
return pluralize(~~(between / 60), ' minute')
} else if (between < 86400) {
return pluralize(~~(between / 3600), ' hour')
} else {
return pluralize(~~(between / 86400), ' day')
}
}
/**
* Number formatting
* like 10000 => 10k
* @param {number} num
* @param {number} digits
*/
export function numberFormatter(num, digits) {
const si = [
{value: 1E18, symbol: 'E'},
{value: 1E15, symbol: 'P'},
{value: 1E12, symbol: 'T'},
{value: 1E9, symbol: 'G'},
{value: 1E6, symbol: 'M'},
{value: 1E3, symbol: 'k'}
]
for (let i = 0; i < si.length; i++) {
if (num >= si[i].value) {
return (num / si[i].value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
}
}
return num.toString()
}
/**
* 10000 => "10,000"
* @param {number} num
*/
export function toThousandFilter(num) {
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
/**
* Upper case first char
* @param {String} string
*/
export function uppercaseFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
/**
* 保留两位小数点
* @param value
* @returns {*|string}
*/
export function toFixed2(value) {
let result = ''
if (value) {
// 截取当前数据到小数点后两位
result = value.toFixed(2)
} else {
result = '0.00'
}
return result
}
/**
* 保留小数点位数
* @param value
* @param retain 保留小数点位数
* @returns {*|string}
*/
export function toFixed(value, retain = 0) {
let result = ''
if (value) {
// 截取当前数据到小数点后两位
result = value.toFixed(retain)
} else {
result = 0.0.toFixed(retain);
}
return result
}
/**
* 如果是null则显示成空字符串
* @param value
* @param defaultValue
* @returns {string}
*/
export function toEmptyStr(value, defaultValue) {
value = value + '' // 转成字符串,数字没有.replace方法。
if (value === null || value === undefined || value === 'null' || value === 'undefined' || value.replace(/(^\s*)|(\s*$)/g, '') === '') {
if (defaultValue) {
return defaultValue
}
return ''
}
return value
}
/**
* 后台返回的base64字符串图片前端不能显示需要使用这个过滤器后才能显示出来
* @param value
* @returns {*}
*/
export function captchaSrc(value) {
let result = ''
if (value) {
return value.replace(/[\r\n]/g, '')
}
return result
}
/**
* 输出对象某个属性值如果属性不存在则返回null防止a.b.c时a或b为null输出属性c报错
* @param value 实际对象需要调用的属性字符串形式
* @param target 实际对象
* @param defaultValue 如果对象中间的某个属性不存在则会报错则返回默认值
* @returns {*}
*
* 使用方式
* 过滤器作用{{'selectedItem.code' | toValue(selectedItem)}}
* 当普通函数使用{{toValue('selectedItem.code', selectedItem) + 'abc'}} // 需要在src/main.js配置Vue.prototype[key] = filters[key]
*/
export function toValue(value, target, defaultValue = null) {
if (!target) {
return defaultValue
}
let attrs = value.split('.')
let clone = Object.assign({}, target)
for (let i = 1; i < attrs.length; i++) {
let attr = attrs[i]
if (i < attrs.length - 1) {
if (!clone[attr]) {
return defaultValue
} else {
clone = clone[attr]
}
} else {
return clone[attr]
}
}
return defaultValue
}

View File

@ -0,0 +1,118 @@
import Vue from 'vue'
import globalVariable from "../global-variable";
/**
* todo 网络超时设置方式https://uniapp.dcloud.net.cn/collocation/manifest?id=networktimeout
* 在配置文件manifest.json中配置
* "networkTimeout":{
* "request": 600000 单位/毫秒
* },
* "app-plus" : {
* }
*/
export class HttpUtil {
/**
* 版本: develop, //开发版
* 版本: trial, //体验版
* 版本: release, //正式版
*/
static appendProfilesActive(params) {
let profilesActive = '';
if (this.__wxConfig) {
if (__wxConfig.envVersion === 'develop') {
profilesActive = 'dev';
} else if (__wxConfig.envVersion === 'trial') {
profilesActive = 'dev'; // test
} else if (__wxConfig.envVersion === 'release') {
profilesActive = 'prod';
}
if (params.data) {
params.data.profilesActive = profilesActive;
}
}
}
static getRequestParams(params) {
if (params) {
if (typeof params === 'string') {
params = {url: params}
}
if (params.url.indexOf('http') === -1) {
params.url = globalVariable.baseUrl + params.url
}
// this.appendProfilesActive(params);
let data = params.data;
if (!data) {
params.data = {};
return params
}
// 删除data参数中值为null或者空字符串或者是undefined的属性。
if (params.isOptimizeData !== false) { // 是否优化参数
// 对于更新的请求,不显示优化属性的话,一般不删除空字符串的属性。
if (params.url.substring(params.url.lastIndexOf('/') + 1).indexOf('update') === 0 && params.isOptimizeData !== true) {
return params
}
for (let attrName in data) {
if (data[attrName] === undefined
|| data[attrName] == null
|| data[attrName] === 'undefined'
|| data[attrName] === 'null'
|| (data[attrName] + '').trim() === '') {
delete data[attrName]
}
}
}
}
return params
}
/**
* post请求时将url附加的参数追加到data中
* 2020-8-31 17:12:45 uView框架post请求url附加参数会报错运行时就卡死
* @param params
*/
static urlParamsToData(params) {
if (params.url.indexOf("?") !== -1) { // url=test?a=1&b=2
let url = params.url.substring(0, params.url.indexOf("?")); // url=test
let keyValueStr = params.url.substring(params.url.indexOf("?") + 1); // keyValueStr -> a=1&b=2
let keyValueList = keyValueStr.split("&"); // keyValueList=["a=1", "b=2"]
// 去掉url中的参数
params.url = url;
// 将url中的参数追加到data中
keyValueList.forEach((value, index) => {
// todo 覆盖data中同属性值
params.data[value.split("=")[0]] = value.split("=")[1]
})
}
}
static myGet(params) {
const _self = this;
params = _self.getRequestParams(params);
return Vue.prototype.$u.get(params.url, params.data)
}
static myPost(params) {
const _self = this;
params = _self.getRequestParams(params);
_self.urlParamsToData(params);
return Vue.prototype.$u.post(params.url, params.data, {
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
})
}
static myPostJson(params) {
const _self = this;
params = _self.getRequestParams(params);
_self.urlParamsToData(params);
return Vue.prototype.$u.post(params.url, params.data, {
'content-type': 'application/json; charset=UTF-8'
})
}
}

View File

@ -0,0 +1,71 @@
import globalVariable from "../global-variable";
/**
* 本地存储工具类
*/
export class LocalStorageUtil {
static setItem(key, value) {
let v = null;
if (typeof (value) == 'object') {
v = JSON.stringify(value);
} else {
v = value;
}
try {
key = globalVariable.localStoragePrefix + key;
console.log('存储【' + key + '】值: ', v);
uni.setStorageSync(key, v);
} catch (e) {
console.log('存储【' + key + '】失败');
}
return value
}
static getItem(key) {
key = globalVariable.localStoragePrefix + key;
let value = null;
try {
value = uni.getStorageSync(key);
if (value) {
value = JSON.parse(value);
} else {
return;
}
console.log('获取【' + key + '】值: ', value);
} catch (e) {
console.log('存储的值不是对象类型: ', value);
}
return value;
}
static removeItem(key) {
try {
key = globalVariable.localStoragePrefix + key;
uni.removeStorageSync(key);
console.log('移除【' + key + '】成功')
} catch (e) {
console.log('移除【' + key + '】失败')
}
}
static setOrGetItem(key, value) {
if (value && (JSON.stringify(value) + '') != '{}') {
return this.setItem(key, value)
} else {
return this.getItem(key)
}
}
static setOrGetQueryParams(page, params) {
const _self = this
// let className = page.__proto__.constructor.name; // 返回上一级时手机端this还是子对象导致返回上级页面时获取的是子页面的数据导致错误。
let className = page
console.log(className + '导航参数---------------' + JSON.stringify(params))
let result = _self.setOrGetItem(`navParams${className}`, params)
if (!result) {
result = {}
}
return result
}
}

667
src/dev/core/utils/pay.js Normal file
View File

@ -0,0 +1,667 @@
import {HttpUtil} from "./http.util";
import globalVariable from "../global-variable";
import {WechatService} from "../../services/wechat.service";
import {LocalStorageUtil} from "./local-storage.util";
/**
* 初始化支付环境
*/
export function initPayEnvironment() {
const _self = this;
console.log("globalVariable---------------------", globalVariable);
return new Promise(function (resolve, reject) {
// 微信小程序版-微信支付
if (globalVariable.runPlatform === "0") {
console.log("准备获得微信小程序code");
// 如果没有openid则无法支付需要先授权获取unionid
if (!globalVariable.userInfo.unionid) {
new WechatService().findUnionidByWeixinMiniAppCode().then(result => {
globalVariable.userInfo.unionid = result.data;
LocalStorageUtil.setItem("userInfo", globalVariable.userInfo);
resolve('支付环境初始化成功!');
})
} else {
resolve('支付环境初始化成功!');
}
} else if (globalVariable.runPlatform === "1") {
console.log("准备获得微信应用code");
// 如果没有openid则无法支付需要先授权获取unionid
if (!globalVariable.userInfo.unionid) {
new WechatService().findUnionidByWeixinAppCode().then(result => {
globalVariable.userInfo.unionid = result.data;
LocalStorageUtil.setItem("userInfo", globalVariable.userInfo);
resolve('支付环境初始化成功!');
})
} else {
resolve('支付环境初始化成功!');
}
}
});
}
/**
* 支付订单
*/
export function pay_order(params) {
if (globalVariable.runPlatform === "0") {
wxMiniAppPay(params);
} else if (globalVariable.runPlatform === "1") {
appPay(params);
}
}
/**
* 充值店铺保证金
*/
export function pay_tbStoreCashDeposit(params) {
if (globalVariable.runPlatform === "0") {
wxMiniAppPay_tbStoreCashDeposit(params);
} else if (globalVariable.runPlatform === "1") {
appPay_tbStoreCashDeposit(params)
}
}
/**
* 购买邮箱支付码
*/
export function pay_tbEmailPayCodeOrder(params) {
if (globalVariable.runPlatform === "0") {
wxMiniAppPay_tbEmailPayCodeOrder(params);
} else if (globalVariable.runPlatform === "1") {
appPay_tbEmailPayCodeOrder(params)
}
}
// todo ------------------------------------------------微信小程序支付------------------------------------------------
// todo ------------------------------------------------微信小程序支付------------------------------------------------
// todo ------------------------------------------------微信小程序支付------------------------------------------------
// todo ------------------------------------------------微信小程序支付------------------------------------------------
// todo ------------------------------------------------微信小程序支付------------------------------------------------
/**
* 微信支付-微信小程序版
* @param params
*/
export function wxMiniAppPay(params) {
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/miniAppPay',
data: {
unionid: globalVariable.userInfo.unionid,
orderId: params.orderId, // 根据商户自己的秘钥进行支付,后台没有查询到则使用自己默认的。
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
timeStamp: result.data.timeStamp,
nonceStr: result.data.nonceStr,
package: result.data.package,
signType: result.data.signType,
paySign: result.data.paySign,
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/miniAppPayOrderQuery',
data: {
orderId: params.orderId
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
duration: 1500,
mask: true,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}
/**
* 微信支付-微信小程序版
* 充值店铺保证金
*/
export function wxMiniAppPay_tbStoreCashDeposit(params) {
const _self = this;
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/miniAppPay_tbStoreCashDeposit',
data: {
unionid: globalVariable.userInfo.unionid,
payMoney: params.payMoney
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
timeStamp: result.data.timeStamp,
nonceStr: result.data.nonceStr,
package: result.data.package,
signType: result.data.signType,
paySign: result.data.paySign,
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/miniAppPay_tbStoreCashDepositQuery',
data: {
code: result.data.code, // 订单编号
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}
/**
* 微信支付-微信小程序版
* 购买邮件支付码
*/
export function wxMiniAppPay_tbEmailPayCodeOrder(params) {
const _self = this;
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/miniAppPay_tbEmailPayCodeOrder',
data: {
unionid: globalVariable.userInfo.unionid,
email: params.email,
type: params.type,
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
timeStamp: result.data.timeStamp,
nonceStr: result.data.nonceStr,
package: result.data.package,
signType: result.data.signType,
paySign: result.data.paySign,
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/miniAppPay_tbEmailPayCodeOrderQuery',
data: {
code: result.data.code, // 订单编号
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}
// todo ------------------------------------------------微信APP支付------------------------------------------------
// todo ------------------------------------------------微信APP支付------------------------------------------------
// todo ------------------------------------------------微信APP支付------------------------------------------------
// todo ------------------------------------------------微信APP支付------------------------------------------------
// todo ------------------------------------------------微信APP支付------------------------------------------------
/**
* 微信支付-微信小程序版
* 订单支付
* @param params
*/
export function appPay(params) {
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/appPay',
data: {
unionid: globalVariable.userInfo.unionid,
orderId: params.orderId, // 根据商户自己的秘钥进行支付,后台没有查询到则使用自己默认的。
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
provider: 'wxpay',
orderInfo: { //微信、支付宝订单数据
appid: result.data.appid,
noncestr: result.data.noncestr,
package: result.data.package, // 固定值,以微信支付文档为主
partnerid: result.data.partnerid,
prepayid: result.data.prepayid,
timestamp: result.data.timestamp,
sign: result.data.sign // 根据签名算法生成签名
},
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/appPayOrderQuery',
data: {
orderId: params.orderId
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
duration: 1500,
mask: true,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}
/**
* 微信支付-微信小程序版
* 充值店铺保证金
*/
export function appPay_tbStoreCashDeposit(params) {
const _self = this;
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/appPay_tbStoreCashDeposit',
data: {
unionid: globalVariable.userInfo.unionid,
payMoney: params.payMoney
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
provider: 'wxpay',
orderInfo: { //微信、支付宝订单数据
appid: result.data.appid,
noncestr: result.data.noncestr,
package: result.data.package, // 固定值,以微信支付文档为主
partnerid: result.data.partnerid,
prepayid: result.data.prepayid,
timestamp: result.data.timestamp,
sign: result.data.sign // 根据签名算法生成签名
},
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/appPay_tbStoreCashDepositQuery',
data: {
code: result.data.code, // 订单编号
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}
/**
* 微信支付-微信小程序版
* 购买邮件支付码
*/
export function appPay_tbEmailPayCodeOrder(params) {
const _self = this;
HttpUtil.myPost({ // 封装微信请求方法
url: 'wxPay/appPay_tbEmailPayCodeOrder',
data: {
unionid: globalVariable.userInfo.unionid,
email: params.email,
type: params.type,
}
}).then(result => {
// 支付密钥生成成功
if (result.code === 0) {
// 支付密钥生成成功,调起支付功能
uni.requestPayment({
provider: 'wxpay',
orderInfo: { //微信、支付宝订单数据
appid: result.data.appid,
noncestr: result.data.noncestr,
package: result.data.package, // 固定值,以微信支付文档为主
partnerid: result.data.partnerid,
prepayid: result.data.prepayid,
timestamp: result.data.timestamp,
sign: result.data.sign // 根据签名算法生成签名
},
success: (res) => {
// 支付成功! 请求后台校验是否支付成功
HttpUtil.myPost({
url: 'wxPay/appPay_tbEmailPayCodeOrderQuery',
data: {
code: result.data.code, // 订单编号
}
}).then(queryResult => {
if (queryResult.code === 0) { // 校验成功/支付成功
uni.showToast({
title: '支付成功!',
icon: 'success',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(queryResult.data)
}, 1500)
}
}
})
} else {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
}
})
},
fail: function (res) {
uni.showToast({
title: '支付失败!',
icon: 'warn',
mask: true,
duration: 1500,
complete: () => {
if (params.callback) {
setTimeout(() => {
params.callback(null)
}, 1500)
}
}
})
},
complete: function (res) {
console.log(res)
}
})
} else { // 支付密钥生成失败
uni.showToast({
title: '支付失败!',
icon: 'warn',
duration: 1500,
mask: true,
})
}
})
}

View File

@ -0,0 +1,120 @@
import {CommonService} from "../../services/common.service";
import {CommonUtil} from "./common.util";
import {HttpUtil} from "./http.util";
const qiniuUploader = require("./qiniuUploader");
/**
* 七牛云工具类
*/
export class QiniuCloudUtil {
static base64Encode(str) {
// 对字符串进行编码
var encode = encodeURI(str);
// 对编码的字符串转化base64
// var base64 = btoa(encode); // 微信小程序不支持
var base64 = CommonUtil.toBase64Encode(encode);
return base64;
}
/**
* 帮助文档https://github.com/gpake/qiniu-wxapp-sdk
* @param params
* @returns {Promise<any>}
*/
static upload(params) {
const _self = this;
if (!params.id) {
params.id = CommonUtil.generateUUID();
}
return new Promise(function (resolve, reject) {
new CommonService().findQiNiuUploadToken().then(result => {
// 交给七牛上传
qiniuUploader.upload(params.filePath,
(res) => { // todo 上传成功
// 每个文件上传成功后,处理相关的事情
// 其中 info 是文件上传成功后服务端返回的json形式如
// {
// "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",
// "key": "gogopher.jpg"
// }
// 参考http://developer.qiniu.com/docs/v6/api/overview/up/response/simple-response.html
console.log('file url is: ' + res.fileUrl);
resolve({
id: params.id,
status: "success"
});
}, (error) => { // todo 上传失败
console.log('error: ' + error);
resolve({
id: params.id,
status: "fail"
});
},
{
region: 'SCN', // qiniuUploader.js文件 uploadURLFromRegionCode 方法可以看到
domain: 'http://image.xxxxxxx.com', // // bucket 域名,下载资源时用到。如果设置,会在 success callback 的 res 参数加上可以直接使用的 ImageURL 字段。否则需要自己拼接
key: params.id, // todo 对应sysFile主键 [非必须]自定义文件 key。如果不设置默认为使用微信小程序 API 的临时文件名
// 以下方法三选一即可优先级为uptoken > uptokenURL > uptokenFunc
uptoken: result.token, // 由其他程序生成七牛 uptoken
}, (res) => {
console.log('上传进度', res.progress)
console.log('已经上传的数据长度', res.totalBytesSent)
console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend)
}, () => {
// 取消上传
}, () => {
// `before` 上传前执行的操作
}, (err) => {
// `complete` 上传接受后执行的操作(无论成功还是失败都执行)
});
});
});
}
/**
* 将图片上传到七牛云并将上传的图片id保存到后台服务端
* @param fkId sysFile表的外键fkId
* @param filePath 图片路径
* @param data
* @returns {Promise<any>}
*/
static uploadToCloud(fkId, filePath, data = {clearOldImage: true, typeMark: "thumbnail"}) {
const _self = this;
return new Promise(function (resolve, reject) {
_self.upload({
filePath: filePath
}).then(qiniuCloudResult => {
console.log(qiniuCloudResult);
if (qiniuCloudResult.status === "success") {
HttpUtil.myPost({
url: `sysfile/saveBase64Image`,
data: {
id: qiniuCloudResult.id,
name: "移动端上传的图片",
fkId: fkId,
type: 'image/jpeg',
clearOldImage: data.clearOldImage,
typeMark: data.typeMark,
content: "jsUploaded" // 在js端就将图片上传到七牛云了
}
}).then(result => {
/*let = {
id: "sysFile.id",
sysFile: sysFile,
status: "success"
};*/
result.message = "上传图片成功";
resolve(result);
});
} else {
resolve({
status: "fail",
message: "上传图片失败"
});
}
})
});
}
}

View File

@ -0,0 +1,176 @@
// created by gpake
(function() {
var config = {
qiniuRegion: '',
qiniuImageURLPrefix: '',
qiniuUploadToken: '',
qiniuUploadTokenURL: '',
qiniuUploadTokenFunction: null,
qiniuShouldUseQiniuFileName: false
}
module.exports = {
init: init,
upload: upload,
}
// 在整个程序生命周期中,只需要 init 一次即可
// 如果需要变更参数,再调用 init 即可
function init(options) {
config = {
qiniuRegion: '',
qiniuImageURLPrefix: '',
qiniuUploadToken: '',
qiniuUploadTokenURL: '',
qiniuUploadTokenFunction: null,
qiniuShouldUseQiniuFileName: false
};
updateConfigWithOptions(options);
}
function updateConfigWithOptions(options) {
if (options.region) {
config.qiniuRegion = options.region;
} else {
console.error('qiniu uploader need your bucket region');
}
if (options.uptoken) {
config.qiniuUploadToken = options.uptoken;
} else if (options.uptokenURL) {
config.qiniuUploadTokenURL = options.uptokenURL;
} else if(options.uptokenFunc) {
config.qiniuUploadTokenFunction = options.uptokenFunc;
}
if (options.domain) {
config.qiniuImageURLPrefix = options.domain;
}
config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName
}
function upload(filePath, success, fail, options, progress, cancelTask, before, complete) {
if (null == filePath) {
console.error('qiniu uploader need filePath to upload');
return;
}
if (options) {
updateConfigWithOptions(options);
}
if (config.qiniuUploadToken) {
doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
} else if (config.qiniuUploadTokenURL) {
getQiniuToken(function() {
doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
});
} else if (config.qiniuUploadTokenFunction) {
config.qiniuUploadToken = config.qiniuUploadTokenFunction();
if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
console.error('qiniu UploadTokenFunction result is null, please check the return value');
return
}
doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
} else {
console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]');
return;
}
}
function doUpload(filePath, success, fail, options, progress, cancelTask, before, complete) {
if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
console.error('qiniu UploadToken is null, please check the init config or networking');
return
}
var url = uploadURLFromRegionCode(config.qiniuRegion);
var fileName = filePath.split('//')[1];
if (options && options.key) {
fileName = options.key;
}
var formData = {
'token': config.qiniuUploadToken
};
if (!config.qiniuShouldUseQiniuFileName) {
formData['key'] = fileName
}
before && before();
var uploadTask = wx.uploadFile({
url: url,
filePath: filePath,
name: 'file',
formData: formData,
success: function (res) {
var dataString = res.data
// // this if case is a compatibility with wechat server returned a charcode, but was fixed
// if(res.data.hasOwnProperty('type') && res.data.type === 'Buffer'){
// dataString = String.fromCharCode.apply(null, res.data.data)
// }
try {
var dataObject = JSON.parse(dataString);
//do something
var fileUrl = config.qiniuImageURLPrefix + '/' + dataObject.key;
dataObject.fileUrl = fileUrl
dataObject.imageURL = fileUrl;
console.log(dataObject);
if (success) {
success(dataObject);
}
} catch(e) {
console.log('parse JSON failed, origin String is: ' + dataString)
if (fail) {
fail(e);
}
}
},
fail: function (error) {
console.error(error);
if (fail) {
fail(error);
}
},
complete: function(err) {
complete && complete(err);
}
})
uploadTask.onProgressUpdate((res) => {
progress && progress(res)
})
cancelTask && cancelTask(() => {
uploadTask.abort()
})
}
function getQiniuToken(callback) {
wx.request({
url: config.qiniuUploadTokenURL,
success: function (res) {
var token = res.data.uptoken;
if (token && token.length > 0) {
config.qiniuUploadToken = token;
if (callback) {
callback();
}
} else {
console.error('qiniuUploader cannot get your token, please check the uptokenURL or server')
}
},
fail: function (error) {
console.error('qiniu UploadToken is null, please check the init config or networking: ' + error);
}
})
}
function uploadURLFromRegionCode(code) {
var uploadURL = null;
switch(code) {
case 'ECN': uploadURL = 'https://up.qiniup.com'; break;
case 'NCN': uploadURL = 'https://up-z1.qiniup.com'; break;
case 'SCN': uploadURL = 'https://up-z2.qiniup.com'; break;
case 'NA': uploadURL = 'https://up-na0.qiniup.com'; break;
case 'ASG': uploadURL = 'https://up-as0.qiniup.com'; break;
default: console.error('please make the region is with one of [ECN, SCN, NCN, NA, ASG]');
}
return uploadURL;
}
})();

View File

@ -0,0 +1,286 @@
import globalVariable from "../global-variable";
export class TabbarUtil {
static getTabbar() {
let list = [
{
type: "0",
tabbar: [
{
"componentRef": "indexRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/home_fill_light.png"
},
{
"componentRef": "goodsClassRef",
"text": "分类",
"title": "商品分类",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/sort_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/sort.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/cart_fill_light.png"
},
{
"componentRef": "communityDynamicRef",
"text": "动态",
"title": "商城动态",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/community_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/community_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/my_fill_light.png"
}
]
},
{
type: "1",
tabbar: [
{
"componentRef": "indexRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "goodsClassRef",
"text": "分类",
"title": "商品分类",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/sort_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/sort.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
},
{
type: "2",
tabbar: [
{
"componentRef": "indexRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "goodsClassRef",
"text": "分类",
"title": "商品分类",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/sort_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/sort.png"
},
{
"componentRef": "goodsSeckillRef",
"text": "商品秒杀",
"title": "商品秒杀",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_fill.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
},
{
type: "3",
tabbar: [
{
"componentRef": "indexEateryRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
},
{
type: "4",
tabbar: [
{
"componentRef": "indexEateryRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "communityDynamicRef",
"text": "动态",
"title": "商城动态",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/community_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/community_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
},
{
type: "5",
tabbar: [
{
"componentRef": "indexEateryRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "goodsSeckillRef",
"text": "商品秒杀",
"title": "商品秒杀",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_fill.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
},
{
type: "6",
tabbar: [
{
"componentRef": "indexEateryRef",
"text": "首页",
"title": globalVariable.userInfo.tbCommunity ? globalVariable.userInfo.tbCommunity.name : '首页',
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/home_fill_light.png"
},
{
"componentRef": "shoppingCartRef",
"text": "购物车",
"title": "购物车",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/cart_fill_light.png"
},
{
"componentRef": "goodsSeckillRef",
"text": "商品秒杀",
"title": "商品秒杀",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/seckill_fill.png"
},
{
"componentRef": "communityDynamicRef",
"text": "动态",
"title": "商城动态",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/community_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/community_fill_light.png"
},
{
"componentRef": "personRef",
"text": "我的",
"title": "我的",
"iconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_light.png",
"selectedIconPath": "/pages/sub/sub1-tabs/static/icon/tabbar/tabs/my_fill_light.png"
}
]
}
];
// 更新选中的底部导航栏
let tabbar = list[0].tabbar;
list.forEach((item, index) => {
if (item.type === globalVariable.userInfo.tbCommunity.tabbarType) {
tabbar = item.tabbar;
}
});
return tabbar;
/*// 更新选择的底部导航栏tab
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
let curRoute = routes[routes.length - 1].route; //获取当前页面路由
_self.tabbar.forEach((item, index) => {
console.log(item.pagePath, curRoute);
if (item.pagePath === curRoute) {
_self.current = index;
}
});
console.log('TabbarUtil---------------------------------', TabbarUtil.current, TabbarUtil.tabbar);*/
}
static getIndexByComponentRef(componentRef) {
const _self = this;
let tarbar = _self.getTabbar();
tarbar.forEach((item, index) => {
if (item.componentRef === componentRef) {
return index;
}
})
}
}

View File

@ -0,0 +1,361 @@
import {CommonUtil} from "./common.util";
export class UFormUtil {
/**
* 初始化表单对象
* @param validateForm
*/
static init(validateForm) {
// console.log("-------------------------------init-------------------------------", validateForm);
// 给表单对象添加controls属性
const _self = this;
let controls = {};
let i = 0;
for (let attrName in validateForm.value) {
controls[attrName] = {
id: CommonUtil.generateUUID(),
rawValue: validateForm.value[attrName], // 原始值,可以用重置表单
value: validateForm.value, // 引用value对线可以在control中直接操作value对象
timestamp: new Date().getTime() + i++,
valueName: attrName,
options: [],
isShow: false,
textDesc: '',
defaultIndex: -1,
}
}
// 添加重置表单方法
validateForm.resetValues = function () {
for (let attrName in validateForm.value) {
validateForm.value[attrName] = validateForm.controls[attrName].rawValue;
if (validateForm.controls[attrName].options) {
_self.selectOptions(validateForm.controls[attrName], validateForm.controls[attrName].selectColNums, validateForm.controls[attrName].selectValues);
}
}
console.log("resetValues------------------------", validateForm);
};
// 添加搜索事件
validateForm.doSearch = function (_selfVue, dataList, uDropdownRef = 'uDropdown') {
console.log(_selfVue)
console.log(_selfVue.$refs)
if (_selfVue.$refs[uDropdownRef]) {
_selfVue.$refs[uDropdownRef].close();
}
_selfVue.doRefresh(dataList);
console.log("doSearch------------------------", validateForm);
};
validateForm.controls = controls;
return validateForm;
}
/**
* 给表单字段设置默认值
* @param validateForm
* @param data
*/
static setDefaultValues(validateForm, data) {
console.log("-------------------------------setDefaultValues-------------------------------", validateForm, data);
if (data === null || data === undefined) {
return;
}
for (let controlName in validateForm.value) {
for (let dataName in data) {
if (controlName == dataName) {
if (typeof data[dataName] === 'boolean') {
validateForm.value[controlName] = data[dataName];
validateForm.controls[controlName].rawValue = data[dataName];
} else {
validateForm.value[controlName] = data[dataName] + ""; // todo 值必须转成字符串类型,表单校验规则数字和字符串类型不兼容。
validateForm.controls[controlName].rawValue = data[dataName] + ""; // 原始值,可以用重置表单 todo 值必须转成字符串类型,表单校验规则数字和字符串类型不兼容。
}
}
}
}
}
/**
* 选择地区回调事件
*/
static regionConfirm(e, control, provinceName = 'provinceName', cityName = 'cityName', areaName = 'areaName') {
console.log(e);
let value = control.value;
value[control.valueName] = e.province.label + '-' + e.city.label + '-' + e.area.label;
value[provinceName] = e.province.label;
value[cityName] = e.city.label;
value[areaName] = e.area.label;
control.isShow = false;
}
/**
* 选择时间回调事件
*/
static timeConfirm(e, control) {
console.log(e);
let value = control.value;
let yyyyMMdd = [];
if (e.year) {
yyyyMMdd.push(e.year);
}
if (e.month) {
yyyyMMdd.push(e.month);
}
if (e.day) {
yyyyMMdd.push(e.day);
}
let hhmmss = [];
if (e.hour) {
hhmmss.push(e.hour);
}
if (e.minute) {
hhmmss.push(e.minute);
}
if (e.second) {
hhmmss.push(e.second);
}
value[control.valueName] = `${yyyyMMdd.join("-")} ${hhmmss.join(":")}`.trim();
control.isShow = false;
}
/**
* @param control
* @param options
* @param colNums 列数
* @param values 默认值
*/
static setOptions(control, options, colNums = 1, values) {
console.log("-------------------------------setOptions-------------------------------", control, options, colNums, values);
if (colNums === 1) { // 删除第一列的子节点
options.forEach((item1, index) => {
delete item1.children;
});
} else if (colNums === 2) { // 删除第二列的子节点
options.forEach((item1, index1) => {
item1.children.forEach((item2, index2) => {
delete item2.children;
});
});
} else if (colNums === 3) { // 删除第三列的子节点
options.forEach((item1, index1) => {
item1.children.forEach((item2, index2) => {
item2.children.forEach((item3, index3) => {
delete item3.children;
});
});
});
}
control.options = options;
control.selectColNums = colNums;
control.selectValues = values;
this.selectOptions(control, colNums, values);
}
/**
* 选中某个控件值
*
* 模式选择"single-column"-单列模式"mutil-column"-多列模式"mutil-column-auto"-多列联动模式
* 三列数据格式
* [
* {
* value: 1,
* label: '中国',
* children: [
* {
* value: 2,
* label: '广东',
* children: [
* {
* value: 3,
* label: '深圳'
* },
* {
* value: 4,
* label: '广州'
* }
* ]
* }
* ]
* }
* ]
*/
static selectOptions(control, colNums, values) {
let defaultValue = control.value[control.valueName];
if (values) {
defaultValue = values;
}
// todo 如果值是boolean类型则换成1或0
if (defaultValue === false || defaultValue === 'false') {
defaultValue = "0";
} else if (defaultValue === true || defaultValue === 'true') {
defaultValue = "1";
}
// 单列模式
if (colNums === 1) {
control.options.forEach((item, index) => {
if (item.label !== undefined && item.value !== undefined) {
if (item.value + "" === defaultValue + "") {
control.textDesc = item.label;
control.defaultIndex = index;
control.defaultValue = [index];
}
} else if (item.code !== undefined && item.name !== undefined) {
if (item.code + "" === defaultValue + "") {
control.textDesc = item.name;
control.defaultIndex = index;
control.defaultValue = [index];
}
}
});
} else if (colNums === 2) {
// 一般默认值是第二列的值
control.options.forEach((item1, index1) => {
item1.children.forEach((item2, index2) => {
if (item2.label !== undefined && item2.value !== undefined) {
if (item2.value + "" === defaultValue + "") {
let labels = [];
if (item1.label) {
labels.push(item1.label);
}
if (item2.label) {
labels.push(item2.label);
}
control.textDesc = labels.join("-");
control.defaultIndex = index2;
control.defaultValue = [index1, index2];
}
} else if (item2.code !== undefined && item2.name !== undefined) {
if (item2.code + "" === defaultValue + "") {
let names = [];
if (item1.name) {
names.push(item1.name);
}
if (item2.name) {
names.push(item2.name);
}
control.textDesc = names.join("-");
control.defaultIndex = index2;
control.defaultValue = [index1, index2];
}
}
});
});
} else if (colNums === 3) {
// 一般默认值是第三列的值
control.options.forEach((item1, index1) => {
item1.children.forEach((item2, index2) => {
item2.children.forEach((item3, index3) => {
if (item3.label !== undefined && item3.value !== undefined) {
if (item3.value + "" === defaultValue + "") {
let labels = [];
if (item1.label) {
labels.push(item1.label);
}
if (item2.label) {
labels.push(item2.label);
}
if (item3.label) {
labels.push(item3.label);
}
control.textDesc = labels.join("-");
control.defaultIndex = index3;
control.defaultValue = [index1, index2, index3];
}
} else if (item3.code !== undefined && item3.name !== undefined) {
if (item3.code + "" === defaultValue + "") {
let names = [];
if (item1.name) {
names.push(item1.name);
}
if (item2.name) {
names.push(item2.name);
}
if (item3.name) {
names.push(item3.name);
}
control.textDesc = names.join("-");
control.defaultIndex = index3;
control.defaultValue = [index1, index2, index3];
}
}
});
});
});
}
}
/**
* 单列下拉选择选中事件
*/
static selectSingleColumnConfirm($event, control) {
console.log($event, control);
control.value[control.valueName] = $event[0].value;
control.textDesc = $event[0].label;
this.selectOptions(control, $event.length);
control.isShow = false;
}
/**
* 多列联动下拉选择选中事件
*/
static selectMutilColumnConfirm($event, control) {
console.log($event, control); // $event = [{label: '', value: ''}, {label: '', value: ''}, ...]
control.value[control.valueName] = $event[$event.length - 1].value; // 多列联动,取最后一列的值
let labels = [];
$event.forEach(item => {
if (item.label) {
labels.push(item.label);
}
});
control.textDesc = labels.join("-");
// 解决弹框不会选中问题。
this.selectOptions(control, $event.length);
control.isShow = false;
}
/**
* 获取表单中某个字段
* @param formRef this.$refs.uForm
* @param prop 'code'
* @returns {*}
*/
static getFormItem(formRef, prop) {
if (!formRef) {
return undefined;
}
const list = formRef.fields.filter(item => item.prop === prop);
if (list.length) {
return list[0];
}
return undefined;
}
/**
* 校验单个字段触发单个字段的校验规则
* @param formRef this.$refs.uForm
* @param prop 'code'
*
* UFormUtil.validation(_self.$refs.validateFormRef, 'sysFileId');
*/
static validation(formRef, prop) {
const _self = this;
return new Promise(function (resolve, reject) {
const item = _self.getFormItem(formRef, prop);
item.validation('', error => {
if (error) {
CommonUtil.toast(error);
resolve(false);
} else {
resolve(true);
}
});
});
}
}

View File

@ -0,0 +1,84 @@
import {BaseService} from '../core/base/base.service'
export class CommonService extends BaseService {
/**
* 唯一性检查
*/
uniqueCheck(tableName, fieldName, fieldValue, excludeId) {
return this.httpUtil.myPost({
url: `common/uniqueCheck`,
data: {
tableName: tableName,
fieldName: fieldName,
fieldValue: fieldValue,
excludeId: excludeId
}
})
}
/**
* 多字段唯一性检查
*
* {
* "tableName": "sys_user",
* "fieldList": [
* {"fieldName": "code11", "fieldValue": "111"},
* {"fieldName": "code", "fieldValue": "1"}
* ],
* "excludeId": ""
* }
*/
uniqueCheckByFields(parameterMap) {
return this.httpUtil.myPostJson({
url: `common/uniqueCheckByFields`,
data: parameterMap
})
}
/**
* 生成分享图片
* @param storeId
*/
generateShareImage(data) {
return this.httpUtil.myPost({
url: `common/generateShareImage`,
data: data
})
}
/**
* web端测试
*/
downloadApp() {
return this.httpUtil.myGet({ // 获得服务器更新信息
url: 'tbappversioninfo/selectNewest',
data: {
platformType: 'android',
versionType: 'release',
deleted: 0
}
})
}
/**
* 后台生成二维码自定义二维码内容
* @param content
*/
generateQrcodeBase64(content) {
return this.httpUtil.myGet({ // 获得服务器更新信息
url: 'common/generateQrcodeToBase64',
data: {
content: content
}
})
}
/**
* 获取七牛云上传Token
*/
findQiNiuUploadToken() {
return this.httpUtil.myGet({ // 获得服务器更新信息
url: 'common/findQiNiuUploadToken',
})
}
}

View File

@ -0,0 +1,59 @@
import {BaseService} from '../core/base/base.service'
export class LoginService extends BaseService {
login(params) {
return this.httpUtil.myPost({
url: 'sysuser/login',
data: {
username: params.username,
password: params.password
}
})
}
/**
* 扫码登陆
* @param data
* @returns {*}
*/
loginByScan(data) {
return this.httpUtil.myPost({
url: 'sysuser/loginByScan',
data: data
})
}
/**
* 从服务号登陆
* @param data
* @returns {*}
*/
loginByFwh(data) {
return this.httpUtil.myPost({
url: 'sysuser/loginByFwh',
data: data
})
}
/**
* 小程序登录
* @param data
* @returns {*}
*/
miniAppLogin(data) {
return this.httpUtil.myPost({
url: 'wechat/miniAppLogin',
data: data
})
}
gotoIndexPage() {
if (!this.globalVariable.userInfo.tbCommunityUser || this.globalVariable.userInfo.tbCommunityUser.type === '1') {
uni.showToast({title: '登录成功,即将跳转到首页', icon: 'none'})
uni.navigateTo({
url: `/pages/sub/sub1-tabs/index`
})
}
}
}

View File

@ -0,0 +1,11 @@
import {BaseService} from "../core/base/base.service";
export class OrderGoodsAfterSaleReportService extends BaseService {
statisticOrderGoodsAfterSaleTotal(params) {
return this.httpUtil.myPost({
url: `ordergoodaftersalesreport/statisticOrderGoodsAfterSaleTotal`,
data: params
});
}
}

View File

@ -0,0 +1,67 @@
import {BaseService} from "../core/base/base.service";
export class OrderReportService extends BaseService {
statisticOrderTotal(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderTotal`,
data: params
});
}
statisticOrderNumber(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderNumber`,
data: params
});
}
statisticOrderSaleMoney(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderSaleMoney`,
data: params
});
}
statisticOrderNumber24Hours(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderNumber24Hours`,
data: params
});
}
statisticOrderSaleMoney24Hours(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderSaleMoney24Hours`,
data: params
});
}
statisticOrderNumberRecent30Days(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderNumberRecent30Days`,
data: params
});
}
statisticOrderSaleMoneyRecent30Days(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderSaleMoneyRecent30Days`,
data: params
});
}
statisticOrderNumberRecentMonthsOfYear(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderNumberRecentMonthsOfYear`,
data: params
});
}
statisticOrderSaleMoneyRecentMonthsOfYear(params) {
return this.httpUtil.myPost({
url: `orderreport/statisticOrderSaleMoneyRecentMonthsOfYear`,
data: params
});
}
}

View File

@ -0,0 +1,11 @@
import {BaseService} from "../core/base/base.service";
export class StoreReportService extends BaseService {
statisticStoreInfo(params) {
return this.httpUtil.myPost({
url: `storereport/statisticStoreInfo`,
data: params
});
}
}

Some files were not shown because too many files have changed in this diff Show More