异常日志处理 钉钉单点登录

This commit is contained in:
caorui 2024-09-20 15:55:17 +08:00
parent f38c969b42
commit 4dce911ac2
797 changed files with 96297 additions and 26 deletions

43
App.vue Normal file
View File

@ -0,0 +1,43 @@
<script>
import config from "./config";
import store from "@/store";
import { getToken } from "@/utils/auth";
import eruda from "eruda";
export default {
onLaunch: function () {
// new VConsole();
eruda.init();
this.initApp();
},
methods: {
//
initApp() {
//
this.initConfig();
},
initConfig() {
this.globalData.config = config;
},
checkLogin() {
if (!getToken()) {
this.$tab.reLaunch("/pages/login");
}
},
},
};
</script>
<style lang="scss">
@import "@/uni_modules/uview-ui/index.scss";
@import "@/static/scss/index.scss";
@import "@/static/font/iconfont.css";
.overflowTextHidden{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
page{
height:100vh;
}
</style>

36
LICENSE
View File

@ -1,23 +1,21 @@
Attribution Assurance License
MIT License
Copyright (c) 2002 by AUTHOR PROFESSIONAL IDENTIFICATION * URL "PROMOTIONAL SLOGAN FOR AUTHOR'S PROFESSIONAL PRACTICE"
Copyright (c) 2022 若依
All Rights Reserved
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:
ATTRIBUTION ASSURANCE LICENSE (adapted from the original BSD license)
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the conditions below are met. These conditions require a modest attribution to <AUTHOR> (the "Author"), who hopes that its promotional value may help justify the thousands of dollars in otherwise billable time invested in writing this and other freely available, open-source software.
1. Redistributions of source code, in whole or part and with or without modification (the "Code"), must prominently display this GPG-signed text in verifiable form.
2. Redistributions of the Code in binary form must be accompanied by this GPG-signed text in any documentation and, each time the resulting executable program or a program dependent thereon is launched, a prominent display (e.g., splash screen or banner text) of the Author's attribution information, which includes:
(a) Name ("AUTHOR"),
(b) Professional identification ("PROFESSIONAL IDENTIFICATION"), and
(c) URL ("URL").
3. Neither the name nor any trademark of the Author may be used to endorse or promote products derived from this software without specific prior written permission.
4. Users are entirely responsible, to the exclusion of the Author and any other persons, for compliance with (1) regulations set by owners or administrators of employed equipment, (2) licensing terms of any other software, and (3) local regulations regarding use, including those regarding import, export, and use of encryption software.
THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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.

View File

@ -1,3 +1,71 @@
# middleground_H5
项目安装依赖报错时切换node到16.20.2版本使用npm安装依赖不要使用yarn
中台移动端
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-43e3941654fa3054c9684bf53d1b1d356a1.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v1.1.0</h1>
<h4 align="center">基于UniApp开发的轻量级移动端框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-App/stargazers"><img src="https://gitee.com/y_project/RuoYi-App/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-App"><img src="https://img.shields.io/badge/RuoYi-v1.1.0-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-App/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
## 平台简介
RuoYi App 移动解决方案采用uniapp框架一份代码多终端适配同时支持APP、小程序、H5实现了与[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)、[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)完美对接的移动解决方案!目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。
* 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 或 [RuoYi-Cloud](https://github.com/yangzongzhuan/RuoYi-Cloud) 版本。
* 应用框架基于[uniapp](https://uniapp.dcloud.net.cn/)支持小程序、H5、Android和IOS。
* 前端组件采用[uni-ui](https://github.com/dcloudio/uni-ui)全端兼容的高性能UI框架。
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;
## 技术文档
- 官网网站:[http://ruoyi.vip](http://ruoyi.vip)
- 文档地址:[http://doc.ruoyi.vip](http://doc.ruoyi.vip)
- H5页体验[http://h5.ruoyi.vip](http://h5.ruoyi.vip)
- QQ交流群 ①133713780
- 小程序体验
<img src="https://oscimg.oschina.net/oscnet/up-26c76dc90b92acdbd9ac8cd5252f07c8ad9.jpg" alt="小程序演示"/>
## 演示图
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-3ea20e447ac621a161e395fb53ccc683d84.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-a6f23cf9a371a30165e135eff6d9ae89a9d.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-ff5f62016bf6624c1ff27eee57499dccd44.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-b9a582fdb26ec69d407fabd044d2c8494df.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-96427ee08fca29d77934cfc8d1b1a637cef.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-5fdadc582d24cccd7727030d397b63185a3.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-0a36797b6bcc50c36d40c3c782665b89efc.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-d77995cc00687cedd00d5ac7d68a07ea276.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-fa8f5ab20becf59b4b38c1b92a9989e7109.png"/></td>
</tr>
</table>

117
api/login.js Normal file
View File

@ -0,0 +1,117 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password) {
const data = {
loginCode: username,
password: password,
}
return request({
'url': 'kangarooDataCenterV3/entranceController/option',
header: {
isToken: false,
tl: 'loginService',
as: 'sysTestjdbc',
dj: 'doLogin'
},
'method': 'post',
'data': data
})
}
export function authApi(tl, as, dj, url = '', data) {
return request({
url: 'kangarooDataCenterV3/entranceController/option' + url,
header: {
tl: tl,
as: as,
dj: dj,
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
'url': '/getInfo',
'method': 'get'
})
}
// 退出方法
export function logout() {
return request({
'url': '/logout',
'method': 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
'url': '/captchaImage',
header: {
isToken: false
},
method: 'get',
timeout: 20000
})
}
// 钉钉单点登录
export function DDSSO(data) {
return request({
url: "Api/SSO/DDSSO",
method: "post",
data,
});
}
// 钉钉认证
export function DDAuthen(data) {
return request({
url: "Api/SSO/DDAuthen",
method: "post",
data,
});
}
// wx认证
export function WeChatSSO(data) {
return request({
url: "Api/SSO/WeChatSSO",
method: "post",
data,
});
}
// wx认证
export function WeChatAuthen(data) {
return request({
url: "Api/SSO/WeChatAuthen",
method: "post",
data,
});
}
// wx认证
export function GetAPPMenu(data) {
return request({
url: "/api/Menu/GetAPPMenu",
method: "post",
data,
});
}
// 用户所属公司列表
export function OrganGetUserCompany(data) {
return request({
url: "/api/Organ/GetUserCompany",
method: "post",
data,
});
}
//切换公司
export function ChangeCompany(data) {
return request({
url: "/api/Organ/ChangeCompany",
method: "post",
data,
});
}

19
api/system/assembly.js Normal file
View File

@ -0,0 +1,19 @@
import request from '@/utils/request'
export function GetOrganTree(data) {
return request({
url: '/Api/Organ/GetOrganTree',
method: 'post',
data: data
})
}
export function GetBillList(data) {
return request({
url: '/Api/Person/GetBillList',
method: 'post',
data: data
})
}

76
api/system/audit.js Normal file
View File

@ -0,0 +1,76 @@
import request from '@/utils/request'
//审批流-提交审核
export function submitAudit(data) {
return request({
url: "/Api/Workflow/SubmitAudit",
method: "post",
data,
});
}
//获取单据审批流程
export function getAuditList(data) {
return request({
url: "/Api/Workflow/SowBillWork",
method: "post",
data,
});
}
//获取单据审批记录
export function getAuditNote(data) {
return request({
url: "/Api/Workflow/GetAuditNoteList",
method: "post",
data,
});
}
//催办
export function auditUrging(data) {
return request({
url: "/Api/Workflow/Urging",
method: "post",
data,
});
}
//审批流-审核
export function audit(data) {
return request({
url: "/Api/Workflow/Audit",
method: "post",
data,
});
}
//加签
export function auditAddFlow(data) {
return request({
url: "/Api/Workflow/AddBillWorkFlowNote",
method: "post",
data,
});
}
//获取单据审批按钮权限
export function getAuditBtn(data) {
return request({
url: "/Api/Workflow/GetBillOperateBtn",
method: "post",
data,
});
}
//审批流-已读
export function read(data) {
return request({
url: "/Api/Workflow/Read",
method: "post",
data,
});
}
//审批流-撤销审核
export function removeAudit(data) {
return request({
url: "/Api/Workflow/Revocation",
method: "post",
data,
});
}

18
api/system/basePerson.js Normal file
View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
// 人员列表接口
export function PersonList(data) {
return request({
url: "/Api/Person/GetBillList",
method: "post",
data,
});
}
// 部门树形数据
export function GetOrganTree(data) {
return request({
url: "/Api/Organ/GetOrganTree",
method: "post",
data,
});
}

28
api/system/home.js Normal file
View File

@ -0,0 +1,28 @@
import request from '@/utils/request'
// 获取消息列表
export function GetMessageData(data) {
return request({
url: '/api/Message/GetMessageData',
method: 'post',
data: data
})
}
// 全部已读
export function ReadMessage(data) {
return request({
url: '/api/Message/ReadMessage',
method: 'post',
data: data
})
}
// 全部已读
export function GetAllWfToDo(data) {
return request({
url: '/Api/Workflow/GetWfToDo',
method: 'post',
data: data
})
}

41
api/system/user.js Normal file
View File

@ -0,0 +1,41 @@
import upload from '@/utils/upload'
import request from '@/utils/request'
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
params: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return upload({
url: '/system/user/profile/avatar',
name: data.name,
filePath: data.filePath
})
}

View File

@ -0,0 +1,106 @@
/** * 单选人员 */
<template>
<u-picker
:show="show"
ref="uPicker"
:columns="columns"
:closeOnClickOverlay="true"
keyName="label"
@close="show = false"
@cancel="show = false"
@confirm="confirm"
@change="changeHandler"
></u-picker>
</template>
<script>
import { GetOrganTree, GetBillList } from '@/api/system/assembly.js';
export default {
data() {
return {
show: false,
columns: [[], []],
columnData: []
};
},
components: {},
computed: {},
mounted() {},
created() {
this.init();
},
methods: {
changeHandler(e) {
const {
columnIndex,
value,
values, // values
index,
// pickerref
picker = this.$refs.uPicker
} = e;
// ()
if (columnIndex === 0) {
// pickerthis
picker.setColumnValues(1, this.columnData[index]);
}
},
// columnIndexvaluevalues
confirm(e) {
this.$emit('confirm',e.value)
this.show = false;
},
async init() {
const res = await GetOrganTree({ companyID: 'null' });
let item = await GetBillList({ departmentID: '', limit: '999', page: '1' });
item.data[1].forEach(el => {
el.label = el.p_PersonName
})
this.columns[0].push(...this.treeToArray(JSON.parse(res.data[0])));
let keys = item.data[1].map((val) => {
return val.o_OrganName;
});
keys = [...new Set(keys)];
let data = {};
keys.forEach((el) => {
data[el] = [];
});
item.data[1].map((e) => {
keys.some((value) => {
if (e.o_OrganName == value) {
data[value].push(e);
return;
}
});
});
let treatment = this.sort(this.treeToArray(JSON.parse(res.data[0])),data)
this.columns[1] = data[this.treeToArray(JSON.parse(res.data[0]))[0].label]
this.columnData.push(...treatment)
},
//
treeToArray(items) {
let children = [];
items.forEach((item) => {
children.push(item);
if (item.children) {
children = children.concat(this.treeToArray(item.children));
}
});
return children;
},
sort(item,data) {
let list = []
item.forEach(el => {
list.push(data[el.label])
})
return list
}
}
};
</script>
<style scoped lang="scss"></style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
<template>
<view class="u-avatar" :class="[`u-avatar--${shape}`]" :style="[{
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
width: $u.addUnit(size),
height: $u.addUnit(size),
}, $u.addStyle(customStyle)]" @tap="clickHandler">
<slot>
<image class="u-avatar__image" v-if="isSuccessSrc" :class="[`u-avatar__image--${shape}`]"
:src="avatarUrl || defaultUrl" :mode="mode" @error="errorHandler" :style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"></image>
<u--text v-else :text="text" :size="fontSize" :color="color" align="center"
customStyle="justify-content: center"></u--text>
</slot>
</view>
</template>
<script>
import props from './props.js';
const base64Avatar =
"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
/**
* Avatar 头像
* @description 本组件一般用于展示头像的地方如个人中心或者评论列表页的用户头像展示等场所
* @tutorial https://www.uviewui.com/components/avatar.html
*
* @property {String} src 头像路径如加载失败将会显示默认头像(不能为相对路径)
* @property {String} shape 头像形状 circle (默认) | square
* @property {String | Number} size 头像尺寸可以为指定字符串(large, default, mini)或者数值 默认 40
* @property {String} mode 头像图片的裁剪类型与uni的image组件的mode参数一致如效果达不到需求可尝试传widthFix值 默认 'scaleToFill'
* @property {String} text 用文字替代图片级别优先于src
* @property {String} bgColor 背景颜色一般显示文字时用 默认 '#c0c4cc'
* @property {String} color 文字颜色 默认 '#ffffff'
* @property {String | Number} fontSize 文字大小 默认 18
* @property {String} icon 显示的图标
* @property {Boolean} mpAvatar 显示小程序头像只对百度微信QQ小程序有效 默认 false
* @property {Boolean} randomBgColor 是否使用随机背景色 默认 false
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
* @property {String | Number} colorIndex 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
* @property {String} name 组件标识符 默认 'level'
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击组件时触发 index: 用户传递的标识符
* @example <u-avatar :src="src" mode="square"></u-avatar>
*/
export default {
name: 'u-avatar',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
// randomBgColortrue
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
'#73d1f1',
'#80a7dc'
],
avatarUrl: this.src,
allowMp: false,
isSuccessSrc:false,
}
},
watch: {
// srcavatarUrlsrc
// props
src: {
immediate: true,
handler(newVal) {
this.isSuccessSrc = true
this.avatarUrl = newVal
// srcerrorsrc''
if (!newVal) {
this.isSuccessSrc = false
this.errorHandler()
}
}
}
},
computed: {
imageStyle() {
const style = {}
return style
}
},
created() {
this.init()
},
methods: {
init() {
// open-data
// uni.getUserInfo()
//
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
this.allowMp = true
// #endif
},
// name"/"
isImg() {
return this.src.indexOf('/') !== -1
},
//
errorHandler() {
this.isSuccessSrc = false
// this.avatarUrl = this.defaultUrl || base64Avatar
},
clickHandler() {
this.$emit('click', this.name)
}
}
}
</script>
<style lang="scss" scoped>
// @import "../../libs/css/components.scss";
.u-avatar {
@include flex;
align-items: center;
justify-content: center;
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
&__image {
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
}
}
</style>

View File

@ -0,0 +1,78 @@
export default {
props: {
// 头像图片路径(不能为相对路径)
src: {
type: String,
default: uni.$u.props.avatar.src
},
// 头像形状circle-圆形square-方形
shape: {
type: String,
default: uni.$u.props.avatar.shape
},
// 头像尺寸
size: {
type: [String, Number],
default: uni.$u.props.avatar.size
},
// 裁剪模式
mode: {
type: String,
default: uni.$u.props.avatar.mode
},
// 显示的文字
text: {
type: String,
default: uni.$u.props.avatar.text
},
// 背景色
bgColor: {
type: String,
default: uni.$u.props.avatar.bgColor
},
// 文字颜色
color: {
type: String,
default: uni.$u.props.avatar.color
},
// 文字大小
fontSize: {
type: [String, Number],
default: uni.$u.props.avatar.fontSize
},
// 显示的图标
icon: {
type: String,
default: uni.$u.props.avatar.icon
},
// 显示小程序头像只对百度微信QQ小程序有效
mpAvatar: {
type: Boolean,
default: uni.$u.props.avatar.mpAvatar
},
// 是否使用随机背景色
randomBgColor: {
type: Boolean,
default: uni.$u.props.avatar.randomBgColor
},
// 加载失败的默认头像(组件有内置默认图片)
defaultUrl: {
type: String,
default: uni.$u.props.avatar.defaultUrl
},
// 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
colorIndex: {
type: [String, Number],
// 校验参数规则索引在0-19之间
validator(n) {
return uni.$u.test.range(n, [0, 19]) || n === ''
},
default: uni.$u.props.avatar.colorIndex
},
// 组件标识符
name: {
type: String,
default: uni.$u.props.avatar.name
}
}
}

View File

@ -0,0 +1,297 @@
<template>
<view>
<base-popup
:title="'关联客户'"
ref="basePopup"
@handleConfirmClick="handlerCustomerConfirm"
@handleCloseClick="resetDialog"
>
<view style="padding: 20rpx 30rpx 0 30rpx">
<u-search
v-if="showSearch"
:placeholder="placeholder"
v-model="CodeOrName"
shape="square"
clearabled
:showAction="false"
@change="contractSearch"
></u-search>
<scroll-view
:scroll-top="scrollTop"
scroll-y="true"
class="scroll-Y"
@scrolltolower="scrolltolower"
:lower-threshold="0"
style="margin-top: 20rpx"
v-if="!isLoading"
>
<!--单选-->
<u-radio-group
v-if="type == 'radio'"
:borderBottom="true"
iconPlacement="right"
placement="column"
@change="groupChange"
v-model="radioValue"
>
<u-radio
:customStyle="{ marginBottom: '12px' }"
v-for="(item, index) in dataLists"
:key="index"
:name="item.cusCode"
>
<view class="listData">
<view class="content">
<text>客户编码</text>
{{ item.cusCode }}
</view>
<view class="content">
<text>客户名称</text>
{{ item.cusName }}
</view>
<view class="flex time">
<view class="overflowTextHidden">
<text>客户简称</text>
{{ item.cusShortName }}
</view>
<view class="overflowTextHidden">
<text>客户分类</text>
{{ item.cusClassifyName }}
</view>
<view class="overflowTextHidden">
<text>分管部门</text>
{{ item.orgainName }}
</view>
<view class="overflowTextHidden">
<text>法人</text>
{{ item.legalPerson }}
</view>
<view class="overflowTextHidden">
<text>税号</text>
{{ item.taxNumber }}
</view>
<view class="overflowTextHidden">
<text>电话</text>
{{ item.telphone }}
</view>
<view>
<text>地址</text>
{{ item.address }}
</view>
</view>
</view>
</u-radio>
</u-radio-group>
<!--多选-->
<u-checkbox-group
v-if="type == 'checkbox'"
:borderBottom="true"
placement="column"
iconPlacement="right"
@change="checkboxChange"
v-model="checkboxValue"
>
<u-checkbox
:customStyle="{ marginBottom: '12px', paddingBottom: '12px' }"
v-for="(item, index) in dataLists"
:key="index"
:name="item.cusCode"
:label="item.cusName + ' ' + item.cusCode"
>
</u-checkbox>
</u-checkbox-group>
<view class="contractNoData" v-show="noData">
<u-divider text="我是有底线哒!" :hairline="true"></u-divider>
</view>
</scroll-view>
<u-loadmore
v-else
status="loading"
:loadingText="'数据加载中'"
:marginTop="150"
></u-loadmore>
</view>
</base-popup>
</view>
</template>
<script>
import { OrganGetCustomer } from "@/api/system/projectAdd.js";
import basePopup from "@/components/basePopup/index.vue";
export default {
components: {
basePopup,
},
props: {
//
showSearch: {
default: true,
type: Boolean,
},
placeholder: {
default: "请输入客户名称、客户编码",
type: String,
},
type: {
default: "checkbox",
type: String,
},
},
data() {
return {
noData: false,
CodeOrName: "",
scrollTop: 0,
pages: {
page: 1, //
limit: 20, //
cusClassify: "", //id
Sequence: "", //
SequenceName: "", //
CodeOrName: "",
},
dataLists: [],
checkboxData: [],
checkboxValue: [],
radioData: "",
radioValue: "",
timer: null,
isLoading: false,
};
},
methods: {
openDialog() {
this.OrganGetCustomer();
this.$refs.basePopup.isShowPopup = true;
},
//
contractSearch(value) {
if (this.timer !== null) clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.pages.CodeOrName = value;
this.OrganGetCustomer();
this.radioValue = "";
this.checkboxValue = Object.assign([], []);
}, 800);
},
resetDialog() {
this.CodeOrName = "";
this.pages.page = 1;
this.pages.CodeOrName = "";
this.radioValue = "";
this.checkboxValue = Object.assign([], []);
},
checkboxChange(n) {
this.checkboxData = [];
n.forEach((key) => {
this.dataLists.forEach((item) => {
if (item.cusCode == key) {
this.checkboxData.push(item);
}
});
});
},
//
groupChange(n) {
this.radioData = this.dataLists.filter((item) => item.cusCode === n);
},
//
scrolltolower() {
if (this.noData != true) {
this.pages.page++;
this.OrganGetCustomer();
}
},
// --
async OrganGetCustomer() {
this.isLoading = true;
this.noData = false;
let params = {
...this.pages,
};
const res = await OrganGetCustomer(params);
this.isLoading = false;
if (this.pages.page > 1) {
this.dataLists.push(...res.data[1]);
} else {
this.dataLists = res.data[1];
}
if (res.data[1].length < 20) {
this.noData = true;
}
},
//
handlerCustomerConfirm() {
if (this.type == "radio") {
if (
this.radioData == "" ||
this.radioData == undefined ||
this.radioData == null
) {
uni.$u.toast("请选择数据");
return;
}
this.$emit("handlerCustomerConfirm", this.radioData);
this.$refs.basePopup.isShowPopup = false;
this.resetDialog();
} else if (this.type == "checkbox") {
if (this.checkboxData.length == 0) {
uni.$u.toast("请选择数据");
return;
}
this.$emit("handlerCustomerConfirm", this.checkboxData);
this.$refs.basePopup.isShowPopup = false;
this.resetDialog();
}
},
},
};
</script>
<style lang="scss" scoped>
.scroll-Y {
height: 680rpx;
}
.contractNoData .u-divider {
margin: 0;
}
.content {
line-height: 1.5;
font-size: 28rpx;
margin-bottom: 20rpx;
text {
font-size: 28rpx;
color: #979797;
}
}
.time {
font-size: 28rpx;
flex-wrap: wrap;
line-height: 1.5;
text {
display: inline-block;
font-size: 26rpx;
color: #979797;
margin-bottom: 30rpx;
}
view {
height: 48rpx;
}
view:nth-child(2n + 1) {
width: 50%;
}
view:nth-child(2n) {
width: 50%;
}
view:nth-child(4) {
text:nth-child(2) {
font-size: 28rpx;
}
}
}
</style>

View File

@ -0,0 +1,297 @@
<!--
@desc 自定义表单组件
@date 20230720
--------对于整个表单-----------
labelFormPosition: 表单域提示文字的位置left-左侧top-上方
borderFormBottom: 是否显示表单域的下划线边框
labelFormWidth: 提示文字的宽度单位px
labelFormAlignlable字体的对齐方式 默认left 可选 center/right
-->
<template>
<view>
<u--form :labelPosition="labelFormPosition" :borderBottom="borderFormBottom" :labelWidth="labelFormWidth"
class="baseform" :labelAlign="labelFormAlign" :labelStyle="labelStyle" :model="formModel" :rules="formRules"
ref="baseForm">
<view style="padding-bottom: 40rpx;">
<u-row v-for="(item,index) in formRow" :key="index">
<u-col v-for="(row,rowIndex) in item.uCol" :span="row.span ? row.span : spanNumber" :key="rowIndex">
<u-form-item v-if="row.tag == 'input'" :label="row.label" :prop="row.prop" ref="item1"
:borderBottom="row.borderBottom" @click="handlerRowInputClickEvent(row,rowIndex)"
:labelWidth="row.labelWidth" :labelPosition="row.labelPosition" :rightIcon="row.rightIcon"
:leftIcon="row.leftIcon" :required="row.required"
:class="(getRule(row.prop)?'ruleFormClass ':'')">
<u--input v-if="row.type == 'uInput'" :placeholder="row.placeholder" clearable
v-model="formModel.formData[row.prop]" :suffixIcon="row.suffixIcon"
:disabled="row.disabled" :border="row.border"
:disabledColor="row.disabledColor"></u--input>
<u--textarea v-if="row.type == 'uTextarea'" v-model="formModel.formData[row.prop]"
:height="row.height?row.height: 100" :maxlength="row.maxlength ? row.maxlength: '-1'"
:placeholder="row.placeholder" :suffixIcon="row.suffixIcon" :disabled="row.disabled"
:border="row.border" :disabledColor="row.disabledColor"></u--textarea>
<u-radio-group v-if="row.type == 'uRadio'" v-model="formModel.formData[row.prop]"
@change="handlerRadioChange($event,row,rowIndex)">
<u-radio :customStyle="{marginRight: '16px'}" v-for="(item, index) in row.options"
:key="index" :label="item.label" :name="item.value">
</u-radio>
</u-radio-group>
<u-checkbox-group v-if="row.type == 'uCheckbox'" v-model="formModel.formData[row.prop]"
shape="square" placement="column" @change="handlerCheckboxChange($event,row,rowIndex)">
<u-checkbox :customStyle="{marginBottom: '8px'}" v-for="(item, index) in row.options"
:key="index" :label="item.label" :name="item.value"
:disabled="item.disabled ? true:false">
</u-checkbox>
</u-checkbox-group>
</u-form-item>
<!-- 简单下拉框 -->
<u-form-item v-if="row.tag == 'select'" :label="row.label" :prop="row.prop" ref="item2"
:class="(getRule(row.prop)?'ruleFormClass ':'')" :borderBottom="row.borderBottom"
@click="row.show = true" :labelWidth="row.labelWidth" :labelPosition="row.labelPosition"
:rightIcon="row.rightIcon" :leftIcon="row.leftIcon" :required="row.required">
<!-- keyName自定义需要展示的text属性键名 -->
<u-picker :show="row.show" :columns="[row.options]"
:closeOnClickOverlay="row.closeOnClickOverlay ? true:false"
@close="handlerSelectClose(row,rowIndex)" @cancel="handlerSelectClose(row,rowIndex)"
@confirm="selectConfirm($event,row,rowIndex)" :keyName="row.keyName"></u-picker>
<u--input :placeholder="row.placeholder" v-model="formModel.formData[row.prop]" clearable
:suffixIcon="row.suffixIcon ? row.suffixIcon:''" :disabled="row.disabled"
:border="row.border" :disabledColor="row.disabledColor"></u--input>
</u-form-item>
<!-- 此组件用于单个选择日期范围选择日期等
mode
为single只能选择单个日期
为multiple可以选择多个日期
为range可以选择日期范围
-->
<u-form-item v-if="row.tag == 'calendar'" :label="row.label" :prop="row.prop" ref="item2"
:class="(getRule(row.prop)?'ruleFormClass ':'')" :borderBottom="row.borderBottom"
@click="row.show = true" :labelWidth="row.labelWidth" :labelPosition="row.labelPosition"
:rightIcon="row.rightIcon" :leftIcon="row.leftIcon" :required="row.required">
<!-- keyName自定义需要展示的text属性键名 -->
<u-calendar :show="row.show" :mode="row.mode" :showTitle="row.title" round="10"
:closeOnClickOverlay="row.closeOnClickOverlay ? true:false"
@close="handlerCalendarClose(row,rowIndex)"
@confirm="calendarConfirm($event,row,rowIndex)" :maxDate="row.maxDate"
:minDate="row.minDate" :monthNum="row.monthNum"></u-calendar>
<u--input :placeholder="row.placeholder" v-model="formModel.formData[row.prop]"
suffixIcon="calendar" clearable :disabled="row.disabled" :border="row.border"
:disabledColor="row.disabledColor"></u--input>
</u-form-item>
<!-- 此选择器用于时间日期
mode 配置选择何种日期格式datetime年月日时分 date为日期选择time为时间选择year-month为年月选择
参数minDate和maxDate可以设置最大值和最小值传入时间戳
-->
<u-form-item v-if="row.tag == 'datetime'" :label="row.label" :prop="row.prop" ref="item2"
:class="(getRule(row.prop)?'ruleFormClass ':'')" :borderBottom="row.borderBottom"
@click="row.show = true" :labelWidth="row.labelWidth" :labelPosition="row.labelPosition"
:rightIcon="row.rightIcon" :leftIcon="row.leftIcon" :required="row.required">
<!-- keyName自定义需要展示的text属性键名 -->
<u-datetime-picker :show="row.show" :mode="row.mode" :value="defaultTime(row)"
:closeOnClickOverlay="row.closeOnClickOverlay ? true:false" :maxDate="row.maxDate"
:minDate="row.minDate" @confirm="dateTimeConfirm($event,row,rowIndex)"
@cancel="handlerDateTimeClose(row,rowIndex)"
@close="handlerDateTimeClose(row,rowIndex)"></u-datetime-picker>
<u--input :placeholder="row.placeholder" v-model="formModel.formData[row.prop]" clearable
suffixIcon="arrow-right" :disabled="row.disabled" :border="row.border"
:disabledColor="row.disabledColor"></u--input>
</u-form-item>
</u-col>
</u-row>
</view>
</u--form>
</view>
</template>
<script>
export default {
props: {
labelFormPosition: {
type: String,
default: "left"
},
borderFormBottom: {
type: Boolean,
default: true
},
labelFormWidth: {
type: [Number, String],
default: 100
},
labelFormAlign: {
type: String,
default: "left"
},
labelStyle: {
type: Object,
default: () => {
return {
padding: '10px 0 10px 10px'
};
},
},
//
formRules: {
type: Object,
default: () => {
return {};
},
},
//
formRow: {
type: Array,
default: () => {
return [];
},
},
},
data() {
return {
spanNumber: 12,
formModel: {
formData: {
hour: ''
}
},
}
},
mounted() {},
methods: {
bbb(a, b) {
console.log(a, "测试", b)
},
defaultTime(row) {
if (row.mode == 'datetime' || row.mode == 'date' || row.mode == 'year-month') {
return Number(new Date())
} else if (row.mode == 'time') {
return new Date().toLocaleTimeString().slice(0, 5)
} else {
return
}
},
handlerRowInputClickEvent(row, index) {
this.$emit("handlerRowInputClickEvent", row, index)
},
//
selectConfirm(value, row, index) {
this.$emit("selectConfirm", value, row, index)
row.show = false
},
//
handlerSelectClose(row, index) {
row.show = false
},
//
handlerCalendarClose(row, index) {
row.show = false
},
//
handlerDateTimeClose(row, index) {
row.show = false
},
//
calendarConfirm(value, row, index) {
this.$emit("calendarConfirm", value, row, index)
row.show = false
},
//
dateTimeConfirm(e, row, index) {
const timeFormat = uni.$u.timeFormat
let time = ''
if (row.mode == 'datetime') {
time = timeFormat(e.value, 'yyyy-mm-dd hh:MM')
} else if (row.mode == 'date') {
time = timeFormat(e.value, 'yyyy-mm-dd')
} else if (row.mode == 'year-month') {
time = timeFormat(e.value, 'yyyy-mm')
} else if (row.mode == 'time') {
// time = timeFormat(e.value, 'hh:MM')
time = e.value
} else {
time = ''
}
this.$emit("dateTimeConfirm", time, row, index)
row.show = false
},
// change
handlerCheckboxChange(e, row, rowIndex) {
this.$emit("handlerCheckboxChange", e, row, rowIndex)
},
// change
handlerRadioChange(e, row, rowIndex) {
this.$emit("handlerRadioChange", e, row, rowIndex)
},
setField(propLabel, value) {
this.$set(this.formModel.formData, propLabel, value);
},
incomingParameters(vale) {
for (let i in vale) {
this.setField(i, vale[i]);
}
},
//
submitForm(formName) {
let formRules = {
formData: {
...this.formRules
}
}
// this.formRules = formRules
console.log(this.$refs[formName].validate(), "formRules")
this.$refs[formName].validate((valid) => {
if (valid) {
console.log(valid)
// this.$emit('onSubmit', this.formModel.formData)
} else {
console.log('error submit!!');
return false
}
})
},
//
resetForm(formName) {
this.choiceAssignment({})
},
//
choiceAssignment(value) {
this.formModel.formData = Object.assign({}, value)
},
getRule(rowList) {
let requiredType = false
if (this.formRules[rowList] && this.formRules[rowList].length > 0) {
this.formRules[rowList].forEach(el => {
if (el.required) {
requiredType = true
}
})
}
return requiredType
}
},
}
</script>
<style lang="scss" scoped>
.baseform {
padding: 20rpx;
}
.u-form-item {
padding: 0 30rpx;
}
.u-popup {
flex: none;
}
::v-deep .u-form-item__body__right__message {
margin: 0 !important;
}
::v-deep .ruleFormClass {
.u-line {
border-bottom: 2rpx solid #E6A23C !important;
}
}
</style>

View File

@ -0,0 +1,325 @@
<!-- 选择人员组件 非弹窗
@desc 多选
-->
<template>
<view :style="{ marginTop: tarbarHeight }">
<view style="padding-bottom: 160rpx">
<u-collapse>
<!-- 手风琴headImageUr1 -->
<u-collapse-item
v-for="(item, index) in dataList"
:key="index"
:title="item.o_OrganName"
class="department"
:name="index"
>
<u-icon
name="star-fill"
size="20"
slot="icon"
:color="color"
class="el-icon-star-on star"
@click.native="selectAll(item, index)"
:class="{ active: item.active }"
></u-icon>
<u-list :height="'auto'">
<u-list-item
v-for="(elItem, elIndex) in item.personList"
:key="elIndex"
>
<u-cell
:title="elItem.p_PersonName + ' ' + elItem.p_Telphone"
@click="selectPerson(elItem)"
>
<base-avatar
slot="icon"
shape="square"
size="35"
:text="
elItem.p_PersonName ? elItem.p_PersonName.slice(-2) : ''
"
bg-color="#3c9cff"
color="#ffffff"
font-size="10"
:src="elItem.headImageUrl"
customStyle="margin: -3px 5px -3px 0"
></base-avatar>
<u-icon
name="checkbox-mark"
slot="right-icon"
size="20"
:color="color"
class="el-icon-star-on star"
:class="{ active: elItem.active }"
></u-icon>
</u-cell>
</u-list-item>
</u-list>
</u-collapse-item>
</u-collapse>
</view>
<view class="bottomPage">
<view style="width: 58%; font-weight: 600"
>已选 {{ selectedDataList.length }} </view
>
<u-button
text="确认"
type="primary"
size="normal"
style="width: 35%"
@click="personConfirmClick"
></u-button>
</view>
<base-tarbar ref="baseTarbar" :pageTitle="'选择人员'"></base-tarbar>
<u-loading-page :loading="personLoading"></u-loading-page>
</view>
</template>
<script>
import baseAvatar from "@/components/baseAvatar/index.vue";
import { PersonList, GetOrganTree } from "@/api/system/basePerson";
import baseTarbar from "@/components/baseTarbar/index.vue";
import config from "@/config";
import { getUserInfo } from "@/utils/auth";
export default {
components: {
baseAvatar,
baseTarbar,
},
onReady() {
this.$refs.baseTarbar.currentEnvironment();
if (this.$refs.baseTarbar.isOther) {
this.tarbarHeight = "88rpx";
}
},
watch: {
selectedDataList: {
deep: true, // true
handler: function (newV, oldV) {
this.dataList.forEach((el) => {
let personNum = 0;
el.personList.forEach((personEl) => {
if (personEl.active) {
personNum = personNum + 1;
}
});
if (personNum == 0) {
el.active = false;
} else {
el.active = true;
}
});
},
},
dataList: {
deep: true, // true
handler: function (newV, oldV) {
let selectedDataList = [];
newV.forEach((el) => {
el.personList.forEach((item) => {
if (item.active) {
selectedDataList.push(item);
}
});
});
this.selectedDataList = selectedDataList;
},
},
},
data() {
return {
dataList: [],
selectedDataList: [],
personLoading: false,
color: "f0f0f0",
configData: {},
tarbarHeight:"",
};
},
mounted() {
this.openDialog();
},
methods: {
//
openDialog(selectedDataList = [], type) {
this.configData = config;
this.selectedDataList = [];
this.getMenuData(selectedDataList);
},
//
personConfirmClick() {
this.$store.commit("SET_SELECTSDATA", this.selectedDataList);
uni.navigateBack({
delta: 1, //*
});
},
closePersonClick() {
uni.navigateBack({
delta: 1, //*
});
},
//
async getMenuData(selectedDataList) {
this.personLoading = true;
setTimeout(() => {
this.personLoading = false;
}, 5000);
let params = {
CompanyID: getUserInfo().companyID,
};
let res = await GetOrganTree(params);
let dataList = JSON.parse(res.data[0]);
let departmentList = [];
function setDepartmentList(data) {
data.forEach((item) => {
let arr = {
o_OrganName: item.label,
personList: [],
active: false,
};
departmentList.push(arr);
if (item.children && item.children.length > 0) {
setDepartmentList(item.children);
}
});
}
setDepartmentList(dataList);
this.getPersonList(departmentList, selectedDataList);
this.personLoading = false
},
//
async getPersonList(departmentList, selectedDataList) {
let params = {
page: "1",
limit: "999",
departmentID: "",
};
let res = await PersonList(params);
if (res.code === 1) {
departmentList.forEach((el) => {
res.data[1].forEach((item) => {
if (el.o_OrganName == item.o_OrganName) {
let personArr = {
o_OrganName: item.o_OrganName,
p_PersonName: item.p_PersonName,
p_PersonID: item.p_PersonID,
p_Telphone: item.p_Telphone,
headImageUrl: item.headImageUrl
? this.configData.baseUrl +
String(item.headImageUrl).split("/wwwroot")[1]
: "",
active: false,
};
el.personList.push(personArr);
}
});
});
this.dataList = departmentList;
this.dataList.forEach((el) => {
el.personList.forEach((elItem) => {
selectedDataList.forEach((item) => {
if (item.p_PersonID == elItem.p_PersonID) {
elItem.active = true;
this.selectedDataList.push(elItem);
}
});
});
});
this.personLoading = false;
}
},
selectPerson(val) {
let personActive = false;
val.active = !val.active;
},
//
selectAll(item) {
item.active = !item.active;
item.personList.forEach((el) => {
el.active = item.active;
});
},
},
};
</script>
<style scoped lang="scss">
$activeColor: var(--bg-color, "#00aaff");
::v-deep .u-collapse-item__content__text {
padding: 0;
}
::v-deep .u-list-item.u-list-item- .u-cell .u-line {
border-bottom: 0 solid rgb(214, 215, 217) !important;
}
.bottomPage {
width: 100%;
position: fixed;
bottom: 0;
padding: 20rpx 30rpx 30rpx 30rpx;
background-color: #fff;
margin-top: 15rpx;
display: flex;
border-top: 8rpx solid #f1f1f1;
align-items: center;
}
.dataBox {
padding: 10rpx 0;
border-bottom: 2rpx solid #ccc;
min-height: 100rpx;
display: flex;
align-items: center;
}
.personBox {
border-radius: 6rpx;
text-align: center;
background-color: #f0f0f0;
color: #817582;
padding: 20rpx 0;
cursor: pointer;
min-width: 200rpx;
.name {
}
.phone {
font-size: 24rpx;
margin-top: 10rpx;
}
}
.personBox {
margin-right: 20rpx;
margin-bottom: 10rpx;
}
.personBox.active {
color: #fff;
background-color: #3c9cff;
}
.department {
.el-icon-star-on {
color: #f0f0f0;
}
}
.el-icon-star-on.active {
color: #3c9cff;
}
.personItem {
display: flex;
align-items: center;
flex-wrap: wrap;
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,291 @@
<!-- 选择人员组件
@desc 多选 弹窗
-->
<template>
<view>
<base-popup
ref="basePopup"
@handleConfirmClick="personConfirmClick"
:title="'选择人员'"
>
<view>
<u-collapse>
<!-- 手风琴headImageUr1 -->
<u-collapse-item
v-for="(item, index) in dataList"
:key="index"
:title="item.o_OrganName"
class="department"
:name="index"
>
<u-icon
name="star-fill"
size="20"
slot="icon"
:color="color"
class="el-icon-star-on star"
@click.native.stop="selectAll(item, index)"
:class="{ active: item.active }"
></u-icon>
<u-list :height="'auto'" v-if="item.personList && item.personList.length > 0">
<u-list-item
v-for="(elItem, elIndex) in item.personList"
:key="elIndex"
>
<u-cell
:title="elItem.p_PersonName + ' ' + elItem.p_Telphone"
@click="selectPerson(elItem)"
>
<base-avatar
slot="icon"
shape="square"
size="35"
:text="
elItem.p_PersonName ? elItem.p_PersonName.slice(-2) : ''
"
bg-color="#3c9cff"
color="#ffffff"
font-size="10"
:src="elItem.headImageUrl"
customStyle="margin: -3px 5px -3px 0"
></base-avatar>
<u-icon
name="checkbox-mark"
slot="right-icon"
size="20"
:color="color"
class="el-icon-star-on star"
:class="{ active: elItem.active }"
></u-icon>
</u-cell>
</u-list-item>
</u-list>
<view v-else class="empty">暂无数据</view>
</u-collapse-item>
</u-collapse>
</view>
</base-popup>
</view>
</template>
<script>
import baseAvatar from "@/components/baseAvatar/index.vue";
import basePopup from "@/components/basePopup/index.vue";
import { PersonList, GetOrganTree } from "@/api/system/basePerson";
import config from "@/config";
import { getUserInfo } from "@/utils/auth";
export default {
components: {
basePopup,
baseAvatar,
},
watch: {
selectedDataList: {
deep: true, // true
handler: function (newV, oldV) {
this.dataList.forEach((el) => {
let personNum = 0;
el.personList.forEach((personEl) => {
if (personEl.active) {
personNum = personNum + 1;
}
});
if (personNum == 0) {
el.active = false;
} else {
el.active = true;
}
});
},
},
dataList: {
deep: true, // true
handler: function (newV, oldV) {
let selectedDataList = [];
newV.forEach((el) => {
el.personList.forEach((item) => {
if (item.active) {
selectedDataList.push(item);
}
});
});
this.selectedDataList = selectedDataList;
},
},
},
data() {
return {
dataList: [],
selectedDataList: [],
personLoading: false,
color: "f0f0f0",
configData: {},
};
},
methods: {
//
openDialog(selectedDataList = [], type) {
this.configData = config;
this.$refs.basePopup.isShowPopup = true;
this.selectedDataList = [];
this.getMenuData(selectedDataList);
},
//
personConfirmClick() {
this.$emit("personConfirmClick", this.selectedDataList);
this.$refs.basePopup.isShowPopup = false;
},
//
async getMenuData(selectedDataList) {
this.personLoading = true;
setTimeout(() => {
this.personLoading = false;
}, 5000);
let params = {
CompanyID: getUserInfo().companyID,
};
let res = await GetOrganTree(params);
let dataList = JSON.parse(res.data[0]);
let departmentList = [];
function setDepartmentList(data) {
data.forEach((item) => {
let arr = {
o_OrganName: item.label,
personList: [],
active: false,
};
departmentList.push(arr);
if (item.children && item.children.length > 0) {
setDepartmentList(item.children);
}
});
}
setDepartmentList(dataList);
this.getPersonList(departmentList, selectedDataList);
},
//
async getPersonList(departmentList, selectedDataList) {
let params = {
page: "1",
limit: "999",
departmentID: "",
};
let res = await PersonList(params);
if (res.code === 1) {
departmentList.forEach((el) => {
res.data[1].forEach((item) => {
if (el.o_OrganName == item.o_OrganName) {
let personArr = {
o_OrganName: item.o_OrganName,
p_PersonName: item.p_PersonName,
p_PersonID: item.p_PersonID,
p_Telphone: item.p_Telphone,
headImageUrl: item.headImageUrl ? this.configData.baseUrl + String(item.headImageUrl).split('/wwwroot')[1]:'',
active: false,
};
el.personList.push(personArr);
}
});
});
this.dataList = departmentList;
this.dataList.forEach((el) => {
el.personList.forEach((elItem) => {
selectedDataList.forEach((item) => {
if (item.p_PersonID == elItem.p_PersonID) {
elItem.active = true;
this.selectedDataList.push(elItem);
}
});
});
});
this.personLoading = false;
}
},
selectPerson(val) {
let personActive = false;
val.active = !val.active;
},
//
selectAll(item) {
item.active = !item.active;
item.personList.forEach((el) => {
el.active = item.active;
});
},
},
};
</script>
<style scoped lang="scss">
$activeColor: var(--bg-color, "#00aaff");
::v-deep .u-collapse-item__content__text {
padding: 0;
}
.empty {
text-align: center;
font-size: 14px;
color: #919398;
padding: 10px 0;
}
::v-deep .u-list-item.u-list-item- .u-cell .u-line {
border-bottom: 0 solid rgb(214, 215, 217) !important;
}
.dataBox {
padding: 10rpx 0;
border-bottom: 2rpx solid #ccc;
min-height: 100rpx;
display: flex;
align-items: center;
}
.personBox {
border-radius: 6rpx;
text-align: center;
background-color: #f0f0f0;
color: #817582;
padding: 20rpx 0;
cursor: pointer;
min-width: 200rpx;
.name {
}
.phone {
font-size: 24rpx;
margin-top: 10rpx;
}
}
.personBox {
margin-right: 20rpx;
margin-bottom: 10rpx;
}
.personBox.active {
color: #fff;
background-color: #3c9cff;
}
.department {
.el-icon-star-on {
color: #f0f0f0;
}
}
.el-icon-star-on.active {
color: #3c9cff;
}
.personItem {
display: flex;
align-items: center;
flex-wrap: wrap;
}
</style>

View File

@ -0,0 +1,174 @@
<!--
desc: 弹窗组件
date: 20230719
参数说明
isShowPopup是否打开弹窗布尔类型
isOverlay: 是否显示遮罩
mode: 弹出方向 String类型 默认bottom 可选值 top / right / bottom / center
duration: 遮罩打开或收起的动画过渡时间单位ms
closeable: 是否显示关闭图标
overlayOpacity:遮罩透明度0-1之间勿与overlayStyle共用
closeOnClickOverlay: 点击遮罩是否关闭
safeAreaInsetTop:是否留出顶部安全距离状态栏高度默认false
closeIconPos自定义关闭图标位置top-left为左上角top-right为右上角bottom-left为左下角bottom-right为右下角
round: 设置圆角值仅对mode = top | bottom | center有效
bgColor:背景色一般用于特殊弹窗内容场景设置为transparent可去除默认的白色背景
zoom:当mode=center时 是否开启缩放
-->
<template>
<view>
<u-popup
:show="isShowPopup"
:overlay="isOverlay"
:mode="mode"
:duration="duration"
:closeable="closeable"
:overlayOpacity="overlayOpacity"
:closeOnClickOverlay="closeOnClickOverlay"
:overlayStyle="{ 'touch-action': 'none' }"
:safeAreaInsetTop="safeAreaInsetTop"
:closeIconPos="closeIconPos"
:round="round"
bgColor="bgColor"
:zoom="zoom"
@close="handleCloseClick"
@open="handlerPopupOpen"
>
<view class="buttom" v-if="buttomBtn">
<text @click="handleCloseClick" v-if="showCancle">取消</text>
<text class="title" v-if="showtitle">{{ title }}</text>
<text @click="handleConfirmClick" v-if="showSubmitBtn">确定</text>
<slot name="btn" style="width:100%;"></slot>
</view>
<view class="scrool" :style="{ height: popuoHeight }">
<slot></slot>
</view>
</u-popup>
</view>
</template>
<script>
export default {
props: {
isOverlay: {
type: Boolean,
default: true,
},
mode: {
type: String,
default: "bottom",
},
popuoHeight: {
type: String,
default: "800rpx",
},
duration: {
type: [Number, String],
default: 300,
},
closeable: {
type: Boolean,
default: false,
},
overlayOpacity: {
type: [Number, String],
default: 0.5,
},
closeOnClickOverlay: {
type: Boolean,
default: true,
},
showSubmitBtn: {
type: Boolean,
default: true,
},
showCancle: {
type: Boolean,
default: true,
},
showtitle: {
type: Boolean,
default: true,
},
buttomBtn: {
type: Boolean,
default: true,
},
safeAreaInsetTop: {
type: Boolean,
default: false,
},
closeIconPos: {
type: String,
default: "top-right",
},
title: {
type: String,
default: "",
},
round: {
type: [Number, String],
default: 0,
},
bgColor: {
type: String,
default: "",
},
zoom: {
type: Boolean,
default: true,
},
},
data() {
return {
isShowPopup: false,
};
},
methods: {
//
handlerPopupClose() {
this.isShowPopup = false;
},
//
handlerPopupOpen() {
// this.isShowPopup = true
},
handleConfirmClick() {
this.$emit("handleConfirmClick");
},
handleCloseClick() {
this.isShowPopup = false;
this.$emit("handleCloseClick");
},
},
};
</script>
<style scoped lang="scss">
.buttom {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #f2f3f4;
width: 100%;
view{
width: 100%;
}
text {
padding: 20rpx 40rpx;
font-size: 28rpx;
}
text:last-child {
color: #3c9cff;
}
}
.scrool {
overflow-y: scroll; //
overscroll-behavior: none; //
}
.title {
font-weight: bold;
}
</style>

View File

@ -0,0 +1,287 @@
<template>
<view>
<base-popup
:title="'关联项目'"
ref="basePopup"
@handleConfirmClick="handlerProjectConfirm"
@handleCloseClick="resetDialog"
>
<view style="padding: 20rpx 30rpx 0 30rpx">
<u-search
v-if="showSearch"
:placeholder="placeholder"
v-model="CodeOrName"
shape="square"
clearabled
:showAction="false"
@change="contractSearch"
></u-search>
<scroll-view
:scroll-top="scrollTop"
scroll-y="true"
class="scroll-Y"
@scrolltolower="scrolltolower"
:lower-threshold="0"
style="margin-top: 20rpx"
v-if="!isLoading"
>
<!--单选-->
<u-radio-group
v-if="type == 'radio'"
:borderBottom="true"
iconPlacement="right"
placement="column"
@change="groupChange"
v-model="radioValue"
>
<u-radio
:customStyle="{ marginBottom: '12px' }"
v-for="(item, index) in dataLists"
:key="index"
:name="item.projectID"
>
<view class="listData">
<view class="content">
<text>项目名称</text>
{{ item.projectName }}
</view>
<view class="flex time">
<view>
<text>项目任务</text>
{{ item.projectTotalCount }}
</view>
<view>
<text>当前BUG</text>
{{ item.bugTotalCount || 0 }}
</view>
<view>
<text>项目经理</text>
{{ item.pmPersonName }}
</view>
<view>
<text>业务员</text>
{{ item.salesName }}
</view>
</view>
</view>
</u-radio>
</u-radio-group>
<!--多选-->
<u-checkbox-group
v-if="type == 'checkbox'"
:borderBottom="true"
placement="column"
iconPlacement="right"
@change="checkboxChange"
v-model="checkboxValue"
>
<u-checkbox
:customStyle="{ marginBottom: '12px', paddingBottom: '12px' }"
v-for="(item, index) in dataLists"
:key="index"
:name="item.projectID"
:label="item.cusName + ' ' + item.projectID"
>
</u-checkbox>
</u-checkbox-group>
<view class="contractNoData" v-show="noData">
<u-divider text="我是有底线哒!" :hairline="true"></u-divider>
</view>
</scroll-view>
<u-loadmore
v-else
status="loading"
:loadingText="'数据加载中'"
:marginTop="150"
></u-loadmore>
</view>
</base-popup>
</view>
</template>
<script>
import { GetProjectListData } from "@/api/system/projectAdd.js";
import basePopup from "@/components/basePopup/index.vue";
export default {
components: {
basePopup,
},
props: {
//
showSearch: {
default: true,
type: Boolean,
},
placeholder: {
default: "请输入项目名称",
type: String,
},
type: {
default: "checkbox",
type: String,
},
},
data() {
return {
noData: false,
CodeOrName: "",
scrollTop: 0,
pages: {
page: 1, //
limit: 20, //
CodeOrName: "",
},
dataLists: [],
checkboxData: [],
checkboxValue: [],
radioData: "",
radioValue: "",
timer: null,
isLoading: false,
};
},
methods: {
openDialog(radioValue = "") {
this.GetProjectListData();
setTimeout(() => {
this.$nextTick(() => {
this.radioValue = radioValue;
if (radioValue) {
this.groupChange(radioValue);
}
this.$refs.basePopup.isShowPopup = true;
});
}, 100);
},
//
contractSearch(value) {
if (this.timer !== null) clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.pages.CodeOrName = value;
this.GetProjectListData();
this.radioValue = "";
this.checkboxValue = Object.assign([], []);
}, 800);
},
resetDialog() {
this.CodeOrName = "";
this.pages.page = 1;
this.pages.CodeOrName = "";
this.radioValue = "";
this.radioData = "";
this.checkboxValue = Object.assign([], []);
},
checkboxChange(n) {
this.checkboxData = [];
n.forEach((key) => {
this.dataLists.forEach((item) => {
if (item.projectID == key) {
this.checkboxData.push(item);
}
});
});
},
//
groupChange(n) {
this.radioData = this.dataLists.filter((item) => item.projectID === n);
},
//
scrolltolower() {
if (this.noData != true) {
this.pages.page++;
this.GetProjectListData();
}
},
// --
async GetProjectListData() {
this.isLoading = true;
this.noData = false;
let params = {
...this.pages,
};
const res = await GetProjectListData(params);
this.isLoading = false;
if (this.pages.page > 1) {
this.dataLists.push(...res.data[1]);
} else {
this.dataLists = res.data[1];
}
if (res.data[1].length < 20) {
this.noData = true;
}
},
//
handlerProjectConfirm() {
if (this.type == "radio") {
if (
this.radioData == "" ||
this.radioData == undefined ||
this.radioData == null
) {
uni.$u.toast("请选择数据");
return;
}
this.$emit("handlerProjectConfirm", this.radioData);
this.$refs.basePopup.isShowPopup = false;
this.resetDialog();
} else if (this.type == "checkbox") {
if (this.checkboxData.length == 0) {
uni.$u.toast("请选择数据");
return;
}
this.$emit("handlerProjectConfirm", this.checkboxData);
this.$refs.basePopup.isShowPopup = false;
this.resetDialog();
}
},
},
};
</script>
<style lang="scss" scoped>
.scroll-Y {
height: 680rpx;
}
.contractNoData .u-divider {
margin: 0;
}
.content {
line-height: 1.5;
font-size: 28rpx;
margin-bottom: 10rpx;
text {
font-size: 28rpx;
color: #979797;
}
}
.time {
font-size: 28rpx;
flex-wrap: wrap;
line-height: 1.5;
text {
display: inline-block;
font-size: 26rpx;
color: #979797;
margin-bottom: 30rpx;
}
view {
height: 48rpx;
}
view:nth-child(2n + 1) {
width: 50%;
}
view:nth-child(2n) {
width: 50%;
}
view:nth-child(4) {
text:nth-child(2) {
font-size: 28rpx;
}
}
}
</style>

View File

@ -0,0 +1,258 @@
<!-- 选择人员组件
@desc 单选 弹窗
-->
<template>
<view>
<base-popup
ref="basePopup"
@handleConfirmClick="personConfirmClick"
:title="'选择人员'"
>
<view>
<u-collapse>
<!-- 手风琴headImageUr1 -->
<u-collapse-item
v-for="(item, index) in dataList"
:key="index"
:title="item.o_OrganName"
class="department"
:name="index"
>
<u-icon
name="star-fill"
size="20"
slot="icon"
:color="color"
class="el-icon-star-on star"
:class="{ active: item.active }"
></u-icon>
<u-list :height="'auto'" v-if="item.personList && item.personList.length > 0">
<u-list-item
v-for="(elItem, elIndex) in item.personList"
:key="elIndex"
>
<u-cell
:title="elItem.p_PersonName + ' ' + elItem.p_Telphone"
@click="selectPerson(elItem)"
>
<base-avatar
slot="icon"
shape="square"
size="35"
:text="
elItem.p_PersonName ? elItem.p_PersonName.slice(-2) : ''
"
bg-color="#3c9cff"
color="#ffffff"
font-size="10"
:src="elItem.headImageUrl"
customStyle="margin: -3px 5px -3px 0"
></base-avatar>
<u-icon
name="checkbox-mark"
slot="right-icon"
size="20"
:color="color"
class="el-icon-star-on star"
:class="{ active: elItem.p_PersonID == chooseData.p_PersonID }"
></u-icon>
</u-cell>
</u-list-item>
</u-list>
<view v-else class="empty">暂无数据</view>
</u-collapse-item>
</u-collapse>
<u-toast ref="uToast"></u-toast>
</view>
</base-popup>
</view>
</template>
<script>
import baseAvatar from "@/components/baseAvatar/index.vue";
import basePopup from "@/components/basePopup/index.vue";
import { PersonList, GetOrganTree } from "@/api/system/basePerson";
import config from "@/config";
import { getUserInfo } from "@/utils/auth";
export default {
components: {
basePopup,
baseAvatar,
},
data() {
return {
dataList: [],
selectedDataList: [],
personLoading: false,
color: "f0f0f0",
configData: {},
chooseData: {},
};
},
methods: {
//
openDialog(selectedDataList = [], type) {
this.configData = config;
this.$refs.basePopup.isShowPopup = true;
this.selectedDataList = [];
this.getMenuData(selectedDataList);
},
//
personConfirmClick() {
if (JSON.stringify(this.chooseData) == "{}") {
this.$refs.uToast.show({
type: "warning",
message: "请选择人员!",
});
return;
}
this.$emit("personConfirmClick", this.chooseData);
this.$refs.basePopup.isShowPopup = false;
},
//
async getMenuData(selectedDataList) {
this.personLoading = true;
setTimeout(() => {
this.personLoading = false;
}, 5000);
let params = {
CompanyID: getUserInfo().companyID,
};
let res = await GetOrganTree(params);
let dataList = JSON.parse(res.data[0]);
let departmentList = [];
function setDepartmentList(data) {
data.forEach((item) => {
let arr = {
o_OrganName: item.label,
personList: [],
active: false,
};
departmentList.push(arr);
if (item.children && item.children.length > 0) {
setDepartmentList(item.children);
}
});
}
setDepartmentList(dataList);
this.getPersonList(departmentList, selectedDataList);
},
//
async getPersonList(departmentList, selectedDataList) {
let params = {
page: "1",
limit: "999",
departmentID: "",
};
let res = await PersonList(params);
if (res.code === 1) {
departmentList.forEach((el) => {
res.data[1].forEach((item) => {
if (el.o_OrganName == item.o_OrganName) {
let personArr = {
o_OrganName: item.o_OrganName,
p_PersonName: item.p_PersonName,
p_PersonID: item.p_PersonID,
p_Telphone: item.p_Telphone,
headImageUrl: item.headImageUrl
? this.configData.baseUrl +
String(item.headImageUrl).split("/wwwroot")[1]
: "",
active: false,
};
el.personList.push(personArr);
}
});
});
this.dataList = departmentList;
this.dataList.forEach((el) => {
el.personList.forEach((elItem) => {
selectedDataList.forEach((item) => {
if (item.p_PersonID == elItem.p_PersonID) {
elItem.active = true;
this.selectedDataList.push(elItem);
}
});
});
});
this.personLoading = false;
}
},
selectPerson(val) {
this.chooseData = val;
},
},
};
</script>
<style scoped lang="scss">
$activeColor: var(--bg-color, "#00aaff");
::v-deep .u-collapse-item__content__text {
padding: 0;
}
::v-deep .u-list-item.u-list-item- .u-cell .u-line {
border-bottom: 0 solid rgb(214, 215, 217) !important;
}
.empty {
text-align: center;
font-size: 14px;
color: #919398;
padding: 10px 0;
}
.dataBox {
padding: 10rpx 0;
border-bottom: 2rpx solid #ccc;
min-height: 100rpx;
display: flex;
align-items: center;
}
.personBox {
border-radius: 6rpx;
text-align: center;
background-color: #f0f0f0;
color: #817582;
padding: 20rpx 0;
cursor: pointer;
min-width: 200rpx;
.name {
}
.phone {
font-size: 24rpx;
margin-top: 10rpx;
}
}
.personBox {
margin-right: 20rpx;
margin-bottom: 10rpx;
}
.personBox.active {
color: #fff;
background-color: #3c9cff;
}
.department {
.el-icon-star-on {
color: #f0f0f0;
}
}
.el-icon-star-on.active {
color: #3c9cff;
}
.personItem {
display: flex;
align-items: center;
flex-wrap: wrap;
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<!-- h5显示导航栏 -->
<view>
<u-navbar
:autoBack="true"
:title="pageTitle"
:titleStyle="{ fontSize: '16px', fontWeight: '700' }"
:leftIcon="leftIcon"
v-if="isOther"
>
</u-navbar>
</view>
</template>
<script>
export default {
props: {
pageTitle: {
type: String,
required: "",
},
isAuditTitle: {
type: String,
required: "",
},
leftIcon: {
type: String,
required: "arrow-left",
},
},
data() {
return {
isOther: false, //H5
//
isWeChatOrDingTalk: "",
//
};
},
methods: {
currentEnvironment() {
//
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("dingtalk") !== -1) {
//
this.$ddFunction.setTitle(this.pageTitle);
if (this.isAuditTitle == "external") {
this.$ddFunction.setRight();
}
this.isOther = false;
} else if (userAgent.indexOf("micromessenger") !== -1) {
//
this.isOther = true
} else {
this.isOther = true;
}
},
},
};
</script>
<style>
</style>

View File

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

View File

@ -0,0 +1,167 @@
<template>
<view class="uni-section">
<view class="uni-section-header" @click="onClick">
<view class="uni-section-header__decoration" v-if="type" :class="type" />
<slot v-else name="decoration"></slot>
<view class="uni-section-header__content">
<text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
<text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
</view>
<view class="uni-section-header__slot-right">
<slot name="right"></slot>
</view>
</view>
<view class="uni-section-content" :style="{padding: _padding}">
<slot />
</view>
</view>
</template>
<script>
/**
* Section 标题栏
* @description 标题栏
* @property {String} type = [line|circle|square] 标题装饰类型
* @value line 竖线
* @value circle 圆形
* @value square 正方形
* @property {String} title 主标题
* @property {String} titleFontSize 主标题字体大小
* @property {String} titleColor 主标题字体颜色
* @property {String} subTitle 副标题
* @property {String} subTitleFontSize 副标题字体大小
* @property {String} subTitleColor 副标题字体颜色
* @property {String} padding 默认插槽 padding
*/
export default {
name: 'UniSection',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
title: {
type: String,
required: true,
default: ''
},
titleFontSize: {
type: String,
default: '14px'
},
titleColor:{
type: String,
default: '#333'
},
subTitle: {
type: String,
default: ''
},
subTitleFontSize: {
type: String,
default: '12px'
},
subTitleColor: {
type: String,
default: '#999'
},
padding: {
type: [Boolean, String],
default: false
}
},
computed:{
_padding(){
if(typeof this.padding === 'string'){
return this.padding
}
return this.padding?'10px':''
}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" >
$uni-primary: #2979ff !default;
.uni-section {
background-color: #fff;
.uni-section-header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 12px 10px;
font-weight: normal;
&__decoration{
margin-right: 6px;
background-color: $uni-primary;
&.line {
width: 4px;
height: 12px;
border-radius: 10px;
}
&.circle {
width: 8px;
height: 8px;
border-top-right-radius: 50px;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
}
&.square {
width: 8px;
height: 8px;
}
}
&__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
flex: 1;
color: #333;
.distraction {
flex-direction: row;
align-items: center;
}
&-sub {
margin-top: 2px;
}
}
&__slot-right{
font-size: 14px;
}
}
.uni-section-content{
font-size: 14px;
}
}
</style>

26
config.js Normal file
View File

@ -0,0 +1,26 @@
// 应用全局配置
module.exports = {
baseUrl: `http://ufidahz.com.cn:9067/`,//正式环境
// baseUrl: `http://192.168.2.78:10086/`,//刚子
// 应用信息
appInfo: {
// 应用名称
name: "用安数智中台",
// 应用版本
version: "1.1.0",
// 应用logo
logo: "/static/logo1.png",
// 官方网站
site_url: "http://ruoyi.vip",
// 政策协议
agreements: [{
title: "隐私政策",
url: "https://ruoyi.vip/protocol.html"
},
{
title: "用户服务协议",
url: "https://ruoyi.vip/protocol.html"
}
]
}
}

26
main.js Normal file
View File

@ -0,0 +1,26 @@
import Vue from 'vue'
import App from './App'
import store from './store' // store
import plugins from './plugins' // plugins
import './permission' // permission
Vue.use(plugins)
import uView from '@/uni_modules/uview-ui'
Vue.use(uView)
import * as whole from '@/utils/common.js'
Vue.prototype.$whole = whole
import * as utilDD from '@/utils/dd.js'
Vue.prototype.$ddFunction = utilDD
Vue.config.productionTip = false
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()

78
manifest.json Normal file
View File

@ -0,0 +1,78 @@
{
"name" : "用安数智中台移动端",
"appid" : "__UNI__A6D00FF",
"description" : "",
"versionName" : "1.1.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {
"OAuth" : {}
},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios" : {},
"sdkConfigs" : {
"oauth" : {
"weixin" : {
"appid" : "wwb46c3f5e6ffe3e2b",
"UniversalLinks" : ""
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "wx7dff96a8822ea082",
"setting" : {
"urlCheck" : false,
"es6" : false,
"minified" : true,
"postcss" : true
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true
},
"vueVersion" : "2",
"h5" : {
"template" : "static/index.html",
"devServer" : {
"port" : 9090,
"https" : false
},
"title" : "用安数智中台",
"router" : {
"mode" : "hash",
"base" : "./"
}
}
}

319
package-lock.json generated Normal file
View File

@ -0,0 +1,319 @@
{
"name": "middleground_H5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@fullcalendar/daygrid": "^6.1.8",
"@fullcalendar/interaction": "^6.1.8",
"@fullcalendar/list": "^6.1.8",
"@fullcalendar/timegrid": "^6.1.8",
"@fullcalendar/vue": "^6.1.8",
"dingtalk-jsapi": "^3.0.25",
"eruda": "^3.0.1"
}
},
"node_modules/@babel/parser": {
"version": "7.22.16",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.16.tgz",
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
"peer": true,
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@fullcalendar/core": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/core/-/core-6.1.8.tgz",
"integrity": "sha512-i8JBIvZCWGO9dsMEDcx9bnsQZ9PtGSJdOXGgWbhLaGq2iq41OBdp9g9gM4b/Otv2oK8bL5Gl6CsMmb/HkDtA6Q==",
"peer": true,
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/daygrid/-/daygrid-6.1.8.tgz",
"integrity": "sha512-kCZxQFKb9Vqa3CZRX0v7rMSJ2mlTt4gDpyLfiNJKxUAq7W51uKurPaFZWicaXy1ESHVBxKNlbx5uNjBpyu50JQ==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.8"
}
},
"node_modules/@fullcalendar/interaction": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/interaction/-/interaction-6.1.8.tgz",
"integrity": "sha512-r6W4E9ohaA87M2uPSlmpE2WT7Fzu7LN0u2pE6D/tThruCEaAPbN8Pw5+sqclsuyTIL09mg0eSJm/ggJekTabSA==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.8"
}
},
"node_modules/@fullcalendar/list": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/list/-/list-6.1.8.tgz",
"integrity": "sha512-10N0T/vCtId1cE3JGLpnbAivWVnaWCCkVO7wmbsyr5Y+I939kr/zq4BUNwBoP/xSFVVxx59FETh3iyA+MkV8Fw==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.8"
}
},
"node_modules/@fullcalendar/timegrid": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/timegrid/-/timegrid-6.1.8.tgz",
"integrity": "sha512-3+3KHHCoNcaLs/gQt004hAqICbY5+WAffrZ0ePv+80HFB1OVh8BQ5XXLHSOUbTvXdgtUTcfBHuw9fhO31kt5gA==",
"dependencies": {
"@fullcalendar/daygrid": "~6.1.8"
},
"peerDependencies": {
"@fullcalendar/core": "~6.1.8"
}
},
"node_modules/@fullcalendar/vue": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/vue/-/vue-6.1.8.tgz",
"integrity": "sha512-rCfmpwsNkMQhhNiSGt2ZVW0yNmFyXC6O5dto+Rsj3MsJDVXAjI9pR2KRtg1vBh/6hgp8vHcMFcSCJZxIqfui+A==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.8",
"vue": "^2.6.12"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "2.7.14",
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
"integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.18.4",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
}
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
"peer": true
},
"node_modules/dingtalk-jsapi": {
"version": "3.0.25",
"resolved": "https://registry.npmmirror.com/dingtalk-jsapi/-/dingtalk-jsapi-3.0.25.tgz",
"integrity": "sha512-l+q2lRzTCH/00DM2EZ+GKFiP/3TZHOupCM7rpG/hgrNpYkexGvF/O6yDI0XNqSMs8iFqWv9haCLOPf1nvCqB/w==",
"dependencies": {
"promise-polyfill": "^7.1.0"
}
},
"node_modules/eruda": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/eruda/-/eruda-3.0.1.tgz",
"integrity": "sha512-6q1Xdwga4JTr1mKSW4mzuWSSbmXgqpm/8Wa1QGFGfCWRjC0bCQjbS4u06M1te1moucIS3hBLlbSTPWYH2W0qbQ=="
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"peer": true
},
"node_modules/postcss": {
"version": "8.4.30",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.30.tgz",
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
"peer": true,
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"peer": true
},
"node_modules/promise-polyfill": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/promise-polyfill/-/promise-polyfill-7.1.2.tgz",
"integrity": "sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ=="
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vue": {
"version": "2.7.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz",
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
"peer": true,
"dependencies": {
"@vue/compiler-sfc": "2.7.14",
"csstype": "^3.1.0"
}
}
},
"dependencies": {
"@babel/parser": {
"version": "7.22.16",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.16.tgz",
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
"peer": true
},
"@fullcalendar/core": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/core/-/core-6.1.8.tgz",
"integrity": "sha512-i8JBIvZCWGO9dsMEDcx9bnsQZ9PtGSJdOXGgWbhLaGq2iq41OBdp9g9gM4b/Otv2oK8bL5Gl6CsMmb/HkDtA6Q==",
"peer": true,
"requires": {
"preact": "~10.12.1"
}
},
"@fullcalendar/daygrid": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/daygrid/-/daygrid-6.1.8.tgz",
"integrity": "sha512-kCZxQFKb9Vqa3CZRX0v7rMSJ2mlTt4gDpyLfiNJKxUAq7W51uKurPaFZWicaXy1ESHVBxKNlbx5uNjBpyu50JQ==",
"requires": {}
},
"@fullcalendar/interaction": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/interaction/-/interaction-6.1.8.tgz",
"integrity": "sha512-r6W4E9ohaA87M2uPSlmpE2WT7Fzu7LN0u2pE6D/tThruCEaAPbN8Pw5+sqclsuyTIL09mg0eSJm/ggJekTabSA==",
"requires": {}
},
"@fullcalendar/list": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/list/-/list-6.1.8.tgz",
"integrity": "sha512-10N0T/vCtId1cE3JGLpnbAivWVnaWCCkVO7wmbsyr5Y+I939kr/zq4BUNwBoP/xSFVVxx59FETh3iyA+MkV8Fw==",
"requires": {}
},
"@fullcalendar/timegrid": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/timegrid/-/timegrid-6.1.8.tgz",
"integrity": "sha512-3+3KHHCoNcaLs/gQt004hAqICbY5+WAffrZ0ePv+80HFB1OVh8BQ5XXLHSOUbTvXdgtUTcfBHuw9fhO31kt5gA==",
"requires": {
"@fullcalendar/daygrid": "~6.1.8"
}
},
"@fullcalendar/vue": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/@fullcalendar/vue/-/vue-6.1.8.tgz",
"integrity": "sha512-rCfmpwsNkMQhhNiSGt2ZVW0yNmFyXC6O5dto+Rsj3MsJDVXAjI9pR2KRtg1vBh/6hgp8vHcMFcSCJZxIqfui+A==",
"requires": {}
},
"@vue/compiler-sfc": {
"version": "2.7.14",
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
"integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
"peer": true,
"requires": {
"@babel/parser": "^7.18.4",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
}
},
"csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
"peer": true
},
"dingtalk-jsapi": {
"version": "3.0.25",
"resolved": "https://registry.npmmirror.com/dingtalk-jsapi/-/dingtalk-jsapi-3.0.25.tgz",
"integrity": "sha512-l+q2lRzTCH/00DM2EZ+GKFiP/3TZHOupCM7rpG/hgrNpYkexGvF/O6yDI0XNqSMs8iFqWv9haCLOPf1nvCqB/w==",
"requires": {
"promise-polyfill": "^7.1.0"
}
},
"eruda": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/eruda/-/eruda-3.0.1.tgz",
"integrity": "sha512-6q1Xdwga4JTr1mKSW4mzuWSSbmXgqpm/8Wa1QGFGfCWRjC0bCQjbS4u06M1te1moucIS3hBLlbSTPWYH2W0qbQ=="
},
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"peer": true
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"peer": true
},
"postcss": {
"version": "8.4.30",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.30.tgz",
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
"peer": true,
"requires": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
},
"preact": {
"version": "10.12.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"peer": true
},
"promise-polyfill": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/promise-polyfill/-/promise-polyfill-7.1.2.tgz",
"integrity": "sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"peer": true
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"peer": true
},
"vue": {
"version": "2.7.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz",
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
"peer": true,
"requires": {
"@vue/compiler-sfc": "2.7.14",
"csstype": "^3.1.0"
}
}
}
}

11
package.json Normal file
View File

@ -0,0 +1,11 @@
{
"dependencies": {
"@fullcalendar/daygrid": "^6.1.8",
"@fullcalendar/interaction": "^6.1.8",
"@fullcalendar/list": "^6.1.8",
"@fullcalendar/timegrid": "^6.1.8",
"@fullcalendar/vue": "^6.1.8",
"dingtalk-jsapi": "^3.0.25",
"eruda": "^3.0.1"
}
}

148
pages.json Normal file
View File

@ -0,0 +1,148 @@
{
"pages": [
{
"path": "pages/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{
"path": "pages/homePage/index",
"style": {
"navigationBarTitleText": "工作台",
"navigationStyle": "custom"
}
},
{
"path": "components/basePeople/index",
"style": {
"navigationBarTitleText": "选择人员",
"onReachBottomDistance": 50,
// "enablePullDownRefresh": true,
"navigationStyle": "custom"
}
},
{
"path": "pages/logsError/index",
"style": {
"navigationBarTitleText": "异常日志",
"onReachBottomDistance": 50,
"enablePullDownRefresh": true,
"navigationStyle": "custom"
}
},
{
"path": "pages/logsError/details",
"style": {
"navigationBarTitleText": "处理异常日志",
"onReachBottomDistance": 50,
// "enablePullDownRefresh": true,
"navigationStyle": "custom",
"app-plus":{
"bounce":"none"
}
}
},
{
"path": "pages/logsError/show",
"style": {
"navigationBarTitleText": "查看异常日志",
"onReachBottomDistance": 50,
// "enablePullDownRefresh": true,
"navigationStyle": "custom",
"app-plus":{
"bounce":"none"
}
}
},
{
"path": "pages/loginAuthen/authenDingDing",
"style": {
"navigationBarTitleText": "钉钉免登录认证",
"onReachBottomDistance": 50,
"enablePullDownRefresh": true,
"navigationStyle": "custom"
}
},
{
"path": "pages/loginAuthen/loginDingDing",
"style": {
"navigationBarTitleText": "钉钉免登录认证",
"navigationStyle": "custom"
}
},
{
"path": "pages/loginAuthen/selectCompany",
"style": {
"navigationBarTitleText": "钉钉免登录认证",
"navigationStyle": "custom"
}
},
{
"path": "pages/loginAuthen/authenWeChat",
"style": {
"navigationBarTitleText": "微信免登录认证",
"navigationStyle": "custom"
}
},
{
"path": "pages/loginAuthen/authenDingDingAudit",
"style": {
"navigationBarTitleText": "钉钉免登录认证",
"navigationStyle": "custom"
}
},
{
"path": "pages/loginAuthen/loginWeChat",
"style": {
"navigationBarTitleText": "微信免登录认证",
"navigationStyle": "custom"
}
}
],
"tabBar": {
"color": "#000000",
"selectedColor": "#000000",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/homePage/index",
"iconPath": "static/images/tabbar/staging.png",
"selectedIconPath": "static/images/tabbar/staging_.png",
"text": "工作台"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "RuoYi",
"navigationBarBackgroundColor": "#FFFFFF",
"usingComponents": {
// "van-button": "/wxcomponents/vant/button/index",
// "van-checkbox": "/wxcomponents/vant/checkbox/index",
// "van-checkbox-group": "/wxcomponents/vant/checkbox-group/index",
// "van-nav-bar": "/wxcomponents/vant/nav-bar/index"
// "van-action-sheet": "/wxcomponents/vant/action-sheet/index",
// "van-overlay": "/wxcomponents/vant/overlay/index",
// "van-popup": "/wxcomponents/vant/popup/index"
}
},
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue"
}
},
"condition" : { //
"current": 0, //(list )
"list": [
{
"name": "", //
"path": "", //
"query": "" //onLoad
}
]
}
}

154
pages/homePage/index.vue Normal file
View File

@ -0,0 +1,154 @@
<template>
<view
class="container"
:style="{ marginTop: tarbarHeight }"
style="padding-bottom: 200rpx"
>
<view v-for="(item, index) in errList" :key="index" class="planBox">
<div class="errItem" @click="logDetails(item)">
<div class="img">
<img
:src="require('@/static/images/defaultIcon.png')"
alt=""
@error="handleImageError(item)"
/>
</div>
<div class="title">
<u--text
:lines="1"
:text="item.name"
:size="14"
:align="'right'"
></u--text>
<u--text
:lines="1"
:text="item.num"
:bold="true"
:align="'right'"
:margin="'5px 0'"
:size="16"
></u--text>
</div>
</div>
</view>
<base-tarbar ref="baseTarbar" :pageTitle="'工作台'" :leftIcon="' '"></base-tarbar>
<u-empty
v-show="noData"
mode="data"
:icon="require('@/static/images/empty.png')"
>
</u-empty>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import baseTarbar from "@/components/baseTarbar/index.vue";
import { authApi } from "@/api/login";
import request from "@/utils/request";
export default {
components: {
baseTarbar,
},
onReady() {
this.$refs.baseTarbar.currentEnvironment();
if (this.$refs.baseTarbar.isOther) {
this.tarbarHeight = "88rpx";
}
},
data() {
return {
tarbarHeight: "0",
errList: [],
noData: false,
msgType: "warn",
};
},
onShow() {},
mounted() {
this.getErrorLogs();
},
methods: {
logDetails(row) {
this.$tab.navigateTo("/pages/logsError/index?appId=" + row.appId);
},
//
async getErrorLogs() {
const res = await authApi("homeService", "app", "appErrorNum", "", {});
if (res.status === "200") {
this.errList = [];
//
this.imgHandle(res.attribute);
this.errList = res.attribute;
console.log(this.errList, "异常日志");
}
},
//
imgHandle(arr = []) {
arr.map((el) => {
return request({
url:
"kangarooDataCenterV3/entranceController/fileDownloadNew?id=" +
el.path,
method: "get",
responseType: "arraybuffer",
}).then((res) => {
let tempImgUrl =
"data:image/png/jpg;base64," +
btoa(
new Uint8Array(res).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
if (el.path) {
this.$set(el, "imgUrl", tempImgUrl);
} else {
this.$set(el, "imgUrl", null);
}
});
});
},
// 使
handleImageError(row = {}) {
console.log("ksksksk");
row.imgUrl = require("@/static/images/defaultIcon.png");
},
},
};
</script>
<style scoped lang="scss">
.container {
display: grid;
grid-template-columns: repeat(2, 1fr); /* 创建两列,每列占 1fr */
gap: 10px; /* 可以设置列与列之间的间距 */
padding: 15px 10px;
}
.planBox {
background: #fff;
border-radius: 12px;
}
.title {
margin-left: 10px;
width: calc(100% - 58px);
}
.errItem {
padding: 10px;
display: flex;
align-items: center;
.img {
width: 48px;
height: 48px;
img {
width: 100%;
height: 100%;
}
}
}
</style>
<style scoped>
page {
height: 100vh;
background: #f3f4f6;
}
</style>

234
pages/login.vue Normal file
View File

@ -0,0 +1,234 @@
<template>
<view class="normal-login-container">
<view class="logo-content">
<image
style="
width: 330rpx;
background: #c73b26;
border-radius: 10px;
padding: 15px;
"
:src="globalConfig.appInfo.logo"
mode="widthFix"
></image>
</view>
<view class="login-form-content">
<view class="input-item flex align-center">
<u-icon name="account" class="icon" size="20"></u-icon>
<input
v-model="loginForm.username"
class="input"
type="text"
placeholder="请输入账号"
maxlength="30"
/>
</view>
<view class="input-item flex align-center">
<u-icon name="lock" class="icon" size="20"></u-icon>
<input
v-model="loginForm.password"
type="password"
class="input"
placeholder="请输入密码"
maxlength="30"
@confirm="handleLogin"
/>
</view>
<view class="flex">
<u-checkbox-group v-model="checkboxValue1">
<u-checkbox
v-for="(item, index) in checkboxList1"
:key="index"
:label="item.name"
:name="item.key"
></u-checkbox>
</u-checkbox-group>
</view>
<view class="action-btn">
<button
@click="handleLogin"
class="login-btn cu-btn block bg-blue lg round"
>
登录
</button>
</view>
</view>
</view>
</template>
<script>
import { getCodeImg } from "@/api/login";
import localStorage from "@/utils/localStorage";
import { getUserInfo, setUserInfo } from "@/utils/auth";
export default {
data() {
return {
codeUrl: "",
captchaEnabled: true,
globalConfig: getApp().globalData.config,
loginForm: {
username: "",
password: "",
},
checkboxList1: [
{
name: "记住密码",
key: 1,
},
],
checkboxValue1: [],
selectCompany: false,
companyList: [], //
};
},
created() {
this.getData();
},
methods: {
getData() {
let data = localStorage.get("middleGroundNumber");
if (data != "") {
this.checkboxValue1 = [1];
this.loginForm.username = data.username;
this.loginForm.password = data.password;
}
let item = localStorage.get("automaticLogon");
if (item != "") {
this.checkboxValue1 = [1];
this.handleLogin();
}
},
//
async handleLogin() {
if (this.loginForm.username === "") {
this.$modal.msgError("请输入您的账号");
} else if (this.loginForm.password === "") {
this.$modal.msgError("请输入您的密码");
} else {
this.$modal.loading("登录中,请耐心等待...");
if (this.checkboxValue1.includes(1)) {
localStorage.set("middleGroundNumber", this.loginForm);
} else {
localStorage.remove("middleGroundNumber");
}
this.pwdLogin();
}
},
//
async pwdLogin() {
this.$store
.dispatch("Login", this.loginForm)
.then(() => {
this.$modal.closeLoading();
uni.switchTab({
url: "/pages/homePage/index",
});
})
.catch(() => {});
},
},
};
</script>
<style lang="scss" scoped>
page {
background-color: #ffffff;
}
.comBtnBox {
display: flex;
align-items: center;
flex-direction: column;
}
.comBtn {
border: 2rpx solid #f1f1f1;
padding: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
width: 80%;
border-radius: 6rpx;
margin: 16rpx 0;
color: #606266;
}
.comBtnTitle {
width: 100%;
font-size: 32rpx;
color: #666;
text-align: center;
margin: 20rpx 0 20rpx 0;
}
.comBtnText {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 20rpx 0 0;
}
.normal-login-container {
width: 100%;
.logo-content {
width: 100%;
font-size: 25px;
text-align: center;
padding-top: 15%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
display: block;
}
}
.login-form-content {
text-align: center;
margin: 20px auto;
margin-top: 15%;
width: 80%;
.input-item {
margin: 20px auto;
background-color: #f5f6f7;
height: 45px;
border-radius: 20px;
padding-left: 20rpx;
.input {
width: 100%;
font-size: 14px;
line-height: 20px;
text-align: left;
padding-left: 15px;
}
}
.login-btn {
margin-top: 40px;
height: 45px;
}
.xieyi {
color: #333;
margin-top: 20px;
}
.login-code {
height: 38px;
float: right;
.login-code-img {
height: 38px;
position: absolute;
margin-left: 10px;
width: 200rpx;
}
}
}
}
::v-deep .u-checkbox-label--left {
margin-right: 40rpx;
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<view class="login">
<div class="title">
<view class="logo-content">
<img :src="globalConfig" alt="" class="logo" style="width: 250rpx" />
</view>
<span class="text">钉钉登录认证中...</span>
</div>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import * as dd from "dingtalk-jsapi";
import { authApi } from "@/api/login";
import logo from "@/static/logo1.png";
import localStorage from "@/utils/localStorage";
export default {
data() {
return {
globalConfig: logo,
};
},
onReady() {
this.$ddFunction.setTitle("钉钉免登录认证");
},
onShow() {
const currentUrl = document.location.toString();
//urlcorpId
const corpId = currentUrl.split("corpid=")[1];
if (corpId == "" || corpId == null || corpId == undefined) {
this.$modal.showToast("企业id获取失败, 请使用钉钉手机端登录或重新加载");
} else {
this.$store.commit("SET_DINGCROPID", corpId);
this.dingtalkLogin(corpId);
}
},
methods: {
dingtalkLogin(corpId) {
let that = this;
if (dd.env.platform !== "notInDingTalk") {
dd.ready(() => {
//使SDK
dd.runtime.permission.requestAuthCode({
corpId: corpId,
onSuccess: function (result) {
let code = result.code;
that.loginDDSSO(code);
},
onFail: (err) => {
console.info("获取个人信息异常,请稍后重试!", err);
},
});
});
}
},
async loginDDSSO(code) {
let params = {
code: code,
appType: "DD", //
appId: "800043", //APIID
apiCode: "8000430000", //API
userApiCode: "8000430004", //API
};
let res = await authApi("loginService", "", "appDoLogin", "", params);
if (res.status === "200") {
localStorage.set("MIDDLEGROUND-TOKEN", res.attribute.token);
localStorage.set("MIDDLEGROUND-USERINFO", res.attribute.userInfo);
uni.switchTab({
url: "/pages/homePage/index",
});
} else if (res.status == "1005") {
if (
res.attribute.userid == "" ||
res.attribute.userid == null ||
res.attribute.userid == undefined
) {
this.$refs.uToast.show({
type: "warning",
message: "登录时获取的 code 为空, 请联系管理员处理!",
});
} else {
this.$refs.uToast.show({
type: "warning",
message: "您尚未进行登录认证,请先认证!",
});
setTimeout(() => {
localStorage.set("MIDDLEGROUND-USERID", res.attribute.userid);
uni.reLaunch({
url: "/pages/loginAuthen/loginDingDing",
});
}, 1000);
}
} else {
// do something
localStorage.remove("MIDDLEGROUND-TOKEN");
localStorage.remove("MIDDLEGROUND-USERINFO");
localStorage.remove("MIDDLEGROUND-USERID");
}
},
},
};
</script>
<style scoped>
.title {
padding-top: 80rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.logo-content {
background: #c73b26;
border-radius: 10px;
padding: 15px;
}
.title .logo {
vertical-align: middle;
}
.title .text {
font-size: 17px;
font-weight: 700;
vertical-align: middle;
padding: 24px;
color: var(--text-color-light);
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,174 @@
<template>
<view class="login">
<div class="title">
<img :src="globalConfig" alt="" class="logo" style="width: 250rpx" />
<span class="text">钉钉登录认证中...</span>
</div>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import * as dd from "dingtalk-jsapi";
import { DDSSO } from "@/api/login.js";
import logo from "@/static/logo.png";
import localStorage from "@/utils/localStorage";
export default {
data() {
return {
globalConfig: logo,
billID: "",
billKindID: "",
};
},
onReady() {
this.$ddFunction.setTitle("钉钉免登录认证");
},
onShow() {
const currentUrl = document.location.toString();
//urlcorpId
const obj = this.parseURLParams(currentUrl);
const corpId = obj.corpid;
this.billID = obj.billid;
this.billKindID = obj.billKindID;
if (corpId == "" || corpId == null || corpId == undefined) {
this.$modal.showToast("企业id获取失败, 请使用钉钉手机端登录或重新加载");
} else {
this.$store.commit("SET_DINGCROPID", corpId);
this.dingtalkLogin(corpId);
}
},
methods: {
// URL
parseURLParams(url) {
const params = {};
const paramStr = url.split("?")[1];
if (paramStr) {
const paramPairs = paramStr.split("&");
paramPairs.forEach((pair) => {
const [key, value] = pair.split("=");
params[key] = decodeURIComponent(value);
});
}
return params;
},
dingtalkLogin(corpId) {
let that = this;
if (dd.env.platform !== "notInDingTalk") {
dd.ready(() => {
//使SDK
dd.runtime.permission.requestAuthCode({
corpId: corpId,
onSuccess: function (result) {
let code = result.code;
that.loginDDSSO(code);
},
onFail: (err) => {
console.info("获取个人信息异常,请稍后重试!", err);
},
});
});
}
},
async loginDDSSO(code) {
let params = {
code: code,
};
let res = await DDSSO(params);
if (res.code == 1) {
localStorage.set("MIDDLEGROUND-TOKEN", res.data[0]);
localStorage.set("MIDDLEGROUND-USERINFO", res.data[1]);
//
if (this.billKindID == "45") {
let url =
"/pages/contractManagement/contractList/contractAssistant?billid=" +
this.billID +
"&billKindID=" +
this.billKindID +
"&type=audit&external=external";
uni.reLaunch({
url: url,
});
} else if (this.billKindID == "187") {
//
let url =
"/pages/contractManagement/contractHandover/handoverAssistant?billid=" +
this.billID +
"&billKindID=" +
this.billKindID +
"&type=audit&external=external";
uni.reLaunch({
url: url,
});
} else if (this.billKindID == "171") {
//
let url =
"/pages/opportunityManagement/opportunityAssistant?billid=" +
this.billID +
"&billKindID=" +
this.billKindID +
"&type=audit&external=external";
uni.reLaunch({
url: url,
});
} else {
uni.switchTab({
url: "/pages/staging/index",
});
}
} else if (res.code == "1005") {
if (
res.data[0] == "" ||
res.data[0] == null ||
res.data[0] == undefined
) {
this.$refs.uToast.show({
type: "warning",
message: "登录时获取的 code 为空, 请联系管理员处理!",
});
} else {
this.$refs.uToast.show({
type: "warning",
message: "您尚未进行登录认证,请先认证!",
});
setTimeout(() => {
localStorage.set("MIDDLEGROUND-USERID", res.data[0]);
uni.reLaunch({
url: "/pages/loginAuthen/loginDingDing",
});
}, 1000);
}
} else {
// do something
localStorage.remove("MIDDLEGROUND-TOKEN");
localStorage.remove("MIDDLEGROUND-USERINFO");
localStorage.remove("MIDDLEGROUND-USERID");
}
},
},
};
</script>
<style scoped>
.title {
padding-top: 80rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.title .logo {
vertical-align: middle;
}
.title .text {
font-size: 17px;
font-weight: 700;
vertical-align: middle;
padding: 24px;
color: var(--text-color-light);
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<view class="login">
<div class="title">
<img :src="globalConfig" alt="" class="logo" style="width: 250rpx" />
<span class="text">微信登录认证中...</span>
</div>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { WeChatSSO } from "@/api/login.js";
import logo from "@/static/logo.png";
import localStorage from "@/utils/localStorage";
export default {
data() {
return {
globalConfig: logo,
};
},
onShow() {
//code,code
const currentUrl = document.location.toString();
const obj = this.parseURLParams(currentUrl);
//urlcode
const code = obj.code;
if (code == "" || code == null || code == undefined) {
//
var redirect = encodeURIComponent(
"http://ufidahz.com.cn:9085/app/index.html#/pages/loginAuthen/authenWeChat"
);
var url =
"https://open.weixin.qq.com/connect/oauth2/authorize" +
"?appid=wwb46c3f5e6ffe3e2b" +
"&redirect_uri=" +
redirect +
"&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
window.location.href = url;
} else {
this.WXLogin(code);
}
},
methods: {
// URL
parseURLParams(url) {
const params = {};
const paramStr = url.split("?")[1];
if (paramStr) {
const paramPairs = paramStr.split("&");
paramPairs.forEach((pair) => {
const [key, value] = pair.split("=");
params[key] = decodeURIComponent(value);
});
}
return params;
},
async WXLogin(code) {
let params = {
code: code,
};
let res = await WeChatSSO(params);
if (res.code == 1) {
localStorage.set("MIDDLEGROUND-TOKEN", res.data[0]);
localStorage.set("MIDDLEGROUND-USERINFO", res.data[1]);
this.$nextTick(()=>{
uni.reLaunch({
url: "/pages/loginAuthen/selectCompany",
});
})
} else if (res.code == "1005") {
this.$refs.uToast.show({
type: "warning",
message: "您尚未进行登录认证,请先认证!",
});
setTimeout(() => {
localStorage.set("MIDDLEGROUND-USERID", res.data[0]);
uni.reLaunch({
url: "/pages/loginAuthen/loginWeChat",
});
}, 1000);
} else {
localStorage.remove("MIDDLEGROUND-TOKEN");
localStorage.remove("MIDDLEGROUND-USERINFO");
localStorage.remove("MIDDLEGROUND-USERID");
}
},
},
};
</script>
<style scoped>
.title {
padding-top: 80rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.title .logo {
vertical-align: middle;
}
.title .text {
font-size: 17px;
font-weight: 700;
vertical-align: middle;
padding: 24px;
color: var(--text-color-light);
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<view class="loginBox">
<view class="logo-content">
<img :src="globalConfig" alt="" class="logo" style="width: 250rpx" />
</view>
<u-form
:model="userform"
:rules="userRules"
class="loginForm"
ref="loginForm"
>
<u-form-item prop="loginCode" ref="item1" :borderBottom="true">
<u--input
v-model="userform.loginCode"
:border="'none'"
:placeholder="'请输入账号'"
prefixIcon="account"
prefixIconStyle="font-size: 22px;color: #909399"
></u--input>
</u-form-item>
<u-form-item prop="loginPwd" ref="item1" :borderBottom="true">
<u--input
v-model="userform.loginPwd"
:border="'none'"
prefixIcon="lock"
:placeholder="'请输入密码'"
password
prefixIconStyle="font-size: 22px;color: #909399"
></u--input>
</u-form-item>
</u-form>
<view class="btn">
<u-button
text="认证"
size="normal"
type="primary"
@click="handlerSubmit"
></u-button>
</view>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { authApi } from "@/api/login";
import logo from "@/static/logo1.png";
import localStorage from "@/utils/localStorage";
export default {
data() {
return {
globalConfig: logo,
userform: {
loginCode: "",
loginPwd: "",
},
userRules: {
loginCode: [
{
required: true,
message: "请输入账号",
trigger: ["change", "blur"],
},
],
loginPwd: [
{
required: true,
message: "请输入密码",
trigger: ["change", "blur"],
},
],
},
userid: "",
};
},
onReady() {
this.$ddFunction.setTitle("钉钉免登录认证");
},
methods: {
handlerSubmit() {
this.$refs.loginForm
.validate()
.then((res) => {
let params = {
loginCode: this.userform.loginCode,
password: this.userform.loginPwd,
ddUserId: localStorage.get("MIDDLEGROUND-USERID"),
};
this.submit(params);
})
.catch((errors) => {});
},
async submit(params) {
let res = await authApi(
"loginService",
"sysTestjdbc",
"doLogin",
"",
params
);
if (res.status === "200") {
this.$refs.uToast.show({
type: "success",
message: "认证成功!",
});
setTimeout(() => {
localStorage.set("MIDDLEGROUND-TOKEN", res.attribute.token);
localStorage.set("MIDDLEGROUND-USERINFO", res.attribute.userInfo);
uni.switchTab({
url: "/pages/homePage/index",
});
}, 1000);
}
},
},
};
</script>
<style scoped lang="scss">
.logo-content {
background: #c73b26;
border-radius: 10px;
padding: 15px;
display: flex;
align-items: center;
width: 310rpx;
text-align: center;
margin: auto;
}
.loginBox {
background: #ffffff;
padding-top: 20%;
.loginForm {
padding: 70rpx 80rpx;
}
.btn {
padding: 30rpx 80rpx;
}
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<view class="loginBox">
<view class="logo-content">
<image style="width: 250rpx" :src="globalConfig" mode="widthFix"></image>
</view>
<u-form
:model="userform"
:rules="userRules"
class="loginForm"
ref="loginForm"
>
<u-form-item prop="loginCode" ref="item1" :borderBottom="true">
<u--input
v-model="userform.loginCode"
:border="'none'"
:placeholder="'请输入账号'"
prefixIcon="MIDDLEGROUND"
prefixIconStyle="font-size: 22px;color: #909399"
></u--input>
</u-form-item>
<u-form-item prop="loginPwd" ref="item1" :borderBottom="true">
<u--input
v-model="userform.loginPwd"
:border="'none'"
prefixIcon="lock"
:placeholder="'请输入密码'"
password
prefixIconStyle="font-size: 22px;color: #909399"
></u--input>
</u-form-item>
</u-form>
<view class="btn">
<u-button
text="认证"
size="normal"
type="primary"
@click="handlerSubmit"
></u-button>
</view>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { WeChatAuthen } from "@/api/login.js";
import logo from "@/static/logo.png";
import localStorage from "@/utils/localStorage";
export default {
data() {
return {
globalConfig: logo,
userform: {
loginCode: "",
loginPwd: "",
},
userRules: {
loginCode: [
{
required: true,
message: "请输入账号",
trigger: ["change", "blur"],
},
],
loginPwd: [
{
required: true,
message: "请输入密码",
trigger: ["change", "blur"],
},
],
},
userid: "",
};
},
onReady() {
this.$ddFunction.setTitle("钉钉免登录认证");
},
methods: {
handlerSubmit() {
this.$refs.loginForm
.validate()
.then((res) => {
let params = {
...this.userform,
userID: localStorage.get("MIDDLEGROUND-USERID"),
};
this.submit(params);
})
.catch((errors) => {});
},
async submit(params) {
let res = await WeChatAuthen(params);
if (res.code == 1) {
this.$refs.uToast.show({
type: "success",
message: "认证成功!",
});
setTimeout(() => {
window.location.href = "http://ufidahz.com.cn:9085/app/index.html#/pages/loginAuthen/authenWeChat"
}, 1000);
}
},
},
};
</script>
<style scoped lang="scss">
.loginBox {
background: #ffffff;
.logo-content {
width: 100%;
font-size: 25px;
text-align: center;
padding-top: 20%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
display: block;
}
}
.loginForm {
padding: 70rpx 80rpx;
}
.btn {
padding: 30rpx 80rpx;
}
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

View File

@ -0,0 +1,150 @@
<template>
<view class="loginBox">
<view class="logo-content">
<image style="width: 250rpx" :src="globalConfig" mode="widthFix"></image>
</view>
<p class="comBtnTitle">请选择您本次登录的组织</p>
<view class="comBtnBox">
<view
v-for="item in companyList"
:key="item.companyID"
class="comBtn"
@click.native.prevent="handleSelectCompany(item)"
>
<text class="comBtnText" :title="item.companyName">
{{ item.companyName }}
</text>
<u-icon name="arrow-right" color="#606266" size="14"></u-icon>
</view>
</view>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { OrganGetUserCompany, ChangeCompany } from "@/api/login.js";
import logo from "@/static/logo.png";
import localStorage from "@/utils/localStorage";
import { getUserInfo, setUserInfo } from "@/utils/auth";
export default {
data() {
return {
globalConfig: logo,
selectCompany: false,
companyList: [], //
};
},
onReady() {
this.$ddFunction.setTitle("钉钉免登录认证");
},
mounted() {
this.getCompanyList()
},
methods: {
//
async getCompanyList() {
let params = {};
let res = await OrganGetUserCompany(params);
if (res.code == 1) {
//
if (res.data[0].length == 1) {
if (
res.data[0][0].companyID == null ||
res.data[0][0].companyID == "" ||
res.data[0][0].companyID == undefined
) {
this.$refs.uToast.show({
type: "warning",
message: "当前登录人公司信息为空,请联系管理员处理!",
});
} else {
this.handleSelectCompany(res.data[0][0]);
}
} else {
this.companyList = res.data[0];
this.selectCompany = true;
}
}
},
//
handleSelectCompany(item) {
let obj = getUserInfo();
obj.companyID = item.companyID;
obj.companyName = item.companyName;
setUserInfo(obj);
this.ChangeCompany(item.companyID);
uni.switchTab({
url: "/pages/staging/index",
});
},
async ChangeCompany(CompanyID) {
let params = {
CompanyID: CompanyID,
};
let res = await ChangeCompany(params);
},
},
};
</script>
<style scoped lang="scss">
.comBtnBox {
display: flex;
align-items: center;
flex-direction: column;
}
.comBtn {
border: 2rpx solid #f1f1f1;
padding: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
width: 80%;
border-radius: 6rpx;
margin: 16rpx 0;
color: #606266;
}
.comBtnTitle {
width: 100%;
font-size: 32rpx;
color: #666;
text-align: center;
margin: 20rpx 0 20rpx 0;
}
.comBtnText {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 20rpx 0 0;
}
.loginBox {
background: #ffffff;
.logo-content {
width: 100%;
font-size: 25px;
text-align: center;
padding-top: 20%;
image {
border-radius: 4px;
}
.title {
margin-left: 10px;
display: block;
}
}
.loginForm {
padding: 70rpx 80rpx;
}
.btn {
padding: 30rpx 80rpx;
}
}
</style>
<style scoped>
page {
background: #fff;
}
</style>

323
pages/logsError/details.vue Normal file
View File

@ -0,0 +1,323 @@
<template>
<view class="taskContent">
<u--form
:model="model"
ref="uForm"
:labelAlign="'left'"
:labelStyle="{ fontSize: '28rpx' }"
labelPosition="top"
:style="{ marginTop: tarbarHeight }"
class="formBox"
>
<u-form-item
label="发送者应用"
prop="sendAppName"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.sendAppName"
:disabled="true"
:inputBorder="false"
:styles="{ disableColor: '#ffffff', color: '#999999' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="接口名称"
prop="apiName"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.apiName"
:inputBorder="false"
:disabled="true"
:styles="{ disableColor: '#ffffff', color: '#999999' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="源数据"
prop="sourceData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.sourceData"
type="textarea"
autoHeight
:inputBorder="false"
:maxlength="-1"
:styles="{
paddingLeft: '10px',
}"
></uni-easyinput>
</u-form-item>
<u-form-item
label="目标数据"
prop="targetData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.targetData"
type="textarea"
autoHeight
:inputBorder="false"
:maxlength="-1"
:styles="{
paddingLeft: '10px',
}"
></uni-easyinput>
</u-form-item>
<u-form-item
label="状态"
prop="status"
ref="item1"
:borderBottom="true"
:labelWidth="'180rpx'"
>
<u-radio-group
v-model="model.status"
iconPlacement="left"
style="margin-left: 10rpx"
:disabled="true"
>
<u-radio
:customStyle="{ marginRight: '15px' }"
v-for="(item, index) in radiolist"
:key="index"
:label="item.name"
:name="item.id"
:labelSize="13"
:iconSize="13"
></u-radio>
</u-radio-group>
</u-form-item>
<u-form-item
label="错误状态"
prop="errorStatus"
ref="item1"
:borderBottom="true"
:labelWidth="'180rpx'"
:disabled="true"
>
<u-radio-group
v-model="model.errorStatus"
iconPlacement="left"
style="margin-left: 10rpx"
:disabled="true"
>
<u-radio
:customStyle="{ marginRight: '15px' }"
v-for="(item, index) in errorRadiolist"
:key="index"
:label="item.name"
:name="item.id"
:labelSize="13"
:iconSize="13"
></u-radio>
</u-radio-group>
</u-form-item>
<u-form-item
label="返回信息"
prop="returnData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
:disabled="true"
>
<uni-easyinput
v-model="model.returnData"
type="textarea"
autoHeight
:inputBorder="false"
:disabled="true"
:styles="{ disableColor: '#ffffff', color: '#999999' }"
></uni-easyinput>
</u-form-item>
</u--form>
<!-- 按钮控制 -->
<view class="bottomPage">
<u-button
text="标记成功"
@click="signSuccess"
style="margin-right: 30rpx"
></u-button>
<u-button
text="重新推送"
type="primary"
size="normal"
@click="resend"
></u-button>
</view>
<base-tarbar ref="baseTarbar" pageTitle="查看异常日志"></base-tarbar>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { authApi } from "@/api/login";
import baseTarbar from "@/components/baseTarbar/index.vue";
export default {
onLoad: function (option) {
//optionobject
if (Object.getOwnPropertyNames(option).length != 0) {
this.billID = option.billid;
}
},
components: {
baseTarbar,
},
data() {
return {
billID: "",
tarbarHeight: "0",
radiolist: [
{ id: "1", label: "待发送" },
{ id: "2", label: "发送中" },
{ id: "3", label: "发送成功" },
{ id: "4", label: "发送失败" },
],
errorRadiolist: [
{ id: "1", label: "需要重新发送" },
{ id: "2", label: "不需要重新发送" },
],
model: {},
};
},
onReady() {
this.$refs.baseTarbar.currentEnvironment();
if (this.$refs.baseTarbar.isOther) {
this.tarbarHeight = "84rpx";
}
},
created() {
this.init();
},
methods: {
init() {
this.messageLogGetById(this.billID);
},
//
async messageLogGetById(id, row) {
let params = {
id: id,
// status: row.status,
};
let res = await authApi(
"sysMessageManageLogService",
"messageManage",
"thirdInterfacequeryEntity",
"",
params
);
if (res.status == "200") {
let res2 = await authApi(
"sysApplicationApiService",
"application",
"queryEntity",
"",
{ apiCode: res.attribute.receiveCode }
);
if (res2.status == "200") {
this.$set(res.attribute, "apiName", res2.attribute[0].apiName);
} else {
this.$set(res.attribute, "apiName", "未配置该接口");
}
this.$nextTick(() => {
this.model = {
...res.attribute,
};
});
}
},
async signSuccess() {
let params = {
id: this.billID,
status: "3",
};
let res = await authApi(
"sysMessageManageLogService",
"messageManage",
"updateEntity",
"",
params
);
if (res.status == "200") {
this.$vmNews("标记成功", "success");
this.$refs.uToast.show({
type: "success",
message: "标记成功",
});
setTimeout(() => {
uni.navigateBack();
}, 500);
}
},
async resend() {
let formData = new FormData();
formData.append("id", this.billID);
formData.append("sourceData", this.model.sourceData);
let res = await request({
url: "kangarooDataCenterV3/entranceController/externalCallInterfaceResend",
method: "post",
data: formData,
});
if (res.status == "200") {
this.handleDialogClose();
if (res.msg == "重推成功") {
this.$refs.uToast.show({
type: "success",
message: res.msg,
});
}
if (res.msg == "重推失败") {
this.$refs.uToast.show({
type: "error",
message: res.msg,
});
}
setTimeout(() => {
uni.navigateBack();
}, 500);
}
},
},
};
</script>
<style scoped>
.bottomPage {
width: 100%;
position: fixed;
bottom: 0;
padding: 20rpx 30rpx 30rpx 30rpx;
background-color: #fff;
margin-top: 15rpx;
display: flex;
border-top: 8rpx solid #f1f1f1;
}
.formBox {
padding: 10px 10px 100px 10px;
}
::v-deep .uni-easyinput__content-textarea {
padding-left: 10px !important;
}
page {
height: 100vh;
background: #fff;
}
</style>

420
pages/logsError/index.vue Normal file
View File

@ -0,0 +1,420 @@
<template>
<view class="top-level">
<view class="Page_change" :style="{ marginTop: tarbarHeight }">
<u-search
:clearabled="true"
:showAction="false"
shape="square"
v-model="pageModel.sourceData"
:placeholder="'请输入源数据'"
@change="handlerSearchEvent"
></u-search>
</view>
<view
class="listContent"
:style="{ marginTop: isOther ? '220rpx' : '142rpx' }"
>
<view
v-for="(item, index) in tableData"
:key="item.billid"
class="listData"
@click="handlerShowDetails(item, index)"
>
<view class="content">
<text>发送者应用</text>
<view
style="width: calc(100% - 90px); display: flex; align-items: center"
>
<u--text :lines="1" :text="item.sendAppName" :size="14"></u--text>
<img
src="./push.png"
class="pushBtn"
@click.stop.prevent="pushDetails(item, index)"
/>
</view>
</view>
<view class="content">
<text>状态</text>
<view :style="[textColor(item.status)]" class="itemName">{{
textData(item.status)
}}</view>
</view>
<view class="content">
<text>接口名称</text>
<u--text :lines="1" :text="item.receiveApiName" :size="14"></u--text>
</view>
<view class="content">
<text>源数据</text>
<u--text :lines="1" :text="item.sourceData" :size="14"></u--text>
</view>
<view class="content">
<text>目标数据</text>
<u--text :lines="1" :text="item.targetData" :size="14"></u--text>
</view>
<view class="content">
<text>错误状态</text>
<u--text
:lines="1"
:text="item.errorStatus === '1' ? '需要重新发送' : '不需要重新发送'"
:size="14"
></u--text>
</view>
<view class="content">
<text>返回信息</text>
<u--text :lines="1" :text="item.returnData" :size="14"></u--text>
</view>
<view class="content">
<text>创建时间</text>
<u--text :lines="1" :text="item.createTime" :size="14"></u--text>
</view>
<view class="content">
<text>备注</text>
<u--text :lines="1" :text="item.remark" :size="14"></u--text>
</view>
</view>
<view class="noData" v-show="noData">
<u-divider text="我是有底线哒!" :hairline="true"></u-divider>
</view>
</view>
<view class="plusButton" @click="handlerAddProject">
<u-icon name="plus" :color="'#ffffff'"></u-icon
></view>
<u-toast ref="uToast"></u-toast>
<u-loading-page :loading="loading"></u-loading-page>
<base-tarbar ref="baseTarbar" :pageTitle="'异常信息'"></base-tarbar>
</view>
</template>
<script>
import { authApi } from "@/api/login";
import baseTarbar from "@/components/baseTarbar/index.vue";
export default {
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* 神兽保佑
* 代码无BUG!
*/
components: {
baseTarbar,
},
onReady() {
this.$refs.baseTarbar.currentEnvironment();
this.isOther = this.$refs.baseTarbar.isOther;
if (this.$refs.baseTarbar.isOther) {
this.tarbarHeight = "84rpx";
}
},
data() {
return {
isOther: false,
tarbarHeight: "0",
msgType: "warn",
timer: null,
loading: false,
noData: false,
pageModel: {
pageNum: 1,
pageSize: 20,
sourceData: "",
},
tableData: [],
delBillid: "",
appId: "",
};
},
computed: {
textColor() {
return (item) => {
if (item == "1") {
return { backgroundColor: "#CFCFCF", color: "#333" };
} else if (item == "2") {
return { backgroundColor: "#C6DEFF", color: "#1677FF" };
} else if (item == "3") {
return { backgroundColor: "#D0FFEF", color: "#00B578" };
} else if (item == "4") {
return { backgroundColor: "#FFE5E3", color: "#FF3B30" };
} else {
return { backgroundColor: "#CFCFCF", color: "#333" };
}
};
},
textData() {
return (item) => {
if (item == "1") {
return "待发送";
} else if (item == "2") {
return "发送中";
} else if (item == "3") {
return "发送成功";
} else if (item == "4") {
return "发送失败";
} else {
return null;
}
};
},
},
onShow() {
this.resetTable();
},
//
onPullDownRefresh() {
this.pageModel.pageNum = 1;
this.getTableData();
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
onLoad(option) {
//optionobject
if (Object.getOwnPropertyNames(option).length != 0) {
this.appId = option.appId;
}
uni.$on("resetTable", this.resetTable);
},
onUnload() {
uni.$off("resetTable", this.resetTable);
},
methods: {
resetTable() {
this.pageModel.pageNum = 1;
this.tableData = [];
this.getTableData();
},
//
async getTableData() {
this.noData = false;
this.loading = true;
setTimeout(() => {
this.loading = false;
}, 5000);
let param = {
...this.pageModel,
receiveApp: this.appId,
status: "4",
};
let res = await authApi(
"sysApplicationService",
"application",
"thirdInterfacequeryAppApiLog",
"",
param
);
if (this.pageModel.pageNum > 1) {
this.tableData.push(...res.attribute.list);
} else {
this.tableData = res.attribute.list;
}
if (res.attribute.list.length < 20) {
this.noData = true;
}
this.loading = false;
},
//
onReachBottom() {
if (this.noData != true) {
this.pageModel.pageNum++;
this.getTableData();
}
},
//
handlerSearchEvent() {
if (this.timer !== null) clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.pageModel.pageNum = 1;
this.getTableData();
}, 100);
},
//
handlerShowDetails(row, index) {
let url = "/pages/logsError/show?billid=" + row.id;
this.$tab.navigateTo(url);
},
//
pushDetails(row, index) {
let url = "/pages/logsError/details?billid=" + row.id;
this.$tab.navigateTo(url);
},
},
};
</script>
<style scoped lang="scss">
.itemName {
font-size: 24rpx;
margin: 0 20rpx;
font-weight: 400;
color: #fff;
padding: 2rpx 8rpx;
height: fit-content;
border-radius: 2px;
}
.pushBtn {
width: 19px;
height: 19px;
}
.top-level {
.listContent {
margin: 20rpx 24rpx 0 24rpx;
}
.swipe-action-item {
margin: 20rpx 0 20rpx 0;
}
.listData {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx 20rpx;
margin-bottom: 20rpx;
.head {
// height: 64rpx;
border-bottom: 1px solid #f7f7f7;
justify-content: space-between;
}
.head {
display: flex;
flex-direction: column;
color: #333;
margin-bottom: 16rpx;
padding: 10rpx 0 20rpx 0;
}
.head .itembox {
font-size: 32rpx;
font-weight: 600;
display: flex;
justify-content: space-between;
align-items: center;
.levelbox {
display: flex;
justify-content: center;
align-items: center;
border: 4rpx solid #3c9cff;
border-radius: 50%;
width: 40rpx;
height: 40rpx;
color: #3c9cff;
font-weight: 700;
font-size: 28rpx;
margin: 0 10rpx;
}
}
.head .itemName {
font-size: 24rpx;
color: #999999;
margin-left: 10px;
font-weight: 400;
text {
color: #fff;
padding: 4rpx 8rpx;
}
}
.state {
margin: 25rpx 0;
}
.time {
margin: 4rpx 0 0;
font-size: 28rpx;
flex-wrap: wrap;
line-height: 1.5;
text {
display: inline-block;
font-size: 28rpx;
color: #979797;
margin-bottom: 15rpx;
}
view {
height: 60rpx;
width: 50%;
}
view:nth-child(4) {
text:nth-child(2) {
font-size: 28rpx;
}
}
}
.content {
line-height: 1.5;
font-size: 28rpx;
margin-bottom: 15rpx;
display: flex;
align-items: center;
text {
font-size: 28rpx;
color: #979797;
}
}
}
.noData {
text-align: center;
margin: 20rpx 0 60rpx 0;
}
.Page_change {
width: 100%;
background-color: #fff;
padding: 20rpx 20rpx 20rpx 20rpx;
position: fixed;
top: 0;
z-index: 1;
.buttom {
justify-content: space-between;
padding-top: 30rpx;
::v-deep .u-button--circle {
width: 30%;
}
}
.input_box {
margin-top: 20rpx;
::v-deep .u-input--radius:nth-child(1) {
margin-right: 20rpx;
}
}
}
}
::v-deep .subsetion.u-subsection--button {
height: 70rpx;
margin-top: 10px;
}
::v-deep .u-subsection--button__bar {
background-color: #3c9cff;
}
</style>
<style scoped>
page {
height: 100vh;
}
</style>

BIN
pages/logsError/push.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

310
pages/logsError/show.vue Normal file
View File

@ -0,0 +1,310 @@
<template>
<view class="taskContent">
<u--form
:model="model"
ref="uForm"
:labelAlign="'left'"
:labelStyle="{ fontSize: '28rpx' }"
labelPosition="top"
:style="{ marginTop: tarbarHeight }"
class="formBox"
>
<u-form-item
label="发送者应用"
prop="sendAppName"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.sendAppName"
:disabled="true"
:inputBorder="false"
:styles="{ disableColor: '#ffffff' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="接口名称"
prop="apiName"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.apiName"
:inputBorder="false"
:disabled="true"
:styles="{ disableColor: '#ffffff' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="源数据"
prop="sourceData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.sourceData"
type="textarea"
autoHeight
:disabled="true"
:inputBorder="false"
:maxlength="-1"
:styles="{ disableColor: '#ffffff', paddingLeft: '10px' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="目标数据"
prop="targetData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
>
<uni-easyinput
v-model="model.targetData"
type="textarea"
autoHeight
:styles="{ disableColor: '#ffffff', paddingLeft: '10px' }"
:inputBorder="false"
:maxlength="-1"
:disabled="true"
></uni-easyinput>
</u-form-item>
<u-form-item
label="状态"
prop="status"
ref="item1"
:borderBottom="true"
:labelWidth="'180rpx'"
>
<u--text :lines="1" :text="textData(model.status)" :size="14" style="padding-left:10px;"></u--text>
<!-- <uni-easyinput
v-model="model.status"
:disabled="true"
:inputBorder="false"
:styles="{ disableColor: '#ffffff' }"
></uni-easyinput> -->
</u-form-item>
<u-form-item
label="错误状态"
prop="errorStatus"
ref="item1"
:borderBottom="true"
:labelWidth="'180rpx'"
:disabled="true"
>
<uni-easyinput
v-model="
model.errorStatus === '1' ? '需要重新发送' : '不需要重新发送'
"
:disabled="true"
:inputBorder="false"
:styles="{ disableColor: '#ffffff' }"
></uni-easyinput>
</u-form-item>
<u-form-item
label="返回信息"
prop="returnData"
ref="item1"
required
:borderBottom="true"
:labelWidth="'180rpx'"
:disabled="true"
>
<uni-easyinput
v-model="model.returnData"
type="textarea"
autoHeight
:inputBorder="false"
:disabled="true"
:styles="{ disableColor: '#ffffff' }"
></uni-easyinput>
</u-form-item>
</u--form>
<base-tarbar ref="baseTarbar" pageTitle="查看异常日志"></base-tarbar>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { authApi } from "@/api/login";
import baseTarbar from "@/components/baseTarbar/index.vue";
export default {
onLoad: function (option) {
//optionobject
if (Object.getOwnPropertyNames(option).length != 0) {
this.billID = option.billid;
}
},
components: {
baseTarbar,
},
data() {
return {
billID: "",
tarbarHeight: "0",
radiolist: [
{ id: "1", label: "待发送" },
{ id: "2", label: "发送中" },
{ id: "3", label: "发送成功" },
{ id: "4", label: "发送失败" },
],
errorRadiolist: [
{ id: "1", label: "需要重新发送" },
{ id: "2", label: "不需要重新发送" },
],
model: {},
};
},
computed: {
textData() {
return (item) => {
if (item == "1") {
return "待发送";
} else if (item == "2") {
return "发送中";
} else if (item == "3") {
return "发送成功";
} else if (item == "4") {
return "发送失败";
} else {
return null;
}
};
},
},
onReady() {
this.$refs.baseTarbar.currentEnvironment();
if (this.$refs.baseTarbar.isOther) {
this.tarbarHeight = "84rpx";
}
},
created() {
this.init();
},
methods: {
init() {
this.messageLogGetById(this.billID);
},
//
async messageLogGetById(id, row) {
let params = {
id: id,
// status: row.status,
};
let res = await authApi(
"sysMessageManageLogService",
"messageManage",
"thirdInterfacequeryEntity",
"",
params
);
if (res.status == "200") {
let res2 = await authApi(
"sysApplicationApiService",
"application",
"queryEntity",
"",
{ apiCode: res.attribute.receiveCode }
);
if (res2.status == "200") {
this.$set(res.attribute, "apiName", res2.attribute[0].apiName);
} else {
this.$set(res.attribute, "apiName", "未配置该接口");
}
this.$nextTick(() => {
this.model = {
...res.attribute,
};
});
}
},
async signSuccess() {
let params = {
id: this.billID,
status: "3",
};
let res = await authApi(
"sysMessageManageLogService",
"messageManage",
"updateEntity",
"",
params
);
if (res.status == "200") {
this.$vmNews("标记成功", "success");
this.$refs.uToast.show({
type: "success",
message: "标记成功",
});
setTimeout(() => {
uni.navigateBack();
}, 500);
}
},
async resend() {
let formData = new FormData();
formData.append("id", this.billID);
formData.append("sourceData", this.model.sourceData);
let res = await request({
url: "kangarooDataCenterV3/entranceController/externalCallInterfaceResend",
method: "post",
data: formData,
});
if (res.status == "200") {
this.handleDialogClose();
if (res.msg == "重推成功") {
this.$refs.uToast.show({
type: "success",
message: res.msg,
});
}
if (res.msg == "重推失败") {
this.$refs.uToast.show({
type: "error",
message: res.msg,
});
}
setTimeout(() => {
uni.navigateBack();
}, 500);
}
},
},
};
</script>
<style scoped>
.bottomPage {
width: 100%;
position: fixed;
bottom: 0;
padding: 20rpx 30rpx 30rpx 30rpx;
background-color: #fff;
margin-top: 15rpx;
display: flex;
border-top: 8rpx solid #f1f1f1;
}
.formBox {
padding: 10px 10px 100px 10px;
}
::v-deep .uni-easyinput__content-textarea {
padding-left: 10px !important;
}
::v-deep .uni-easyinput__content.is-disabled {
color: #333333 !important;
}
page {
height: 100vh;
background: #fff;
}
</style>

41
permission.js Normal file
View File

@ -0,0 +1,41 @@
import { getToken } from '@/utils/auth'
// 登录页面
const loginPageH5 = "/pages/login"
const loginPageDingDing = "/pages/loginAuthen/authenDingDing"
const loginPageWeChat = "/pages/loginAuthen/authenWeChat"
// 页面白名单 //页面进行跳转时,会判断是否是白名单页面,如何不是,不运行跳转
const whiteList = [
'/pages/login', '/pages/loginAuthen/authenDingDing', '/pages/loginAuthen/authenWeChat', '/pages/common/webview/index','/pages/loginAuthen/loginDingDing','/pages/loginAuthen/loginWeChat','/pages/loginAuthen/authenDingDingAudit','/pages/loginAuthen/selectCompany'
]
// 检查地址白名单
function checkWhite(url) {
const path = url.split('?')[0]
return whiteList.indexOf(path) !== -1
}
// 页面跳转验证拦截器
let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
list.forEach(item => {
uni.addInterceptor(item, {
invoke(to) {
if (getToken()) {
if (to.url === loginPageH5 || to.url === loginPageDingDing || to.url === loginPageWeChat) {
uni.reLaunch({ url: "/" })
}
return true
} else {
if (checkWhite(to.url)) {
return true
}
// uni.reLaunch({ url: loginPage })
return false
}
},
fail(err) {
console.log(err)
}
})
})

60
plugins/auth.js Normal file
View File

@ -0,0 +1,60 @@
import store from '@/store'
function authPermission(permission) {
const all_permission = "*:*:*"
const permissions = store.getters && store.getters.permissions
if (permission && permission.length > 0) {
return permissions.some(v => {
return all_permission === v || v === permission
})
} else {
return false
}
}
function authRole(role) {
const super_admin = "admin"
const roles = store.getters && store.getters.roles
if (role && role.length > 0) {
return roles.some(v => {
return super_admin === v || v === role
})
} else {
return false
}
}
export default {
// 验证用户是否具备某权限
hasPermi(permission) {
return authPermission(permission)
},
// 验证用户是否含有指定权限,只需包含其中一个
hasPermiOr(permissions) {
return permissions.some(item => {
return authPermission(item)
})
},
// 验证用户是否含有指定权限,必须全部拥有
hasPermiAnd(permissions) {
return permissions.every(item => {
return authPermission(item)
})
},
// 验证用户是否具备某角色
hasRole(role) {
return authRole(role)
},
// 验证用户是否含有指定角色,只需包含其中一个
hasRoleOr(roles) {
return roles.some(item => {
return authRole(item)
})
},
// 验证用户是否含有指定角色,必须全部拥有
hasRoleAnd(roles) {
return roles.every(item => {
return authRole(item)
})
}
}

14
plugins/index.js Normal file
View File

@ -0,0 +1,14 @@
import tab from './tab'
import auth from './auth'
import modal from './modal'
export default {
install(Vue) {
// 页签操作
Vue.prototype.$tab = tab
// 认证对象
Vue.prototype.$auth = auth
// 模态框对象
Vue.prototype.$modal = modal
}
}

74
plugins/modal.js Normal file
View File

@ -0,0 +1,74 @@
export default {
// 消息提示
msg(content) {
uni.showToast({
title: content,
icon: 'none'
})
},
// 错误消息
msgError(content) {
uni.showToast({
title: content,
icon: 'error'
})
},
// 成功消息
msgSuccess(content) {
uni.showToast({
title: content,
icon: 'success'
})
},
// 隐藏消息
hideMsg(content) {
uni.hideToast()
},
// 弹出提示
alert(content) {
uni.showModal({
title: '提示',
content: content,
showCancel: false
})
},
// 确认窗体
confirm(content) {
return new Promise((resolve, reject) => {
uni.showModal({
title: '系统提示',
content: content,
cancelText: '取消',
confirmText: '确定',
success: function(res) {
if (res.confirm) {
resolve(res.confirm)
}
}
})
})
},
// 提示信息
showToast(option) {
if (typeof option === "object") {
uni.showToast(option)
} else {
uni.showToast({
title: option,
icon: "none",
duration: 2500
})
}
},
// 打开遮罩层
loading(content) {
uni.showLoading({
title: content,
icon: 'none'
})
},
// 关闭遮罩层
closeLoading() {
uni.hideLoading()
}
}

30
plugins/tab.js Normal file
View File

@ -0,0 +1,30 @@
export default {
// 关闭所有页面,打开到应用内的某个页面
reLaunch(url) {
return uni.reLaunch({
url: url
})
},
// 跳转到tabBar页面并关闭其他所有非tabBar页面
switchTab(url) {
return uni.switchTab({
url: url
})
},
// 关闭当前页面,跳转到应用内的某个页面
redirectTo(url) {
return uni.redirectTo({
url: url
})
},
// 保留当前页面,跳转到应用内的某个页面
navigateTo(url) {
return uni.navigateTo({
url: url
})
},
// 关闭当前页面,返回上一页面或多级页面
navigateBack() {
return uni.navigateBack()
}
}

BIN
static/daishu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

539
static/font/demo.css Normal file
View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

1614
static/font/demo_index.html Normal file

File diff suppressed because it is too large Load Diff

260
static/font/iconfont.css Normal file
View File

@ -0,0 +1,260 @@
@font-face {
font-family: "iconfont"; /* Project id 4141561 */
src: url('@/static/font/iconfont.ttf') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-biaoqian:before {
content: "\e606";
}
.icon-approval-opinion2:before {
content: "\e60f";
}
.icon-wenjianjiashezhi:before {
content: "\e87a";
}
.icon-banxingshezhi:before {
content: "\e601";
}
.icon-shezhi-jiemianshezhi:before {
content: "\e602";
}
.icon-shiliangzhinengduixiang-:before {
content: "\e6ad";
}
.icon-fl-shuazi:before {
content: "\e619";
}
.icon-danju:before {
content: "\e89b";
}
.icon-lingdang:before {
content: "\e8c0";
}
.icon-laba:before {
content: "\e628";
}
.icon-zhang:before {
content: "\e610";
}
.icon-jiaojieqingkuang:before {
content: "\e600";
}
.icon-bianji:before {
content: "\e621";
}
.icon-shenhe1:before {
content: "\e65d";
}
.icon-gengxinrizhi:before {
content: "\e66b";
}
.icon-caidanguanli:before {
content: "\e66c";
}
.icon-anniuguanli:before {
content: "\e66d";
}
.icon-jihuakanban:before {
content: "\e66e";
}
.icon-hetongjieduandangan:before {
content: "\e66f";
}
.icon-cunhuodangan:before {
content: "\e670";
}
.icon-kehudangan:before {
content: "\e671";
}
.icon-lanjierizhi:before {
content: "\e672";
}
.icon-quanxianguanli:before {
content: "\e674";
}
.icon-fapiaoguanli:before {
content: "\e675";
}
.icon-kaoqinguanli:before {
content: "\e676";
}
.icon-liuchengguanli:before {
content: "\e677";
}
.icon-gongyingshangdangan:before {
content: "\e678";
}
.icon-renwushenhe:before {
content: "\e679";
}
.icon-tubiaoku:before {
content: "\e67a";
}
.icon-sanfangxitong:before {
content: "\e67b";
}
.icon-shujuzidian:before {
content: "\e67c";
}
.icon-wodejihua:before {
content: "\e67d";
}
.icon-shoukuanguanli:before {
content: "\e67e";
}
.icon-shangji:before {
content: "\e67f";
}
.icon-rizhishenhe:before {
content: "\e680";
}
.icon-renwuxiafa:before {
content: "\e681";
}
.icon-woderizhi:before {
content: "\e682";
}
.icon-xiansuo:before {
content: "\e683";
}
.icon-woderenwu:before {
content: "\e684";
}
.icon-yewuyuanzhibiaoshezhi:before {
content: "\e685";
}
.icon-xiangmuxinzeng:before {
content: "\e686";
}
.icon-xiaoshouhetong:before {
content: "\e687";
}
.icon-yonghufankui:before {
content: "\e688";
}
.icon-yongcheguanli:before {
content: "\e689";
}
.icon-xiangmujieduanjihua:before {
content: "\e68a";
}
.icon-xiaoxijilu:before {
content: "\e68b";
}
.icon-yonghuguanli:before {
content: "\e68c";
}
.icon-xiangmuwenti:before {
content: "\e68d";
}
.icon-xiangmuqingdan:before {
content: "\e68e";
}
.icon-xiangmuchakan:before {
content: "\e68f";
}
.icon-shoucangwangzhi:before {
content: "\e690";
}
.icon-yuangongguanhuai:before {
content: "\e691";
}
.icon-zuzhijigou:before {
content: "\e692";
}
.icon-zaixianrenshu:before {
content: "\e693";
}
.icon-zuzhijiagou:before {
content: "\e694";
}
.icon-bugguanli:before {
content: "\e695";
}
.icon-dingshirenwu:before {
content: "\e666";
}
.icon-danjuguanli:before {
content: "\e667";
}
.icon-caozuorizhi:before {
content: "\e668";
}
.icon-chushihuashezhi:before {
content: "\e669";
}
.icon-denglurizhi:before {
content: "\e66a";
}
.icon-loukong:before {
content: "\e673";
}

1
static/font/iconfont.js Normal file

File diff suppressed because one or more lines are too long

443
static/font/iconfont.json Normal file
View File

@ -0,0 +1,443 @@
{
"id": "4141561",
"name": "移动端——公司用安数智中台",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "17930629",
"name": "标签",
"font_class": "biaoqian",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "28174575",
"name": "approval-opinion2",
"font_class": "approval-opinion2",
"unicode": "e60f",
"unicode_decimal": 58895
},
{
"icon_id": "34220364",
"name": "文件夹设置",
"font_class": "wenjianjiashezhi",
"unicode": "e87a",
"unicode_decimal": 59514
},
{
"icon_id": "34586059",
"name": "班型设置",
"font_class": "banxingshezhi",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "35472944",
"name": "设置-界面设置",
"font_class": "shezhi-jiemianshezhi",
"unicode": "e602",
"unicode_decimal": 58882
},
{
"icon_id": "3629124",
"name": "列表空空",
"font_class": "shiliangzhinengduixiang-",
"unicode": "e6ad",
"unicode_decimal": 59053
},
{
"icon_id": "2406018",
"name": "刷子",
"font_class": "fl-shuazi",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "1727362",
"name": "25单据",
"font_class": "danju",
"unicode": "e89b",
"unicode_decimal": 59547
},
{
"icon_id": "1727435",
"name": "211铃铛",
"font_class": "lingdang",
"unicode": "e8c0",
"unicode_decimal": 59584
},
{
"icon_id": "1929807",
"name": "喇叭",
"font_class": "laba",
"unicode": "e628",
"unicode_decimal": 58920
},
{
"icon_id": "7933562",
"name": "章",
"font_class": "zhang",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "4360975",
"name": "交接情况",
"font_class": "jiaojieqingkuang",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "33987167",
"name": "编辑",
"font_class": "bianji",
"unicode": "e621",
"unicode_decimal": 58913
},
{
"icon_id": "31716702",
"name": "审核",
"font_class": "shenhe1",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "36301611",
"name": "更新日志",
"font_class": "gengxinrizhi",
"unicode": "e66b",
"unicode_decimal": 58987
},
{
"icon_id": "36301612",
"name": "菜单管理",
"font_class": "caidanguanli",
"unicode": "e66c",
"unicode_decimal": 58988
},
{
"icon_id": "36301613",
"name": "按钮管理",
"font_class": "anniuguanli",
"unicode": "e66d",
"unicode_decimal": 58989
},
{
"icon_id": "36301614",
"name": "计划看板",
"font_class": "jihuakanban",
"unicode": "e66e",
"unicode_decimal": 58990
},
{
"icon_id": "36301615",
"name": "合同阶段档案",
"font_class": "hetongjieduandangan",
"unicode": "e66f",
"unicode_decimal": 58991
},
{
"icon_id": "36301616",
"name": "存货档案",
"font_class": "cunhuodangan",
"unicode": "e670",
"unicode_decimal": 58992
},
{
"icon_id": "36301617",
"name": "客户档案",
"font_class": "kehudangan",
"unicode": "e671",
"unicode_decimal": 58993
},
{
"icon_id": "36301618",
"name": "拦截日志",
"font_class": "lanjierizhi",
"unicode": "e672",
"unicode_decimal": 58994
},
{
"icon_id": "36301619",
"name": "权限管理",
"font_class": "quanxianguanli",
"unicode": "e674",
"unicode_decimal": 58996
},
{
"icon_id": "36301620",
"name": "发票管理",
"font_class": "fapiaoguanli",
"unicode": "e675",
"unicode_decimal": 58997
},
{
"icon_id": "36301621",
"name": "考勤管理",
"font_class": "kaoqinguanli",
"unicode": "e676",
"unicode_decimal": 58998
},
{
"icon_id": "36301622",
"name": "流程管理",
"font_class": "liuchengguanli",
"unicode": "e677",
"unicode_decimal": 58999
},
{
"icon_id": "36301623",
"name": "供应商档案",
"font_class": "gongyingshangdangan",
"unicode": "e678",
"unicode_decimal": 59000
},
{
"icon_id": "36301624",
"name": "任务审核",
"font_class": "renwushenhe",
"unicode": "e679",
"unicode_decimal": 59001
},
{
"icon_id": "36301625",
"name": "图标库",
"font_class": "tubiaoku",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "36301626",
"name": "三方系统",
"font_class": "sanfangxitong",
"unicode": "e67b",
"unicode_decimal": 59003
},
{
"icon_id": "36301627",
"name": "数据字典",
"font_class": "shujuzidian",
"unicode": "e67c",
"unicode_decimal": 59004
},
{
"icon_id": "36301628",
"name": "我的计划",
"font_class": "wodejihua",
"unicode": "e67d",
"unicode_decimal": 59005
},
{
"icon_id": "36301629",
"name": "收款管理",
"font_class": "shoukuanguanli",
"unicode": "e67e",
"unicode_decimal": 59006
},
{
"icon_id": "36301630",
"name": "商机",
"font_class": "shangji",
"unicode": "e67f",
"unicode_decimal": 59007
},
{
"icon_id": "36301631",
"name": "日志审核",
"font_class": "rizhishenhe",
"unicode": "e680",
"unicode_decimal": 59008
},
{
"icon_id": "36301632",
"name": "任务下发",
"font_class": "renwuxiafa",
"unicode": "e681",
"unicode_decimal": 59009
},
{
"icon_id": "36301633",
"name": "我的日志",
"font_class": "woderizhi",
"unicode": "e682",
"unicode_decimal": 59010
},
{
"icon_id": "36301634",
"name": "线索",
"font_class": "xiansuo",
"unicode": "e683",
"unicode_decimal": 59011
},
{
"icon_id": "36301635",
"name": "我的任务",
"font_class": "woderenwu",
"unicode": "e684",
"unicode_decimal": 59012
},
{
"icon_id": "36301636",
"name": "业务员指标设置",
"font_class": "yewuyuanzhibiaoshezhi",
"unicode": "e685",
"unicode_decimal": 59013
},
{
"icon_id": "36301637",
"name": "项目新增",
"font_class": "xiangmuxinzeng",
"unicode": "e686",
"unicode_decimal": 59014
},
{
"icon_id": "36301638",
"name": "销售合同",
"font_class": "xiaoshouhetong",
"unicode": "e687",
"unicode_decimal": 59015
},
{
"icon_id": "36301639",
"name": "用户反馈",
"font_class": "yonghufankui",
"unicode": "e688",
"unicode_decimal": 59016
},
{
"icon_id": "36301640",
"name": "用车管理",
"font_class": "yongcheguanli",
"unicode": "e689",
"unicode_decimal": 59017
},
{
"icon_id": "36301641",
"name": "项目阶段计划",
"font_class": "xiangmujieduanjihua",
"unicode": "e68a",
"unicode_decimal": 59018
},
{
"icon_id": "36301642",
"name": "消息记录",
"font_class": "xiaoxijilu",
"unicode": "e68b",
"unicode_decimal": 59019
},
{
"icon_id": "36301643",
"name": "用户管理",
"font_class": "yonghuguanli",
"unicode": "e68c",
"unicode_decimal": 59020
},
{
"icon_id": "36301644",
"name": "项目问题",
"font_class": "xiangmuwenti",
"unicode": "e68d",
"unicode_decimal": 59021
},
{
"icon_id": "36301645",
"name": "项目清单",
"font_class": "xiangmuqingdan",
"unicode": "e68e",
"unicode_decimal": 59022
},
{
"icon_id": "36301646",
"name": "项目查看",
"font_class": "xiangmuchakan",
"unicode": "e68f",
"unicode_decimal": 59023
},
{
"icon_id": "36301647",
"name": "收藏网址",
"font_class": "shoucangwangzhi",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "36301648",
"name": "员工关怀",
"font_class": "yuangongguanhuai",
"unicode": "e691",
"unicode_decimal": 59025
},
{
"icon_id": "36301649",
"name": "组织机构",
"font_class": "zuzhijigou",
"unicode": "e692",
"unicode_decimal": 59026
},
{
"icon_id": "36301650",
"name": "在线人数",
"font_class": "zaixianrenshu",
"unicode": "e693",
"unicode_decimal": 59027
},
{
"icon_id": "36301651",
"name": "组织架构",
"font_class": "zuzhijiagou",
"unicode": "e694",
"unicode_decimal": 59028
},
{
"icon_id": "36301652",
"name": "bug管理",
"font_class": "bugguanli",
"unicode": "e695",
"unicode_decimal": 59029
},
{
"icon_id": "36301606",
"name": "定时任务",
"font_class": "dingshirenwu",
"unicode": "e666",
"unicode_decimal": 58982
},
{
"icon_id": "36301607",
"name": "单据管理",
"font_class": "danjuguanli",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "36301608",
"name": "操作日志",
"font_class": "caozuorizhi",
"unicode": "e668",
"unicode_decimal": 58984
},
{
"icon_id": "36301609",
"name": "初始化设置",
"font_class": "chushihuashezhi",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "36301610",
"name": "登录日志",
"font_class": "denglurizhi",
"unicode": "e66a",
"unicode_decimal": 58986
},
{
"icon_id": "36293495",
"name": "镂空",
"font_class": "loukong",
"unicode": "e673",
"unicode_decimal": 58995
}
]
}

BIN
static/font/iconfont.ttf Normal file

Binary file not shown.

BIN
static/font/iconfont.woff Normal file

Binary file not shown.

BIN
static/font/iconfont.woff2 Normal file

Binary file not shown.

BIN
static/images/advance.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/images/audit/0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

BIN
static/images/audit/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

BIN
static/images/audit/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

BIN
static/images/audit/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
static/images/delay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
static/images/empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
static/images/normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/images/profile.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

20
static/index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="shortcut icon" type="image/x-icon" href="<%= BASE_URL %>static/favicon.ico">
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<noscript>
<strong>本站点必须要开启JavaScript才能运行.</strong>
</noscript>
<div id="app"></div>
</html>

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

5142
static/scss/colorui.css Normal file

File diff suppressed because one or more lines are too long

109
static/scss/global.css Normal file
View File

@ -0,0 +1,109 @@
.text-center {
text-align: center;
}
.font-13 {
font-size: 13px;
}
.font-12 {
font-size: 12px;
}
.font-11 {
font-size: 11px;
}
.text-grey1 {
color: #888;
}
.text-grey2 {
color: #aaa;
}
.list-cell-arrow::before {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #c0c0c0;
border-style: solid;
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
position: absolute;
top: 50%;
margin-top: -6px;
right: 30rpx;
}
.list-cell {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #fff;
color: #333;
padding: 26rpx 30rpx;
}
.list-cell:first-child {
border-radius: 8rpx 8rpx 0 0;
}
.list-cell:last-child {
border-radius: 0 0 8rpx 8rpx;
}
.list-cell::after {
content: '';
position: absolute;
border-bottom: 1px solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
}
.menu-list .menu-item-box {
width: 100%;
display: flex;
align-items: center;
}
.menu-list .menu-item-box .menu-icon {
color: #007AFF;
font-size: 16px;
margin-right: 5px;
}
.menu-list .menu-item-box .text-right {
margin-left: auto;
margin-right: 34rpx;
color: #999;
}
.requiredStyle .is-input-border {
border-color: #e6a23c !important;
}
.requiredStyle .u-radio__icon-wrap.u-radio__icon-wrap--circle {
border-color: #e6a23c !important;
}
.contractTitle::before {
content: "";
background: #3c9cff;
display: inline-block;
width: 3px;
height: 17px;
position: relative;
margin-right: 10px;
top: 4px;
}

1
static/scss/global.min.css vendored Normal file
View File

@ -0,0 +1 @@
.text-center{text-align:center}.font-13{font-size:13px}.font-12{font-size:12px}.font-11{font-size:11px}.text-grey1{color:#888}.text-grey2{color:#aaa}.list-cell-arrow::before{content:' ';height:10px;width:10px;border-width:2px 2px 0 0;border-color:#c0c0c0;border-style:solid;-webkit-transform:matrix(0.5, 0.5, -0.5, 0.5, 0, 0);transform:matrix(0.5, 0.5, -0.5, 0.5, 0, 0);position:absolute;top:50%;margin-top:-6px;right:30rpx}.list-cell{position:relative;width:100%;box-sizing:border-box;background-color:#fff;color:#333;padding:26rpx 30rpx}.list-cell:first-child{border-radius:8rpx 8rpx 0 0}.list-cell:last-child{border-radius:0 0 8rpx 8rpx}.list-cell::after{content:'';position:absolute;border-bottom:1px solid #eaeef1;-webkit-transform:scaleY(0.5) translateZ(0);transform:scaleY(0.5) translateZ(0);transform-origin:0 100%;bottom:0;right:0;left:0;pointer-events:none}.menu-list{margin:15px 15px}.menu-list .menu-item-box{width:100%;display:flex;align-items:center}.menu-list .menu-item-box .menu-icon{color:#007AFF;font-size:16px;margin-right:5px}.menu-list .menu-item-box .text-right{margin-left:auto;margin-right:34rpx;color:#999}.requiredStyle .is-input-border{border-color:#e6a23c !important}.requiredStyle .u-radio__icon-wrap.u-radio__icon-wrap--circle{border-color:#e6a23c !important}.contractTitle::before{content:"";background:#3c9cff;display:inline-block;width:3px;height:17px;position:relative;margin-right:10px;top:4px}

110
static/scss/global.scss Normal file
View File

@ -0,0 +1,110 @@
.text-center {
text-align: center;
}
.font-13 {
font-size: 13px;
}
.font-12 {
font-size: 12px;
}
.font-11 {
font-size: 11px;
}
.text-grey1 {
color: #888;
}
.text-grey2 {
color: #aaa;
}
.list-cell-arrow::before {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #c0c0c0;
border-style: solid;
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
position: absolute;
top: 50%;
margin-top: -6px;
right: 30rpx;
}
.list-cell {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #fff;
color: #333;
padding: 26rpx 30rpx;
}
.list-cell:first-child {
border-radius: 8rpx 8rpx 0 0;
}
.list-cell:last-child {
border-radius: 0 0 8rpx 8rpx;
}
.list-cell::after {
content: '';
position: absolute;
border-bottom: 1px solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
.menu-item-box {
width: 100%;
display: flex;
align-items: center;
.menu-icon {
color: #007AFF;
font-size: 16px;
margin-right: 5px;
}
.text-right {
margin-left: auto;
margin-right: 34rpx;
color: #999;
}
}
}
.requiredStyle .is-input-border{
border-color: #e6a23c !important;
}
.requiredStyle .u-radio__icon-wrap.u-radio__icon-wrap--circle{
border-color: #e6a23c !important;
}
.contractTitle {
&::before {
content: "";
background: #3c9cff;
display: inline-block;
width: 3px;
height: 17px;
position: relative;
margin-right: 10px;
top: 4px;
}
}

6
static/scss/index.scss Normal file
View File

@ -0,0 +1,6 @@
// global
@import "./global.scss";
// color-ui
@import "@/static/scss/colorui.css";
// iconfont
@import "@/static/font/iconfont.css";

10
store/getters.js Normal file
View File

@ -0,0 +1,10 @@
const getters = {
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
roles: state => state.user.roles,
permissions: state => state.user.permissions,
selectsdata: state => state.user.selectsdata,
dingcropid: state => state.user.dingcropid,
}
export default getters

15
store/index.js Normal file
View File

@ -0,0 +1,15 @@
import Vue from 'vue'
import Vuex from 'vuex'
import user from '@/store/modules/user'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user
},
getters
})
export default store

111
store/modules/user.js Normal file
View File

@ -0,0 +1,111 @@
import config from '@/config'
import storage from '@/utils/storage'
import constant from '@/utils/constant'
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken,getUserInfo, setUserInfo,removeUserInfo} from '@/utils/auth'
const baseUrl = config.baseUrl
const user = {
state: {
token: getToken(),
name: storage.get(constant.name),
avatar: storage.get(constant.avatar),
roles: storage.get(constant.roles),
permissions: storage.get(constant.permissions),
selectsdata: [],
dingcropid:'',
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
storage.set(constant.name, name)
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
storage.set(constant.avatar, avatar)
},
SET_ROLES: (state, roles) => {
state.roles = roles
storage.set(constant.roles, roles)
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
storage.set(constant.permissions, permissions)
},
SET_SELECTSDATA: (state,selectsdata)=> {
state.selectsdata = selectsdata
},
SET_DINGCROPID: (state,dingcropid)=> {
state.dingcropid = dingcropid
},
},
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => {
setToken(res.attribute.token)
setUserInfo(res.attribute.userInfo)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar
const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName
if (res.roles && res.roles.length > 0) {
commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions)
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
commit('SET_NAME', username)
commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 退出系统
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
commit('SET_TOKEN', '')
removeToken()
removeUserInfo()
storage.clean()
resolve()
// logout(state.token).then(() => {
// commit('SET_TOKEN', '')
// commit('SET_ROLES', [])
// commit('SET_PERMISSIONS', [])
// removeToken()
// storage.clean()
// resolve()
// }).catch(error => {
// reject(error)
// })
})
}
}
}
export default user

65
uni.scss Normal file
View File

@ -0,0 +1,65 @@
/**
* uni-app内置的常用样式变量
*/
@import '@/uni_modules/uview-ui/theme.scss';
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#e5e5e5;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16px;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;

View File

@ -0,0 +1,173 @@
## 3.8.02023-07-29
- 修复父子联动状态下,数据回显父级半选状态不展示问题
- selectChange 返回数据调整
- 新增 contentHeight 、disabledList 属性
- 文档更新
## 3.7.92023-07-11
- 文档更新
## 3.7.82023-07-10
- 修复父元素未完全选中状态显示异常问题
## 3.7.72023-07-07
- 文档更新
## 3.7.62023-07-07
- 重写checkbox解决与colorui样式冲突问题
- 父级添加子级未全选状态,更直观了解选中数据情况
- 样式优化,提取文件内样式变量
- 代码体积优化
## 3.7.52023-05-15
- 修复visible在数据初始化时配置有时失效问题
## 3.7.42023-05-11
- 修复父元素下某个子元素设置隐藏时,父子联动状态异常问题
- 对性能以及代码体积做了进一步优化
## 3.7.32023-05-08
- 修复子元素展开懒加载功能被覆盖问题
- 优化数据初始化速度
## 3.7.22023-05-04
- uni.$emit 替换 bus事件
## 3.7.12023-04-10
- 解决小程序无法折叠或展开问题
## 3.7.02023-04-09
- 全选默认不开启,并且只在多选模式下生效
## 3.6.912023-04-09
- 文档更新
## 3.6.92023-04-09
- 代码整体优化
- 新增弹窗安全区配置选项
- 新增全选功能配置选项
- 新增搜索框清除按钮是否直接重置搜索结果选项
- 遗留问题:小程序端搜索后无法折叠或打开
## 3.6.82023-04-07
- 优化deepClone
## 3.6.72023-04-03
- 取消对微信小程序的支持
## 3.6.62023-04-03
- 修复listData刷新后不能正确渲染勾选状态问题
## 3.6.52023-03-30
- 修复小程序节点展开或折叠时指示箭头不变换状态
- 修复回显数据有时不展示问题
## 3.6.32023-03-27
- [紧急] 修复单选状态仍可以多选bug
## 3.6.22023-03-27
- 修复偶尔出现节点无法根据绑定数据改变选中状态问题
## 3.6.12023-03-24
- 修复引入问题
## 3.6.02023-03-24
- 重构去除冗余代码,功能不变
## 3.5.02023-03-23
- 修复没有子元素时点击报错问题
## 3.3.92023-03-22
- 解决搜索时 toLowerCase 报错问题
## 3.3.82023-03-22
- 懒加载优化
## 3.3.72023-03-20
- 样式更新
## 3.3.62023-03-20
- 修复子元素折叠或展开不触发问题
## 3.3.52023-03-15
- isArray 替换 instanceof
## 3.3.42023-03-11
- 修复搜索后无法展开或折叠问题
- 搜索后直接展开搜索项
## 3.3.32023-03-06
- 优化展示效果
- 添加引导线选项
## 3.3.22023-02-22
- 修复搜索内容包含隐藏数据的问题
- 优化搜索触发方式
## 3.3.12023-02-16
- 修复异常
## 3.2.92023-02-16
- 修复编译到小程序报错问题
## 3.2.82023-02-16
- 修复多个组件key重复问题
## 3.2.72023-02-16
- 全新底层架构设计
- 修改默认配色,更显成熟稳重
## 3.2.62023-02-15
- 修改文档
## 3.2.52023-02-15
- 文档修改
## 3.2.32023-02-15
- 修复小程序组件无法折叠问题
## 3.2.22023-02-10
- 文档更新
## 3.2.12023-02-09
- 增加节点展开和关闭全局配置
- 修复搜索后数据无法展开和关闭问题
- 修复搜索后不能自动滚动到顶部问题
## 3.2.02023-01-16
- 修复事件冲突
## 3.1.52023-01-13
- 样式调整
## 3.1.42023-01-13
- 样式修复
## 3.1.32023-01-13
- 文档更新
## 3.1.22023-01-13
- 修复一些已知问题
## 3.1.12023-01-12
- 解决微信小程序bus事件冲突问题
## 3.1.02023-01-11
- 支持微信小程序
## 3.0.32023-01-10
- 更新文档
## 3.0.22023-01-09
- 修复了一些已知问题
## 3.0.12023-01-09
- 修复了一些已知问题
## 3.0.02023-01-09
- 全面支持懒加载,大量数据也能快速打开
## 2.0.012022-12-29
- 文档修改
## 2.0.02022-12-28
- 添加搜索功能
- 完善文档
## 1.9.22022-12-14
- 修复了一些已知问题
## 1.9.12022-12-14
- 修复了一些已知问题
## 1.9.02022-12-14
- 增加选项禁用、隐藏功能
- 文档添加示例
## 1.8.42022-12-13
- 文档修复
## 1.8.32022-12-09
- 样式调整
## 1.8.22022-12-07
- 修复弹窗不同设备显示高度问题
## 1.8.12022-12-06
- 修复了一些已知问题
## 1.8.02022-12-05
- 修复了一些已知问题
- 图标替换图片
## 1.7.02022-12-05
- 增加 disabled 属性,适用于查看页面
- 修复了一些已知问题
## 1.6.02022-12-05
- 修复了一些已知问题
## 1.5.02022-12-05
- 根据绑定数据类型自动判断返回值类型
- 完善文档
## 1.4.02022-12-02
- 修复了一些已知问题
## 1.3.12022-12-02
- 修复了一些已知问题
## 1.3.02022-12-02
- 修复了一些已知问题
## 1.2.012022-12-02
- 文档更新
## 1.2.02022-12-02
- 添加一键清除功能
- 添加多选、单选功能
## 1.1.02022-12-02
- 支持数据回显、已选数据移除
- 对标 uni-easyinput 默认样式
- 支持更多属性和事件
## 1.0.32022-12-01
- 修改信息
## 1.0.22022-12-01
- 更新文档
## 1.0.12022-12-01
- 更新预览截图
## 1.0.02022-12-01
- 插件更新

View File

@ -0,0 +1,963 @@
<template>
<view class="custom-tree-select-content">
<view
:class="['select-list', { disabled }, { active: selectList.length }]"
@click.stop="open"
:style="{borderColor:requiredStyle ? '#e6a23c':'#e5e5e5'}"
>
<view class="left">
<view v-if="selectList.length" class="select-items" >
<view
class="select-item"
v-for="item in selectedListBaseinfo"
:key="item[dataValue]"
>
<view class="name">
<text>{{ item[dataLabel] }}</text>
</view>
<view
v-if="!disabled && !item.disabled"
class="close"
@click.stop="removeSelectedItem(item)"
>
<uni-icons type="closeempty" size="16" color="#999"></uni-icons>
</view>
</view>
</view>
<view v-else style="color: #6a6a6a" class="no-data">
<text>{{ placeholder }}</text>
</view>
</view>
<view class="right">
<uni-icons
v-if="!selectList.length || !clearable"
type="right"
size="16"
color="#606266"
></uni-icons>
<uni-icons
v-if="selectList.length && clearable"
type="clear"
size="22"
color="#c0c4cc"
@click.native.stop="clear"
></uni-icons>
</view>
</view>
<u-popup
:show="showPopup"
ref="popup"
@close="showPopup = false"
:mode="'bottom'"
:zoom="true"
:safe-area="safeArea"
>
<view
class="popup-content"
:style="{ height: contentHeight || defaultContentHeight }"
>
<view class="title">
<view
v-if="mutiple && canSelectAll"
class="left"
@click.stop="handleSelectAll"
>
<text>{{ isSelectedAll ? "取消全选" : "全选" }}</text>
</view>
<view class="center">
<text style="font-weight: bold">{{ title }}</text>
</view>
<view
class="right"
:style="{ color: confirmTextColor }"
@click.stop="close"
>
<text>{{ confirmText }}</text>
</view>
</view>
<view v-if="search" class="search-box">
<uni-easyinput
:maxlength="-1"
prefixIcon="search"
placeholder="搜索"
v-model="searchStr"
confirm-type="search"
@confirm="handleSearch(false)"
@clear="handleSearch(true)"
:styles="{borderColor:'e5e5e5'}"
>
</uni-easyinput>
<button
type="primary"
size="mini"
class="search-btn"
@click.stop="handleSearch(false)"
>
搜索
</button>
</view>
<view v-if="treeData.length" class="select-content">
<scroll-view
class="scroll-view-box"
:scroll-top="scrollTop"
scroll-y="true"
@touchmove.stop
>
<view v-if="!filterTreeData.length" class="no-data center">
<text>暂无数据</text>
</view>
<data-select-item
v-for="item in filterTreeData"
:key="item[dataValue]"
:node="item"
:dataLabel="dataLabel"
:dataValue="dataValue"
:dataChildren="dataChildren"
:choseParent="choseParent"
:border="border"
:linkage="linkage"
@handleNodeClick="handleNodeClick"
@handleHideChildren="handleHideChildren"
></data-select-item>
<!-- <view class="sentry" /> -->
</scroll-view>
</view>
<view v-else class="no-data center">
<text>暂无数据</text>
</view>
</view>
</u-popup>
</view>
</template>
<script>
const partCheckedSet = new Set();
import { isString, paging } from "./utils";
import dataSelectItem from "./data-select-item.vue";
export default {
name: "custom-tree-select",
components: {
dataSelectItem,
},
model: {
prop: "value",
event: "input",
},
props: {
canSelectAll: {
type: Boolean,
default: false,
},
safeArea: {
type: Boolean,
default: true,
},
search: {
type: Boolean,
default: false,
},
clearResetSearch: {
type: Boolean,
default: false,
},
"is-mask-click": {
type: Boolean,
default: true,
},
"mask-background-color": {
type: String,
default: "rgba(0,0,0,0.4)",
},
"background-color": {
type: String,
default: "none",
},
"safe-area": {
type: Boolean,
default: true,
},
choseParent: {
type: Boolean,
default: true,
},
title: {
type: String,
default: "请选择",
},
placeholder: {
type: String,
default: "请选择",
},
confirmText: {
type: String,
default: "完成",
},
confirmTextColor: {
type: String,
default: "#007aff",
},
contentHeight: {
type: String,
},
disabledList: {
type: Array,
default: () => [],
},
listData: {
type: Array,
default: () => [],
},
dataLabel: {
type: String,
default: "name",
},
dataValue: {
type: String,
default: "id",
},
dataChildren: {
type: String,
default: "children",
},
linkage: {
type: Boolean,
default: false,
},
requiredStyle: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: false,
},
mutiple: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
showChildren: {
type: Boolean,
default: true,
},
border: {
type: Boolean,
default: false,
},
value: {
type: [Array, String],
default: () => [],
},
},
data() {
return {
defaultContentHeight: "400px",
treeData: [],
filterTreeData: [],
clearTimerList: [],
selectedListBaseinfo: [],
showPopup: false,
clickOpenTimer: null,
isSelectedAll: false,
scrollTop: 0,
searchStr: "",
};
},
computed: {
selectList() {
const newVal = this.value === null ? "" : this.value;
return isString(newVal)
? newVal.length
? newVal.split(",")
: []
: newVal.map((item) => item.toString());
},
},
watch: {
listData: {
deep: true,
immediate: true,
handler(newVal) {
if (newVal) {
partCheckedSet.clear();
this.treeData = this.initData(newVal);
if (this.showPopup) {
this.resetClearTimerList();
this.renderTree(this.treeData);
}
}
},
},
value: {
immediate: true,
handler(newVal) {
if (newVal !== null) {
const ids = Array.isArray(newVal)
? newVal
: typeof newVal === "string"
? newVal.split(",")
: [];
this.changeStatus(this.treeData, ids, true);
this.filterTreeData.length &&
this.changeStatus(this.filterTreeData, ids);
}
},
},
//
showPopup: {
deep: true,
handler(newVal, oldVal) {
if (newVal) {
uni.$on("custom-tree-select-node-click", this.handleNodeClick);
uni.$on("custom-tree-select-name-click", this.handleHideChildren);
} else {
uni.$off("custom-tree-select-node-click", this.handleNodeClick);
uni.$off("custom-tree-select-name-click", this.handleHideChildren);
this.resetClearTimerList();
this.searchStr = "";
}
this.change(newVal)
},
},
},
mounted() {
this.getContentHeight(uni.getSystemInfoSync());
},
methods: {
//
goTop() {
this.scrollTop = 10;
this.$nextTick(() => {
this.scrollTop = 0;
});
},
change(data){
this.$emit('change',data)
},
//
getReflectNode(node, arr) {
const array = [...arr];
while (array.length) {
const item = array.shift();
if (item[this.dataValue] === node[this.dataValue]) {
return item;
}
if (item[this.dataChildren]?.length) {
array.push(...item[this.dataChildren]);
}
}
return {};
},
getContentHeight({ screenHeight }) {
this.defaultContentHeight = `${Math.floor(screenHeight * 0.55)}px`;
},
//
handleSearch(isClear = false) {
this.resetClearTimerList();
if (isClear) {
//
if (this.clearResetSearch) {
this.renderTree(this.treeData);
}
} else {
this.renderTree(this.searchValue(this.searchStr, this.treeData));
}
this.goTop();
uni.hideKeyboard();
},
//
searchValue(str, arr) {
const res = [];
arr.forEach((item) => {
if (item.visible) {
if (
item[this.dataLabel]
.toString()
.toLowerCase()
.indexOf(str.toLowerCase()) > -1
) {
res.push(item);
} else {
if (item[this.dataChildren]?.length) {
const data = this.searchValue(str, item[this.dataChildren]);
if (data?.length) {
if (
str &&
!item.showChildren &&
item[this.dataChildren]?.length
) {
item.showChildren = true;
}
res.push({
...item,
[this.dataChildren]: data,
});
}
}
}
}
});
return res;
},
//
renderTree(arr) {
const pagingArr = paging(arr);
this.filterTreeData.splice(
0,
this.filterTreeData.length,
...(pagingArr?.[0] || [])
);
this.lazyRenderList(pagingArr, 1);
},
//
lazyRenderList(arr, startIndex) {
for (let i = startIndex; i < arr.length; i++) {
let timer = null;
timer = setTimeout(() => {
this.filterTreeData.push(...arr[i]);
}, i * 500);
this.clearTimerList.push(() => clearTimeout(timer));
}
},
//
resetClearTimerList() {
const list = [...this.clearTimerList];
this.clearTimerList = [];
list.forEach((fn) => fn());
},
//
open() {
// disaled
if (this.disabled) return;
this.showPopup = true;
this.$nextTick(() => {
this.renderTree(this.treeData);
});
},
//
close() {
this.showPopup = false;
},
//
maskClick() {
this.$emit("maskClick");
},
//
initData(arr, parentVisible) {
if (!Array.isArray(arr)) return [];
const res = [];
for (let i = 0; i < arr.length; i++) {
const obj = {
...arr[i],
[this.dataLabel]: arr[i][this.dataLabel],
[this.dataValue]: arr[i][this.dataValue],
};
obj.checked = this.selectList.includes(
arr[i][this.dataValue].toString()
);
obj.disabled = false;
if (
Boolean(arr[i].disabled) ||
this.disabledList.includes(obj[this.dataValue].toString())
) {
obj.disabled = true;
}
//
obj.partChecked = Boolean(
arr[i].partChecked === undefined ? false : arr[i].partChecked
);
obj.partChecked && obj.partCheckedSet.add(obj[this.dataValue]);
!obj.partChecked && (this.isSelectedAll = false);
const parentVisibleState =
parentVisible === undefined ? true : parentVisible;
const curVisibleState =
arr[i].visible === undefined ? true : Boolean(arr[i].visible);
if (parentVisibleState === curVisibleState) {
obj.visible = parentVisibleState;
} else if (!parentVisibleState || !curVisibleState) {
obj.visible = false;
} else {
obj.visible = true;
}
obj.showChildren =
"showChildren" in arr[i] && arr[i].showChildren != undefined
? arr[i].showChildren
: this.showChildren;
if (arr[i][this.dataChildren]?.length) {
const childrenVal = this.initData(
arr[i][this.dataChildren],
obj.visible
);
obj[this.dataChildren] = childrenVal;
if (
!obj.checked &&
childrenVal.some((item) => item.checked || item.partChecked)
) {
obj.partChecked = true;
partCheckedSet.add(obj[this.dataValue]);
}
}
res.push(obj);
}
return res;
},
//
getChildren(node) {
if (!node[this.dataChildren]?.length) return [];
const res = node[this.dataChildren].reduce((pre, val) => {
if (val.visible) {
return [...pre, val];
}
return pre;
}, []);
for (let i = 0; i < node[this.dataChildren].length; i++) {
res.push(...this.getChildren(node[this.dataChildren][i]));
}
return res;
},
//
getParentNode(target, arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i][this.dataValue] === target[this.dataValue]) {
return true;
}
if (arr[i][this.dataChildren]?.length) {
const childRes = this.getParentNode(
target,
arr[i][this.dataChildren]
);
if (typeof childRes === "boolean" && childRes) {
res = [arr[i]];
} else if (Array.isArray(childRes) && childRes.length) {
res = [...childRes, arr[i]];
}
}
}
return res;
},
// checkbox
handleNodeClick(data, status) {
const node = this.getReflectNode(data, this.treeData);
node.checked = typeof status === "boolean" ? status : !node.checked;
node.partChecked = false;
partCheckedSet.delete(node[this.dataValue]);
//
if (!this.mutiple) {
let emitData = [];
if (node.checked) {
emitData = [node[this.dataValue].toString()];
}
this.$emit(
"input",
isString(this.value) ? emitData.join(",") : emitData
);
} else {
//
if (!this.linkage) {
//
let emitData = null;
if (node.checked) {
emitData = Array.from(
new Set([...this.selectList, node[this.dataValue].toString()])
);
} else {
emitData = this.selectList.filter(
(id) => id !== node[this.dataValue].toString()
);
}
this.$emit(
"input",
isString(this.value) ? emitData.join(",") : emitData
);
} else {
//
let emitData = [...this.selectList];
const parentNodes = this.getParentNode(node, this.treeData);
const childrenVal = this.getChildren(node).filter(
(item) => !item.disabled
);
if (node.checked) {
//
emitData = Array.from(
new Set([...emitData, node[this.dataValue].toString()])
);
if (childrenVal.length) {
emitData = Array.from(
new Set([
...emitData,
...childrenVal.map((item) => item[this.dataValue].toString()),
])
);
//
childrenVal.forEach((childNode) => {
childNode.partChecked = false;
partCheckedSet.delete(childNode[this.dataValue]);
});
}
if (parentNodes.length) {
let flag = false;
//
while (parentNodes.length) {
const item = parentNodes.shift();
if (!item.disabled) {
if (flag) {
//
item.partChecked = true;
partCheckedSet.add(item[this.dataValue]);
} else {
const allChecked = item[this.dataChildren]
.filter((node) => node.visible && !node.disabled)
.every((node) => node.checked);
if (allChecked) {
item.checked = true;
item.partChecked = false;
partCheckedSet.delete(item[this.dataValue]);
emitData = Array.from(
new Set([...emitData, item[this.dataValue].toString()])
);
} else {
item.partChecked = true;
partCheckedSet.add(item[this.dataValue]);
flag = true;
}
}
}
}
}
} else {
//
emitData = emitData.filter(
(id) => id !== node[this.dataValue].toString()
);
if (childrenVal.length) {
//
childrenVal.forEach((childNode) => {
emitData = emitData.filter(
(id) => id !== childNode[this.dataValue].toString()
);
});
}
if (parentNodes.length) {
parentNodes.forEach((parentNode) => {
if (emitData.includes(parentNode[this.dataValue].toString())) {
parentNode.checked = false;
}
emitData = emitData.filter(
(id) => id !== parentNode[this.dataValue].toString()
);
const hasChecked = parentNode[this.dataChildren]
.filter((node) => node.visible && !node.disabled)
.some((node) => node.checked || node.partChecked);
parentNode.partChecked = hasChecked;
if (hasChecked) {
partCheckedSet.add(parentNode[this.dataValue]);
} else {
partCheckedSet.delete(parentNode[this.dataValue]);
}
});
}
}
this.$emit(
"input",
isString(this.value) ? emitData.join(",") : emitData
);
}
}
},
//
handleHideChildren(node) {
const status = !node.showChildren;
this.getReflectNode(node, this.treeData).showChildren = status;
this.getReflectNode(node, this.filterTreeData).showChildren = status;
},
// dataValue
changeStatus(list, ids, needEmit = false) {
const arr = [...list];
let flag = true;
needEmit && (this.selectedListBaseinfo = []);
while (arr.length) {
const item = arr.shift();
if (ids.includes(item[this.dataValue].toString())) {
this.$set(item, "checked", true);
needEmit && this.selectedListBaseinfo.push(item);
//
item.partChecked = false;
partCheckedSet.delete(item[this.dataValue]);
} else {
this.$set(item, "checked", false);
if (item.visible && !item.disabled) {
flag = false;
}
if (partCheckedSet.has(item[this.dataValue])) {
this.$set(item, "partChecked", true);
} else {
this.$set(item, "partChecked", false);
}
}
if (item[this.dataChildren]?.length) {
arr.push(...item[this.dataChildren]);
}
}
this.isSelectedAll = flag;
needEmit && this.$emit("selectChange", [...this.selectedListBaseinfo]);
},
//
removeSelectedItem(node) {
this.isSelectedAll = false;
if (this.linkage) {
this.handleNodeClick(node, false);
this.$emit("removeSelect", node);
} else {
const emitData = this.selectList.filter(
(item) => item !== node[this.dataValue].toString()
);
this.$emit("removeSelect", node);
this.$emit(
"input",
isString(this.value) ? emitData.join(",") : emitData
);
}
},
//
handleSelectAll() {
this.isSelectedAll = !this.isSelectedAll;
if (this.isSelectedAll) {
if (!this.mutiple) {
uni.showToast({
title: "单选模式下不能全选",
icon: "none",
duration: 1000,
});
return;
}
let emitData = [];
this.treeData.forEach((item) => {
if (item.visible || (item.disabled && item.checked)) {
emitData = Array.from(
new Set([...emitData, item[this.dataValue].toString()])
);
if (item[this.dataChildren]?.length) {
emitData = Array.from(
new Set([
...emitData,
...this.getChildren(item)
.filter(
(item) =>
!item.disabled || (item.disabled && item.checked)
)
.map((item) => item[this.dataValue].toString()),
])
);
}
}
});
this.$emit(
"input",
isString(this.value) ? emitData.join(",") : emitData
);
} else {
this.clear();
}
},
//
clear() {
if (this.disabled) return;
const emitData = [];
partCheckedSet.clear();
this.selectedListBaseinfo.forEach((node) => {
if (node.visible && node.checked && node.disabled) {
emitData.push(node[this.dataValue]);
}
});
this.$emit("input", isString(this.value) ? emitData.join(",") : emitData);
},
},
};
</script>
<style lang="scss" scoped>
$primary-color: #007aff;
$col-sm: 3px;
$col-base: 10px;
$col-lg: 12px;
$row-sm: 4px;
$row-base: 10px;
$row-lg: 15px;
$radius-sm: 4px;
$radius-base: 6px;
.custom-tree-select-content {
overflow: hidden;
width: 100%;
.select-list {
padding-left: $row-base;
min-height: 35px;
border: 1px solid #e5e5e5;
border-radius: $radius-sm;
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
&.active {
padding: calc(#{$col-sm} / 2) 0 calc(#{$col-sm} / 2) $row-base;
}
.left {
flex: 1;
.select-items {
display: flex;
flex-wrap: wrap;
}
.select-item {
margin: $col-sm $row-base $col-sm 0;
padding: $col-sm $row-sm;
max-width: auto;
height: auto;
background-color: #eaeaea;
border-radius: $radius-sm;
color: #333;
display: flex;
align-items: center;
.name {
flex: 1;
padding-right: 5px;
font-size: 14px;
}
.close {
width: 18px;
height: 18px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
}
}
.right {
margin-right: $row-sm;
display: flex;
justify-content: flex-end;
align-items: center;
}
&.disabled {
background-color: #f5f7fa;
.left {
.select-item {
.name {
padding: 0;
}
}
}
}
}
.popup-content {
// flex: 1;
background-color: #fff;
// border-top-left-radius: 20px;
// border-top-right-radius: 20px;
display: flex;
flex-direction: column;
.title {
padding: $col-base 3rem;
border-bottom: 1px solid $uni-border-color;
font-size: 14px;
display: flex;
justify-content: space-between;
position: relative;
.left {
position: absolute;
left: 10px;
}
.center {
flex: 1;
text-align: center;
}
.right {
position: absolute;
right: 10px;
}
}
.search-box {
margin: $col-base $row-base 0;
background-color: #fff;
display: flex;
align-items: center;
.search-btn {
margin-left: $row-base;
height: 35px;
line-height: 35px;
}
}
.select-content {
margin: $col-base $row-base;
flex: 1;
overflow: hidden;
position: relative;
}
.scroll-view-box {
touch-action: none;
flex: 1;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.sentry {
height: 48px;
}
}
.no-data {
width: auto;
color: #999 !important;
font-size: 12px;
}
.no-data.center {
text-align: center;
}
}
.requiredBoxItem{
border-color: #e6a23c;
}
</style>

View File

@ -0,0 +1,302 @@
<template>
<view
class="custom-tree-select-content"
:class="{
border:
border &&
node[dataChildren] &&
node[dataChildren].length &&
node.showChildren
}"
:style="{ marginLeft: `${level ? 14 : 0}px` }"
>
<view v-if="node.visible" class="custom-tree-select-item">
<view class="item-content">
<view class="left">
<view
v-if="node[dataChildren] && node[dataChildren].length"
:class="['right-icon', { active: node.showChildren }]"
>
<uni-icons type="right" size="14" color="#333"></uni-icons>
</view>
<!-- <view v-else class="smallcircle-filled">
<uni-icons
class="smallcircle-filled-icon"
type="smallcircle-filled"
size="10"
color="#333"
></uni-icons>
</view> -->
<view
class="name"
:style="node.disabled ? 'color: #999' : ''"
@click.stop="nameClick(node)"
>
<text>{{ node[dataLabel] }}</text>
</view>
</view>
<view
v-if="
choseParent ||
(!choseParent && !node[dataChildren]) ||
(!choseParent && node[dataChildren] && !node[dataChildren].length)
"
:class="['check-box', { disabled: node.disabled }]"
@click.stop="nodeClick(node)"
>
<view
v-if="!node.checked && node.partChecked && linkage"
class="part-checked"
></view>
<uni-icons
v-if="node.checked"
type="checkmarkempty"
size="18"
:color="node.disabled ? '#333' : '#007aff'"
></uni-icons>
</view>
</view>
</view>
<view
v-if="
node.showChildren && node[dataChildren] && node[dataChildren].length
"
>
<data-select-item
v-for="item in listData"
:key="item[dataValue]"
:node="item"
:dataLabel="dataLabel"
:dataValue="dataValue"
:dataChildren="dataChildren"
:choseParent="choseParent"
:border="border"
:linkage="linkage"
:level="level + 1"
></data-select-item>
</view>
</view>
</template>
<script>
import dataSelectItem from './data-select-item.vue'
import { paging } from './utils'
export default {
name: 'data-select-item',
components: {
'data-select-item': dataSelectItem
},
props: {
node: {
type: Object,
default: () => ({})
},
choseParent: {
type: Boolean,
default: true
},
dataLabel: {
type: String,
default: 'name'
},
dataValue: {
type: String,
default: 'value'
},
dataChildren: {
type: String,
default: 'children'
},
border: {
type: Boolean,
default: false
},
linkage: {
type: Boolean,
default: false
},
level: {
type: Number,
default: 0
}
},
data() {
return {
listData: [],
clearTimerList: []
}
},
computed: {
watchData() {
const { node, dataChildren } = this
return {
node,
dataChildren
}
}
},
watch: {
watchData: {
immediate: true,
handler(newVal) {
const { node, dataChildren } = newVal
if (
node.showChildren &&
node[dataChildren] &&
node[dataChildren].length
) {
this.resetClearTimerList()
this.renderTree(node[dataChildren])
}
}
}
},
methods: {
//
renderTree(arr) {
const pagingArr = paging(arr)
this.listData.splice(0, this.listData.length, ...(pagingArr?.[0] || []))
this.lazyRenderList(pagingArr, 1)
},
//
lazyRenderList(arr, startIndex) {
for (let i = startIndex; i < arr.length; i++) {
let timer = null
timer = setTimeout(() => {
this.listData.push(...arr[i])
}, i * 500)
this.clearTimerList.push(() => clearTimeout(timer))
}
},
//
resetClearTimerList() {
const list = [...this.clearTimerList]
this.clearTimerList.splice(0, this.clearTimerList.length)
list.forEach((item) => item())
},
nameClick(node) {
if (
!node.showChildren &&
node[this.dataChildren] &&
node[this.dataChildren].length
) {
//
this.renderTree(node[this.dataChildren])
} else {
//
this.resetClearTimerList()
this.listData.splice(0, this.listData.length)
}
uni.$emit('custom-tree-select-name-click', node)
},
nodeClick(node) {
if (!node.disabled) {
uni.$emit('custom-tree-select-node-click', node)
}
}
},
options: {
styleIsolation: 'shared'
}
}
</script>
<style lang="scss" scoped>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
$primary-color: #007aff;
$col-sm: 4px;
$col-base: 8px;
$col-lg: 12px;
$row-sm: 5px;
$row-base: 10px;
$row-lg: 15px;
$radius-sm: 3px;
$radius-base: 6px;
$border-color: #c8c7cc;
.custom-tree-select-content {
&.border {
border-left: 1px solid $border-color;
}
/deep/ .uni-checkbox-input {
margin: 0 !important;
}
.item-content {
margin: 0 0 $col-lg;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 3px;
background-color: #fff;
transform: translateX(-2px);
z-index: 1;
}
.left {
flex: 1;
display: flex;
align-items: center;
.right-icon {
transition: 0.15s ease;
&.active {
transform: rotate(90deg);
}
}
// .smallcircle-filled {
// width: 14px;
// height: 13.6px;
// display: flex;
// align-items: center;
// .smallcircle-filled-icon {
// transform-origin: center;
// transform: scale(0.55);
// }
// }
.name {
flex: 1;
}
}
}
}
.check-box {
width: 20px;
height: 20px;
border: 1px solid $border-color;
border-radius: $radius-sm;
display: flex;
justify-content: center;
align-items: center;
&.disabled {
background-color: rgb(225, 225, 225);
}
.part-checked {
width: 60%;
height: 2px;
background-color: $primary-color;
}
}
</style>

View File

@ -0,0 +1,17 @@
export function isString(data) {
return typeof data === 'string'
}
// 分页
export function paging(data, PAGENUM = 50) {
if (!Array.isArray(data) || !data.length) return data
const pages = []
data.forEach((item, index) => {
const i = Math.floor(index / PAGENUM)
if (!pages[i]) {
pages[i] = []
}
pages[i].push(item)
})
return pages
}

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