init
13
.gitee/ISSUE_TEMPLATE.zh-CN.md
Normal file
@@ -0,0 +1,13 @@
|
||||
### 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
|
||||
|
||||
|
14
.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md
Normal file
@@ -0,0 +1,14 @@
|
||||
### 相关的Issue
|
||||
|
||||
|
||||
### 原因(目的、解决的问题等)
|
||||
|
||||
|
||||
### 描述(做了什么,变更了什么)
|
||||
|
||||
|
||||
### 测试用例(新增、改动、可能影响的功能)
|
||||
|
||||
|
||||
|
||||
|
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/unpackage/dist/*
|
||||
/unpackage/cache/*
|
||||
/unpackage/release/*
|
||||
/node_modules/*
|
||||
/.hbuilderx/*
|
||||
/.idea/*
|
||||
deploy.sh
|
31
App.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
export default {
|
||||
onLaunch() {
|
||||
// 国际化,设置当前语言
|
||||
if (this.vuex_locale) {
|
||||
this.$i18n.locale = this.vuex_locale;
|
||||
this.$u.api.lang({
|
||||
lang: this.vuex_locale
|
||||
});
|
||||
}
|
||||
// 设置底部导航栏角标
|
||||
uni.setTabBarBadge({
|
||||
index: 0,
|
||||
text: '3'
|
||||
});
|
||||
// uni.removeTabBarBadge({
|
||||
// index: 0
|
||||
// });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("~@/static/iconfont/iconfont.css");
|
||||
</style>
|
||||
<style lang="scss">
|
||||
@import "uview-ui/index.scss";
|
||||
@import "pages/common/aidex.scss";
|
||||
</style>
|
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 皮皮大刺猬
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
179
README.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# RuoYi-Uniapp(若依-手机端)开源啦
|
||||
|
||||
#### 介绍
|
||||
若依-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类放进去即可
|
||||
|
||||
|
||||
#### 快速体验
|
||||
|
||||
2、微信小程序端:扫码访问(目前只能用用户名密码方式登录,用户名:admin 密码:admin123)<br><br>
|
||||
<img src="https://images.gitee.com/uploads/images/2021/1115/214722_20aaf4c8_9700683.jpeg" width="220" height="220" >
|
||||
|
||||
|
||||
## 基于RuoYi修改的美化皮肤的样式地址
|
||||
|
||||
- [🎉 RuoYi + vue2.x + Max + element-ui(vue2.x 支持 PC、平板、手机)](http://82.157.44.212:8091/index)
|
||||
|
||||
- [🎉 RuoYi + vue3.x + Max + element-plus(vue3.x 支持 PC、平板、手机)](http://82.157.44.212:8090/index)
|
||||
|
||||
- [🎉 RuoYi + vue2.x + Max + element-ui + Cloud(vue2.x 支持 PC、平板、手机)](http://82.157.44.212:8093/index)
|
||||
|
||||
- [🎉 RuoYi + vue3.x + Max + element-plus + Cloud(vue3.x 支持 PC、平板、手机)](http://82.157.44.212:8092/index)
|
||||
|
||||
- [🎉 RuoYi + vue3.x + element-plus + uniapp2(vue3.x 支持 PC、平板、手机)](http://82.157.44.212:8094/#/)
|
||||
|
||||
|
||||
#### 我的另一个项目:
|
||||
|
||||
**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手机端
|
||||
|
||||
#### 关于我们
|
||||
|
||||
我们擅长UI、前端开发、后端架构,有一颗热爱开源的心,致力于打造企业级的通用产品设计UI体系让项目
|
||||
或者更直观,更高效、更简单,未来将持续关注UI交互,持续推出高质量的交互产品。
|
||||
######
|
||||
<img src="https://images.gitee.com/uploads/images/2021/1112/114326_5eb079c2_9700683.jpeg" width="220" height="220" >
|
||||
<img src="https://images.gitee.com/uploads/images/2021/1112/114207_bb1bac92_9700683.jpeg" width="220" height="220" >
|
||||
<img src="https://images.gitee.com/uploads/images/2021/1115/164243_d4e0d61d_9700683.png" width="220" height="220" >
|
||||
|
||||
版权所有Copyright © 2017-2021 By AiDex (http://www.aidex.vip) All rights reserved
|
74
common/base64.js
Normal 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
common/common.js
Normal 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;
|
||||
}
|
30
common/config.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
const config = {
|
||||
|
||||
// 产品名称
|
||||
productName: 'Aidex Mobile',
|
||||
|
||||
// 公司名称
|
||||
companyName: 'Aidex',
|
||||
|
||||
// 产品版本号
|
||||
productVersion: 'V4.3.0',
|
||||
|
||||
// 版本检查标识
|
||||
appCode: 'android',
|
||||
|
||||
// 内部版本号码
|
||||
appVersion: 1,
|
||||
|
||||
// 管理基础路径
|
||||
adminPath: ''
|
||||
|
||||
}
|
||||
|
||||
// 设置后台接口服务的基础地址
|
||||
// config.baseUrl = 'http://tc.cqsznc.com:7080';
|
||||
// config.baseUrl = 'http://192.168.71.139:8080';
|
||||
config.baseUrl = '/api';
|
||||
export default config;
|
23
common/http.api.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
// 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作
|
||||
const install = (Vue, vm) => {
|
||||
|
||||
// 参数配置对象
|
||||
const config = vm.vuex_config;
|
||||
|
||||
// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下
|
||||
vm.$u.api = {
|
||||
codesub: (params = {}) => vm.$u.get(config.adminPath+'/property/visitorManagement/useqr', params),
|
||||
uploadimg: (params = {}) => vm.$u.post(config.adminPath+'/resource/oss/upload', params),
|
||||
fksub: (params = {}) => vm.$u.post(config.adminPath+'/property/visitorManagement/add', params),
|
||||
login: (params = {}) => vm.$u.post(config.adminPath+'/auth/login', params),
|
||||
getUserInfo: (params = {}) => vm.$u.get(config.adminPath+'/system/user/profile', params)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
install
|
||||
}
|
119
common/http.interceptor.js
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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.vuex_config.baseUrl,
|
||||
originalData: true,
|
||||
// 默认头部,http2约定header名称统一小写 aidex
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
'x-requested-with': 'XMLHttpRequest'
|
||||
}
|
||||
});
|
||||
|
||||
// 请求拦截,配置Token等参数
|
||||
Vue.prototype.$u.http.interceptor.request = (req) => {
|
||||
if (!req.header){
|
||||
req.header = [];
|
||||
}
|
||||
req.header["source"] = "uniapp";
|
||||
req.header["clientId"] = "dab457a1ea14411787c240db05bb0832"
|
||||
// 默认指定返回 JSON 数据
|
||||
if (!req.header[ajaxHeader]){
|
||||
req.header[ajaxHeader] = 'json';
|
||||
}
|
||||
// 设定传递 Token 认证参数 aidex
|
||||
if (req.url!="/auth/login"&&!req.header[sessionIdHeader] && vm.vuex_token){
|
||||
req.header[sessionIdHeader] = "Bearer "+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);
|
||||
let data = res.data;
|
||||
if (!(data)){
|
||||
vm.$u.toast('未连接到服务器')
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof data === 'object' && !(data instanceof Array)){
|
||||
if (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 = {}) => {
|
||||
header['content-type'] = 'application/json';
|
||||
return vm.$u.http.request({
|
||||
url,
|
||||
method: 'POST',
|
||||
header,
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
install
|
||||
}
|
34
common/locales/en.js
Normal 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'
|
||||
}
|
||||
|
||||
}
|
41
common/locales/zh_CN.js
Normal 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: '通讯录'
|
||||
}
|
||||
}
|
751
common/spark-md5.js
Normal 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;
|
||||
}));
|
1459
common/uni.css
Normal file
6
common/vue-i18n.min.js
vendored
Normal file
269
components/VisitorDetailModal.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<!-- 弹窗容器 -->
|
||||
<view class="visitor-modal" v-if="visible">
|
||||
<!-- 遮罩层(点击关闭) -->
|
||||
<view class="modal-mask" @click="closeModal"></view>
|
||||
|
||||
<!-- 弹窗内容(阻止遮罩层事件穿透) -->
|
||||
<view class="modal-dialog" @click.stop>
|
||||
<!-- 头部:标题 + 关闭按钮 -->
|
||||
<view class="dialog-header">
|
||||
<text class="dialog-title">访客详情</text>
|
||||
<text class="dialog-close" @click="closeModal">×</text>
|
||||
</view>
|
||||
|
||||
<!-- 主体:信息展示 -->
|
||||
<view class="dialog-body">
|
||||
<view class="info-item">
|
||||
<text class="item-label">访客姓名:</text>
|
||||
<text class="item-value">{{ visitorInfo.visitorName || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">访客电话:</text>
|
||||
<text class="item-value">{{ visitorInfo.visitorPhone || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">所属公司:</text>
|
||||
<text class="item-value">{{ visitorInfo.visitorUnit || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">被访人:</text>
|
||||
<text class="item-value">{{ visitorInfo.interviewedPerson || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">联系电话:</text>
|
||||
<text class="item-value">{{ visitorInfo.interviewedPhone || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">被访单位:</text>
|
||||
<text class="item-value">{{ visitorInfo.interviewedUnit || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">拜访事由:</text>
|
||||
<text class="item-value">{{ visitorInfo.visitingReason || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">拜访时间:</text>
|
||||
<text class="item-value">{{ visitorInfo.visitingBeginTime || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">是否预约车位:</text>
|
||||
<text class="item-value">{{ visitorInfo.bookingParkingSpace ? '是' : '否' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">预约状态:</text>
|
||||
<text
|
||||
class="item-value status-tag"
|
||||
:class="{
|
||||
'status-confirmed': visitorInfo.serveStatus === 1,
|
||||
'status-pending': visitorInfo.serveStatus === 0,
|
||||
'status-rejected': visitorInfo.serveStatus === 2
|
||||
}"
|
||||
>
|
||||
{{ formatServeStatus(visitorInfo.serveStatus) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="item-label">提交时间:</text>
|
||||
<text class="item-value">{{ visitorInfo.createTime || '无' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部:审核操作(仅待确认时显示) -->
|
||||
<view class="dialog-footer" v-if="showActionButtons">
|
||||
<button
|
||||
class="audit-btn reject"
|
||||
@click="handleAudit('reject')"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ loading && auditType === 'reject' ? '驳回中...' : '驳回' }}
|
||||
</button>
|
||||
<button
|
||||
class="audit-btn confirm"
|
||||
@click="handleAudit('confirm')"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ loading && auditType === 'confirm' ? '确认中...' : '确认' }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 是否显示弹窗
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 访客数据
|
||||
visitorInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 是否显示审核按钮(默认仅“待确认”显示)
|
||||
showActionButtons: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false, // 审核按钮加载状态
|
||||
auditType: '' // 记录当前审核类型(确认/驳回)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 关闭弹窗
|
||||
closeModal() {
|
||||
this.$emit('close');
|
||||
},
|
||||
|
||||
// 处理审核操作
|
||||
handleAudit(type) {
|
||||
this.loading = true;
|
||||
this.auditType = type;
|
||||
|
||||
// 模拟接口请求(实际替换为真实接口)
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.closeModal(); // 关闭弹窗
|
||||
|
||||
// 通知父组件更新状态
|
||||
this.$emit('audit', {
|
||||
type: type,
|
||||
visitorId: this.visitorInfo.id // 传递访客ID
|
||||
});
|
||||
|
||||
// 提示用户
|
||||
uni.showToast({
|
||||
title: type === 'confirm' ? '确认成功' : '驳回成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 1500);
|
||||
},
|
||||
|
||||
// 格式化服务状态
|
||||
formatServeStatus(status) {
|
||||
switch (status) {
|
||||
case 0: return '待确认';
|
||||
case 1: return '已确认';
|
||||
case 2: return '已驳回';
|
||||
default: return '未知';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 弹窗容器 */
|
||||
.visitor-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
/* 遮罩层 */
|
||||
.modal-mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 弹窗内容 */
|
||||
.modal-dialog {
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-radius: 16px 16px 0 0;
|
||||
overflow: hidden;
|
||||
transform: translateY(100%);
|
||||
animation: slideUp 0.3s forwards;
|
||||
}
|
||||
|
||||
/* 弹窗滑入动画 */
|
||||
@keyframes slideUp {
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 头部 */
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.dialog-title {
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.dialog-close {
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 主体内容 */
|
||||
.dialog-body {
|
||||
padding: 16px;
|
||||
}
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.item-label {
|
||||
width: 80px;
|
||||
color: #666;
|
||||
}
|
||||
.item-value {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
}
|
||||
.status-tag {
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
.status-pending {
|
||||
background: #ff9900;
|
||||
}
|
||||
.status-confirmed {
|
||||
background: #52c41a;
|
||||
}
|
||||
.status-rejected {
|
||||
background: #ff4d4f;
|
||||
}
|
||||
|
||||
/* 底部操作 */
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.audit-btn {
|
||||
flex: 1;
|
||||
margin: 0 8px;
|
||||
padding: 12px 0;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
}
|
||||
.reject {
|
||||
background: #ff4d4f;
|
||||
}
|
||||
.confirm {
|
||||
background: #52c41a;
|
||||
}
|
||||
</style>
|
64
components/headnavbar/index.vue
Normal 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>
|
BIN
doc/后台集成接口类.rar
Normal file
50
h5.html
Normal 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>
|
64
main.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
App.mpType = 'app';
|
||||
|
||||
// 引入全局 uView 框架
|
||||
import uView from 'uview-ui';
|
||||
Vue.use(uView);
|
||||
|
||||
|
||||
// 全局存储 vuex 的封装
|
||||
import store from '@/store';
|
||||
|
||||
// 引入 uView 提供的对 vuex 的简写法文件
|
||||
let vuexStore = require('@/store/$u.mixin.js');
|
||||
Vue.mixin(vuexStore);
|
||||
|
||||
// 引入 uView 对小程序分享的 mixin 封装
|
||||
let mpShare = require('uview-ui/libs/mixin/mpShare.js');
|
||||
Vue.mixin(mpShare);
|
||||
|
||||
// Vue i18n 国际化
|
||||
import VueI18n from '@/common/vue-i18n.min.js';
|
||||
Vue.use(VueI18n);
|
||||
|
||||
// i18n 部分的配置,引入语言包,注意路径
|
||||
import lang_zh_CN from '@/common/locales/zh_CN.js';
|
||||
import lang_en from '@/common/locales/en.js';
|
||||
|
||||
const i18n = new VueI18n({
|
||||
// 默认语言
|
||||
locale: 'zh_CN',
|
||||
// 引入语言文件
|
||||
messages: {
|
||||
'zh_CN': lang_zh_CN,
|
||||
'en': lang_en,
|
||||
}
|
||||
});
|
||||
|
||||
// 由于微信小程序的运行机制问题,需声明如下一行,H5和APP非必填
|
||||
Vue.prototype._i18n = i18n;
|
||||
const app = new Vue({
|
||||
i18n,
|
||||
store,
|
||||
...App
|
||||
});
|
||||
|
||||
import { replaceAll } from '@/common/common.js'
|
||||
Vue.prototype.replaceAll = replaceAll
|
||||
|
||||
// http 拦截器,将此部分放在 new Vue() 和 app.$mount() 之间,才能 App.vue 中正常使用
|
||||
import httpInterceptor from '@/common/http.interceptor.js';
|
||||
Vue.use(httpInterceptor, app);
|
||||
|
||||
// http 接口 API 抽离,免于写 url 或者一些固定的参数
|
||||
import httpApi from '@/common/http.api.js';
|
||||
Vue.use(httpApi, app);
|
||||
|
||||
app.$mount();
|
38
manifest.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name" : "访客机H5",
|
||||
"appid" : "__UNI__BB8BA25",
|
||||
"description" : "访客机H5",
|
||||
"versionName" : "1.8.4",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true
|
||||
}
|
||||
},
|
||||
"mp-weixin" : {
|
||||
"appid" : "wx04dd806ca2843cc1",
|
||||
"setting" : {
|
||||
"urlCheck" : true,
|
||||
"es6" : false,
|
||||
"minified" : true
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"h5" : {
|
||||
"title" : "访客机H5",
|
||||
"devServer" : {
|
||||
"https" : false
|
||||
},
|
||||
"router" : {
|
||||
"mode" : "history",
|
||||
"base" : "/visitore/"
|
||||
}
|
||||
},
|
||||
"permissions" : {
|
||||
"CAMERA" : {},
|
||||
"WRITE_EXTERNAL_STORAGE" : {}
|
||||
}
|
||||
}
|
32
package-lock.json
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Aidex",
|
||||
"version": "2.3.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@icon-park/vue": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.nlark.com/@icon-park/vue/download/@icon-park/vue-1.3.5.tgz",
|
||||
"integrity": "sha1-twRuLCtdpexNZz/7Wta8gL6loTs=",
|
||||
"requires": {
|
||||
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
|
||||
"csstype": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"@vue/babel-helper-vue-jsx-merge-props": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz",
|
||||
"integrity": "sha1-MWJKelBfsU2h1YAjclpMXycOaoE="
|
||||
},
|
||||
"csstype": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.nlark.com/csstype/download/csstype-3.0.9.tgz?cache=0&sync_timestamp=1631540658518&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcsstype%2Fdownload%2Fcsstype-3.0.9.tgz",
|
||||
"integrity": "sha1-ZBCvMbJr0FIJM9AsvGT86c4/vws="
|
||||
},
|
||||
"vue-i18n": {
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
|
||||
"integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg=="
|
||||
}
|
||||
}
|
||||
}
|
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "Aidex",
|
||||
"version": "2.3.0",
|
||||
"description": "Aidex 移动端快速开发框架",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitee.com/aidex/aidex-uniapp.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Aidex",
|
||||
"快速开发平台"
|
||||
],
|
||||
"author": "aidex",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/aidex/aidex-uniapp/issues"
|
||||
},
|
||||
"homepage": "https://github.com/aidex/aidex-uniapp#readme",
|
||||
"dependencies": {
|
||||
"@icon-park/vue": "^1.3.5",
|
||||
"vue-i18n": "^8.20.0"
|
||||
}
|
||||
}
|
63
pages.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"easycom": {
|
||||
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/sys/msg/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息",
|
||||
"navigationStyle": "custom" // 隐藏系统导航栏
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
|
||||
],
|
||||
"preloadRule": {
|
||||
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "Aidex",
|
||||
"navigationBarBackgroundColor": "#ffffff"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#333333",
|
||||
"selectedColor": "#4094ff",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "white",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/sys/msg/index",
|
||||
"iconPath": "static/aidex/tabbar/msg_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/msg_2.png",
|
||||
"text": "访客等级"
|
||||
},
|
||||
// {
|
||||
// "pagePath": "pages/sys/home/index",
|
||||
// "iconPath": "static/aidex/tabbar/home_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/home_2.png",
|
||||
// "text": "首页"
|
||||
// },
|
||||
{
|
||||
"pagePath": "pages/sys/work/work",
|
||||
"iconPath": "static/aidex/tabbar/apply_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/apply_2.png",
|
||||
"text": "到访确认"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/qrpage/qrpage",
|
||||
"iconPath": "static/aidex/tabbar/book_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/book_2.png",
|
||||
"text": "扫码登记"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/camera/camera",
|
||||
"iconPath": "static/aidex/tabbar/my_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/my_2.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
108
pages/common/aidex.scss
Normal file
@@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
* @author aidex
|
||||
* @version 2020-9-1
|
||||
*/
|
||||
.wrap {
|
||||
|
||||
.search{
|
||||
padding: 20rpx 20rpx 0;
|
||||
background: #f8f8f8;
|
||||
height: 105rpx;
|
||||
}
|
||||
|
||||
.scroll-list {
|
||||
height: calc(100vh - var(--window-top) - var(--window-bottom) - 105rpx); // 105rpx 为 .search 的高度
|
||||
width: 100%;
|
||||
|
||||
.loadmore {
|
||||
padding: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
padding-bottom: 10rpx;
|
||||
|
||||
.item {
|
||||
margin: 0 20rpx 20rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
font-size: 28rpx;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
padding-left: 15rpx;
|
||||
align-items: center;
|
||||
|
||||
.text {
|
||||
margin: 0 20rpx;
|
||||
font-size: 35rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.list {
|
||||
|
||||
.u-cell-item-box {
|
||||
|
||||
.u-swipe-content {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.u-cell_title {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
min-width: 655rpx;
|
||||
}
|
||||
|
||||
.u-border-bottom:last-child:after {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20rpx 30rpx;
|
||||
|
||||
.u-cell-item-box {
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.form-footer {
|
||||
display: flex;
|
||||
margin: 10rpx;
|
||||
padding-bottom: 30rpx;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
margin: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.u-cell-box {
|
||||
|
||||
.u-cell {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.u-cell_title {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.u-cell__left-icon-wrap {
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
}
|
||||
}
|
34
pages/common/webview.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<view>
|
||||
<web-view :webview-styles="webviewStyles" :src="webviewUrl"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
webviewUrl: '',
|
||||
webviewStyles: {
|
||||
progress: {
|
||||
color: '#FF7200'
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
onLoad(params) {
|
||||
this.webviewUrl = params.url;
|
||||
// this.webviewUrl = `http://127.0.0.1:8980/js/a/bpm/bpmCategory/index/process?__sid=${this.vuex_token}&__cookie=true`;
|
||||
if (params.title != ''){
|
||||
uni.setNavigationBarTitle({
|
||||
title: params.title
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
638
pages/sys/msg/index.vue
Normal file
@@ -0,0 +1,638 @@
|
||||
<template>
|
||||
<scroll-view class="container" scroll-y>
|
||||
<view class="form-card">
|
||||
<view class="form-title">访客预约表单</view>
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<view class="section-title">基本信息</view>
|
||||
<view class="form-item">
|
||||
<text class="label required">访客姓名</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请输入您的姓名" v-model="formData.visitorName" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label required">所属公司</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请输入您的公司名称" v-model="formData.visitorUnit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label required">联系电话</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="number" placeholder="请输入您的手机号码" v-model="formData.visitorPhone" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label required">拜访事由</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请简要描述拜访目的" v-model="formData.visitingReason" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 被访人信息 -->
|
||||
<view class="section-title">被访人信息</view>
|
||||
<view class="form-item">
|
||||
<text class="label required">被访人姓名</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请输入被访人姓名" v-model="formData.interviewedPerson" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">被访单位</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请输入被访单位名称" v-model="formData.interviewedUnit" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">被访人电话</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="number" placeholder="请输入被访人联系电话" v-model="formData.interviewedPhone" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拜访时间 -->
|
||||
<view class="section-title">拜访时间</view>
|
||||
<view class="form-item">
|
||||
<text class="label">开始时间</text>
|
||||
<view class="picker-wrapper">
|
||||
<picker mode="date" :value="formData.visitingBeginDate" start="2020-01-01" end="2030-12-31"
|
||||
@change="onBeginDateChange">
|
||||
<view class="picker-value">{{formData.visitingBeginDate}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="picker-wrapper time-picker">
|
||||
<picker mode="time" :value="formData.visitingBeginTime" @change="onBeginTimeChange">
|
||||
<view class="picker-value">{{formData.visitingBeginTime}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">结束时间</text>
|
||||
<view class="picker-wrapper">
|
||||
<picker mode="date" :value="formData.visitingEndDate" start="2020-01-01" end="2030-12-31"
|
||||
@change="onEndDateChange">
|
||||
<view class="picker-value">{{formData.visitingEndDate}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="picker-wrapper time-picker">
|
||||
<picker mode="time" :value="formData.visitingEndTime" @change="onEndTimeChange">
|
||||
<view class="picker-value">{{formData.visitingEndTime}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 预约信息 -->
|
||||
<view class="section-title">预约信息</view>
|
||||
<view class="form-item">
|
||||
<text class="label">预约车位</text>
|
||||
<view class="picker-wrapper">
|
||||
<picker mode="selector" :range="parkingOptions" @change="handleParkingChange">
|
||||
<view class="picker-value">{{formData.bookingParkingSpace ? '需要' : '不需要'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 条件显示:预约车位时显示车牌号 -->
|
||||
<view class="form-item" v-if="formData.bookingParkingSpace">
|
||||
<text class="label required">车牌号</text>
|
||||
<view class="input-wrapper">
|
||||
<input type="text" placeholder="请输入车牌号" v-model="formData.licensePlate" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label required">人脸照片</text>
|
||||
<view class="upload-wrapper">
|
||||
<view class="upload-btn" @click="takePhoto">
|
||||
<text class="upload-text">+ 拍照上传</text>
|
||||
</view>
|
||||
<view class="preview-image" v-if="formData.facePictures">
|
||||
<image :src="formData.facePictures" mode="aspectFill" @click="delimg"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="form-item">
|
||||
<text class="label">预约状态</text>
|
||||
<view class="picker-wrapper">
|
||||
<picker mode="selector" :range="statusOptions" @change="handleStatusChange">
|
||||
<view class="picker-value">{{statusMap[formData.serveStatus]}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-wrapper">
|
||||
<button class="submit-btn" @click="submitForm">确认提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
const now = new Date();
|
||||
const date = now.getFullYear() + '-' +
|
||||
(now.getMonth() + 1).toString().padStart(2, '0') + '-' +
|
||||
now.getDate().toString().padStart(2, '0');
|
||||
const time = now.getHours().toString().padStart(2, '0') + ':' +
|
||||
now.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
return {
|
||||
formData: {
|
||||
visitorName: '1',
|
||||
visitorUnit: '1',
|
||||
visitorPhone: '15555555555',
|
||||
visitingReason: '1',
|
||||
interviewedPerson: '1',
|
||||
interviewedUnit: '1',
|
||||
interviewedPhone: '15555555555',
|
||||
visitingBeginDate: date,
|
||||
visitingBeginTime: time,
|
||||
visitingEndDate: date,
|
||||
visitingEndTime: time,
|
||||
bookingParkingSpace: false,
|
||||
licensePlate: '',
|
||||
facePictures: '',
|
||||
serveStatus: 0
|
||||
},
|
||||
parkingOptions: ['不需要', '需要'],
|
||||
statusOptions: ['待确认', '已确认', '已取消', '已完成'],
|
||||
statusMap: {
|
||||
0: '待确认',
|
||||
1: '已确认',
|
||||
2: '已取消',
|
||||
3: '已完成'
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
// 新增:获取url中的code参数并打印
|
||||
if (options.code) {
|
||||
console.log('从URL中获取到的code参数:', options.code);
|
||||
let p = {};
|
||||
p.qrcode = options.code
|
||||
this.formData.qrCodeId = options.code;
|
||||
this.$u.api.codesub(p).then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
} else {
|
||||
console.log('URL中未包含code参数');
|
||||
uni.showToast({
|
||||
title: '二维码失效,请重新扫描',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('default');
|
||||
// #endif
|
||||
},
|
||||
onReady() {
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('landscape-primary');
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
// 处理日期时间选择
|
||||
onBeginDateChange(e) {
|
||||
this.formData.visitingBeginDate = e.detail.value;
|
||||
},
|
||||
onBeginTimeChange(e) {
|
||||
this.formData.visitingBeginTime = e.detail.value;
|
||||
},
|
||||
onEndDateChange(e) {
|
||||
this.formData.visitingEndDate = e.detail.value;
|
||||
},
|
||||
onEndTimeChange(e) {
|
||||
this.formData.visitingEndTime = e.detail.value;
|
||||
},
|
||||
|
||||
// 处理车位预约选择
|
||||
handleParkingChange(e) {
|
||||
this.formData.bookingParkingSpace = e.detail.value === 1;
|
||||
if (!this.formData.bookingParkingSpace) {
|
||||
this.formData.licensePlate = '';
|
||||
}
|
||||
},
|
||||
|
||||
// 处理状态选择
|
||||
handleStatusChange(e) {
|
||||
this.formData.serveStatus = e.detail.value;
|
||||
},
|
||||
|
||||
// 拍照
|
||||
takePhoto() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sourceType: ['camera'], // 只允许使用相机
|
||||
success: (res) => {
|
||||
// console.log(res.tempFilePaths[0])
|
||||
this.formData.facePictures = res.tempFilePaths[0];
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showToast({
|
||||
title: '拍照失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validateForm() {
|
||||
const {
|
||||
qrCodeId,
|
||||
visitorName,
|
||||
visitorUnit,
|
||||
visitorPhone,
|
||||
visitingReason,
|
||||
interviewedPerson,
|
||||
bookingParkingSpace,
|
||||
licensePlate,
|
||||
facePictures,
|
||||
visitingBeginDate,
|
||||
visitingBeginTime,
|
||||
visitingEndDate,
|
||||
visitingEndTime
|
||||
} = this.formData;
|
||||
|
||||
// 验证姓名
|
||||
if (!visitorName) {
|
||||
return '请输入访客姓名';
|
||||
}
|
||||
|
||||
// 验证公司
|
||||
if (!visitorUnit) {
|
||||
return '请输入所属公司';
|
||||
}
|
||||
|
||||
// 验证电话
|
||||
if (!visitorPhone) {
|
||||
return '请输入联系电话';
|
||||
}
|
||||
|
||||
// 简单的手机号格式验证
|
||||
if (!/^1[3-9]\d{9}$/.test(visitorPhone)) {
|
||||
return '请输入正确的手机号码';
|
||||
}
|
||||
|
||||
// 验证事由
|
||||
if (!visitingReason) {
|
||||
return '请输入拜访事由';
|
||||
}
|
||||
|
||||
// 验证被访人
|
||||
if (!interviewedPerson) {
|
||||
return '请输入被访人姓名';
|
||||
}
|
||||
|
||||
// 验证车牌号(如果需要预约车位)
|
||||
if (bookingParkingSpace && !licensePlate) {
|
||||
return '请输入车牌号';
|
||||
}
|
||||
|
||||
|
||||
if (!facePictures) {
|
||||
return '请拍照上传人脸照片';
|
||||
}
|
||||
|
||||
// 验证时间逻辑
|
||||
const beginDateTime = new Date(`${visitingBeginDate} ${visitingBeginTime}`);
|
||||
const endDateTime = new Date(`${visitingEndDate} ${visitingEndTime}`);
|
||||
|
||||
if (beginDateTime >= endDateTime) {
|
||||
return '开始时间必须早于结束时间';
|
||||
}
|
||||
|
||||
return ''; // 验证通过
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
submitForm() {
|
||||
const errorMsg = this.validateForm();
|
||||
if (errorMsg) {
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 合并日期和时间
|
||||
this.formData.visitingBeginTime = `${this.formData.visitingBeginDate} ${this.formData.visitingBeginTime}`;
|
||||
this.formData.visitingEndTime = `${this.formData.visitingEndDate} ${this.formData.visitingEndTime}`;
|
||||
|
||||
// 准备提交数据
|
||||
const submitData = {
|
||||
...this.formData,
|
||||
bookingParkingSpace: this.formData.bookingParkingSpace ? 0 : 1
|
||||
};
|
||||
console.log(submitData)
|
||||
|
||||
// 显示加载提示
|
||||
uni.showLoading({
|
||||
title: '提交中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 模拟API请求
|
||||
setTimeout(() => {
|
||||
uni.request({url:this.formData.facePictures})
|
||||
// .then(response => response.blob())
|
||||
.then(blob => {
|
||||
// 此时得到了原始Blob对象
|
||||
console.log(blob);
|
||||
const file = new File([blob], 'filename.png', {
|
||||
type: blob.type
|
||||
});
|
||||
// 构建FormData进行上传
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
console.log(formData)
|
||||
// 发送上传请求
|
||||
// this.$u.api.uploadimg()
|
||||
// 接上面的代码,假设Blob是图片类型
|
||||
uni.uploadFile({
|
||||
url: 'http://183.230.235.66:11010/api/resource/oss/qrupload', // 后端上传接口地址
|
||||
filePath: file.filePath, // 要上传的文件路径
|
||||
name: 'file', // 后端接收文件的参数名
|
||||
// FormData中的其他参数
|
||||
formData: {
|
||||
'code': this.formData.qrCodeId // 示例:其他表单字段
|
||||
},
|
||||
// 上传进度回调
|
||||
onProgressUpdate: (res) => {
|
||||
this.progress = res.progress;
|
||||
console.log('上传进度:' + res.progress);
|
||||
},
|
||||
// 上传成功回调
|
||||
success: (res) => {
|
||||
console.log('上传成功', res);
|
||||
this.uploadResult = res.data;
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success'
|
||||
});
|
||||
},
|
||||
// 上传失败回调
|
||||
fail: (err) => {
|
||||
console.error('上传失败', err);
|
||||
uni.showToast({
|
||||
title: '上传失败',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
// 无论成功失败都会执行
|
||||
complete: () => {
|
||||
this.progress = 0; // 重置进度
|
||||
}
|
||||
});
|
||||
// this.$u.api.uploadimg(formData).then(res => {
|
||||
// console.log(res)
|
||||
// if (res.code == 200) {
|
||||
// uni.showToast({
|
||||
// title: "提交成功,请等待审核!",
|
||||
// icon: "success"
|
||||
// })
|
||||
// } else {
|
||||
// uni.showToast({
|
||||
// title: "tp提交失败!",
|
||||
// icon: "error"
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
|
||||
});
|
||||
|
||||
this.$u.api.fksub(submitData).then(res => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
uni.showToast({
|
||||
title: "提交成功,请等待审核!",
|
||||
icon: "success"
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "提交失败!",
|
||||
icon: "error"
|
||||
})
|
||||
}
|
||||
})
|
||||
uni.hideLoading();
|
||||
|
||||
// 显示成功提示
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
// 提交成功后,可跳转到成功页面或重置表单
|
||||
setTimeout(() => {
|
||||
// 重置表单
|
||||
this.resetForm();
|
||||
// 返回到上一页或跳转到其他页面
|
||||
// uni.navigateBack();
|
||||
}, 2000);
|
||||
}, 1500);
|
||||
},
|
||||
delimg() {
|
||||
this.formData.facePictures = ''
|
||||
},
|
||||
|
||||
// 重置表单
|
||||
resetForm() {
|
||||
const now = new Date();
|
||||
const date = now.getFullYear() + '-' +
|
||||
(now.getMonth() + 1).toString().padStart(2, '0') + '-' +
|
||||
now.getDate().toString().padStart(2, '0');
|
||||
const time = now.getHours().toString().padStart(2, '0') + ':' +
|
||||
now.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
this.formData = {
|
||||
visitorName: '',
|
||||
visitorUnit: '',
|
||||
visitorPhone: '',
|
||||
visitingReason: '',
|
||||
interviewedPerson: '',
|
||||
interviewedUnit: '',
|
||||
interviewedPhone: '',
|
||||
visitingBeginDate: date,
|
||||
visitingBeginTime: time,
|
||||
visitingEndDate: date,
|
||||
visitingEndTime: time,
|
||||
bookingParkingSpace: false,
|
||||
licensePlate: '',
|
||||
facePictures: '',
|
||||
serveStatus: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
background-color: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
margin: 16px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 12px;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #007aff;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.label {
|
||||
width: 96px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.label.required::before {
|
||||
content: '*';
|
||||
color: #ff4d4f;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
border: 1px solid #e5e6eb;
|
||||
border-radius: 6px;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-wrapper input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-wrapper {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
border: 1px solid #e5e6eb;
|
||||
border-radius: 6px;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.picker-wrapper::after {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 6px solid #999;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.upload-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px dashed #e5e6eb;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 6px;
|
||||
margin-left: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e5e6eb;
|
||||
}
|
||||
|
||||
.preview-image image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.submit-wrapper {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background-color: #007aff;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
border-radius: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
BIN
static/aidex/banner/banner01.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
static/aidex/banner/banner02.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
static/aidex/banner/banner03.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
static/aidex/favicon.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
static/aidex/images/code01.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
static/aidex/images/code02.jpg
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
static/aidex/images/head.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/aidex/images/list-icon.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
static/aidex/images/new-pic.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
static/aidex/images/service02.png
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
static/aidex/images/user01.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
static/aidex/images/user02.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
static/aidex/images/user03.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
static/aidex/images/user04.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/aidex/images/user05.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
static/aidex/images/user06.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
static/aidex/login-bg.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/aidex/login/eye_close.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
static/aidex/login/eye_open.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
static/aidex/tabbar/apply_1.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/aidex/tabbar/apply_2.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/aidex/tabbar/book_1.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/aidex/tabbar/book_2.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
static/aidex/tabbar/home_1.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
static/aidex/tabbar/home_2.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
static/aidex/tabbar/msg_1.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/aidex/tabbar/msg_2.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/aidex/tabbar/my_1.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
static/aidex/tabbar/my_2.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/common/img/iPhoneX.png
Normal file
After Width: | Height: | Size: 40 KiB |
363
static/common/js/touch-emulator.js
Normal file
@@ -0,0 +1,363 @@
|
||||
(function(window, document, exportName, undefined) {
|
||||
"use strict";
|
||||
|
||||
var isMultiTouch = false;
|
||||
var multiTouchStartPos;
|
||||
var eventTarget;
|
||||
var touchElements = {};
|
||||
|
||||
// polyfills
|
||||
if(!document.createTouch) {
|
||||
document.createTouch = function(view, target, identifier, pageX, pageY, screenX, screenY, clientX, clientY) {
|
||||
// auto set
|
||||
if(clientX == undefined || clientY == undefined) {
|
||||
clientX = pageX - window.pageXOffset;
|
||||
clientY = pageY - window.pageYOffset;
|
||||
}
|
||||
|
||||
return new Touch(target, identifier, {
|
||||
pageX: pageX,
|
||||
pageY: pageY,
|
||||
screenX: screenX,
|
||||
screenY: screenY,
|
||||
clientX: clientX,
|
||||
clientY: clientY
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if(!document.createTouchList) {
|
||||
document.createTouchList = function() {
|
||||
var touchList = new TouchList();
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
touchList[i] = arguments[i];
|
||||
}
|
||||
touchList.length = arguments.length;
|
||||
return touchList;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* create an touch point
|
||||
* @constructor
|
||||
* @param target
|
||||
* @param identifier
|
||||
* @param pos
|
||||
* @param deltaX
|
||||
* @param deltaY
|
||||
* @returns {Object} touchPoint
|
||||
*/
|
||||
function Touch(target, identifier, pos, deltaX, deltaY) {
|
||||
deltaX = deltaX || 0;
|
||||
deltaY = deltaY || 0;
|
||||
|
||||
this.identifier = identifier;
|
||||
this.target = target;
|
||||
this.clientX = pos.clientX + deltaX;
|
||||
this.clientY = pos.clientY + deltaY;
|
||||
this.screenX = pos.screenX + deltaX;
|
||||
this.screenY = pos.screenY + deltaY;
|
||||
this.pageX = pos.pageX + deltaX;
|
||||
this.pageY = pos.pageY + deltaY;
|
||||
}
|
||||
|
||||
/**
|
||||
* create empty touchlist with the methods
|
||||
* @constructor
|
||||
* @returns touchList
|
||||
*/
|
||||
function TouchList() {
|
||||
var touchList = [];
|
||||
|
||||
touchList.item = function(index) {
|
||||
return this[index] || null;
|
||||
};
|
||||
|
||||
// specified by Mozilla
|
||||
touchList.identifiedTouch = function(id) {
|
||||
return this[id + 1] || null;
|
||||
};
|
||||
|
||||
return touchList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple trick to fake touch event support
|
||||
* this is enough for most libraries like Modernizr and Hammer
|
||||
*/
|
||||
function fakeTouchSupport() {
|
||||
var objs = [window, document.documentElement];
|
||||
var props = ['ontouchstart', 'ontouchmove', 'ontouchcancel', 'ontouchend'];
|
||||
|
||||
for(var o=0; o<objs.length; o++) {
|
||||
for(var p=0; p<props.length; p++) {
|
||||
if(objs[o] && objs[o][props[p]] == undefined) {
|
||||
objs[o][props[p]] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* we don't have to emulate on a touch device
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasTouchSupport() {
|
||||
return ("ontouchstart" in window) || // touch events
|
||||
(window.Modernizr && window.Modernizr.touch) || // modernizr
|
||||
(navigator.msMaxTouchPoints || navigator.maxTouchPoints) > 2; // pointer events
|
||||
}
|
||||
|
||||
/**
|
||||
* disable mouseevents on the page
|
||||
* @param ev
|
||||
*/
|
||||
function preventMouseEvents(ev) {
|
||||
// 注释启用默认事件
|
||||
// ev.preventDefault();
|
||||
// ev.stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* only trigger touches when the left mousebutton has been pressed
|
||||
* @param touchType
|
||||
* @returns {Function}
|
||||
*/
|
||||
function onMouse(touchType) {
|
||||
return function(ev) {
|
||||
// prevent mouse events
|
||||
preventMouseEvents(ev);
|
||||
|
||||
if (ev.which !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The EventTarget on which the touch point started when it was first placed on the surface,
|
||||
// even if the touch point has since moved outside the interactive area of that element.
|
||||
// also, when the target doesnt exist anymore, we update it
|
||||
if (ev.type == 'mousedown' || !eventTarget || (eventTarget && !eventTarget.dispatchEvent)) {
|
||||
eventTarget = ev.target;
|
||||
}
|
||||
|
||||
// shiftKey has been lost, so trigger a touchend
|
||||
if (isMultiTouch && !ev.shiftKey) {
|
||||
triggerTouch('touchend', ev);
|
||||
isMultiTouch = false;
|
||||
}
|
||||
|
||||
triggerTouch(touchType, ev);
|
||||
|
||||
// we're entering the multi-touch mode!
|
||||
if (!isMultiTouch && ev.shiftKey) {
|
||||
isMultiTouch = true;
|
||||
multiTouchStartPos = {
|
||||
pageX: ev.pageX,
|
||||
pageY: ev.pageY,
|
||||
clientX: ev.clientX,
|
||||
clientY: ev.clientY,
|
||||
screenX: ev.screenX,
|
||||
screenY: ev.screenY
|
||||
};
|
||||
triggerTouch('touchstart', ev);
|
||||
}
|
||||
|
||||
// reset
|
||||
if (ev.type == 'mouseup') {
|
||||
multiTouchStartPos = null;
|
||||
isMultiTouch = false;
|
||||
eventTarget = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* trigger a touch event
|
||||
* @param eventName
|
||||
* @param mouseEv
|
||||
*/
|
||||
function triggerTouch(eventName, mouseEv) {
|
||||
var touchEvent = document.createEvent('Event');
|
||||
touchEvent.initEvent(eventName, true, true);
|
||||
|
||||
touchEvent.altKey = mouseEv.altKey;
|
||||
touchEvent.ctrlKey = mouseEv.ctrlKey;
|
||||
touchEvent.metaKey = mouseEv.metaKey;
|
||||
touchEvent.shiftKey = mouseEv.shiftKey;
|
||||
|
||||
touchEvent.touches = getActiveTouches(mouseEv, eventName);
|
||||
touchEvent.targetTouches = getActiveTouches(mouseEv, eventName);
|
||||
touchEvent.changedTouches = getChangedTouches(mouseEv, eventName);
|
||||
|
||||
eventTarget.dispatchEvent(touchEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a touchList based on the mouse event
|
||||
* @param mouseEv
|
||||
* @returns {TouchList}
|
||||
*/
|
||||
function createTouchList(mouseEv) {
|
||||
var touchList = new TouchList();
|
||||
|
||||
if (isMultiTouch) {
|
||||
var f = TouchEmulator.multiTouchOffset;
|
||||
var deltaX = multiTouchStartPos.pageX - mouseEv.pageX;
|
||||
var deltaY = multiTouchStartPos.pageY - mouseEv.pageY;
|
||||
|
||||
touchList.push(new Touch(eventTarget, 1, multiTouchStartPos, (deltaX*-1) - f, (deltaY*-1) + f));
|
||||
touchList.push(new Touch(eventTarget, 2, multiTouchStartPos, deltaX+f, deltaY-f));
|
||||
} else {
|
||||
touchList.push(new Touch(eventTarget, 1, mouseEv, 0, 0));
|
||||
}
|
||||
|
||||
return touchList;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive all active touches
|
||||
* @param mouseEv
|
||||
* @returns {TouchList}
|
||||
*/
|
||||
function getActiveTouches(mouseEv, eventName) {
|
||||
// empty list
|
||||
if (mouseEv.type == 'mouseup') {
|
||||
return new TouchList();
|
||||
}
|
||||
|
||||
var touchList = createTouchList(mouseEv);
|
||||
if(isMultiTouch && mouseEv.type != 'mouseup' && eventName == 'touchend') {
|
||||
touchList.splice(1, 1);
|
||||
}
|
||||
return touchList;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive a filtered set of touches with only the changed pointers
|
||||
* @param mouseEv
|
||||
* @param eventName
|
||||
* @returns {TouchList}
|
||||
*/
|
||||
function getChangedTouches(mouseEv, eventName) {
|
||||
var touchList = createTouchList(mouseEv);
|
||||
|
||||
// we only want to return the added/removed item on multitouch
|
||||
// which is the second pointer, so remove the first pointer from the touchList
|
||||
//
|
||||
// but when the mouseEv.type is mouseup, we want to send all touches because then
|
||||
// no new input will be possible
|
||||
if(isMultiTouch && mouseEv.type != 'mouseup' &&
|
||||
(eventName == 'touchstart' || eventName == 'touchend')) {
|
||||
touchList.splice(0, 1);
|
||||
}
|
||||
|
||||
return touchList;
|
||||
}
|
||||
|
||||
/**
|
||||
* show the touchpoints on the screen
|
||||
*/
|
||||
function showTouches(ev) {
|
||||
var touch, i, el, styles;
|
||||
|
||||
// first all visible touches
|
||||
for(i = 0; i < ev.touches.length; i++) {
|
||||
touch = ev.touches[i];
|
||||
el = touchElements[touch.identifier];
|
||||
if(!el) {
|
||||
el = touchElements[touch.identifier] = document.createElement("div");
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
|
||||
styles = TouchEmulator.template(touch);
|
||||
for(var prop in styles) {
|
||||
el.style[prop] = styles[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// remove all ended touches
|
||||
if(ev.type == 'touchend' || ev.type == 'touchcancel') {
|
||||
for(i = 0; i < ev.changedTouches.length; i++) {
|
||||
touch = ev.changedTouches[i];
|
||||
el = touchElements[touch.identifier];
|
||||
if(el) {
|
||||
el.parentNode.removeChild(el);
|
||||
delete touchElements[touch.identifier];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TouchEmulator initializer
|
||||
*/
|
||||
function TouchEmulator() {
|
||||
if (hasTouchSupport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fakeTouchSupport();
|
||||
|
||||
window.addEventListener("mousedown", onMouse('touchstart'), true);
|
||||
window.addEventListener("mousemove", onMouse('touchmove'), true);
|
||||
window.addEventListener("mouseup", onMouse('touchend'), true);
|
||||
|
||||
window.addEventListener("mouseenter", preventMouseEvents, true);
|
||||
window.addEventListener("mouseleave", preventMouseEvents, true);
|
||||
window.addEventListener("mouseout", preventMouseEvents, true);
|
||||
window.addEventListener("mouseover", preventMouseEvents, true);
|
||||
|
||||
// it uses itself!
|
||||
window.addEventListener("touchstart", showTouches, true);
|
||||
window.addEventListener("touchmove", showTouches, true);
|
||||
window.addEventListener("touchend", showTouches, true);
|
||||
window.addEventListener("touchcancel", showTouches, true);
|
||||
}
|
||||
|
||||
// start distance when entering the multitouch mode
|
||||
TouchEmulator.multiTouchOffset = 75;
|
||||
|
||||
/**
|
||||
* css template for the touch rendering
|
||||
* @param touch
|
||||
* @returns object
|
||||
*/
|
||||
TouchEmulator.template = function(touch) {
|
||||
var size = 0;
|
||||
var transform = 'translate('+ (touch.clientX-(size/2)) +'px, '+ (touch.clientY-(size/2)) +'px)';
|
||||
return {
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
top: 0,
|
||||
background: '#fff',
|
||||
border: 'solid 1px #999',
|
||||
opacity: .6,
|
||||
borderRadius: '100%',
|
||||
height: size + 'px',
|
||||
width: size + 'px',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
display: 'block',
|
||||
overflow: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
webkitUserSelect: 'none',
|
||||
mozUserSelect: 'none',
|
||||
userSelect: 'none',
|
||||
webkitTransform: transform,
|
||||
mozTransform: transform,
|
||||
transform: transform,
|
||||
zIndex: 100
|
||||
}
|
||||
};
|
||||
|
||||
// export
|
||||
if (typeof define == "function" && define.amd) {
|
||||
define(function() {
|
||||
return TouchEmulator;
|
||||
});
|
||||
} else if (typeof module != "undefined" && module.exports) {
|
||||
module.exports = TouchEmulator;
|
||||
} else {
|
||||
window[exportName] = TouchEmulator;
|
||||
}
|
||||
})(window, document, "TouchEmulator");
|
463
static/iconfont/iconfont.css
Normal file
@@ -0,0 +1,463 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2874232 */
|
||||
src: url('~@/static/iconfont/iconfont.woff2?t=1636514770782') format('woff2'),
|
||||
url('~@/static/iconfont/iconfont.woff?t=1636514770782') format('woff'),
|
||||
url('~@/static/iconfont/iconfont.ttf?t=1636514770782') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-minus-circle-fill:before {
|
||||
content: "\e844";
|
||||
}
|
||||
|
||||
.icon-close-circle-fill:before {
|
||||
content: "\e845";
|
||||
}
|
||||
|
||||
.icon-plus-circle-fill:before {
|
||||
content: "\e846";
|
||||
}
|
||||
|
||||
.icon-tupian:before {
|
||||
content: "\e8ba";
|
||||
}
|
||||
|
||||
.icon-xiangji:before {
|
||||
content: "\e8bc";
|
||||
}
|
||||
|
||||
.icon-zengjia:before {
|
||||
content: "\e8c0";
|
||||
}
|
||||
|
||||
.icon-youhuiquan:before {
|
||||
content: "\e8c1";
|
||||
}
|
||||
|
||||
.icon-quanbudingdan:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-moban:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-hetongqianzi:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-gongwujiedai:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-kaoqinchuqin:before {
|
||||
content: "\e8d0";
|
||||
}
|
||||
|
||||
.icon-haocaifei:before {
|
||||
content: "\e6bc";
|
||||
}
|
||||
|
||||
.icon-huiyishi1:before {
|
||||
content: "\e662";
|
||||
}
|
||||
|
||||
.icon-baoming1:before {
|
||||
content: "\e632";
|
||||
}
|
||||
|
||||
.icon-jiabanshenqing:before {
|
||||
content: "\e651";
|
||||
}
|
||||
|
||||
.icon-hetongxieyi:before {
|
||||
content: "\e64b";
|
||||
}
|
||||
|
||||
.icon-jiabanshenpi:before {
|
||||
content: "\e774";
|
||||
}
|
||||
|
||||
.icon-yongche:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-baoming:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-qingjia:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tianshenpi:before {
|
||||
content: "\eb67";
|
||||
}
|
||||
|
||||
.icon-icon_yingyongguanli:before {
|
||||
content: "\eb8f";
|
||||
}
|
||||
|
||||
.icon-xingzhuang-xingxing:before {
|
||||
content: "\eb9a";
|
||||
}
|
||||
|
||||
.icon-gongnengdingyi:before {
|
||||
content: "\ebb7";
|
||||
}
|
||||
|
||||
.icon-kongxinduigou:before {
|
||||
content: "\ebe5";
|
||||
}
|
||||
|
||||
.icon-tianjia:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-chucha:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-gongdan:before {
|
||||
content: "\ec37";
|
||||
}
|
||||
|
||||
.icon-daibanshixiang2:before {
|
||||
content: "\ec4e";
|
||||
}
|
||||
|
||||
.icon-bianjisekuai:before {
|
||||
content: "\ec7c";
|
||||
}
|
||||
|
||||
.icon-hetongguanli:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-huiyishi:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-ribao:before {
|
||||
content: "\e835";
|
||||
}
|
||||
|
||||
.icon-banjieshiwu:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-daibanshiwu:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-kaoheguanli:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-shiyanshikaohe:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-baoxiao:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-shenpi:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-baoxiaodan:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-xinwen:before {
|
||||
content: "\e639";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e648";
|
||||
}
|
||||
|
||||
.icon-fujian:before {
|
||||
content: "\e655";
|
||||
}
|
||||
|
||||
.icon-msg-system:before {
|
||||
content: "\e6b9";
|
||||
}
|
||||
|
||||
.icon-daibanshixiang:before {
|
||||
content: "\e65d";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-daibanshixiang1:before {
|
||||
content: "\e6ba";
|
||||
}
|
||||
|
||||
.icon-search:before {
|
||||
content: "\e6b4";
|
||||
}
|
||||
|
||||
.icon-view-list:before {
|
||||
content: "\e6b5";
|
||||
}
|
||||
|
||||
.icon-headset-one:before {
|
||||
content: "\e6b6";
|
||||
}
|
||||
|
||||
.icon-list-checkbox:before {
|
||||
content: "\e6b7";
|
||||
}
|
||||
|
||||
.icon-jiyika:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.icon-chart-histogram-two:before {
|
||||
content: "\e679";
|
||||
}
|
||||
|
||||
.icon-audit:before {
|
||||
content: "\e67a";
|
||||
}
|
||||
|
||||
.icon-check-one:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-bookmark-one:before {
|
||||
content: "\e67c";
|
||||
}
|
||||
|
||||
.icon-a-comment1:before {
|
||||
content: "\e67d";
|
||||
}
|
||||
|
||||
.icon-avatar:before {
|
||||
content: "\e67e";
|
||||
}
|
||||
|
||||
.icon-collection-files:before {
|
||||
content: "\e67f";
|
||||
}
|
||||
|
||||
.icon-copy-one:before {
|
||||
content: "\e680";
|
||||
}
|
||||
|
||||
.icon-add:before {
|
||||
content: "\e681";
|
||||
}
|
||||
|
||||
.icon-currency:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-edit-two:before {
|
||||
content: "\e683";
|
||||
}
|
||||
|
||||
.icon-finance:before {
|
||||
content: "\e684";
|
||||
}
|
||||
|
||||
.icon-find:before {
|
||||
content: "\e685";
|
||||
}
|
||||
|
||||
.icon-folder-plus:before {
|
||||
content: "\e686";
|
||||
}
|
||||
|
||||
.icon-link-break:before {
|
||||
content: "\e687";
|
||||
}
|
||||
|
||||
.icon-financing-one:before {
|
||||
content: "\e688";
|
||||
}
|
||||
|
||||
.icon-help:before {
|
||||
content: "\e689";
|
||||
}
|
||||
|
||||
.icon-chart-pie:before {
|
||||
content: "\e68a";
|
||||
}
|
||||
|
||||
.icon-id-card:before {
|
||||
content: "\e68b";
|
||||
}
|
||||
|
||||
.icon-a-lock1:before {
|
||||
content: "\e68c";
|
||||
}
|
||||
|
||||
.icon-list:before {
|
||||
content: "\e68d";
|
||||
}
|
||||
|
||||
.icon-lock:before {
|
||||
content: "\e68e";
|
||||
}
|
||||
|
||||
.icon-key:before {
|
||||
content: "\e68f";
|
||||
}
|
||||
|
||||
.icon-a-key1:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-me:before {
|
||||
content: "\e691";
|
||||
}
|
||||
|
||||
.icon-equalizer:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-comment:before {
|
||||
content: "\e693";
|
||||
}
|
||||
|
||||
.icon-log:before {
|
||||
content: "\e694";
|
||||
}
|
||||
|
||||
.icon-mall-bag:before {
|
||||
content: "\e695";
|
||||
}
|
||||
|
||||
.icon-list-view:before {
|
||||
content: "\e696";
|
||||
}
|
||||
|
||||
.icon-send:before {
|
||||
content: "\e697";
|
||||
}
|
||||
|
||||
.icon-people:before {
|
||||
content: "\e698";
|
||||
}
|
||||
|
||||
.icon-peoples:before {
|
||||
content: "\e699";
|
||||
}
|
||||
|
||||
.icon-a-message-one1:before {
|
||||
content: "\e69a";
|
||||
}
|
||||
|
||||
.icon-phone-telephone:before {
|
||||
content: "\e69b";
|
||||
}
|
||||
|
||||
.icon-internal-transmission:before {
|
||||
content: "\e69c";
|
||||
}
|
||||
|
||||
.icon-schedule:before {
|
||||
content: "\e69d";
|
||||
}
|
||||
|
||||
.icon-more-one:before {
|
||||
content: "\e69e";
|
||||
}
|
||||
|
||||
.icon-sim:before {
|
||||
content: "\e69f";
|
||||
}
|
||||
|
||||
.icon-a-peoples1:before {
|
||||
content: "\e6a0";
|
||||
}
|
||||
|
||||
.icon-wallet:before {
|
||||
content: "\e6a1";
|
||||
}
|
||||
|
||||
.icon-permissions:before {
|
||||
content: "\e6a2";
|
||||
}
|
||||
|
||||
.icon-faan:before {
|
||||
content: "\e6a3";
|
||||
}
|
||||
|
||||
.icon-transporter:before {
|
||||
content: "\e6a4";
|
||||
}
|
||||
|
||||
.icon-transaction-order:before {
|
||||
content: "\e6a5";
|
||||
}
|
||||
|
||||
.icon-message-one:before {
|
||||
content: "\e6a6";
|
||||
}
|
||||
|
||||
.icon-shouji:before {
|
||||
content: "\e6a7";
|
||||
}
|
||||
|
||||
.icon-liebiaochakanmoshi_view-grid-list:before {
|
||||
content: "\e6a8";
|
||||
}
|
||||
|
||||
.icon-time:before {
|
||||
content: "\e6a9";
|
||||
}
|
||||
|
||||
.icon-transaction:before {
|
||||
content: "\e6aa";
|
||||
}
|
||||
|
||||
.icon-setting-two:before {
|
||||
content: "\e6ab";
|
||||
}
|
||||
|
||||
.icon-plan:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-a-time1:before {
|
||||
content: "\e6ad";
|
||||
}
|
||||
|
||||
.icon-shezhi_setting:before {
|
||||
content: "\e6ae";
|
||||
}
|
||||
|
||||
.icon-zanting:before {
|
||||
content: "\e6af";
|
||||
}
|
||||
|
||||
.icon-sousuo_search:before {
|
||||
content: "\e6b0";
|
||||
}
|
||||
|
||||
.icon-xiangqingliebiao:before {
|
||||
content: "\e6b1";
|
||||
}
|
||||
|
||||
.icon-workbench:before {
|
||||
content: "\e6b2";
|
||||
}
|
||||
|
||||
.icon-shujubiao_data-sheet:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
BIN
static/iconfont/iconfont.ttf
Normal file
BIN
static/iconfont/iconfont.woff
Normal file
BIN
static/iconfont/iconfont.woff2
Normal file
51
static/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!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"/>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="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>aidex Mobile APP</title>
|
||||
<script>
|
||||
window.onresize = function () {
|
||||
if (document.documentElement.clientWidth < 768) {
|
||||
window.location.href = '../#/';
|
||||
}
|
||||
};
|
||||
window.onresize();
|
||||
</script>
|
||||
<style>
|
||||
.mobile-model {
|
||||
margin: 10px auto;
|
||||
background-color: #fff;
|
||||
width: 330px;
|
||||
margin-top: calc(50vh - 350px);
|
||||
box-sizing: border-box;
|
||||
background-image: url(common/img/iPhoneX.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
border-radius: 30px;
|
||||
padding: 48px 23px 38px 16px;
|
||||
}
|
||||
.mobile-content {
|
||||
box-sizing: border-box;
|
||||
width: 298px;
|
||||
height: 582px;
|
||||
border-bottom-left-radius: 20px;
|
||||
}
|
||||
.mobile-iframe {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mobile-model">
|
||||
<div class="mobile-content">
|
||||
<iframe src="../#/" class="mobile-iframe" scrolling="auto" frameborder="0"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
BIN
static/uni.ttf
Normal file
BIN
static/uview/common/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/uview/common/logo.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/uview/example/component.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/uview/example/component_select.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/uview/example/js.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/uview/example/js_bak.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
static/uview/example/js_select.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/uview/example/js_select_bak.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
static/uview/example/min_button.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/uview/example/min_button_select.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/uview/example/template.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
static/uview/example/template_select.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
27
store/$u.mixin.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { mapState } from 'vuex'
|
||||
import store from "@/store"
|
||||
|
||||
// 尝试将用户在根目录中的store/index.js的vuex的state变量,全部加载到全局变量中
|
||||
let $uStoreKey = [];
|
||||
try{
|
||||
$uStoreKey = store.state ? Object.keys(store.state) : [];
|
||||
}catch(e){
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
beforeCreate() {
|
||||
// 将vuex方法挂在到$u中
|
||||
// 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.$u.vuex('user.name', '史诗')
|
||||
// 如果要修改vuex的state的version变量为1.0.1 => this.$u.vuex('version', '1.0.1')
|
||||
this.$u.vuex = (name, value) => {
|
||||
this.$store.commit('$uStore', {
|
||||
name,value
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 将vuex的state中的所有变量,解构到全局混入的mixin中
|
||||
...mapState($uStoreKey)
|
||||
}
|
||||
}
|
94
store/index.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
*/
|
||||
import config from '@/common/config.js';
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
Vue.use(Vuex)
|
||||
|
||||
let lifeData = {};
|
||||
|
||||
try{
|
||||
// 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的
|
||||
lifeData = uni.getStorageSync('lifeData');
|
||||
}catch(e){
|
||||
|
||||
}
|
||||
|
||||
// 需要永久存储,且下次APP启动需要取出的,在state中的变量名
|
||||
let saveStateKeys = ['vuex_user', 'vuex_token', 'vuex_remember', 'vuex_locale','vuex_isAgent'];
|
||||
|
||||
// 保存变量到本地存储中
|
||||
const saveLifeData = function(key, value){
|
||||
// 判断变量名是否在需要存储的数组中
|
||||
if(saveStateKeys.indexOf(key) != -1) {
|
||||
// 获取本地存储的lifeData对象,将变量添加到对象中
|
||||
let tmp = uni.getStorageSync('lifeData');
|
||||
// 第一次打开APP,不存在lifeData变量,故放一个{}空对象
|
||||
tmp = tmp ? tmp : {};
|
||||
tmp[key] = value;
|
||||
// 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中
|
||||
uni.setStorageSync('lifeData', tmp);
|
||||
}
|
||||
}
|
||||
// 简化 vuex 操作,文档:https://uviewui.com/components/vuexDetail.html
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
// 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
|
||||
// 加上vuex_前缀,是防止变量名冲突,也让人一目了然
|
||||
vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {userName: 'Aidex'},
|
||||
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '',
|
||||
vuex_remember: lifeData.vuex_remember ? lifeData.vuex_remember : '',
|
||||
vuex_locale: lifeData.vuex_locale ? lifeData.vuex_locale : '',
|
||||
vuex_isAgent: lifeData.vuex_isAgent ? lifeData.vuex_isAgent : '',
|
||||
|
||||
// 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式
|
||||
vuex_config: config,
|
||||
|
||||
// 自定义tabbar数据
|
||||
// vuex_tabbar: [{
|
||||
// iconPath: "/static/uview/example/component.png",
|
||||
// selectedIconPath: "/static/uview/example/component_select.png",
|
||||
// text: '组件',
|
||||
// pagePath: '/pages/example/components'
|
||||
// },
|
||||
// {
|
||||
// iconPath: "/static/uview/example/js.png",
|
||||
// selectedIconPath: "/static/uview/example/js_select.png",
|
||||
// text: '工具',
|
||||
// midButton: true,
|
||||
// pagePath: '/pages/example/js'
|
||||
// },
|
||||
// {
|
||||
// iconPath: "/static/uview/example/template.png",
|
||||
// selectedIconPath: "/static/uview/example/template_select.png",
|
||||
// text: '模板',
|
||||
// pagePath: '/pages/example/template'
|
||||
// }
|
||||
// ]
|
||||
},
|
||||
mutations: {
|
||||
$uStore(state, payload) {
|
||||
// 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1
|
||||
let nameArr = payload.name.split('.');
|
||||
let saveKey = '';
|
||||
let len = nameArr.length;
|
||||
if(len >= 2) {
|
||||
let obj = state[nameArr[0]];
|
||||
for(let i = 1; i < len - 1; i ++) {
|
||||
obj = obj[nameArr[i]];
|
||||
}
|
||||
obj[nameArr[len - 1]] = payload.value;
|
||||
saveKey = nameArr[0];
|
||||
} else {
|
||||
// 单层级变量,在state就是一个普通变量的情况
|
||||
state[payload.name] = payload.value;
|
||||
saveKey = payload.name;
|
||||
}
|
||||
// 保存变量到本地,见顶部函数定义
|
||||
saveLifeData(saveKey, state[saveKey])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default store
|
41
uni.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://aidex.vip All rights reserved.
|
||||
* 下方引入的为uView UI的集成样式文件,为scss预处理器,其中包含了一些"u-"开头的自定义变量
|
||||
* 使用的时候,请将下面的一行复制到您的uniapp项目根目录的uni.scss中即可
|
||||
* uView自定义的css类名和scss变量,均以"u-"开头,不会造成冲突,请放心使用
|
||||
*/
|
||||
|
||||
$u-main-color: #303133;
|
||||
$u-content-color: #505256;
|
||||
$u-tips-color: #909399;
|
||||
$u-light-color: #c0c4cc;
|
||||
$u-border-color: #dedfe2;
|
||||
$u-bg-color: #f3f4f6;
|
||||
|
||||
$u-type-primary: #2979ff;
|
||||
$u-type-primary-light: #ecf5ff;
|
||||
$u-type-primary-disabled: #a0cfff;
|
||||
$u-type-primary-dark: #2b85e4;
|
||||
|
||||
$u-type-warning: #ff9900;
|
||||
$u-type-warning-disabled: #fcbd71;
|
||||
$u-type-warning-dark: #f29100;
|
||||
$u-type-warning-light: #fdf6ec;
|
||||
|
||||
$u-type-success: #19be6b;
|
||||
$u-type-success-disabled: #71d5a1;
|
||||
$u-type-success-dark: #18b566;
|
||||
$u-type-success-light: #dbf1e1;
|
||||
|
||||
$u-type-error: #fa3534;
|
||||
$u-type-error-disabled: #fab6b6;
|
||||
$u-type-error-dark: #dd6161;
|
||||
$u-type-error-light: #fef0f0;
|
||||
|
||||
$u-type-info: #909399;
|
||||
$u-type-info-disabled: #c8c9cc;
|
||||
$u-type-info-dark: #82848a;
|
||||
$u-type-info-light: #f4f4f5;
|
||||
|
||||
$u-form-item-height: 70rpx;
|
||||
$u-form-item-border-color: #dcdfe6;
|
BIN
unpackage/res/icons/1024x1024.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
unpackage/res/icons/120x120.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
unpackage/res/icons/144x144.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
unpackage/res/icons/152x152.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
unpackage/res/icons/167x167.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
unpackage/res/icons/180x180.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
unpackage/res/icons/192x192.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
unpackage/res/icons/20x20.png
Normal file
After Width: | Height: | Size: 705 B |
BIN
unpackage/res/icons/29x29.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
unpackage/res/icons/40x40.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
unpackage/res/icons/58x58.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
unpackage/res/icons/60x60.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
unpackage/res/icons/72x72.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
unpackage/res/icons/76x76.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
unpackage/res/icons/80x80.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
unpackage/res/icons/87x87.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
unpackage/res/icons/96x96.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
21
uview-ui/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.uviewui.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
106
uview-ui/README.md
Normal file
@@ -0,0 +1,106 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
|
||||
</p>
|
||||
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
|
||||
<h3 align="center">多平台快速开发的UI框架</h3>
|
||||
|
||||
|
||||
## 说明
|
||||
|
||||
uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
|
||||
|
||||
## 特性
|
||||
|
||||
- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
|
||||
- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
|
||||
- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
|
||||
- 众多的常用页面和布局,让您专注逻辑,事半功倍
|
||||
- 详尽的文档支持,现代化的演示效果
|
||||
- 按需引入,精简打包体积
|
||||
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# npm方式安装
|
||||
npm i uview-ui
|
||||
```
|
||||
|
||||
## 快速上手
|
||||
|
||||
1. `main.js`引入uView库
|
||||
```js
|
||||
// main.js
|
||||
import uView from 'uview-ui';
|
||||
Vue.use(uView);
|
||||
```
|
||||
|
||||
2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
|
||||
```css
|
||||
/* App.vue */
|
||||
<style lang="scss">
|
||||
@import "uview-ui/index.scss";
|
||||
</style>
|
||||
```
|
||||
|
||||
3. `uni.scss`引入全局scss变量文件
|
||||
```css
|
||||
/* uni.scss */
|
||||
@import "uview-ui/theme.scss";
|
||||
```
|
||||
|
||||
4. `pages.json`配置easycom规则(按需引入)
|
||||
|
||||
```js
|
||||
// pages.json
|
||||
{
|
||||
"easycom": {
|
||||
// npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
|
||||
// npm安装方式
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||
// 下载安装方式
|
||||
// "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
// 此为本身已有的内容
|
||||
"pages": [
|
||||
// ......
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
|
||||
|
||||
## 使用方法
|
||||
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
|
||||
|
||||
```html
|
||||
<template>
|
||||
<u-button>按钮</u-button>
|
||||
</template>
|
||||
```
|
||||
|
||||
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
|
||||
|
||||
## 链接
|
||||
|
||||
- [官方文档](https://uviewui.com/)
|
||||
- [更新日志](https://uviewui.com/components/changelog.html)
|
||||
- [升级指南](https://uviewui.com/components/changelog.html)
|
||||
- [关于我们](https://uviewui.com/cooperation/about.html)
|
||||
|
||||
## 预览
|
||||
|
||||
您可以通过**微信**扫码,查看最佳的演示效果。
|
||||
<br>
|
||||
<br>
|
||||
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
|
||||
|
||||
<!-- ## 捐赠uView的研发
|
||||
|
||||
uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
|
||||
|
||||
<img src="https://uviewui.com/common/wechat.png" width="220" >
|
||||
<img style="margin-left: 100px;" src="https://uviewui.com/common/alipay.png" width="220" >
|
||||
-->
|
||||
## 版权信息
|
||||
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
|
190
uview-ui/components/u-action-sheet/u-action-sheet.vue
Normal file
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
|
||||
length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
|
||||
<view class="u-tips u-border-bottom" v-if="tips.text" :style="[tipsStyle]">
|
||||
{{tips.text}}
|
||||
</view>
|
||||
<block v-for="(item, index) in list" :key="index">
|
||||
<view
|
||||
@touchmove.stop.prevent
|
||||
@tap="itemClick(index)"
|
||||
:style="[itemStyle(index)]"
|
||||
class="u-action-sheet-item u-line-1"
|
||||
:class="[index < list.length - 1 ? 'u-border-bottom' : '']"
|
||||
:hover-stay-time="150"
|
||||
>
|
||||
<text>{{item.text}}</text>
|
||||
<text class="u-action-sheet-item__subtext u-line-1" v-if="item.subText">{{item.subText}}</text>
|
||||
</view>
|
||||
</block>
|
||||
<view class="u-gab" v-if="cancelBtn">
|
||||
</view>
|
||||
<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
|
||||
:hover-stay-time="150" v-if="cancelBtn" @tap="close">{{cancelText}}</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* actionSheet 操作菜单
|
||||
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
|
||||
* @tutorial https://www.uviewui.com/components/actionSheet.html
|
||||
* @property {Array<Object>} list 按钮的文字数组,见官方文档示例
|
||||
* @property {Object} tips 顶部的提示文字,见官方文档示例
|
||||
* @property {String} cancel-text 取消按钮的提示文字
|
||||
* @property {Boolean} cancel-btn 是否显示底部的取消按钮(默认true)
|
||||
* @property {Number String} border-radius 弹出部分顶部左右的圆角值,单位rpx(默认0)
|
||||
* @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
|
||||
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
|
||||
* @property {Number String} z-index z-index值(默认1075)
|
||||
* @property {String} cancel-text 取消按钮的提示文字
|
||||
* @event {Function} click 点击ActionSheet列表项时触发
|
||||
* @event {Function} close 点击取消按钮时触发
|
||||
* @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
|
||||
*/
|
||||
export default {
|
||||
name: "u-action-sheet",
|
||||
props: {
|
||||
// 点击遮罩是否可以关闭actionsheet
|
||||
maskCloseAble: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx
|
||||
list: {
|
||||
type: Array,
|
||||
default () {
|
||||
// 如下
|
||||
// return [{
|
||||
// text: '确定',
|
||||
// color: '',
|
||||
// fontSize: ''
|
||||
// }]
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 顶部的提示文字
|
||||
tips: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
text: '',
|
||||
color: '',
|
||||
fontSize: '26'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 底部的取消按钮
|
||||
cancelBtn: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
|
||||
safeAreaInsetBottom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 通过双向绑定控制组件的弹出与收起
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹出的顶部圆角值
|
||||
borderRadius: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 弹出的z-index值
|
||||
zIndex: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 取消按钮的文字提示
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 顶部提示的样式
|
||||
tipsStyle() {
|
||||
let style = {};
|
||||
if (this.tips.color) style.color = this.tips.color;
|
||||
if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
|
||||
return style;
|
||||
},
|
||||
// 操作项目的样式
|
||||
itemStyle() {
|
||||
return (index) => {
|
||||
let style = {};
|
||||
if (this.list[index].color) style.color = this.list[index].color;
|
||||
if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx';
|
||||
// 选项被禁用的样式
|
||||
if (this.list[index].disabled) style.color = '#c0c4cc';
|
||||
return style;
|
||||
}
|
||||
},
|
||||
uZIndex() {
|
||||
// 如果用户有传递z-index值,优先使用
|
||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击取消按钮
|
||||
close() {
|
||||
// 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
|
||||
// 这是一个vue发送事件的特殊用法
|
||||
this.popupClose();
|
||||
this.$emit('close');
|
||||
},
|
||||
// 弹窗关闭
|
||||
popupClose() {
|
||||
this.$emit('input', false);
|
||||
},
|
||||
// 点击某一个item
|
||||
itemClick(index) {
|
||||
// disabled的项禁止点击
|
||||
if(this.list[index].disabled) return;
|
||||
this.$emit('click', index);
|
||||
this.$emit('input', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../libs/css/style.components.scss";
|
||||
|
||||
.u-tips {
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
padding: 34rpx 0;
|
||||
line-height: 1;
|
||||
color: $u-tips-color;
|
||||
}
|
||||
|
||||
.u-action-sheet-item {
|
||||
@include vue-flex;;
|
||||
line-height: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
padding: 34rpx 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.u-action-sheet-item__subtext {
|
||||
font-size: 24rpx;
|
||||
color: $u-tips-color;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.u-gab {
|
||||
height: 12rpx;
|
||||
background-color: rgb(234, 234, 236);
|
||||
}
|
||||
|
||||
.u-actionsheet-cancel {
|
||||
color: $u-main-color;
|
||||
}
|
||||
</style>
|