添加uni-modules组件,departSelect

This commit is contained in:
ldeyun 2025-01-12 18:49:20 +08:00
commit f5e9d1e611
557 changed files with 59372 additions and 0 deletions

3
.env.development Normal file
View File

@ -0,0 +1,3 @@
# 开发环境
# 请求接口地址
VITE_REQUEST_BASE_URL = https://36.112.48.190

3
.env.production Normal file
View File

@ -0,0 +1,3 @@
# 生产环境
# 请求接口地址
VITE_REQUEST_BASE_URL = https://36.112.48.190

56
.gitignore vendored Normal file
View File

@ -0,0 +1,56 @@
/unpackage/
/unpackage/cache/apk/__UNI__9F097F0_cm.apk
/unpackage/cache/apk/apkurl
/unpackage/cache/apk/cmManifestCache.json
/unpackage/cache/certdata
/unpackage/cache/wgt/__UNI__9F097F0/app-config-service.js
/unpackage/cache/wgt/__UNI__9F097F0/app-service.js
/unpackage/cache/wgt/__UNI__9F097F0/app.css
/unpackage/cache/wgt/__UNI__9F097F0/manifest.json
/unpackage/cache/wgt/__UNI__9F097F0/pages/checkin/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/document/detail.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/document/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/leave/application.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/login/login.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/meeting/detail.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/meeting/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/product/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/safe/detail.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/safe/manage.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/tab/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/tab/my.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/tab/office.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/talk/conversation.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/talk/message_list.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/talk/system.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/task/handle.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/task/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/task/self.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/task/todotask.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/useredit/add_address.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/useredit/address.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/useredit/addressbook.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/useredit/useredit.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/userlist/index.css
/unpackage/cache/wgt/__UNI__9F097F0/pages/zhiban/index.css
/unpackage/dist/build/app-plus/__uniappautomator.js
/unpackage/dist/build/app-plus/__uniappchooselocation.js
/unpackage/dist/build/app-plus/app-config-service.js
/unpackage/dist/build/app-plus/app-service.js
/unpackage/dist/build/app-plus/app.css
/unpackage/dist/build/app-plus/manifest.json
/unpackage/dist/build/app-plus/pages/document/detail.css
/unpackage/dist/build/app-plus/pages/leave/application.css
/unpackage/dist/build/app-plus/pages/login/login.css
/unpackage/dist/build/app-plus/pages/tab/index.css
/unpackage/dist/build/app-plus/pages/tab/my.css
/unpackage/dist/build/app-plus/pages/useredit/useredit.css
/unpackage/dist/build/app-plus/uni-app-view.umd.js
/unpackage/dist/dev/app-plus/__uniappautomator.js
/unpackage/dist/dev/app-plus/__uniappchooselocation.js
/unpackage/dist/dev/app-plus/app-config-service.js
/unpackage/dist/dev/app-plus/app-service.js
/unpackage/dist/dev/app-plus/app.css
/unpackage/dist/dev/app-plus/manifest.json
/unpackage/dist/dev/app-plus/uni-app-view.umd.js
/node_modules

26
.hbuilderx/launch.json Normal file
View File

@ -0,0 +1,26 @@
{
// launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version" : "0.0",
"configurations" : [
{
"app-plus" :
{
"launchtype" : "local"
},
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
},
{
"playground" : "standard",
"type" : "uni-app:app-android"
}
]
}

13
.vite/deps/_metadata.json Normal file
View File

@ -0,0 +1,13 @@
{
"hash": "5610b5a1",
"browserHash": "3deef0d9",
"optimized": {
"base-64": {
"src": "../../node_modules/base-64/base64.js",
"file": "base-64.js",
"fileHash": "768aae23",
"needsInterop": true
}
},
"chunks": {}
}

117
.vite/deps/base-64.js Normal file
View File

@ -0,0 +1,117 @@
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// ../../../../Documents/HBuilderProjects/B404219-tianranqi/node_modules/base-64/base64.js
var require_base64 = __commonJS({
"../../../../Documents/HBuilderProjects/B404219-tianranqi/node_modules/base-64/base64.js"(exports, module) {
(function(root) {
var freeExports = typeof exports == "object" && exports;
var freeModule = typeof module == "object" && module && module.exports == freeExports && module;
var freeGlobal = typeof global == "object" && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
var InvalidCharacterError = function(message) {
this.message = message;
};
InvalidCharacterError.prototype = new Error();
InvalidCharacterError.prototype.name = "InvalidCharacterError";
var error = function(message) {
throw new InvalidCharacterError(message);
};
var TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g;
var decode = function(input) {
input = String(input).replace(REGEX_SPACE_CHARACTERS, "");
var length = input.length;
if (length % 4 == 0) {
input = input.replace(/==?$/, "");
length = input.length;
}
if (length % 4 == 1 || // http://whatwg.org/C#alphanumeric-ascii-characters
/[^+a-zA-Z0-9/]/.test(input)) {
error(
"Invalid character: the string to be decoded is not correctly encoded."
);
}
var bitCounter = 0;
var bitStorage;
var buffer;
var output = "";
var position = -1;
while (++position < length) {
buffer = TABLE.indexOf(input.charAt(position));
bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
if (bitCounter++ % 4) {
output += String.fromCharCode(
255 & bitStorage >> (-2 * bitCounter & 6)
);
}
}
return output;
};
var encode = function(input) {
input = String(input);
if (/[^\0-\xFF]/.test(input)) {
error(
"The string to be encoded contains characters outside of the Latin1 range."
);
}
var padding = input.length % 3;
var output = "";
var position = -1;
var a;
var b;
var c;
var buffer;
var length = input.length - padding;
while (++position < length) {
a = input.charCodeAt(position) << 16;
b = input.charCodeAt(++position) << 8;
c = input.charCodeAt(++position);
buffer = a + b + c;
output += TABLE.charAt(buffer >> 18 & 63) + TABLE.charAt(buffer >> 12 & 63) + TABLE.charAt(buffer >> 6 & 63) + TABLE.charAt(buffer & 63);
}
if (padding == 2) {
a = input.charCodeAt(position) << 8;
b = input.charCodeAt(++position);
buffer = a + b;
output += TABLE.charAt(buffer >> 10) + TABLE.charAt(buffer >> 4 & 63) + TABLE.charAt(buffer << 2 & 63) + "=";
} else if (padding == 1) {
buffer = input.charCodeAt(position);
output += TABLE.charAt(buffer >> 2) + TABLE.charAt(buffer << 4 & 63) + "==";
}
return output;
};
var base64 = {
"encode": encode,
"decode": decode,
"version": "1.0.0"
};
if (typeof define == "function" && typeof define.amd == "object" && define.amd) {
define(function() {
return base64;
});
} else if (freeExports && !freeExports.nodeType) {
if (freeModule) {
freeModule.exports = base64;
} else {
for (var key in base64) {
base64.hasOwnProperty(key) && (freeExports[key] = base64[key]);
}
}
} else {
root.base64 = base64;
}
})(exports);
}
});
export default require_base64();
/*! Bundled license information:
base-64/base64.js:
(*! https://mths.be/base64 v1.0.0 by @mathias | MIT license *)
*/
//# sourceMappingURL=base-64.js.map

File diff suppressed because one or more lines are too long

3
.vite/deps/package.json Normal file
View File

@ -0,0 +1,3 @@
{
"type": "module"
}

80
App.vue Normal file
View File

@ -0,0 +1,80 @@
<script setup>
import {
useUpdateApp
} from '@/store/update.js';
import {
cxcJurisdictionApi
} from '@/api/api.js';
import {
onLaunch,
onShow
} from "@dcloudio/uni-app";
import {
getLocation,
getWeather,
} from './utils/index.js';
import {
useStore
} from '@/store';
import {
ref
} from 'vue';
onLaunch(() => {
//
useUpdateApp().checkAppUpdate()
//
getLocation()
})
onShow(() => {
//
ifGray()
})
const ifGray = () => {
cxcJurisdictionApi({
id: "1827997127165677570"
}).then((res) => {
// console.log(res)
// 1
if (res.success) {
const store = useStore()
uni.setStorageSync('isgray', res.result.value)
store.setIsgray(res.result.value)
}
})
}
</script>
<style lang="scss">
/*每个页面公共css */
.gray {
filter: grayscale(1);
}
.f-row {
display: flex;
flex-direction: row;
}
.f-col {
display: flex;
flex-direction: column;
}
.jca {
justify-content: space-around;
}
.jce {
justify-content: space-evenly;
}
.jcb {
justify-content: space-between;
}
.aic {
align-items: center;
}
</style>

20
README.md Normal file
View File

@ -0,0 +1,20 @@
数智产销APP正式版
发布需要在pages/login/login.vue中
```javascript
localLoginApi({
username: username.value,
password: password.value,
captcha: 'app'
```
改成
```javascript
loginApi({
username: un,
password: pw,
ip: getDeviceIp()
```

271
api/api.js Normal file
View File

@ -0,0 +1,271 @@
import {
https
} from '@/utils/http.js';
export function taskListApi(config) { // 我的任务列表
return https({
url: '/act/task/list',
method: 'get',
data: config
})
}
export function taskHistoryListApi(config) { // 我的历史任务列表
return https({
url: '/act/task/taskHistoryList',
method: 'get',
data: config
})
}
export function myApplyProcessListApi(config) { // 本人发起列表
return https({
url: '/act/task/myApplyProcessList',
method: 'get',
data: config
})
}
export function taskEntrustApi(config) { // 任务委托操作
return https({
url: '/act/task/taskEntrust',
method: 'put',
data: config
})
}
export function getProcessNodeInfoApi(config) { // 办理任务节点信息获取
return https({
url: '/process/extActProcessNode/getProcessNodeInfo',
method: 'get',
data: config
})
}
export function getHisProcessNodeInfoApi(config) { // 历史任务详情
return https({
url: '/process/extActProcessNode/getHisProcessNodeInfo',
method: 'get',
data: config
})
}
export function queryMyDeptTreeListApi(config) { // 部门
return https({
url: '/sys/sysDepart/queryTreeList',
method: 'get',
data: config
})
}
export function userListApi(config) { // 所有人员列表
return https({
url: '/sys/user/userList',
method: 'get',
data: config
})
}
export function queryUserByDepIdApi(config) { // 根据部门id查询该部门下的人员列表
return https({
url: '/sys/user/queryUserByDepId',
method: 'get',
data: config
})
}
export function indexChartScdtDataApi(config) { // 首页
return https({
url: '/scdt.cxcscdtjldrb/cxcScdtJldRb/indexChartScdtData',
method: 'get',
data: config
})
}
export function bpmlistApi(config) { // 公文
return https({
url: '/cxcoagwfb/cxcOaGwfb/bpmlist',
method: 'get',
data: config
})
}
export function gonggaolistApi(config) { // 公告
return https({
url: '/cxctz/cxcTz/list',
method: 'get',
data: config
})
}
export function zhibanQueryApi(config) { // 值班按月查看
return https({
url: '/zhgl_zbgl/zhglZbglZbb/list',
method: 'get',
data: config
})
}
export function zhibanApi(config) { // 首页值班
return https({
url: '/zhgl_zbgl/zhglZbglZbb/homepageList',
method: 'get',
data: config
})
}
export function faguiApi(config) { // 法规
return https({
url: '/cxcoaflgf/cxcOaFlgf/zslist',
method: 'get',
data: config
})
}
export function cjzhiduApi(config) { // 上级制度
return https({
url: '/cxcjyglsjzdgl/cxcJyglSjzdgl/zslist',
method: 'get',
data: config
})
}
export function zhiduApi(config) { // 厂级制度
return https({
url: '/cxczd/cxcZdgl/list',
method: 'get',
data: config
})
}
export function huiyilistApi(config) { // 会议
return https({
url: '/appConnet/app/list',
method: 'get',
data: config
})
}
export function huiyiDetailApi(config) { // 会议详情
return https({
url: '/zhgl_hygl/zhglHyglHyyc/listbymainid',
method: 'get',
data: config
})
}
export function userProfileApi(config) { // 用户信息
return https({
url: '/sys/user/userList',
method: 'get',
data: config
})
}
export function userEditApi(config) { // 用户编辑
return https({
url: '/sys/user/editApp',
method: 'PUT',
data: config
})
}
export function extActFlowDataApi(config) { // 获取审批流程所需参数
return https({
url: '/process/extActFlowData/getProcessInfo',
method: 'get',
data: config
})
}
export function processHistoryListApi(config) { // 审批流程
return https({
url: '/act/task/processHistoryList',
method: 'get',
data: config
})
}
export function startMutilProcessApi(config) { // 发起流程
return https({
url: '/process/extActProcess/startMutilProcess',
method: 'post',
data: config
})
}
export function processCompleteApi(config) { // 流程办理
return https({
url: '/act/task/processComplete',
method: 'post',
data: config
})
}
export function claimApi(config) { // 流程签收
return https({
url: '/act/task/claim',
method: 'put',
data: config
})
}
export function callBackProcessApi(config) { // 流程取回
return https({
url: '/act/task/callBackProcess',
method: 'put',
data: config
})
}
export function invalidProcessApi(config) { // 流程作废
return https({
url: '/act/task/invalidProcess',
method: 'put',
data: config
})
}
export function getDictItemsApi(dictCode) { // 字典标签专用
return https({
url: `/sys/dict/getDictItems/${dictCode}`,
method: 'get'
})
}
export function getCategoryItemsApi(pid) { // 分类字典专用
return https({
url: '/sys/category/findtree',
method: 'get',
data: {
pid
}
})
}
export function getProcessTaskTransInfoApi(config) { //
return https({
url: '/act/task/getProcessTaskTransInfo',
method: 'get',
data: config
})
}
export function upDateAppApi(config) { // 更新
return https({
url: '/sys/common/upDateApp',
method: 'get',
data: config
})
}
export function cxcDapingApi(config) { // 首页图片
return https({
url: '/CxcDaping/cxcDaping/list',
method: 'get',
data: config
})
}
export function dbSxxqQueryByIdApi(config) { // 督办事项详情
return https({
url: '/cxcdbxt/dbSxxq/queryById',
method: 'get',
data: config
})
}
export function dbJbxxQueryByIdApi(config) { // 督办基本信息
return https({
url: '/cxcdbxt/dbJbxx/queryById',
method: 'get',
data: config
})
}
export function cxcJurisdictionApi(config) { // 是否灰化
return https({
url: '/CxcJurisdiction/cxcJurisdiction/queryById',
method: 'get',
data: config
})
}

23
api/depart.js Normal file
View File

@ -0,0 +1,23 @@
import {
https
} from '@/utils/http.js';
export function queryDepByCode(code) { // 获取部门数据
return https({
url: '/sys/sysDepart/queryDepNameByDepCode',
method: 'get',
data: {
code
}
})
}
export function queryZbDepByLdhth(ldhth) { // 获取人员主表中人员部门
return https({
url: '/sys/sysDepart/queryZbDepByLdhth',
method: 'get',
data: {
ldhth
}
})
}

29
api/login.js Normal file
View File

@ -0,0 +1,29 @@
import { https } from '@/utils/http.js';
export function loginApi(config) { // 登录
return https({
url: '/sys/sinopecLogin',
method: 'post',
data: config
})
}
export function localLoginApi(config) { // 本地登录
return https({
url: '/sys/login',
method: 'post',
data: config
})
}
export function queryRoleApi(config) { // 获取角色职位
return https({
url: '/appConnet/app/queryRoleByRoleIds',
method: 'get',
data: config
})
}
export function getUserPermissionApi(config) { // 获取权限
return https({
url: '/sys/permission/getUserPermissionByToken',
method: 'get',
data: config
})
}

29
api/pages.js Normal file
View File

@ -0,0 +1,29 @@
import {
https
} from '@/utils/http.js';
export function qjAddApi(config) { // 发起请假流程申请
return https({
url: '/CxcQxj/cxcQxj/add',
method: 'post',
data: config
})
}
export function queryZwmcAndExaApi(username) { // 根据username获取职位名称和审批领导列表
return https({
url: '/CxcQxj/cxcQxj/queryZwmcByUsername',
method: 'get',
data: {
username
}
})
}
export function qjQueryByIdApi(config) { // 通过id查询请假数据 流程用
return https({
url: '/CxcQxj/cxcQxj/queryById',
method: 'get',
data: config
})
}

12
api/renyuan.js Normal file
View File

@ -0,0 +1,12 @@
import {
https
} from '@/utils/http.js';
export function queryRenyuanByDepartID(orgCode) { // 获取部门所有人员信息
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/list',
method: 'get',
data: orgCode
})
}

36
bpm/customNav.vue Normal file
View File

@ -0,0 +1,36 @@
<template>
<view class="">
<view class="nav ">
<slot></slot>
</view>
<view class="place">
</view>
</view>
</template>
<script setup>
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = (statusHeight + 44) + "px";
</script>
<style lang="scss" scoped>
.nav {
width: calc(100% - 60rpx);
padding: 0 30rpx;
height: v-bind(cusnavbarheight);
background: linear-gradient(270deg, #256FBC 0%, #044D87 100%);
font-size: 24rpx;
color: #FFFFFF;
position: fixed;
top: 0;
left: 0;
z-index: 99;
}
.place {
height: v-bind(cusnavbarheight);
}
</style>

143
bpm/dataCom.vue Normal file
View File

@ -0,0 +1,143 @@
<template>
<view class="">
<view class="info">
<view class="item_box">
<view class="item">
<view class="title_box f-row aic jcb">
<view class="title">
{{title}}
</view>
<view class="f-row aic more" v-if="list.length>6" @click="open=!open">
<text>{{!open?'展开':'收起'}}</text>
<uni-icons type="down" color="#999999" v-if="!open"></uni-icons>
<uni-icons type="up" color="#999999" v-else></uni-icons>
</view>
</view>
<view :class="['data_wrapper',{'close':list.length>6&&open}]">
<view class="data_box f-row aic ">
<view class="data f-col aic" v-for="item,i in list">
<view class="">
{{item?.dailyVolume}}
</view>
<text>{{item.gas}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
computed,
watch,
nextTick
} from 'vue';
const props = defineProps({
title: {
type: String,
default: ''
},
list: {
type: Array,
default: function() {
return []
}
},
})
const open = ref(false)
const moreHeight = ref(null)
watch(() => props.list, () => {
nextTick(() => {
uni.createSelectorQuery().select('.data_box').boundingClientRect(data => {
moreHeight.value = (data?.height || 0) + 'px'
}).exec()
})
}, {
immediate: true
})
</script>
<style>
page {
background-color: #F8F8F8;
}
</style>
<style lang="scss" scoped>
.data_wrapper {
height: 288rpx;
transition: all .3s;
overflow: hidden;
}
.close {
height: v-bind(moreHeight);
}
.info {
.item_box {
.item {
width: 690rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx 0;
margin-top: 24rpx;
.title_box {
padding: 0 30rpx;
margin-bottom: -20rpx;
}
.title {
font-size: 28rpx;
color: #333333;
background-image: url('../../static/index/line.png');
background-size: 44rpx 13rpx;
background-repeat: no-repeat;
background-position: left bottom;
}
.more {
font-size: 24rpx;
color: #999999;
text {
margin-right: 6rpx;
}
}
.data_box {
flex-wrap: wrap;
.data {
width: 33.33%;
margin-top: 60rpx;
height: 80rpx;
view {
font-size: 32rpx;
color: #333333;
margin-bottom: 8rpx;
}
text {
font-size: 24rpx;
color: #333333;
}
}
}
}
}
}
</style>

203
bpm/extendCom.vue Normal file
View File

@ -0,0 +1,203 @@
<template>
<view class="content">
<view class="todo f-col aic">
<view class="f-col aic">
<view class="title_box f-row aic jcb" @click="tolist('')">
<view class="title f-row aic">
<image :src="`/static/my/${img}.png`" mode=""></image>
{{title}}
</view>
<view class="num">
{{total}}
</view>
</view>
<view class="list" v-if="list.length">
<view :class="['box',{'close':list.length>5&&open}]">
<view class="item_box">
<view @click="tolist(item.title)" class="item f-row aic" v-for="item,i in list" :key="i">
<view class="">
{{item.title}}
</view>
<text>{{item.num}}</text>
</view>
</view>
</view>
<view class="more" v-show="list.length>5" @click="open = !open">
{{!open?'显示更多':'收起'}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted,
nextTick,
computed,
watch,
getCurrentInstance
} from 'vue';
import {
beforeJump
} from '@/utils/index.js';
const props = defineProps({
title: {
type: String,
default: ''
},
img: {
type: String,
default: ''
},
list: {
type: Array,
default: function() {
return []
}
},
total: {
type: Number,
default: 0
},
type:{
type: String,
default: ''
}
})
const open = ref(false)
const moreHeight = ref(null)
const CurrentInstance = getCurrentInstance()
watch(() => props.list, () => {
nextTick(() => {
uni.createSelectorQuery().in(CurrentInstance.proxy).select('.item_box')
.boundingClientRect(data => {
moreHeight.value = data?.height + 'px'
}).exec()
})
}, {
immediate: true
})
const tolist = (title) => {
let id = null
beforeJump('/pages/task/index', () => {
if (props.type == '0') {
id = 0
}
if (props.type == '1') {
id = 1
}
if (props.type == '2') {
return uni.navigateTo({
url: `/pages/task/self?title=${title}`
})
}
uni.navigateTo({
url: `/pages/task/index?id=${id}&title=${title}`
})
})
}
</script>
<style>
page {
background-color: #F8F8F8;
}
</style>
<style lang="scss" scoped>
.content {
padding-top: 30rpx;
}
.todo {
.title_box {
width: 630rpx;
height: 108rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 0rpx rgba(0, 0, 0, 0.16);
border-radius: 16rpx;
padding: 0 30rpx;
.title {
image {
width: 48rpx;
height: 48rpx;
}
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.num {
width: 54rpx;
height: 54rpx;
background: url('../../static/my/num.png') no-repeat;
background-size: 54rpx 54rpx;
font-size: 24rpx;
color: #FFFFFF;
text-align: center;
line-height: 54rpx;
}
}
.list {
width: 570rpx;
padding: 20rpx 30rpx 30rpx 30rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 0rpx rgba(0, 0, 0, 0.16);
border-radius: 0rpx 0rpx 16rpx 16rpx;
.box {
max-height: 120rpx;
transition: all .3s;
overflow: hidden;
.item_box {
display: flex;
flex-wrap: wrap;
}
.item {
font-size: 28rpx;
height: 60rpx;
width: 50%;
view {
color: #666666;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
}
text {
color: #ED361D;
margin: 0 10rpx;
}
}
}
.close {
// height: 300rpx;
max-height: v-bind(moreHeight);
}
.more {
font-size: 28rpx;
color: #008DFF;
text-decoration: underline;
margin-top: 20rpx;
}
}
}
</style>

View File

@ -0,0 +1,320 @@
<template>
<view class="f-col aic">
<view class="info_box">
<view class="title">
申请信息
</view>
<view class="info f-row aic jcb">
<view>
请假职工
</view>
<text>{{info.username_dictText}}</text>
</view>
<view class="info f-row aic jcb">
<view>
所属单位
</view>
<text>{{info.sysOrgCode_dictText}}</text>
</view>
<view class="info f-row aic jcb">
<view>
联系方式
</view>
<text>{{info.phone}}</text>
</view>
<view class="info f-row aic jcb">
<view>
请假类型
</view>
<text>{{info.type}}</text>
</view>
<view class="info f-row aic jcb">
<view>
请假开始时间
</view>
<text>{{info.begintime}}</text>
</view>
<view class="info f-row aic jcb">
<view>
请假结束时间
</view>
<text>{{info.endtime}}</text>
</view>
<view class="info f-row aic jcb">
<view>
请假天数
</view>
<text>{{info.days}}</text>
</view>
<view class="info f-row aic jcb">
<view>
审批人
</view>
<text>{{info.examineleader_dictText}}</text>
</view>
<view class="info f-row aic jcb">
<view>
出发地
</view>
<text>{{info.departure}}</text>
</view>
<view class="info f-row aic jcb">
<view>
目的地
</view>
<text>{{info.destination}}</text>
</view>
<view class="info f-row aic jcb">
<view>
请假原因
</view>
<text>{{info.reason}}</text>
</view>
<view class="info f-row aic jcb" v-if="ifShowFj">
<view>
附件
</view>
<uni-file-picker v-model="imageValue" :image-styles="imageStyles" />
</view>
</view>
</view>
<view class="f-col aic">
<view class="progress">
<view class="title">
审批流程
</view>
<view class="progress_box">
<view class="box" v-for="(item,index) in step" :key="index">
<view class="topic f-row aic">
<view>
{{item.name}}
</view>
<view
:class="['status',{'complete':item.deleteReason=='已完成'},{'refuse':item.deleteReason=='已拒绝'}]">
{{item.deleteReason}}
</view>
</view>
<view class="name_time">
{{item.assigneeName}} | {{item.endTime}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
extActFlowDataApi,
processHistoryListApi
} from '@/api/api.js';
import {
qjQueryByIdApi
} from '@/api/pages.js';
import {
ref,
onBeforeMount,
watch,
onMounted
} from 'vue'
import {
imgUrl
} from '@/utils/index.js';
const props = defineProps({
dataId: {
type: String,
default: ''
},
})
const imageValue = ref([])
const ifShowFj = ref(false)
const imageStyles = {
width: 64,
height: 64,
border: {
color: "#dce7e1",
width: 2,
style: 'dashed',
radius: '2px'
}
}
const info = ref({})
//
const qjQueryById = () => {
qjQueryByIdApi({
id: props.dataId
}).then((res) => {
if (res.success) {
info.value = res.result.records[0]
// imageValue
if (info.value.path) {
ifShowFj.value = true;
imageValue.value = info.value.path.split(',').map(path => {
const name = path.split('/').pop(); //
const extname = name.split('.').pop(); //
return {
name,
extname,
url: imgUrl(path)
};
});
}
}
})
}
/**审批步骤*/
const extActFlowData = () => {
extActFlowDataApi({
flowCode: "dev_cxc_qxj",
dataId: props.dataId
}).then((res) => {
if (res.success) {
processHistoryList(res.result.processInstanceId)
}
})
}
const step = ref([])
const processHistoryList = (processInstanceId) => {
processHistoryListApi({
processInstanceId
}).then((res) => {
if (res.success) {
step.value = res.result.records
}
})
}
// watch(() => props.dataId, (nval, oval) => {
// if (nval) {
// qjQueryById()
// extActFlowData()
// }
// })
onMounted(() => {
qjQueryById()
extActFlowData()
})
</script>
<style lang="scss" scoped>
.info_box {
padding: 40rpx 30rpx 16rpx 30rpx;
width: 630rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
margin-top: 30rpx;
.title {
font-size: 28rpx;
color: #333333;
background-image: url(../../static/index/line.png);
background-size: 44rpx 12rpx;
background-repeat: no-repeat;
background-position: left bottom;
margin-bottom: 30rpx;
}
.info {
font-size: 28rpx;
margin-bottom: 24rpx;
view {
color: #666666;
}
text {
color: #333333;
}
}
}
.progress {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
width: 630rpx;
padding: 40rpx 30rpx 16rpx 30rpx;
margin-top: 30rpx;
margin-bottom: 30rpx;
.status {
padding: 4rpx 8rpx;
display: inline-block;
color: #FFFFFF;
font-size: 20rpx;
margin-left: 8rpx;
border-radius: 8rpx;
}
.complete {
background-color: #7AC756;
}
.refuse {
background-color: #FE4600;
}
.title {
font-size: 28rpx;
color: #333333;
background-image: url(../../static/index/line.png);
background-size: 44rpx 12rpx;
background-repeat: no-repeat;
background-position: left bottom;
margin-bottom: 40rpx;
}
// .box:not(:first-child) {
// padding-top: 60rpx;
// }
.box:not(:last-child) {
position: relative;
padding-bottom: 60rpx;
&::before {
position: absolute;
content: ' ';
width: 1px;
height: 100%;
background: #efefef;
left: -42rpx;
top: 10rpx;
}
}
.box {
margin-left: 50rpx;
.topic {
position: relative;
font-size: 28rpx;
color: #333333;
&::before {
position: absolute;
content: ' ';
width: 18rpx;
height: 18rpx;
background: #01508B;
border-radius: 14rpx;
left: -50rpx;
top: 50%;
transform: translateY(-50%);
}
}
.name_time {
font-size: 24rpx;
color: #888888;
margin-top: 12rpx;
}
}
}
</style>

62
bpm/processCom.vue Normal file
View File

@ -0,0 +1,62 @@
<template>
<view class="f-col aic">
<view class="info_box">
<view class="title">
申请信息
</view>
<view class="" v-for="item,i in info" :key="i">
<view class="info f-row aic jcb">
<view class="">
{{item.title}}
</view>
<rich-text :nodes="item.data" v-if="item.title=='事项内容'"></rich-text>
<text v-else>{{item.data}}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
info: {
type: Array,
default: () => []
}
})
</script>
<style scoped lang="scss">
.info_box {
padding: 40rpx 30rpx 16rpx 30rpx;
width: 630rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
margin-top: 30rpx;
.title {
font-size: 28rpx;
color: #333333;
background-image: url(../../static/index/line.png);
background-size: 44rpx 12rpx;
background-repeat: no-repeat;
background-position: left bottom;
margin-bottom: 30rpx;
}
.info {
font-size: 28rpx;
margin-bottom: 24rpx;
view {
color: #666666;
}
text {
color: #333333;
}
}
}
</style>

54
bpm/safeCom.vue Normal file
View File

@ -0,0 +1,54 @@
<template>
<view class="list f-row aic jcb">
<view class="item" v-for="item,i in 20" :key="i" @click="jump('/pages/safe/detail')">
<view class="">
<image src="" mode=""></image>
</view>
<view class="text">
五月天突然好想你线上演唱会精彩回放
</view>
</view>
</view>
</template>
<script setup>
import {
beforeJump
} from '@/utils/index.js';
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
</script>
<style lang="scss" scoped>
.list {
flex-wrap: wrap;
.item {
width: 340rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
margin-top: 20rpx;
font-size: 28rpx;
color: #333333;
line-height: 40rpx;
.text {
padding: 16rpx;
}
image {
width: 340rpx;
height: 200rpx;
border-radius: 16rpx 16rpx 0 0;
background-color: #efefef;
display: block;
}
}
}
</style>

331
bpm/supervise.vue Normal file
View File

@ -0,0 +1,331 @@
<template>
<view class="">
<view class="tab f-row aic">
<view :class="{'active':currentTab==item.id}" v-for="item,i in tabArr" :key="i" @click="changeTab(item.id)">
{{item.title}}
</view>
</view>
<processCom :info="info"></processCom>
<view class="f-col aic">
<view class="progress">
<view class="title">
审批流程
</view>
<view class="progress_box">
<view class="box" v-for="(item,index) in step" :key="index">
<view class="topic f-row aic">
<view class="">
{{item.name}}
</view>
<view
:class="['status',{'complete':item.deleteReason=='已完成'},{'refuse':item.deleteReason=='已拒绝'}]">
{{item.deleteReason}}
</view>
</view>
<view class="name_time">
{{item.assigneeName}} | {{item.endTime}}
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
dbSxxqQueryByIdApi,
dbJbxxQueryByIdApi,
extActFlowDataApi,
processHistoryListApi
} from '@/api/api.js';
import processCom from './processCom.vue';
import {
ref,
onBeforeMount,
watch,
onMounted
} from 'vue';
const props = defineProps({
dataId: {
type: String,
default: ''
}
})
const tabArr = [{
title: '基本信息',
id: 1
}, {
title: '事项详情',
id: 2
}, {
title: '添加下级',
id: 3
}, {
title: '节点顺序',
id: 4
}, {
title: '运行计划',
id: 5
}]
const currentTab = ref(1)
const changeTab = (id) => {
currentTab.value = id
dbSxxqQueryById()
}
const info = ref([])
/**事项详情*/
const dbSxxqQueryById = () => {
dbSxxqQueryByIdApi({
id: props.dataId
}).then((res) => {
if (res.success) {
if(currentTab.value==1){
dbJbxxQueryById(res.result.jbxxid)
}
if(currentTab.value==2){
let d = res.result
info.value = [{
title: '承办部门',
data: d.zbdw
}, {
title: '协办部门',
data: d.xbdw
}, {
title: '部门领导',
data: d.fgld
}, {
title: '办理人员',
data: d.dbry
}, {
title: '要求反馈时间',
data: d.yqfksj
}, {
title: '节点名称',
data: ''
}, {
title: '预计完成时间',
data: ''
}, {
title: '实际反馈时间',
data: d.sjfksj
}, {
title: '自评价',
data: d.zpj
}, {
title: '发起时间',
data: d.fqsj
}, {
title: '序号',
data: ''
}, {
title: '概述',
data: ''
}, {
title: '时间进度',
data: ''
}, {
title: '事项内容',
data: d.sxnr
}]
}
}
})
}
/**基本信息*/
const dbJbxxQueryById = (id) => {
dbJbxxQueryByIdApi({
id
}).then((res) => {
if (res.success) {
let d = res.result
info.value = [{
title: '督办分类',
data: d.fl
}, {
title: '协办部门',
data: d.xbbm
}, {
title: '督办部门',
data: d.cbbm
}, {
title: '督办人员',
data: d.dbry
}, {
title: '督办部门负责人',
data: d.zrr
}, {
title: '是否涉密',
data: d.sfsm
}, {
title: '计划完成时间',
data: d.jhwcsj
}, {
title: '实际完成时间',
data: d.wcsj
}, {
title: '完成状态',
data: d.wczt
}, {
title: '备注',
data: d.bz
}, {
title: '督办事项',
data: d.dbsx
}, {
title: '时间进度',
data: d.sjjd
}]
}
})
}
const extActFlowData = (dataId) => {
extActFlowDataApi({
flowCode: "dev_db_sxxq_001",
dataId: props.dataId
}).then((res) => {
if (res.success) {
processHistoryList(res.result.processInstanceId)
}
})
}
const step = ref([])
/**审批步骤*/
const processHistoryList = (processInstanceId) => {
console.log('000', processInstanceId);
processHistoryListApi({
processInstanceId
}).then((res) => {
console.log('0088800', res);
if (res.success) {
step.value = res.result.records
}
})
}
onMounted(() => {
dbSxxqQueryById()
extActFlowData()
})
</script>
<style lang="scss" scoped>
.tab {
background-color: #fff;
overflow-x: auto;
view {
padding: 20rpx 30rpx;
white-space: nowrap;
}
.active {
position: relative;
color: #1890ff;
&::after {
content: ' ';
position: absolute;
width: 100rpx;
height: 6rpx;
border-radius: 3rpx;
background-color: #1890ff;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
}
}
.progress {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
width: 630rpx;
padding: 40rpx 30rpx 16rpx 30rpx;
margin-top: 30rpx;
margin-bottom: 30rpx;
.status {
padding: 4rpx 8rpx;
display: inline-block;
color: #FFFFFF;
font-size: 20rpx;
margin-left: 8rpx;
border-radius: 8rpx;
}
.complete {
background-color: #7AC756;
}
.refuse {
background-color: #FE4600;
}
.title {
font-size: 28rpx;
color: #333333;
background-image: url(../../static/index/line.png);
background-size: 44rpx 12rpx;
background-repeat: no-repeat;
background-position: left bottom;
margin-bottom: 40rpx;
}
// .box:not(:first-child) {
// padding-top: 60rpx;
// }
.box:not(:last-child) {
position: relative;
padding-bottom: 60rpx;
&::before {
position: absolute;
content: ' ';
width: 1px;
height: 100%;
background: #efefef;
left: -42rpx;
top: 10rpx;
}
}
.box {
margin-left: 50rpx;
.topic {
position: relative;
font-size: 28rpx;
color: #333333;
&::before {
position: absolute;
content: ' ';
width: 18rpx;
height: 18rpx;
background: #01508B;
border-radius: 14rpx;
left: -50rpx;
top: 50%;
transform: translateY(-50%);
}
}
.name_time {
font-size: 24rpx;
color: #888888;
margin-top: 12rpx;
}
}
}
</style>

194
bpm/tasklistCom.vue Normal file
View File

@ -0,0 +1,194 @@
<template>
<view class="list_box">
<view class="list" v-for="item,i in taskArr" :key="i"
@click="tojump(`/pages/task/handle?info=${JSON.stringify(item)}&type=${currentIndex}`)">
<view class="title f-row aic jcb">
<view>
<view>
{{item.bpmBizTitle}}
</view>
</view>
<text>{{item.durationStr}}</text>
</view>
<view class="info">
<view>
申请理由{{item.bpmBizTitle}}
</view>
<view v-if="currentIndex != 2">
当前环节{{item.taskName}}
</view>
<view>
流程名称{{item.processDefinitionName}}
</view>
<view>
发起人{{item.processApplyUserName}}
</view>
<view>
开始时间{{item.taskBeginTime}}
</view>
<view v-if="item.taskEndTime">
结束时间{{item.taskEndTime}}
</view>
</view>
<view class="btn f-row aic jcb" v-if="currentIndex == 0 && item.taskAssigneeName">
<view class="entrust" @click.stop="tojump(`/pages/userlist/index?isradio=1&id=${item.id}`)">
委托
</view>
<view class="handle" @click="tojump(`/pages/task/handle?info=${JSON.stringify(item)}&type=${currentIndex}`)">
办理
</view>
</view>
<view class="btn f-row aic jcb" v-if="currentIndex == 0 && !item.taskAssigneeName">
<view>
</view>
<view class="handle" @click.stop="handleClaim(item.id)">
签收
</view>
</view>
<view class="btn f-row aic jcb" v-if="currentIndex == 2 && !item.endTime">
<view class="entrust" @click.stop="invalidProcess(item.processInstanceId)">
作废流程
</view>
<view class="handle" @click.stop="callBackProcess(item.processInstanceId)">
取回流程
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
claimApi,
callBackProcessApi,
invalidProcessApi
} from '@/api/api.js';
import {
getCurrentInstance,
} from 'vue';
const {
proxy
} = getCurrentInstance()
const props = defineProps({
taskArr: {
type: Array,
default: () => []
},
currentIndex: {
type: Number,
default: 0
},
})
const emit = defineEmits(['jump'])
const tojump = (url) => {
emit('jump', url)
}
/**流程签收*/
const handleClaim = (id) => {
claimApi({
taskId: id
}).then((res) => {
if (res.success) {
uni.redirectTo({
url: './index?id=0'
});
proxy.$toast(res.message)
}
})
}
/**流程取回*/
const callBackProcess = (id) => {
callBackProcessApi({
processInstanceId: id
}).then((res) => {
if (res.success) {
uni.redirectTo({
url: './self'
});
proxy.$toast(res.message)
}
})
}
/**流程作废*/
const invalidProcess = (id) => {
invalidProcessApi({
processInstanceId: id
}).then((res) => {
if (res.success) {
uni.redirectTo({
url: './self'
});
proxy.$toast(res.message)
}
})
}
</script>
<style lang="scss" scoped>
.list_box {
padding: 0 30rpx 0 30rpx;
margin-top: 24rpx;
.list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.title {
border-bottom: 1px solid #efefef;
padding-bottom: 24rpx;
margin-bottom: 8rpx;
view {
font-size: 28rpx;
color: #333333;
}
text {
font-size: 28rpx;
color: #999999;
}
}
.info {
font-size: 28rpx;
color: #666666;
view {
padding-top: 16rpx;
}
}
.btn {
margin-top: 30rpx;
view {
width: 300rpx;
height: 64rpx;
border-radius: 8rpx;
font-size: 28rpx;
text-align: center;
line-height: 64rpx;
}
.entrust {
background: #FFFFFF;
border: 2rpx solid #01508B;
box-sizing: border-box;
color: #01508B;
}
.handle {
background: #01508B;
color: #FFFFFF;
}
}
}
}
</style>

BIN
certificate/book.keystore Normal file

Binary file not shown.

View File

@ -0,0 +1,9 @@
证书指纹:
MD5: 9A:AD:4D:78:17:EE:17:D3:62:B2:6E:B2:56:0B:18:C3
SHA1: B1:1E:CE:4B:70:C7:88:B3:6E:8B:B9:05:98:4B:FD:67:81:C1:3A:8F
SHA256: A9:78:BD:BF:BB:DE:35:14:AA:5D:45:E9:6A:D0:E5:17:6D:BE:58:86:7A:1D:66:A2:F3:62:2F:E7:9C:9E:59:F6
别名: __uni__9f097f0
证书密码为uZ6Stufj
包名com.tianranqi.app

View File

@ -0,0 +1,119 @@
<template>
<view>
<view v-if="customReturnValue === 'orgCode'">
<uni-data-picker :openSearch="true" placeholder="请选择单位" popup-title="请选择单位" :localdata="dataList"
@nodeclick="onNodeClick" @popupclosed="onPopupClosed" v-model="ID"
:map="{ text: 'title', value: 'orgCode' }"></uni-data-picker>
</view>
<view v-else>
<uni-data-picker :openSearch="true" placeholder="请选择单位" popup-title="请选择单位" :localdata="dataList"
@nodeclick="onNodeClick" @popupclosed="onPopupClosed" v-model="ID"
:map="{ text: 'title', value: 'id' }"></uni-data-picker>
</view>
</view>
</template>
<script setup>
import {
queryDepByCode,
queryZbDepByLdhth
} from '@/api/depart.js'
import {
useStore
} from '@/store';
const store = useStore()
const props = defineProps([{
value: {
type: String,
default: ''
},
customReturnValue: {
require: true,
type: String,
default: 'orgCode'
}
}]),
watch(value,(newValue,oldValue)=>{
console.log("新值是"+newValue, "旧址是"+oldValue);
this.ID = val;
}),
watch(value,(newValue,oldValue)=>{
console.log("新值是"+newValue, "旧址是"+oldValue);
this.ID = val;
}),
data() {
return {
reset: true,
url: {
list: '/sys/sysDepart/queryTreeList'
},
pageNo: 1,
pageSize: 3000,
params: {
pageNo: this.pageNo,
pageSize: this.pageSize
},
dataList: [],
ID: '',
bmText: '',
tempID: '',
field: ''
};
},
onReady() {
this.getData();
},
mounted() {
this.getData();
},
methods: {
onNodeClick(e) {
console.log(JSON.stringify(e));
console.log(e.orgCode, e.title, e.id, this.customReturnValue);
this.$nextTick(() => {
if (this.customReturnValue == 'orgCode') {
this.tempID = e.orgCode;
}
if (this.customReturnValue == 'id') {
this.tempID = e.id;
}
this.bmText = e.title;
})
},
onPopupClosed() {
this.$nextTick(() => {
this.ID = this.tempID;
console.log(this.ID, this.bmText);
this.$emit('input', this.ID);
this.$emit('change', this.ID, this.bmText);
});
},
onchange(e) {
this.$nextTick(() => {
this.ID = this.tempID;
console.log(this.ID, this.bmText);
this.$emit('input', this.ID);
this.$emit('change', this.ID, e.detail.value);
})
},
getData() {
// console.log(111)
let that = this;
queryDepByCode(store.userinfo.workNo).then((res) => { //
console.log(res)
depart.value = res.departName
orgCode.value = res.orgCode
})
}
}
</script>
<style></style>

View File

@ -0,0 +1,51 @@
<template>
<view class="date-picker-container">
<picker mode=multiSelector @change="bindPickerChange" :value="index" :range="range">
<slot />
</picker>
</view>
</template>
<script>
import { ref } from 'vue'
import dayjs from 'dayjs'
// range
const getRange = () => {
const dateArr = [[], []]
for (var i = 2000; i <= 2099; i++) { dateArr[0].push(`${i}`) }
for (var i = 1; i <= 12; i++) { dateArr[1].push(`${i}`) }
return { dateArr }
}
export default {
name: 'date-picker',
setup(props) {
// range:
const { dateArr } = getRange()
const range = ref(dateArr)
// index: ,
// date
// [year, month] yearmonth 20223 year = 22month = 2
const date = dayjs(props.date).format("YYYY-MM")
const year = Number(date.slice(2, 4))
const month = Number(date.slice(5, 7))
const index = ref([year, month - 1])
console.log(index.value)
// bindPickerChange: index
const bindPickerChange = (e) => {
index.value = e.detail.value
console.log(`用户选中20${index.value[0]}${index.value[1] + 1}`)
}
return { index, range, bindPickerChange }
}
}
</script>
<style scoped>
.date-picker-container {
}
</style>

View File

@ -0,0 +1,289 @@
<template>
<view
class="customthree-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" @click.stop="handleNameClick(node)">
<view class="icon-group">
<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>
<view v-if="loadingArr.includes(node[props.dataValue].toString())" class="loading-icon-box">
<uni-icons class="loading-icon" type="spinner-cycle" size="14" color="#333"></uni-icons>
</view>
<view class="name" :style="node.disabled ? 'color: #999' : ''">
<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 }]"
:style="{ 'border-radius': mutiple ? '3px' : '50%' }"
@click.stop="!node.disabled && 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"
:lazyLoadChildren="lazyLoadChildren"
:border="border"
:linkage="linkage"
:level="level + 1"
></data-select-item>
</view>
</view>
</template>
<script lang="ts" setup>
import dataSelectItem from './data-select-item.vue'
import { paging } from './utils'
import { ref, inject, watchEffect } from 'vue'
const { nodeClick, nameClick, loadNode, initData, addNode } = inject('nodeFn')
const props = defineProps({
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
},
lazyLoadChildren: {
type: Boolean,
default: false
},
level: {
type: Number,
default: 0
},
mutiple: {
type: Boolean,
default: false
},
})
const listData = ref([])
const clearTimerList = ref([])
const loadingArr = ref([])
watchEffect(() => {
if (props.node.showChildren && props.node[props.dataChildren] && props.node[props.dataChildren].length) {
resetClearTimerList()
renderTree(props.node[props.dataChildren])
}
})
//
function resetClearTimerList() {
const list = [...clearTimerList.value]
clearTimerList.value = []
list.forEach((fn) => fn())
}
//
function renderTree(arr: any[]) {
const pagingArr = paging(arr)
listData.value = pagingArr?.[0] || []
lazyRenderList(pagingArr, 1)
}
//
function lazyRenderList(arr: any[], startIndex: number) {
for (let i = startIndex; i < arr.length; i++) {
let timer: any = null
timer = setTimeout(() => {
listData.value.push(...arr[i])
}, i * 500)
clearTimerList.push(() => clearTimeout(timer))
}
}
//
function handleNameClick(node: any) {
if (!node.visible) return
if (!node[props.dataChildren]?.length && props.lazyLoadChildren) {
loadingArr.value.push(node[props.dataValue].toString())
loadNode(node)
.then((res: any) => {
addNode(node, initData(res, node.visible))
})
.finally(() => {
loadingArr.value = []
})
} else {
nameClick(node)
}
}
</script>
<style lang="scss" scoped>
$primary-color: #007aff;
$col-sm: 4px;
$col-base: 8px;
$col-lg: 12px;
$row-sm: 5px;
$row-base: 10px;
$row-lg: 15px;
$radius-base: 6px;
$border-color: #c8c7cc;
.customthree-tree-select-content {
&.border {
border-left: 1px solid $border-color;
}
::v-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);
}
}
.loading-icon-box {
margin-right: $row-sm;
width: 14px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.loading-icon {
transform-origin: center;
animation: rotating infinite 0.2s ease;
}
}
.name {
flex: 1;
}
}
}
.check-box {
margin: 0;
padding: 0;
box-sizing: border-box;
width: 23.6px;
height: 23.6px;
border: 1px solid $border-color;
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;
}
}
}
@keyframes rotating {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
</style>

View File

@ -0,0 +1,240 @@
# customthree-tree-select 使用指南
**提示:** 使用该插件前确保你已经导入 `uni-popup` `uni-icons` `uni-easyinput` 插件。
**有问题可以加 QQ 群297080738**
## 优势
💪:基于 `uni-popup``uni-icons``uni-easyinput` 插件进行开发,默认样式与 `uni-easyinput` 样式对标。
⚡:全面支持懒加载应对大量数据。
🚀v-model 绑定数据、数据回显、移除选项。
⚙ :提供更多配置项。
📦:开箱即用。
## Props
| 属性名 | 类型 | 默认值 | 说明 |
| :--------------------: | :-----------------: | :-------------: | :----------------------------------------------------------: |
| canSelectAll | Boolean | false | 开启一键全选功能 |
| clearResetSearch | Boolean | false | 设置为 `true` 并且搜索之后,点击输入框清除按钮,会清空搜索内容并且会直接重置整个弹窗内树形选择器内容,默认情况下只有清除之后再次进行查询才会重置选择器 |
| animation | Boolean | ture | 是否开启弹窗动画 |
| is-mask-click | Boolean | true | 点击遮罩关闭弹窗 |
| mask-background-color | String | rgba(0,0,0,0.4) | 蒙版颜色,建议使用 rgba 颜色值 |
| background-color | String | none | 主窗口背景色 |
| safe-area | Boolean | true | 是否适配底部安全区 |
| **choseParent** | **Boolean** | **false** | **父节点是否可选** |
| **linkage** | **Boolean** | **false** | **父子节点是否联动** |
| placeholder | String | 请选择 | 空状态信息提示、弹窗标题 |
| confirmText | String | 完成 | 确定按钮文字 |
| confirmTextColor | String | #007aff | 确定按钮文字颜色 |
| dataSource | Array | - | 展示的数据 |
| **dataLabel** | **String** | **name** | **dataSource 中对应数据的 label** |
| **dataValue** | **String** | **id** | **dataSource 中对应数据的 value** |
| **dataChildren** | **String** | **children** | **dataSource 中对应数据的 children** |
| clearable | Boolean | false | 是否显示清除按钮,点击清除所有已选项 |
| **mutiple** | **Boolean** | **false** | **是否可以多选** |
| **disabled** | **Boolean** | **false** | **是否允许修改** |
| search | Boolean | false | 是否可以搜索(常用于数据较多的情况) |
| showChildren | Boolean | false | 默认不展开(数据内部 showChildren 属性优先级更高,可以设置全局收起,单独展开某一条数据) |
| border | Boolean | false | 显示引导线 |
| load | Function | function(){} | lazyLoadChildren 设置为true 后,点击某个节点发送请求获取子节点数据,用法见下方异步懒加载示例 |
| lazyLoadChildren | Boolean | false | 是否开启异步懒加载节点 |
| **v-model/modelValue** | **Array \| String** | **[ ]** | **已选择的值,通过 v-model 进行绑定例如v-model="formData.selectedList" 根据你绑定数据的类型自动返回相同类型的数据String 类型通过 `,` 进行分隔** |
| deleteSource | Boolean | false | 是否可删除已选数据
## Events
| 事件名称 | 说明 | 返回值 |
| ----------------- | ------------------------ | ------------------------------------------- |
| change | 弹窗组件状态发生变化触发 | e={show: true false,type:当前模式} |
| maskClick | 点击遮罩层触发 | |
| update:modelValue | 选中数据或取消选中时触发 | 以数组形式返回已选择数据的 dataValue 对应值 |
| select-change | 选中数据或取消选中时触发 | 以数组形式返回选中数据完整信息 |
| removeSelect | 从选择框内删除元素时触发 | |
## 基础使用示例
```vue
<template>
<customthree-tree-select :listData="listData" v-model="formData.selectedArr" />
<customthree-tree-select :listData="listData" v-model="formData.selectedString" />
</template>
<script setup>
import { reactive } from 'vue'
const formData = reactive({
selectedArr: [],
selectedString: ''
})
const listData = [
{
id: 1,
name: '城市1',
children: [
{
id: 3,
name: '街道1',
children: [
{
id: 4,
name: '小区1'
}
]
}
]
},
{
id: 2,
name: '城市2',
children: [
{
id: 6,
name: '街道2'
}
]
}
]
</script>
```
## 禁用某些选项,或隐藏某些选项
```vue
<template>
<customthree-tree-select
mutiple
linkage
clearable
search
dataLabel="text"
dataValue="value"
:listData="listData"
v-model="formData.selected"
></custom-tree-select>
</template>
<script setup>
import { reactive } from 'vue'
const formData = reactive({
selected: ''
})
const listData = [
{
id: 1,
name: '城市1',
children: [
{
id: 3,
name: '街道1',
disabled: true
children: [
{
id: 4,
name: '小区1'
}
]
}
]
},
{
id: 2,
name: '城市2',
children: [
{
id: 6,
name: '街道2',
visible: false
}
]
}
]
</script>
```
## 异步懒加载
```vue
<template>
<view class="content">
<customthree-tree-select
search
linkage
clearable
clearResetSearch
border
mutiple
lazyLoadChildren
canSelectAll
:showChildren="false"
:listData="listData"
:load="loadNode"
dataLabel="text"
dataValue="value"
v-model="selectedStr"
></customthree-tree-select>
</view>
</template>
<script>
export default {
data() {
return {
selectedStr: '',
listData: [
{
value: '0',
text: '测试懒加载'
},
{
value: '1',
text: '城市1',
children: [
{
value: '1-1',
text: '街道1',
disabled: true
}
]
}
]
}
},
methods: {
loadNode(node) {
return new Promise((resolve) => {
setTimeout(() => {
const item = this.listData.find((item) => item.value === node.value)
if (item) {
resolve([
{
value: '0-1',
text: '懒加载子元素'
}
])
}
resolve([])
}, 500)
})
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
```

View File

@ -0,0 +1,811 @@
<template>
<view :class="['select-list', { disabled }, { active: selectList.length }]" @click="open">
<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 && deleteSource" class="close"
@click.stop="removeSelectedItem(item)">
<uni-icons type="closeempty" size="16" color="#999"></uni-icons>
</view>
</view>
</view>
<view v-else class="no-data">
<text>{{ placeholder }}</text>
</view>
</view>
<view>
<uni-icons v-if="!selectList.length || !clearable" type="bottom" color="#333333"></uni-icons>
<view @click.stop>
<uni-icons v-if="selectList.length && clearable" type="clear" size="24" color="#c0c4cc"
@click="clearSelectList"></uni-icons>
</view>
</view>
</view>
<uni-popup ref="popup" :animation="animation" :is-mask-click="isMaskClick"
:mask-background-color="maskBackgroundColor" :background-color="backgroundColor" :safe-area="safeArea"
type="bottom" @change="change" @maskClick="maskClick">
<view class="popup-content" :style="{ height: contentHeight }">
<view class="title">
<view v-if="mutiple && canSelectAll" class="left" @click="handleSelectAll">
<text>{{ isSelectedAll ? '取消全选' : '全选' }}</text>
</view>
<view class="center">
<text>{{ placeholder }}</text>
</view>
<view class="right" :style="{ color: confirmTextColor }" @click="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)">
</uni-easyinput>
<button type="primary" size="mini" class="search-btn" @click="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"
:lazyLoadChildren="lazyLoadChildren"></data-select-item>
<view class="sentry" />
</scroll-view>
</view>
<view v-else class="no-data center">
<text>暂无数据</text>
</view>
</view>
</uni-popup>
</template>
<script lang="ts" setup>
import { ref, computed, watch, onMounted, nextTick, provide } from 'vue'
import dataSelectItem from './data-select-item.vue';
import { isString, paging } from './utils';
const props = defineProps({
canSelectAll: {
type: Boolean,
default: false
},
safeArea: {
type: Boolean,
default: true
},
search: {
type: Boolean,
default: false
},
clearResetSearch: {
type: Boolean,
default: false
},
animation: {
type: Boolean,
default: true
},
'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: false
},
placeholder: {
type: String,
default: '请选择'
},
confirmText: {
type: String,
default: '确认'
},
confirmTextColor: {
type: String,
default: '#007aff'
},
dataSource: {
type: Array,
default: () => []
},
dataLabel: {
type: String,
default: 'name'
},
dataValue: {
type: String,
default: 'id'
},
dataChildren: {
type: String,
default: 'children'
},
linkage: {
type: Boolean,
default: false
},
removeLinkage: {
type: Boolean,
default: true
},
clearable: {
type: Boolean,
default: false
},
mutiple: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
deleteSource: {
type: Boolean,
default: false
},
showChildren: {
type: Boolean,
default: false
},
border: {
type: Boolean,
default: false
},
lazyLoadChildren: {
type: Boolean,
default: false
},
load: {
type: Function,
default: function () { }
},
modelValue: {
type: [Array, String],
default: () => []
}
})
const emits = defineEmits(['update:modelValue', 'change', 'maskClick', 'select-change', 'removeSelect'])
const contentHeight = ref('500px')
const treeData = ref([])
const filterTreeData = ref([])
const clearTimerList = ref([])
const selectedListBaseinfo = ref([])
const showPopup = ref(false)
const isSelectedAll = ref(false)
const scrollTop = ref(0)
const searchStr = ref('')
const popup = ref<any>(null)
const partCheckedSet = new Set()
provide('nodeFn', {
nodeClick: handleNodeClick,
nameClick: handleHideChildren,
loadNode: props.load,
initData: initData,
addNode: addNode
})
const selectList = computed(() => {
const newVal = props.modelValue === null ? '' : props.modelValue
return isString(newVal) ? (newVal.length ? newVal.split(',') : []) : newVal.map((item : any) => item.toString())
})
onMounted(() => {
getContentHeight(uni.getSystemInfoSync())
})
function getContentHeight({ screenHeight } : { screenHeight : number }) {
contentHeight.value = `${Math.floor(screenHeight * 0.7)}px`
}
watch(
() => props.dataSource,
(newVal : any[]) => {
if (newVal) {
treeData.value = initData(newVal)
if (showPopup.value) {
resetClearTimerList()
renderTree(treeData.value)
}
}
},
{ immediate: true, deep: true }
)
watch(
() => props.modelValue,
(newVal : any[] | string) => {
const ids = newVal ? (Array.isArray(newVal) ? newVal : newVal.split(',')) : []
changeStatus(treeData.value, ids, true)
filterTreeData.value.length && changeStatus(filterTreeData.value, ids)
},
{ immediate: true }
)
//
function goTop() {
scrollTop.val = 10
nextTick(() => {
scrollTop.value = 0
})
}
//
function handleSearch(isClear = false) {
resetClearTimerList()
if (isClear) {
//
if (props.clearResetSearch) {
renderTree(treeData.value)
}
} else {
renderTree(searchValue(searchStr.value, treeData.value))
}
goTop()
uni.hideKeyboard()
}
//
function searchValue(str : any, arr : any[]) {
const res : any = []
arr.forEach((item) => {
if (item.visible) {
if (item[props.dataLabel].toString().toLowerCase().indexOf(str.toLowerCase()) > -1) {
res.push(item)
} else {
if (item[props.dataChildren]?.length) {
const data = searchValue(str, item[props.dataChildren])
if (data?.length) {
if (str && !item.showChildren && item[props.dataChildren]?.length) {
item.showChildren = true
}
res.push({
...item,
[props.dataChildren]: data
})
}
}
}
}
})
return res
}
//
async function open() {
// disaled
if (props.disabled) return
showPopup.value = true
popup.value.open()
renderTree(treeData.value)
}
//
function close() {
popup.value.close()
}
//
function change(data : any) {
if (!data.show) {
resetClearTimerList()
searchStr.value = ''
showPopup.value = false
}
emits('change', data)
}
//
function maskClick() {
emits('maskClick')
}
//
function initData(arr : any[], parentVisible ?: undefined | boolean) {
if (!Array.isArray(arr)) return []
const res = []
for (let i = 0; i < arr.length; i++) {
const obj : any = {
[props.dataLabel]: arr[i][props.dataLabel],
[props.dataValue]: arr[i][props.dataValue]
}
obj.checked = selectList.value.includes(arr[i][props.dataValue].toString())
obj.disabled = Boolean(arr[i].disabled)
//
obj.partChecked = Boolean(arr[i].partChecked === undefined ? false : arr[i].partChecked)
obj.partChecked && obj.partCheckedSet.add(obj[props.dataValue])
!obj.partChecked && (isSelectedAll.value = 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 : props.showChildren
if (arr[i].visible && !arr[i].disabled && !arr[i].checked) {
isSelectedAll.value = false
}
if (arr[i][props.dataChildren]?.length) {
obj[props.dataChildren] = initData(arr[i][props.dataChildren], obj.visible)
}
res.push(obj)
}
return res
}
function addNode(node : any, children : any[]) {
getReflectNode(node, treeData.value)[props.dataChildren] = children
handleHideChildren(node)
}
//
function resetClearTimerList() {
const list = [...clearTimerList.value]
clearTimerList.value = []
list.forEach((fn) => fn())
}
//
function renderTree(arr : any[]) {
const pagingArr = paging(arr)
filterTreeData.value = pagingArr?.[0] || []
lazyRenderList(pagingArr, 1)
}
//
function lazyRenderList(arr : any[], startIndex : number) {
for (let i = startIndex; i < arr.length; i++) {
let timer : any = null
timer = setTimeout(() => {
filterTreeData.value.push(...arr[i])
}, i * 500)
clearTimerList.push(() => clearTimeout(timer))
}
}
// dataValue
function changeStatus(list : any[], ids : any[] | string, needEmit = false) {
const arr = [...list]
let flag = true
needEmit && (selectedListBaseinfo.value = [])
while (arr.length) {
const item = arr.shift()
if (ids.includes(item[props.dataValue].toString())) {
item.checked = true
//
item.partChecked = false
partCheckedSet.delete(item[props.dataValue])
needEmit && selectedListBaseinfo.value.push(item)
} else {
item.checked = false
if (item.visible && !item.disabled) {
flag = false
}
if (partCheckedSet.has(item[props.dataValue])) {
// filtertreedata
item.partChecked = true
} else {
item.partChecked = false
}
}
if (item[props.dataChildren]?.length) {
arr.push(...item[props.dataChildren])
}
}
isSelectedAll.value = flag
needEmit && emits('select-change', [...selectedListBaseinfo.value])
}
//
function removeSelectedItem(node : any) {
isSelectedAll.value = false
if (props.linkage) {
handleNodeClick(node, false)
emits('removeSelect', node)
} else {
const emitData = selectList.value.filter((item : any) => item !== node[props.dataValue].toString())
emits('removeSelect', node)
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
}
}
//
function getReflectNode(node : any, arr : any[]) {
const array = [...arr]
while (array.length) {
const item = array.shift()
if (item[props.dataValue] === node[props.dataValue]) {
return item
}
if (item[props.dataChildren]?.length) {
array.push(...item[props.dataChildren])
}
}
return {}
}
//
function getChildren(node : any) {
if (!node[props.dataChildren]?.length) return []
const res = node[props.dataChildren].reduce((pre : any, val : any) => {
if (val.visible) {
return [...pre, val]
}
return pre
}, [])
for (let i = 0; i < node[props.dataChildren].length; i++) {
res.push(...getChildren(node[props.dataChildren][i]))
}
return res
}
//
function getParentNode(target : any, arr : any[]) {
let res : any[] = []
for (let i = 0; i < arr.length; i++) {
if (arr[i][props.dataValue] === target[props.dataValue]) {
return true
}
if (arr[i][props.dataChildren]?.length) {
const childRes = getParentNode(target, arr[i][props.dataChildren])
if (typeof childRes === 'boolean' && childRes) {
res = [arr[i]]
} else if (Array.isArray(childRes) && childRes.length) {
res = [...childRes, arr[i]]
}
}
}
return res
}
// checkbox
function handleNodeClick(data : any, status : boolean | undefined) {
const node = getReflectNode(data, treeData.value)
node.checked = typeof status === 'boolean' ? status : !node.checked
node.partChecked = false
partCheckedSet.delete(node[props.dataValue])
//
if (!props.mutiple) {
let emitData : any[] = []
if (node.checked) {
emitData = [node[props.dataValue].toString()]
}
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
} else {
//
if (!props.linkage) {
//
let emitData = null
if (node.checked) {
emitData = Array.from(new Set([...selectList.value, node[props.dataValue].toString()]))
} else {
emitData = selectList.value.filter((id : number | string) => id !== node[props.dataValue].toString())
}
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
} else {
//
let emitData = [...selectList.value]
const parentNodes : any = getParentNode(node, treeData.value)
const childrenVal = getChildren(node).filter((item : any) => !item.disabled)
if (node.checked) {
//
emitData = Array.from(new Set([...emitData, node[props.dataValue].toString()]))
if (childrenVal.length) {
emitData = Array.from(
new Set([...emitData, ...childrenVal.map((item : any) => item[props.dataValue].toString())])
)
//
childrenVal.forEach((childNode : any) => {
childNode.partChecked = false
partCheckedSet.delete(childNode[props.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[props.dataValue])
} else {
const allChecked = item[props.dataChildren]
.filter((node : any) => node.visible && !node.disabled)
.every((node : any) => node.checked)
if (allChecked) {
item.checked = true
item.partChecked = false
partCheckedSet.delete(item[props.dataValue])
emitData = Array.from(new Set([...emitData, item[props.dataValue].toString()]))
} else {
item.partChecked = true
partCheckedSet.add(item[props.dataValue])
flag = true
}
}
}
}
}
} else {
//
emitData = emitData.filter((id) => id !== node[props.dataValue].toString())
if (childrenVal.length) {
//
childrenVal.forEach((childNode : any) => {
emitData = emitData.filter((id) => id !== childNode[props.dataValue].toString())
})
}
if (parentNodes.length) {
parentNodes.forEach((parentNode : any) => {
if (emitData.includes(parentNode[props.dataValue].toString())) {
parentNode.checked = false
}
emitData = emitData.filter((id) => id !== parentNode[props.dataValue].toString())
const hasChecked = parentNode[props.dataChildren]
.filter((node : any) => node.visible && !node.disabled)
.some((node : any) => node.checked || node.partChecked)
parentNode.partChecked = hasChecked
if (hasChecked) {
partCheckedSet.add(parentNode[props.dataValue])
} else {
partCheckedSet.delete(parentNode[props.dataValue])
}
})
}
}
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
}
}
}
//
function handleHideChildren(node : any) {
const status = !node.showChildren
getReflectNode(node, treeData.value).showChildren = status
getReflectNode(node, filterTreeData.value).showChildren = status
}
//
function handleSelectAll() {
isSelectedAll.value = !isSelectedAll.value
if (isSelectedAll.value) {
if (!props.mutiple) {
uni.showToast({
title: '单选模式下不能全选',
icon: 'none',
duration: 1000
})
return
}
let emitData : any[] = []
treeData.value.forEach((item : any) => {
if (item.visible || (item.disabled && item.checked)) {
emitData = Array.from(new Set([...emitData, item[props.dataValue].toString()]))
if (item[props.dataChildren]?.length) {
emitData = Array.from(
new Set([
...emitData,
...getChildren(item)
.filter((item : any) => !item.disabled || (item.disabled && item.checked))
.map((item : any) => item[props.dataValue].toString())
])
)
}
}
})
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
} else {
clearSelectList()
}
}
//
function clearSelectList() {
if (props.disabled) return
partCheckedSet.clear()
const emitData : any[] = []
selectedListBaseinfo.value.forEach((node : any) => {
if (node.visible && node.checked && node.disabled) {
emitData.push(node[props.dataValue])
}
})
emits('update:modelValue', isString(props.modelValue) ? emitData.join(',') : emitData)
}
</script>
<style lang="scss" scoped>
$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;
.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;
&.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 {
max-width: auto;
height: auto;
// background-color: #eaeaea;
// border-radius: $radius-sm;
display: flex;
align-items: center;
.name {
flex: 1;
// padding-right: $row-base;
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 {
font-size: 28rpx;
color: #999999;
}
// .no-data.center {
// text-align: center;
// }
</style>

View File

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

20
index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<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>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

38
main.js Normal file
View File

@ -0,0 +1,38 @@
import App from './App';
import {
toast
} from './utils/index.js';
import {
createPinia
} from "pinia";
import leaveApplication from '@/bpm/leaveApplication/index.vue';
import supervise from '@/bpm/supervise.vue'
const pinia = createPinia();
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
app.use(pinia)
app.component('leaveApplication', leaveApplication)
app.component('supervise', supervise)
app.config.globalProperties.$toast = toast
return {
app
}
}
// #endif

123
manifest.json Normal file
View File

@ -0,0 +1,123 @@
{
"name" : "数智产销",
"appid" : "__UNI__9F097F0",
"description" : "",
"versionName" : "1.1.1",
"versionCode" : 20250106,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"compatible" : {
"ignoreVersion" : true
},
/* */
"modules" : {
"Geolocation" : {},
"Fingerprint" : {},
"Camera" : {},
"Barcode" : {}
},
/* */
"distribute" : {
/* android */
"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 */
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {},
"geolocation" : {
"system" : {
"__platform__" : [ "android" ]
}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3"
}
/* */

47
package-lock.json generated Normal file
View File

@ -0,0 +1,47 @@
{
"name": "cxc-szcx-uniapp",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@dcloudio/uni-ui": "^1.5.6",
"base-64": "^1.0.0",
"dayjs": "^1.11.13"
}
},
"node_modules/@dcloudio/uni-ui": {
"version": "1.5.6",
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.6.tgz",
"integrity": "sha512-jmb98PasFvZkrIDXGh94GbdWg2/jyhgs1HUG+bU8eyL7Ltias/5XBz4q8w9RXyWUfqepJRqapPA2IIQpLCuTIg==",
"license": "Apache-2.0"
},
"node_modules/base-64": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/base-64/-/base-64-1.0.0.tgz",
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
},
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
}
},
"dependencies": {
"@dcloudio/uni-ui": {
"version": "1.5.6",
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.6.tgz",
"integrity": "sha512-jmb98PasFvZkrIDXGh94GbdWg2/jyhgs1HUG+bU8eyL7Ltias/5XBz4q8w9RXyWUfqepJRqapPA2IIQpLCuTIg=="
},
"base-64": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/base-64/-/base-64-1.0.0.tgz",
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
},
"dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
}
}
}

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"dependencies": {
"@dcloudio/uni-ui": "^1.5.6",
"base-64": "^1.0.0",
"dayjs": "^1.11.13"
}
}

271
pages.json Normal file
View File

@ -0,0 +1,271 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/tab/index",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "pages/task/todotask",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "pages/tab/office",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/tab/my",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/task/index",
"style": {
"enablePullDownRefresh": true,
"app-plus": {
"titleNView": {
"titleText": "我的任务",
"titleColor": "#fff"
}
}
}
},
{
"path": "pages/task/handle",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/talk/message_list",
"style": {
"navigationBarTitleText": "消息",
"enablePullDownRefresh": true,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/talk/conversation",
"style": {
"navigationBarTitleText": "昵称",
"enablePullDownRefresh": true,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/talk/system",
"style": {
"navigationBarTitleText": "系统通知",
"enablePullDownRefresh": true,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/document/index",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "pages/document/detail",
"style": {
"navigationBarTitleText": "详情",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/document/onlinePreview",
"style": {
"navigationBarTitleText": "在线预览",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/zhongheguanli/meeting/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/views/zhongheguanli/meeting/detail",
"style": {
"navigationBarTitleText": "详情",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/leave/application",
"style": {
"navigationBarTitleText": "请假申请",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/checkin/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/useredit/useredit",
"style": {
"navigationBarTitleText": "资料编辑",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/useredit/address",
"style": {
"navigationBarTitleText": "地址",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/useredit/add_address",
"style": {
"navigationBarTitleText": "添加地址",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/useredit/addressbook",
"style": {
"navigationBarTitleText": "通讯录",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
// {
// "path": "pages/task/todotask",
// "style": {
// "navigationBarTitleText": "个人办公",
// "enablePullDownRefresh": false,
// "navigationBarTextStyle": "white"
// }
// },
{
"path": "pages/safe/manage",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/product/index",
"style": {
"navigationBarTitleText": "生产数据",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/userlist/index",
"style": {
"navigationBarTitleText": "",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/safe/detail",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/views/zhongheguanli/zhiban/index",
"style": {
"navigationBarTitleText": "值班信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/task/self",
"style": {
"navigationBarTitleText": "本人发起",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/renyuanxinxi/index",
"style": {
"navigationBarTitleText": "人员信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/renyuanxinxi/taizhang",
"style": {
"navigationBarTitleText": "台账信息",
"navigationBarTextStyle": "white"
}
}
],
"tabBar": {
"color": "#333333",
"selectedColor": "#01508B",
"borderStyle": "black",
"backgroundColor": "#FFFFFF",
"list": [{
"text": "首页",
"pagePath": "pages/tab/index",
"iconPath": "static/tab/index1.png",
"selectedIconPath": "static/tab/index2.png"
},
{
"text": "任务",
"pagePath": "pages/task/todotask",
"iconPath": "static/tab/office1.png",
"selectedIconPath": "static/tab/office2.png"
},
{
"text": "办公",
"pagePath": "pages/tab/office",
"iconPath": "static/tab/product1.png",
"selectedIconPath": "static/tab/product2.png"
},
{
"text": "我的",
"pagePath": "pages/tab/my",
"iconPath": "static/tab/user1.png",
"selectedIconPath": "static/tab/user2.png"
}
]
// "midButton": {
// "width": "65px",
// "height": "75px",
// "text": "",
// "iconPath": "static/tab/todo.png",
// "iconWidth": "50px",
// }
},
"globalStyle": {
"app-plus": {
"titleNView": {
"backgroundImage": "linear-gradient(to left , #256FBC, #044D87)"
}
}
},
"uniIdRouter": {}
}

232
pages/checkin/index.vue Normal file
View File

@ -0,0 +1,232 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<customNav>
<view class="nav_box f-row aic">
<view class="back" @click="back">
<uni-icons type="left" size="20" color="#fff"></uni-icons>
</view>
<view class="avatar">
<image :src="store.userinfo.avatar" mode=""></image>
</view>
<view class="f-col">
<view class="name">
{{store.userinfo.realname}}
</view>
<view class="position">
{{store.role}}
</view>
</view>
</view>
</customNav>
<view class="time_box f-row aic jcb">
<view class="box">
<view class="time f-row aic">
<view class="">
上班 9:30
</view>
<image src="../../static/checkin/chenggong.png" mode=""></image>
</view>
<view class="text">
重庆市渝北区上弯路
</view>
</view>
<view class="box">
<view class="time f-row aic">
<view class="">
下班 16:30
</view>
<image src="../../static/checkin/shibai.png" mode=""></image>
</view>
<view class="text">
打卡已超时
</view>
</view>
</view>
<view class="checkin">
<view class=" f-col aic">
<view class="status f-col aic">
<!-- <image src="../../static/checkin/position1.png" mode=""></image>
<image src="../../static/checkin/position2.png" mode=""></image>
<image src="../../static/checkin/position3.png" mode=""></image> -->
<image src="../../static/checkin/position4.png" mode=""></image>
<text>打卡失败</text>
</view>
<view :class="['circle', 'f-col', 'aic','out','check','success','fail']">
<view class="title">
上班打卡
</view>
<view class="time">
9:00
</view>
<view class="ontime">
已超时
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
useStore
} from '@/store';
const store = useStore();
import customNav from '../../bpm/customNav.vue';
const back = () => {
uni.navigateBack()
}
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content {
padding-bottom: 120rpx;
}
.nav_box {
position: absolute;
bottom: 16rpx;
left: 0;
width: calc(100% - 60rpx);
}
.back {
padding-left: 30rpx;
}
image {
width: 64rpx;
height: 64rpx;
border-radius: 32rpx;
background-color: #fff;
margin-right: 20rpx;
margin-left: 50rpx;
}
.name {
font-size: 28rpx;
color: #FFFFFF;
}
.position {
font-size: 24rpx;
color: #FFFFFF;
}
.time_box {
padding: 30rpx;
.box {
padding: 40rpx 30rpx;
flex: 1;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
}
.box:nth-child(1) {
border: 1rpx solid #3AC050;
background: #F5FFF7;
margin-right: 30rpx;
}
.box:nth-child(2) {
background: #FFF7F5;
border: 1rpx solid #F05C43;
}
.time {
font-size: 28rpx;
color: #333333;
image {
width: 28rpx;
height: 28rpx;
margin-left: 10rpx;
}
}
.text {
font-size: 24rpx;
color: #888888;
margin-top: 18rpx;
}
}
.checkin {
margin: 0 30rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
height: 818rpx;
.status {
image {
width: 58rpx;
height: 69rpx;
margin-top: 71rpx;
}
font-weight: 600;
font-size: 46rpx;
color: #F05C43;
text {
margin-top: 23rpx;
}
}
.out {
background-image: url('../../static/checkin/circle1.png');
}
.check {
background-image: url('../../static/checkin/circle2.png');
}
.success {
background-image: url('../../static/checkin/circle3.png');
}
.fail {
background-image: url('../../static/checkin/circle4.png');
}
.circle {
width: 350rpx;
height: 350rpx;
background-size: 350rpx 350rpx;
margin-top: 150rpx;
.title,
.time {
font-weight: 600;
font-size: 46rpx;
color: #333333;
}
.title {
margin-top: 80rpx;
}
.time {
margin-top: 8rpx;
}
.ontime {
font-size: 28rpx;
color: #888888;
margin-top: 12rpx;
}
}
}
</style>

120
pages/document/detail.vue Normal file
View File

@ -0,0 +1,120 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="title_box">
<view class="title">
{{detail._title}}
</view>
<view class="time">
{{detail._time}}
</view>
</view>
<view class="document f-row">
<text class="">
附件
</text>
<view class="f-col">
<view v-if="ifH5">
<!-- 在线预览 by -->
<view class="" style="padding: 5rpx 0;" @click="onlinePreview(`/pages/document/onlinePreview?data=${JSON.stringify(item)}`)"
v-for="item,i in detail?.pdf?.split(',')">
{{item}}
</view>
</view>
<view v-else>
<view class="" style="padding: 5rpx 0;" @click="opendocument(item)"
v-for="item,i in detail?.pdf?.split(',')">
{{item}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app';
import {
opendocument
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const store = useStore();
const detail = ref({})
//h5 by
var ifH5 = false;
const onlinePreview = (url)=>{ //线 by
uni.navigateTo({
url
})
}
onLoad((options) => {
detail.value = JSON.parse(options.data)
if (options.id == 0) {
detail.value.pdf = detail.value.wjbt
} else if (options.id == 2) {
if (detail.value.jdwj) {
detail.value.pdf = detail.value.jdwj + ',' + detail.value.sszd
} else {
detail.value.pdf = detail.value.sszd
}
} else if (options.id == 3) {
detail.value.pdf = detail.value.mingcheng
}
//#ifdef H5 || MP-WEIXIN
ifH5 = true;
//#endif
})
</script>
<style>
/* page{
background-color: #f8f8f8;
} */
</style>
<style lang="scss" scoped>
.content {
padding: 0 30rpx;
}
.title_box {
.title {
font-size: 32rpx;
color: #333333;
padding: 30rpx 0 20rpx 0;
}
.time {
font-size: 24rpx;
color: #888888;
padding-bottom: 30rpx;
}
}
.document {
text {
font-size: 28rpx;
color: #333333;
white-space: nowrap;
}
view {
font-size: 28rpx;
color: #5A79F8;
text-decoration: underline;
}
}
</style>

329
pages/document/index.vue Normal file
View File

@ -0,0 +1,329 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<customNav>
<view class="nav_box f-row aic jcb">
<view class="back f-row aic" @click="back">
<uni-icons type="left" size="20" color="#fff"></uni-icons>
</view>
<view class="search f-row aic">
<input type="text" v-model="searchKey" @confirm="search" @blur="showicon=true&&!searchKey"
@focus="showicon=false" />
<view class="f-row aic" v-if="showicon">
<image src="../../static/search.png" mode=""></image>
<text>搜索</text>
</view>
</view>
</view>
</customNav>
<view class="list">
<view class="item" v-for="item,i in list" :key="i"
@click="jump(`/pages/document/detail?data=${JSON.stringify(item)}&id=${id}`,item)">
<!-- <view class="dot">
</view> -->
<view class="title">
{{item._title}}
</view>
<view class="time_box f-row aic">
<view class="time">
{{item._time}}
</view>
<view class="look f-row aic" v-if="item._depart">
{{item._depart}}
</view>
<!-- <view class="look f-row aic">
<image src="../../static/index/eye.png" mode=""></image>
999+
</view> -->
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
watch
} from 'vue';
import {
onReachBottom,
onPullDownRefresh,
onLoad
} from '@dcloudio/uni-app';
import {
bpmlistApi,
faguiApi,
zhiduApi,
gonggaolistApi,
cjzhiduApi
} from '@/api/api.js';
import {
useStore
} from '@/store';
const store = useStore();
import customNav from '../../bpm/customNav.vue';
import {
beforeJump,
opendocument
} from '@/utils/index.js';
const showicon = ref(true)
const searchKey = ref('')
const list = ref([])
let pageNo = 1
let pageSize = 15
let loading = false
/**公文接口*/
const bpmlist = () => {
loading = true
bpmlistApi({
pageNo,
pageSize,
fwbt: formatSearchkey()
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'fwbt', 'fwtime', null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
/**制度接口*/
const zhidu = () => {
loading = true
let getzhidu = zhiduid == 0 ? zhiduApi : cjzhiduApi
getzhidu({
pageNo,
pageSize,
zdmc: formatSearchkey()
}).then((res) => {
if (res.success) {
let str = zhiduid == 0 ? 'zbbm_dictText' : 'sbbm'
list.value = [...list.value, ...formatObj(res.result.records, 'zdmc', str, null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
/**法规接口*/
const fagui = () => {
loading = true
faguiApi({
pageNo,
pageSize,
flfgmc: formatSearchkey()
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'flfgmc', 'ssbm', null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
/**公告接口*/
const gonggaolist = () => {
loading = true
gonggaolistApi({
pageNo,
pageSize,
neirong:formatSearchkey()
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'neirong', 'fbdw', 'createTime')]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
const formatObj = (arr, title, time, depart) => {
arr.map((item) => {
item['_title'] = item[title]
item['_time'] = item[time]
item['_depart'] = item[depart]
})
return arr
}
const formatSearchkey = () => {
if (searchKey.value.trim()) {
return '*' + searchKey.value + '*'
}
}
const search = () => {
pageNo = 1
loading = false
list.value = []
getlist()
}
watch(searchKey, (nval, oval) => {
if (!nval.trim()) {
getlist()
}
})
const back = () => {
uni.navigateBack()
}
const jump = (url, item) => {
if (id.value == 3) {
return opendocument(item.mingcheng)
}
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
const id = ref(null)
let zhiduid = null
onLoad((options) => {
id.value = options.id
zhiduid = options.zhiduid
getlist()
})
const getlist = () => {
if (id.value == 0) {
bpmlist()
} else if (id.value == 1) {
gonggaolist()
} else if (id.value == 2) {
zhidu()
} else if (id.value == 3) {
fagui()
}
}
onPullDownRefresh(() => {
pageNo = 1
loading = false
list.value = []
getlist()
uni.stopPullDownRefresh()
})
onReachBottom(() => {
if (loading) return
pageNo++
getlist()
})
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content {
padding-top: v-bind(cusnavbarheight);
padding-bottom: 24rpx;
}
.list {
padding: 0 30rpx;
.item {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx;
margin-top: 24rpx;
position: relative;
.dot {
width: 12rpx;
height: 12rpx;
background: #ED361D;
position: absolute;
border-radius: 50%;
left: 9rpx;
top: 44rpx;
}
.title {
margin-bottom: 20rpx;
font-size: 28rpx;
color: #333333;
}
.time_box {
font-size: 24rpx;
color: #888888;
.look {
position: relative;
margin-left: 60rpx;
&::after {
position: absolute;
content: ' ';
width: 2rpx;
height: 20rpx;
background: #999999;
top: 50%;
transform: translateY(-50%);
left: -30rpx;
}
}
}
image {
width: 28rpx;
height: 22rpx;
margin-left: 62rpx;
margin-right: 8rpx;
}
}
}
.nav_box {
position: absolute;
bottom: 14rpx;
width: 100%;
left: 0;
}
.back {
padding: 0 30rpx;
}
.search {
position: relative;
padding-right: 30rpx;
flex: 1;
view {
position: absolute;
left: 28rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #999999;
}
input {
flex: 1;
height: 72rpx;
background: #F8F8F8;
border-radius: 44rpx;
padding: 0 28rpx;
color: #333333;
}
image {
width: 34rpx;
height: 34rpx;
margin-right: 16rpx;
}
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<iframe id="bdIframe" :src="fileUrl" ref="bdIframe" style="border: none;" class="iframe" />
</view>
</template>
<script setup>
import {
useStore
} from '@/store';
import {
onLoad
} from '@dcloudio/uni-app';
import Base64 from '@/utils/code.js';
const baseUrl = import.meta.env.VITE_REQUEST_BASE_URL + '/jeecg-boot/sys/common/static/'
const store = useStore();
var fileUrl = "";
onLoad((options) => {
let base64 = new Base64();
var url= JSON.parse(options.data)
url = baseUrl + url;
fileUrl = 'https://10.75.166.6/preview/onlinePreview' + '?url=' + encodeURIComponent(base64.encode(url))
})
</script>
<style>
.container {
position: relative;
width: 100%;
height: 100vh;
}
#bdIframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>

366
pages/leave/application.vue Normal file
View File

@ -0,0 +1,366 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="form">
<view class="f-row aic jcb input_box">
<view class="title">
职工姓名
</view>
<input v-model="realname" disabled />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
工作单位
</view>
<input v-model="depart" disabled />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
联系方式
</view>
<input v-model="phone" />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
请假类型
</view>
<tree-select :dataSource="dataSource" v-model="type" dataValue="name" />
</view>
<picker mode="date" fields="day" @change="chooseStart" :value="beginTime" :end="endTime">
<view class="f-row aic jcb box">
<view class="title">
开始时间
</view>
<view class="f-row aic">
<view :class="[{'choose':!beginTime},{'choosed':beginTime}]">
{{beginTime?beginTime:'请选择'}}
</view>
<uni-icons type="bottom" color="#333333"></uni-icons>
</view>
</view>
</picker>
<picker mode="date" fields="day" @change="chooseEnd" :value="endTime" :start="beginTime">
<view class="f-row aic jcb box">
<view class="title">
截止时间
</view>
<view class="f-row aic">
<view :class="[{'choose':!endTime},{'choosed':endTime}]">
{{endTime?endTime:'请选择'}}
</view>
<uni-icons type="bottom" color="#333333"></uni-icons>
</view>
</view>
</picker>
<picker @change="bindType" :value="typeIndex" :range="typeArr" range-key="realname" v-if="ifShow">
<view class="f-row aic jcb box">
<view class="title">
审批领导
</view>
<view class="f-row aic">
<view :class="[{'choose':typeIndex==null},{'choosed':typeIndex!=null}]">
{{typeIndex!=null?typeArr[typeIndex].realname:'请选择'}}
</view>
<uni-icons type="bottom" color="#333333"></uni-icons>
</view>
</view>
</picker>
<view class="f-row aic jcb input_box">
<view class="title">
出发地
</view>
<input v-model="departure" placeholder="请输入" nplaceholder-style="font-size: 28rpx;color: #999999;" />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
目的地
</view>
<input v-model="destination" placeholder="请输入" nplaceholder-style="font-size: 28rpx;color: #999999;" />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
请假事由
</view>
<input v-model="reason" placeholder="请输入" placeholder-style="font-size: 28rpx;color: #999999;" />
</view>
<view class="f-row aic jcb input_box">
<view class="title">
上传附件
</view>
<uni-file-picker @select="select" :image-styles="imageStyles" />
</view>
</view>
<view class="btn f-col aic">
<view @click="qjAdd">
提交
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
getCurrentInstance
} from 'vue';
import {
startMutilProcessApi,
getCategoryItemsApi,
} from '@/api/api.js';
import {
qjAddApi,
queryZwmcAndExaApi
} from '@/api/pages.js';
import {
queryDepByCode,
queryZbDepByLdhth
} from '@/api/depart.js'
import {
onLoad
} from '@dcloudio/uni-app'
import {
useStore
} from '@/store';
import treeSelect from "@/components/treeSelect/treeSelect.vue"
const store = useStore()
const {
proxy
} = getCurrentInstance()
/**职工姓名*/
const realname = ref(store.userinfo.realname)
/**工作单位*/
const depart = ref('')
/**工作单位*/
const orgCode = ref('')
/**联系方式*/
const phone = ref(store.userinfo.phone)
/**请假类型*/
const type = ref('')
const dataSource = ref([])
/**开始时间*/
const beginTime = ref('')
const chooseStart = (e) => {
beginTime.value = e.detail.value
}
/**结束时间*/
const endTime = ref('')
const chooseEnd = (e) => {
endTime.value = e.detail.value
}
/**审批领导*/
const typeArr = ref([])
const typeIndex = ref(null)
/**判断是否显示审批领导字段*/
const ifShow = ref(true)
/**职位层级*/
const zwcj = ref('')
/**出发地*/
const departure = ref('')
/**目的地*/
const destination = ref('')
/**请假事由*/
const reason = ref('')
/**附件路径*/
const path = ref([])
const baseUrl = import.meta.env.VITE_REQUEST_BASE_URL + '/jeecg-boot/sys/common/upload/'
const imageStyles = {
width: 64,
height: 64,
border: {
color: "#dce7e1",
width: 2,
style: 'dashed',
radius: '2px'
}
}
onLoad(() => {
loadData()
getTomorrowDate()
})
const select = (e) => {
const tempFilePaths = e.tempFilePaths
for (let i = 0; i < e.tempFilePaths.length; i++) {
let photoPath = '职工请假/' + depart.value + '/' + store.userinfo.realname
uni.uploadFile({
url: baseUrl,
filePath: e.tempFilePaths[i],
name: 'file',
formData: {
appPath: photoPath
},
success: (res) => {
path.value.push(JSON.parse(res.data).message)
}
});
}
}
const qjAdd = () => {
if (!phone.value.trim()) return proxy.$toast('请输入联系方式')
if (!type.value) return proxy.$toast('请选择请假类型')
if (!beginTime.value) return proxy.$toast('请选择开始时间')
if (!endTime.value) return proxy.$toast('请选择结束时间')
if (ifShow.value) {
if (typeIndex.value == null) { //
return proxy.$toast('请选择审批领导')
}
}
if (!departure.value.trim()) return proxy.$toast('请输入出发地')
if (!destination.value.trim()) return proxy.$toast('请输入目的地')
if (!reason.value.trim()) return proxy.$toast('请输入请假事由')
qjAddApi({
sysOrgCode: orgCode.value,
username: store.userinfo.username,
phone: phone.value,
type: type.value,
begintime: beginTime.value,
endtime: endTime.value,
examineleader: typeArr.value[typeIndex.value] ? typeArr.value[typeIndex.value].username : '',
departure: departure.value,
destination: destination.value,
reason: reason.value,
zwmc: zwcj.value,
path: path.value.toString()
}).then((res) => {
if (res.success) {
startMutilProcess(res.message)
} else {
proxy.$toast(res.message);
}
})
}
const startMutilProcess = (id) => {
startMutilProcessApi({
flowCode: "dev_cxc_qxj",
id,
formUrl: "modules/qxj/modules/CxcQxjBpmModel",
formUrlMobile: "leaveApplication" //main.jscreateApp() app.component('leaveApplication',index)
}).then((res) => {
if (res.success) {
proxy.$toast(res.message)
setTimeout(() => {
uni.navigateBack()
}, 2000)
}
}).catch((err) => {
console.log(err);
})
}
const loadData = () => {
getCategoryItemsApi('1838487445813645313').then((res) => { //
if (res.success) {
dataSource.value = res.result
}
})
queryZbDepByLdhth(store.userinfo.workNo).then((res) => { //
depart.value = res.departName
orgCode.value = res.orgCode
})
queryZwmcAndExaApi(store.userinfo.username).then((res) => { //
if (res.success) {
typeArr.value = res.result.list
zwcj.value = res.result.zwmc
if (zwcj.value == '单位专家' || zwcj.value == '基层正职' || zwcj.value == '高级主管') {
ifShow.value = false;
}
} else {
proxy.$toast(res.message);
}
})
}
const bindType = (e) => {
typeIndex.value = e.detail.value
}
const getTomorrowDate = () => {
let today = new Date();
let tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
// yyyy-mm-dd
let year = tomorrow.getFullYear();
let month = String(tomorrow.getMonth() + 1).padStart(2, '0'); // 01
let day = String(tomorrow.getDate()).padStart(2, '0');
beginTime.value = year + '-' + month + '-' + day;
}
</script>
<style>
page {
background-color: #fff;
}
</style>
<style lang="scss" scoped>
.btn {
border-top: 1px solid #EFEFEF;
height: 120rpx;
justify-content: center;
position: fixed;
bottom: 0;
width: 100vw;
view {
width: 690rpx;
height: 88rpx;
background: #01508B;
border-radius: 16rpx;
font-size: 28rpx;
color: #FFFFFF;
text-align: center;
line-height: 88rpx;
}
}
.input_box {
height: 100rpx;
.title {
font-size: 28rpx;
color: #333333;
}
input {
flex: 1;
height: 100%;
text-align: right;
font-size: 28rpx;
color: #333333;
}
}
.form {
padding: 0 30rpx;
background-color: #fff;
.title {
font-size: 28rpx;
color: #333333;
}
.box {
height: 100rpx;
}
.box:not(:last-child) {
border-bottom: 1px solid #EFEFEF;
}
.choose {
font-size: 28rpx;
color: #999999;
}
.choosed {
font-size: 28rpx;
color: #333333;
}
}
</style>

322
pages/login/login.vue Normal file
View File

@ -0,0 +1,322 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="logo f-col aic">
<image src="@/static/login/logo.png"></image>
</view>
<view class="form f-col aic">
<view class="box f-row aic">
<image src="@/static/login/phone.png"></image>
<input v-model="username" type="text" placeholder="请输入统一身份认证"
placeholder-style="font-size: 28rpx;color: #999999;" />
</view>
<view class="box f-row aic">
<image src="@/static/login/pwd.png"></image>
<input v-model="password" :type="!showpwd?'password':'text'" placeholder="请输入密码"
placeholder-style="font-size: 28rpx;color: #999999;" />
<image v-if="showpwd" src="@/static/login/eye.png" @click="showpwd = !showpwd"></image>
<image v-else src="@/static/login/eye-off.png" @click="showpwd = !showpwd"></image>
</view>
</view>
<view class="pwd f-row aic">
<view style="display: inline-block;" @click="check = !check">
<view class="f-row aic">
<image v-if="!check" src="@/static/login/nocheck.png"></image>
<image v-else src="@/static/login/checked.png"></image>
<text>记住密码</text>
</view>
</view>
</view>
<view class="login f-col aic">
<view @click="login">
登录
</view>
</view>
<view class="login f-col aic">
<text style="font-size: 10px;">Copyright (c) 2024 天然气产销厂</text>
<text style="font-size: 10px;">版本号:{{systemInfo.appWgtVersion}}</text>
</view>
</view>
</template>
<script setup>
import {
ref,
getCurrentInstance,
watch
} from 'vue';
import {
loginApi,
localLoginApi,
queryRoleApi
} from '@/api/login.js';
import {
taskListApi
} from '@/api/api.js';
import Base64 from 'base-64';
import {
onLoad
} from '@dcloudio/uni-app'
import {
useStore
} from '@/store'
const store = useStore()
const {
proxy
} = getCurrentInstance()
/** 系统信息 */
const systemInfo = uni.getSystemInfoSync()
/**是否明文显示密码*/
const showpwd = ref(false)
/**用于用户缓存账号和密码*/
let localObj = {}
/**记住账号和密码*/
const savePwd = () => {
let localObj = {
un: username.value
}
if (check.value) {
localObj.pw = password.value
}
uni.setStorageSync('accountObj', JSON.stringify(localObj))
}
/**是否选中记住密码*/
const check = ref(true);
/**账号*/
const username = ref('')
/**密码*/
const password = ref('')
const login = () => {
if (!username.value.trim()) return proxy.$toast('请输入账号')
if (!password.value.trim()) return proxy.$toast('请输入密码')
let un = Base64.encode(encodeURIComponent(username.value))
let pw = Base64.encode(encodeURIComponent(password.value))
uni.showLoading({
title: '登录中...'
});
/*生产环境 begin */
// loginApi({
// username: un,
// password: pw,
// ip: getDeviceIp()
/*生产环境 end */
/*开发环境 begin */
localLoginApi({
username: username.value,
password: password.value,
captcha: 'app'
/*开发环境 end */
}).then((loginres) => {
if (loginres.success) {
uni.setStorageSync('token', loginres.result.token)
store.setToken(loginres.result.token)
savePwd()
queryRoleApi({
roles: loginres.result.userInfo.roles
}).then((roleres) => {
//
uni.setStorageSync('logintime', Date.now())
//
uni.setStorageSync('role', roleres)
store.setRole(roleres)
//
uni.setStorageSync('user', JSON.stringify(loginres.result
.userInfo))
store.setUserInfo(loginres.result.userInfo)
//
loadBadge()
//
uni.switchTab({
url: '/pages/tab/index'
})
})
}
}).catch((err) => {
console.log(err);
})
}
let localAccountArr = []
const accountArr = ref([])
onLoad(() => {
if (uni.getStorageSync('accountObj')) {
let obj = JSON.parse(uni.getStorageSync('accountObj'))
username.value = obj.un ? obj.un : ''
password.value = obj.pw ? obj.pw : ''
}
// localAccountArr = uni.getStorageSync('accountArr') ? JSON.parse(uni.getStorageSync('accountArr')) : []
// accountArr.value = localAccountArr
})
const loadBadge = () => {
taskListApi().then((res) => {
if (res.success) {
if (res.result.total > 0) {
uni.setTabBarBadge({
index: '1',
text: res.result.total //
});
} else {
uni.removeTabBarBadge({ //
index: '1',
});
}
}
})
}
function getDeviceIp() {
// #ifdef APP-PLUS
let deviceIp
if (plus.os.name == "Android") {
let Context = plus.android.importClass('android.content.Context')
let main = plus.android.runtimeMainActivity()
let cm = main.getSystemService(Context.CONNECTIVITY_SERVICE)
plus.android.importClass(cm)
let linkProperties = cm.getLinkProperties(cm.getActiveNetwork())
let linkAddrs = plus.android.invoke(linkProperties, 'getLinkAddresses')
plus.android.importClass(linkAddrs)
for (var i = 0; i < linkAddrs.size(); i++) {
let inetAddr = plus.android.invoke(linkAddrs.get(i), 'getAddress')
deviceIp = plus.android.invoke(inetAddr, 'getHostAddress')
}
//wifi
if (deviceIp == '') {
var wifiManager = plus.android.runtimeMainActivity().getSystemService(Context.WIFI_SERVICE);
var wifiInfo = plus.android.invoke(wifiManager, "getConnectionInfo");
var ipAddress = plus.android.invoke(wifiInfo, "getIpAddress");
if (ipAddress != 0) {
deviceIp = ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "." + (ipAddress >> 16 &
0xff) + "." + (ipAddress >> 24 & 0xff));
}
}
}
console.log(deviceIp)
return deviceIp;
// #endif
}
</script>
<style lang="scss" scoped>
:deep(.uni-select) {
border: none;
padding-left: 0;
height: 88rpx;
}
:deep(.uni-select__input-placeholder) {
font-size: 28rpx;
color: #999999;
}
:deep(.uni-icons) {
display: none;
}
.logo {
padding-top: 184rpx;
image {
width: 475rpx;
height: 199rpx;
}
}
.form {
margin-top: 60rpx;
.box {
width: 570rpx;
height: 88rpx;
background: #F8F8F8;
border-radius: 44rpx;
padding: 0 30rpx;
margin-top: 40rpx;
position: relative;
.account_box {
position: absolute;
top: 100rpx;
left: 90rpx;
width: 500rpx;
background-color: #fff;
box-shadow: 0px 0px 3px 1px #dfdfdf;
z-index: 99;
border-radius: 10rpx;
// &::after {
// position: absolute;
// content: ' ';
// border: 15rpx solid;
// border-color: transparent transparent #fff transparent;
// top: -30rpx;
// left: 30rpx;
// z-index: 999;
// }
.account {
max-height: 200rpx;
overflow-y: auto;
view {
padding: 10rpx;
}
}
}
image {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
input {
height: 100%;
flex: 1;
}
}
}
.pwd {
image {
width: 34rpx;
height: 34rpx;
margin-right: 4rpx;
}
justify-content: flex-end;
margin-top: 20rpx;
margin-right: 60rpx;
font-size: 24rpx;
color: #01508B;
}
.login {
margin-top: 63rpx;
view {
width: 630rpx;
height: 88rpx;
background: #4e74fb;
border-radius: 44rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
line-height: 88rpx;
}
}
</style>

32
pages/product/index.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<view :class="['f-col','aic',{'gray':store.isgray==1}]">
<dataCom title="实时输差" :list="shishiArr"></dataCom>
<dataCom title="偏远计量点" :list="shishiArr"></dataCom>
<dataCom title="生产实时数据" :list="productArr"></dataCom>
</view>
</template>
<script setup>
import dataCom from '@/bpm/dataCom.vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
ref
} from 'vue';
import {
useStore
} from '@/store'
const store = useStore()
const shishiArr = ref([])
const productArr = ref([])
onLoad((options) => {
shishiArr.value = JSON.parse(options.shishi)
productArr.value = JSON.parse(options.product)
})
</script>
<style lang="scss" scoped>
</style>

47
pages/safe/detail.vue Normal file
View File

@ -0,0 +1,47 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="">
<video src=""></video>
<view class="title">
五月天突然好想你线上演唱会精彩回放这里就是标题
</view>
</view>
<view class="listcom">
<safeCom></safeCom>
</view>
</view>
</template>
<script setup>
import safeCom from '../../bpm/safeCom.vue';
import {
useStore
} from '@/store'
const store = useStore()
</script>
<style>
page{
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content {
.title{
background-color: #fff;
font-size: 32rpx;
color: #333333;
line-height: 45rpx;
padding: 30rpx;
}
video{
width: 750rpx;
height: 500rpx;
}
}
.listcom{
padding:0 30rpx 30rpx 30rpx;
margin-top: 20rpx;
background-color: #fff;
}
</style>

86
pages/safe/manage.vue Normal file
View File

@ -0,0 +1,86 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<customNav>
<view class="nav_box f-row aic jcb">
<view class="back f-row aic" @click="back">
<uni-icons type="left" size="20" color="#fff"></uni-icons>
</view>
<view class="search f-row aic">
<input type="text" v-model="searchKey" @confirm="search" @blur="showicon=true&&!searchKey"
@focus="showicon=false" />
<view class="f-row aic" v-if="showicon">
<image src="../../static/search.png" mode=""></image>
<text>搜索</text>
</view>
</view>
</view>
</customNav>
<view class="">
<safeCom></safeCom>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import safeCom from '../../bpm/safeCom.vue';
import customNav from '../../bpm/customNav.vue';
import {
useStore
} from '@/store';
const store = useStore()
const showicon = ref(true)
const searchKey = ref('')
</script>
<style lang="scss" scoped>
.content {
padding: 0 30rpx 30rpx 30rpx;
}
.nav_box {
position: absolute;
bottom: 14rpx;
width: 100%;
left: 0;
}
.back {
padding: 0 30rpx;
}
.search {
position: relative;
padding-right: 30rpx;
flex: 1;
view {
position: absolute;
left: 28rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #999999;
}
input {
flex: 1;
height: 72rpx;
background: #F8F8F8;
border-radius: 44rpx;
padding: 0 28rpx;
}
image {
width: 34rpx;
height: 34rpx;
margin-right: 16rpx;
}
}
</style>

666
pages/tab/index.vue Normal file
View File

@ -0,0 +1,666 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="nav">
<view class="nav_box f-row aic jcb">
<!-- <view class="menu" @click="showDrawer()">
<image src="../../static/index/menu.png" mode=""></image>
</view> -->
<view class="weather_calender f-row aic">
<view class="position f-row aic">
<image src="../../static/index/position.png" mode=""></image>
<text>{{!store.position?'暂未定位':store.position}}</text>
</view>
<view class="position f-row aic">
<image style="height:80rpx;width:80rpx;"
:src="`http://openweathermap.org/img/w/${store.wenduIcon}.png`" mode=""></image>
<text>{{store.wendu}}</text>
</view>
<uni-datetime-picker type="date">
<view class="position f-row aic">
<image src="../../static/index/calendar.png" mode=""></image>
<text>{{getTime()}}</text>
</view>
</uni-datetime-picker>
</view>
</view>
</view>
<view class="f-col aic">
<swiper class="swiper" autoplay>
<swiper-item v-for="item,i in banner" :key="i" class="swiper-item">
<image :src="item" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<view class="wrapper f-col aic">
<view class="onduty">
<view class="title f-row aic jcb">
值班信息
<view class="more" @click="jump(`/pages/zhiban/index`)">
查看更多
<image src="../../static/index/back.png" mode=""></image>
</view>
</view>
<view class="info">
<view class="info_title f-row aic">
<view class="">
日期
</view>
<view class="">
带班领导
</view>
<view class="">
值班领导
</view>
<view class="">
值班干部
</view>
</view>
<view class="data_box">
<view :class="['data',' f-row', 'aic',{'first':i==0}]" v-for="item,i in zhibanArr">
<view class="">
{{item.date}}
</view>
<view class="">
{{item.dbld_dictText}}
</view>
<view class="">
{{item.zbld_dictText}}
</view>
<view class="">
{{item.zbgbrealname}}
</view>
</view>
</view>
</view>
</view>
<view class="list_wrapper">
<view class="">
<view class="list_title f-row aic jca">
<view v-for="item,i in tabArr" :class="{'active':current==i}" @click="changeTab(i)">
{{item}}
</view>
</view>
<view class="f-row aic zhidu" v-if="current==2">
<view :class="{'active':current_zhidu==0}" @click="changeZhidu(0)">
厂级制度
</view>
<view :class="{'active':current_zhidu==1}" @click="changeZhidu(1)">
上级制度
</view>
</view>
</view>
<view style="padding-top: 24rpx;" class="more"
@click="jump(`/pages/document/index?id=${current}`,current)">
查看更多
<image src="../../static/index/back.png" mode=""></image>
</view>
<view class="list_box">
<view class="list" v-for="item,i in list" :key="i"
@click="jump(`/pages/document/detail?data=${JSON.stringify(item)}&id=${current}`,current,item,'detail')">
<view class="topic">
{{item._title}}
</view>
<view class="time_Box f-row aic" v-if="item._time||item._depart">
<view class="time" v-if="item._time">
{{item._time}}
</view>
<view class="look f-row aic" v-if="item._depart">
{{item._depart}}
</view>
</view>
</view>
</view>
</view>
</view>
<!-- <uni-drawer ref="showLeft" mode="left" :width="156">
<view class="menu_list">
<view class="f-row aic jcb" v-for="item,i in menu" :key="i" @click="totask(item.path)">
<text>{{item.text}}</text>
<uni-icons type="right" size="20" color="#333333"></uni-icons>
</view>
</view>
</uni-drawer> -->
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
onLoad,
onPullDownRefresh,
// onReachBottom
} from '@dcloudio/uni-app';
import {
bpmlistApi,
gonggaolistApi,
zhibanApi,
faguiApi,
cjzhiduApi,
zhiduApi,
cxcDapingApi
} from '@/api/api.js';
import {
getUserPermissionApi
} from '@/api/login.js';
import customNav from '../../bpm/customNav.vue';
import {
useStore
} from '@/store';
import {
beforeJump,
getTime,
opendocument,
preview
} from '@/utils/index.js';
const baseurl = import.meta.env.VITE_REQUEST_BASE_URL + '/jeecg-boot'
const store = useStore();
onLoad(() => {
// list.value = []
// if (!uni.getStorageSync('token')) {
// return uni.navigateTo({
// url: '/pages/login/login'
// })
// }
cxcDaping()
zhiban()
// bpmlist()
// gonggaolist()
// zhidu()
// fagui()
getlist()
})
const banner = ref([])
/**轮播图*/
const cxcDaping = () => {
cxcDapingApi({
zslb: 6
}).then((res) => {
if (res.success) {
let arr = res.result.records[0].wenjian.split(',')
banner.value = arr.map((item) => {
return baseurl + '/sys/common/static/' + item
})
}
})
}
/**公文公告制度法规切换index*/
const current = ref(0)
/**厂级制度上级制度index 默认厂级*/
const current_zhidu = ref(0)
/**公文公告制度法规*/
const tabArr = ['公文', '公告', '制度', '法规']
/**公文公告制度法规切换*/
const changeTab = (i) => {
current.value = i
pageNo = 1
loading = false
list.value = []
getlist()
}
/**厂级制度上级制度切换*/
const changeZhidu = (i) => {
current_zhidu.value = i
pageNo = 1
loading = false
list.value = []
zhidu()
}
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = (statusHeight + 44) + "px";
const showLeft = ref(null)
const showDrawer = (e) => {
showLeft.value.open()
}
//
const closeDrawer = (e) => {
showLeft.value.close()
}
const totask = (url) => {
closeDrawer()
jump(url)
}
const jump = (url, type, item, page) => {
//
if (type && type == 1 && page == 'detail') return
//
if (type && type == 3 && item) {
return opendocument(item.mingcheng)
}
//
if (type && type == 2) {
url = url + `&zhiduid=${current_zhidu.value}`
}
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
// const menu = ref([{
// text: '',
// path: '/pages/task/index?id=0'
// },{
// text: '',
// path: '/pages/task/index?id=2'
// }])
let pageNo = 1
let pageSize = 5
let loading = false
const list = ref([])
/**公文接口*/
const bpmlist = () => {
loading = true
bpmlistApi({
pageNo,
pageSize
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'fwbt', 'fwtime', null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
/**公告接口*/
const gonggaolist = () => {
loading = true
gonggaolistApi({
pageNo,
pageSize
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'neirong', 'fbdw', 'createTime')]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
const zhibanArr = ref([])
/**值班接口*/
const zhiban = () => {
zhibanApi().then((res) => {
if (res.success) {
zhibanArr.value = res.result.records.slice(0, 2)
}
}).catch((err) => {
console.log('err', err);
})
}
/**法规接口*/
const fagui = () => {
loading = true
faguiApi({
pageNo,
pageSize
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...formatObj(res.result.records, 'flfgmc', 'ssbm', null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
/**制度接口*/
const zhidu = () => {
loading = true
let getzhidu = current_zhidu.value == 0 ? zhiduApi : cjzhiduApi
getzhidu({
pageNo,
pageSize
}).then((res) => {
if (res.success) {
let str = current_zhidu.value == 0 ? 'zbbm_dictText' : 'sbbm'
list.value = [...list.value, ...formatObj(res.result.records, 'zdmc', str, null)]
}
loading = false
}).catch((err) => {
console.log('err', err);
})
}
const formatObj = (arr, title, time, depart) => {
arr.map((item) => {
item['_title'] = item[title]
item['_time'] = item[time]
item['_depart'] = item[depart]
})
return arr
}
onPullDownRefresh(() => {
loading = false
list.value = []
cxcDaping()
zhiban()
getlist()
uni.stopPullDownRefresh()
})
const getlist = () => {
if (current.value == 0) {
bpmlist()
} else if (current.value == 1) {
gonggaolist()
} else if (current.value == 2) {
zhidu()
} else if (current.value == 3) {
fagui()
}
}
// onReachBottom(() => {
// if (loading) return
// pageNo++
// getlist()
// })
</script>
<style lang="scss" scoped>
.content {
padding-top: v-bind(cusnavbarheight);
}
::v-deep .uni-drawer {
margin-top: v-bind(cusnavbarheight);
}
// .menu_list {
// padding: 0 30rpx;
// font-size: 28rpx;
// color: #333333;
// view {
// height: 110rpx;
// border-bottom: 1px solid #EFEFEF;
// }
// image {
// width: 13rpx;
// height: 23rpx;
// }
// }
.nav {
width: calc(100% - 60rpx);
padding: 0 30rpx;
height: v-bind(cusnavbarheight);
font-size: 24rpx;
color: #333333;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-image: url('../../static/my/navbg.png');
background-repeat: no-repeat;
background-size: 750rpx 458rpx;
}
.nav_box {
position: absolute;
bottom: 26rpx;
width: calc(100% - 60rpx);
}
// .menu {
// image {
// width: 36rpx;
// height: 46rpx;
// }
// }
.weather_calender {
image {
width: 36rpx;
height: 36rpx;
margin-right: 8rpx;
}
.position:not(:last-child) {
position: relative;
margin-right: 60rpx;
&::after {
position: absolute;
content: ' ';
width: 2rpx;
height: 20rpx;
background: #EFEFEF;
right: -30rpx;
top: 50%;
transform: translateY(-50%);
}
}
}
.swiper {
width: 100vw;
height: 400rpx;
.swiper-item {
image {
width: 100vw;
height: 400rpx;
background-color: #a8a8a8;
}
}
}
.wrapper {
padding: 0 30rpx;
transform: translateY(-50rpx);
.onduty {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 20rpx 24rpx 24rpx 24rpx;
.title {
font-size: 32rpx;
color: #333333;
background-size: 44rpx 12rpx;
background-repeat: no-repeat;
background-position: left bottom;
}
.info {
background: #F8F8F8;
border-radius: 8rpx;
text-align: center;
width: 642rpx;
margin-top: 23rpx;
.info_title {
font-size: 24rpx;
color: #333333;
padding: 24rpx 0;
border-bottom: 1px solid #EFEFEF;
view {
flex: 1;
}
}
.data_box {
font-size: 24rpx;
padding-bottom: 24rpx;
color: #888888;
.first {
font-weight: bold;
color: #333333;
}
.data {
margin-top: 23rpx;
view {
flex: 1;
}
}
}
}
}
.more {
font-size: 24rpx;
color: #999999;
text-align: right;
image {
width: 10rpx;
height: 18rpx;
}
}
.list_wrapper {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 26rpx 24rpx 24rpx 24rpx;
position: relative;
margin-top: 30rpx;
width: 642rpx;
&::after {
position: absolute;
top: 100rpx;
left: 0;
content: ' ';
width: 100%;
height: 1px;
background-color: #EFEFEF;
}
.zhidu {
font-size: 24rpx;
color: #666666;
justify-content: flex-end;
padding-top: 40rpx;
view {
width: 120rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
&:first-child {
margin-right: 40rpx;
}
}
.active {
position: relative;
color: #3179d6;
&::after {
content: ' ';
width: 120rpx;
height: 60rpx;
border-radius: 60rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
background-color: rgba(49, 121, 214, 0.1);
}
}
}
.list_title {
text-align: center;
padding-bottom: 29rpx;
font-size: 32rpx;
color: #666666;
.active {
position: relative;
color: #3179d6;
&::after {
content: ' ';
width: 120rpx;
height: 70rpx;
border-radius: 70rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
background-color: rgba(49, 121, 214, 0.1);
}
}
}
.list_box {
margin-top: 24rpx;
.list {
margin-bottom: 24rpx;
padding: 30rpx 30rpx 35rpx 30rpx;
// width: 570rpx;
background: #F8F8F8;
border-radius: 8rpx;
.topic {
font-size: 28rpx;
color: #333333;
}
.time_Box {
font-size: 24rpx;
color: #888888;
margin-top: 20rpx;
.time {
margin-right: 62rpx;
}
.look {
position: relative;
&::before {
position: absolute;
left: -30rpx;
top: 50%;
transform: translateY(-50%);
content: ' ';
width: 2rpx;
height: 20rpx;
background: #999999;
}
}
image {
width: 28rpx;
height: 22rpx;
margin-right: 8rpx;
}
}
}
}
}
}
</style>

339
pages/tab/my.vue Normal file
View File

@ -0,0 +1,339 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="nav">
<view class="user f-row aic">
<view class="avatar">
<image @click="toProfile('/pages/useredit/useredit')" :src="imgUrl(store.userinfo.avatar)" mode="">
</image>
</view>
<view class="f-row aic jcb right">
<view class="name_job " @click="toProfile('/pages/useredit/useredit')">
<view class="f-row aic">
<view class="name">
{{store.userinfo.realname}}
</view>
</view>
<view class="job">
{{store.role}}
</view>
</view>
<view class="shezhi">
<image @click="scan" style="width: 50rpx;height: 50rpx;margin-right: 20rpx;"
src="../../static/tab/scan.png"></image>
<!-- <image src="../../static/my/shezhi.png" mode="" @click="toProfile('/pages/useredit/useredit')">
</image> -->
</view>
</view>
</view>
<view class="f-col aic">
<view class="msg f-row aic jca">
<!-- <view class="box f-col aic" @click="jump('/pages/task/todotask')">
<view class="num">
{{todoNum}}
</view>
<text>个人办公</text>
</view> -->
<view class="box f-col aic">
<view class="num">
{{0}}
</view>
<text>步数</text>
</view>
<view class="box f-col aic" @click="jump('/pages/useredit/addressbook')">
<view class="num">
0
</view>
<text>通讯录</text>
</view>
</view>
</view>
</view>
<view class="operate">
<view class="f-row aic jcb item" v-for="item,i in arr" :key="i" @click="jump(item.path)">
<view class="left f-row aic">
<image :src="item.img" mode=""></image>
<text>{{item.text}}</text>
</view>
<view class="right f-row aic">
<!-- <view class="" v-show="i==0">
<uni-icons type="right" color="#2C2C2C"></uni-icons>
</view> -->
<view class="switch" v-show="i==0" @click="messageSwitch=!messageSwitch">
<image v-show="messageSwitch" src="../../static/my/open.png" mode=""></image>
<image v-show="!messageSwitch" src="../../static/my/close.png" mode=""></image>
</view>
<view class="switch" v-show="i==2" @click="position">
<image v-show="positionSwitch" src="../../static/my/open.png" mode=""></image>
<image v-show="!positionSwitch" src="../../static/my/close.png" mode=""></image>
</view>
<view class="version" v-show="i==3">
当前版本v{{currentVersion}}
</view>
</view>
</view>
</view>
<view class="btn" @click="loginout">
退出登录
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
useStore
} from '@/store';
import {
queryRoleApi
} from '@/api/login.js';
import {
onLoad,
onShow
} from '@dcloudio/uni-app';
import {
beforeJump,
getLocation,
toast,
getWeather
} from '@/utils/index.js';
import {
imgUrl
} from '@/utils/index.js';
const store = useStore();
// h5访plus by
// #ifdef APP_PLUS
const currentVersion = ref(plus.runtime.version)
// #endif
const arr = ref([
// {
// img: '../../static/my/biao.png',
// text: '',
// path: '/pages/zhiban/index'
// },
// {
// img: '../../static/my/xiaoxi.png',
// text: '',
// path: ''
// }
// , {
// img: '../../static/my/dingwei.png',
// text: '',
// path: ''
// }, {
// img: '../../static/my/shengji.png',
// text: '',
// path: ''
// },
])
const messageSwitch = ref(false)
const positionSwitch = ref(store.positionSwitch)
const jump = (url) => {
if (!url) return
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
/**跳转个人资料*/
const toProfile = (url) => {
uni.navigateTo({
url
})
}
/**定位*/
const position = () => {
positionSwitch.value = !positionSwitch.value
uni.setStorageSync('positionSwitch', positionSwitch.value)
store.setPositionSwitch(positionSwitch.value)
if (!positionSwitch.value) {
toast('定位已关闭')
}
getLocation()
}
/**扫码*/
const scan = () => {
uni.scanCode({
success: function(res) {
plus.runtime.openWeb(res.result)
}
})
}
const loginout = () => {
uni.showModal({
title: '退出登录',
content: '您确认要退出登录吗?',
success(res) {
if (res.confirm) {
uni.removeStorageSync('token')
uni.removeStorageSync('user')
uni.removeStorageSync('role')
uni.removeStorageSync('logintime')
uni.reLaunch({
url: '/pages/login/login'
})
}
}
})
}
// onShow(() => {
// taskList()
// })
// const todoNum = ref(0)
// const taskList = () => {
// taskListApi({
// pageNo: 1,
// pageSize: 4,
// _t: new Date().getTime()
// }).then((res) => {
// if (res.success) {
// todoNum.value = res.result.total
// }
// })
// }
</script>
<style lang="scss" scoped>
.btn {
position: fixed;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-size: 32rpx;
color: #DB4B31;
}
.operate {
padding: 0 30rpx;
transform: translateY(-10rpx);
.item {
height: 104rpx;
border-bottom: 1px solid #EFEFEF;
.version {
font-size: 24rpx;
color: #888888;
}
}
.switch {
image {
width: 68rpx;
height: 38rpx;
}
}
.left {
font-size: 28rpx;
color: #333333;
image {
width: 44rpx;
height: 44rpx;
margin-right: 30rpx;
}
}
}
.msg {
width: 690rpx;
height: 142rpx;
background-image: url('../../static/my/bg1.png');
background-size: 690rpx 142rpx;
margin-top: 30rpx;
.box {
justify-content: center;
width: 33.33%;
.num {
font-size: 32rpx;
color: #333333;
margin-bottom: 4rpx;
}
text {
font-size: 24rpx;
color: #888888;
}
}
.box:not(:last-child) {
position: relative;
&::after {
content: ' ';
width: 1rpx;
height: 32rpx;
background: #D8D8D8;
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
.nav {
height: 458rpx;
background-image: url('../../static/my/navbg.png');
background-size: 750rpx 458rpx;
.user {
padding: 128rpx 30rpx 0 30rpx;
.right {
flex: 1;
}
.avatar {
margin-right: 24rpx;
image {
width: 110rpx;
height: 110rpx;
border-radius: 50%;
background-color: #fff;
}
}
.name_job {
.name {
font-size: 36rpx;
color: #333333;
}
.status {
padding: 4rpx 12rpx;
background: #55B800;
border-radius: 8rpx;
font-size: 20rpx;
color: #FFFFFF;
display: inline-block;
margin-left: 8rpx;
}
.job {
font-size: 24rpx;
color: #666666;
margin-top: 6rpx;
}
}
.shezhi {
image {
width: 42rpx;
height: 42rpx;
}
}
}
}
</style>

197
pages/tab/office.vue Normal file
View File

@ -0,0 +1,197 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="nav"></view>
<view class="placeholder"></view>
<!-- <view class="drag" v-if="listorder?.length"> //20240929 yzq 注释 这部分是拖拽组件
<view class="title">
{{ listtitle}}
</view>
<l-drag :list="listorder" @change="change" :column="4" gridHeight="100px">
<template #grid="{active, content}">
<view class="inner f-col aic" :class="{'active': active}" @click="jump(content.path)">
<view class="img f-row aic">
<image :src="`../../static/office/${content.meta.icon}.png`" mode=""></image>
</view>
<view class="text">
{{content?.meta.title}}
</view>
</view>
</template>
</l-drag>
</view> -->
<view class="title f-col aic" style="padding-top: 30rpx;" v-if="!listorder?.length&&!arr?.length">
暂无权限请联系管理员
</view>
<view class="content">
<view class="list" v-if="arr?.length">
<view class="item" v-for="item,i in arr" :key="i">
<view class="title">
{{item.meta.title}}
</view>
<view class="info_box f-row aic">
<view class="info f-col aic" @click="jump(e.path)" v-for="e,i in item.children" :key="i">
<view class="img f-row aic">
<image :src="`../../static/office/${e.meta.icon}.png`"></image>
</view>
<view class="text">
{{e.meta.title}}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
beforeJump
} from '@/utils/index.js';
import {
onLoad
} from '@dcloudio/uni-app';
import {
getUserPermissionApi
} from '@/api/login.js';
import {
useStore
} from '@/store';
const store = useStore();
const list = new Array(7).fill(0).map((v, i) => i);
//
const newList = ref([])
const change = v => newList.value = v
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = (statusHeight + 44) + "px";
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
onLoad(() => {
getUserPermission()
})
const arr = ref([])
const listorder = ref([]) //
const listtitle = ref([]) //title
const getUserPermission = () => {
getUserPermissionApi({
token: store.token,
type: 'mobile'
}).then((res) => {
if (res.success) {
let data = res.result.menu
data.map(item => item.children = item?.children.filter(e => e?.meta?.icon))
data = data.filter(item => item?.children?.length)
listtitle.value = data[0]?.meta?.title
// arr.value = data.slice(1, data?.length)
arr.value = data;
listorder.value = data.slice(0, 1)[0]?.children
}
}).catch((err) => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.drag {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
margin: 24rpx 30rpx 0 30rpx;
.title {
font-size: 28rpx;
color: #333333;
padding: 30rpx 0 0 30rpx;
}
}
.inner {
image {
width: 98rpx;
height: 98rpx;
background-color: #efefef;
}
.text {
font-size: 28rpx;
color: #333333;
margin-top: 20rpx;
}
}
.placeholder {
height: v-bind(cusnavbarheight);
}
.nav {
width: calc(100% - 60rpx);
padding: 0 30rpx;
height: v-bind(cusnavbarheight);
font-size: 24rpx;
color: #FFFFFF;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-image: url('../../static/my/navbg.png');
background-repeat: no-repeat;
background-size: 750rpx 458rpx;
}
.content {
padding: 0 30rpx 20rpx 30rpx;
}
.list {
margin-bottom: 24rpx;
.item {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx 0;
margin-top: 24rpx;
.title {
font-size: 28rpx;
color: #333333;
padding-left: 30rpx;
}
}
image {
width: 98rpx;
height: 98rpx;
}
.info_box {
flex-wrap: wrap;
.info {
margin-top: 40rpx;
width: 25%;
.text {
font-size: 28rpx;
color: #333333;
margin-top: 20rpx;
}
}
}
}
</style>

244
pages/tab/product.vue Normal file
View File

@ -0,0 +1,244 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="nav">
</view>
<view class="content">
<view class="info f-col aic">
<view class="item_box">
<dataCom title="实时输差" :list="shishiArr"></dataCom>
<dataCom title="偏远计量点" :list="shishiArr"></dataCom>
<dataCom title="生产实时数据" :list="productArr"></dataCom>
<view class="item">
<view class="title_box other f-row aic jcb">
<view class="title">
其他信息
</view>
</view>
<view class="other_box f-row aic">
<view class="data" v-for="other,i in otherArr" :key="i" @click="jump(other.path)">
<view class="f-col aic">
<image :src="other.img" mode=""></image>
<view class="">
{{other.text}}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
indexChartScdtDataApi
} from '@/api/api.js';
import {
beforeJump
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const store = useStore();
import dataCom from '@/bpm/dataCom.vue';
const shishiArr = [{
gas: '今日进气总量',
dailyVolume: '28392'
}, {
gas: '今日进气总量',
dailyVolume: '28392'
}, {
gas: '今日输差百分数',
dailyVolume: '0.32'
}, {
gas: '实时进气总量',
dailyVolume: '28392'
}, {
gas: '实时进气总量',
dailyVolume: '28392'
}, {
gas: '实时输差百分数',
dailyVolume: '0.32'
}, ]
const productArr = ref([])
let otherArr
onLoad(() => {
indexChartScdtData()
})
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = (statusHeight + 44) + "px";
const indexChartScdtData = () => {
indexChartScdtDataApi().then((res) => {
if (res.success) {
productArr.value = handleData(res.result.today)
otherArr = [{
text: '安全管理',
img: '../../static/tab/anquan.png',
path: '/pages/safe/manage'
}, {
text: '生产数据',
img: '../../static/tab/product.png',
path: `/pages/product/index?shishi=${JSON.stringify(shishiArr)}&product=${JSON.stringify(productArr.value)}`
}, {
text: '运输管理',
img: '../../static/tab/yunshu.png',
path: ''
}, {
text: '设备台账',
img: '../../static/tab/taizhang.png',
path: ''
}, {
text: '车辆派遣',
img: '../../static/tab/cheliang.png',
path: ''
}, {
text: '事项审批',
img: '../../static/tab/shenpi.png',
path: ''
}]
}
}).catch((err) => {
console.log(err);
})
}
const handleData = (arr) => {
let arrMap = new Map()
arr.forEach(el => {
if (arrMap.has(el.gas)) {
let obj = arrMap.get(el.gas)
arrMap.set(el.gas, {
...el,
dailyVolume: Number(el.dailyVolume + +obj.dailyVolume).toFixed(4)
})
} else {
arrMap.set(el.gas, el)
}
})
return [...arrMap.values()]
}
const jump = (url) => {
beforeJump(url, () => {
if (!url) return
uni.navigateTo({
url
})
})
}
</script>
<style>
page {
background-color: #F8F8F8;
}
</style>
<style lang="scss" scoped>
.nav {
width: calc(100% - 60rpx);
padding: 0 30rpx;
height: v-bind(cusnavbarheight);
font-size: 24rpx;
color: #FFFFFF;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-image: url('../../static/my/navbg.png');
background-repeat: no-repeat;
background-size: 750rpx 458rpx;
}
.content {
padding: v-bind(cusnavbarheight) 0 42rpx 0;
}
.info {
.item_box {
.item {
width: 690rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx 0;
margin-top: 24rpx;
.title_box {
padding: 0 30rpx;
margin-bottom: -20rpx;
}
.title {
font-size: 28rpx;
color: #333333;
background-image: url('../../static/index/line.png');
background-size: 44rpx 13rpx;
background-repeat: no-repeat;
background-position: left bottom;
}
.more {
font-size: 24rpx;
color: #999999;
text {
margin-right: 6rpx;
}
}
.data_box {
.data {
width: 33.33%;
margin-top: 60rpx;
}
flex-wrap: wrap;
view {
font-size: 32rpx;
color: #333333;
margin-bottom: 8rpx;
}
text {
font-size: 24rpx;
color: #333333;
}
}
.other {
margin-bottom: -10rpx;
}
.other_box {
flex-wrap: wrap;
.data {
width: 25%;
margin-top: 40rpx;
font-size: 28rpx;
color: #333333;
image {
width: 98rpx;
height: 98rpx;
margin-bottom: 20rpx;
}
}
}
}
}
}
</style>

120
pages/talk/conversation.vue Normal file
View File

@ -0,0 +1,120 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="list">
<view class="item" v-for="item,i in 14" :key="i">
<view class="left f-row aic" v-show="i%2==0">
<view class="avatar f-row aic">
<image src="../../static/system.png" mode=""></image>
</view>
<view class="content">
你今天在干嘛呢为什么这么久不回我信息真的生气了
</view>
</view>
<view class="right f-row aic" v-show="i%2!=0">
<view class="content">
请问如何退款
</view>
<view class="avatar f-row aic">
<image src="" mode=""></image>
</view>
</view>
</view>
</view>
<view class="input_box f-row aic jce">
<input type="text" placeholder="请输入内容......" placeholder-style="font-size: 28rpx;color: #999999;" />
<view class="send">
发送
</view>
</view>
</view>
</template>
<script setup>
import {
useStore
} from '@/store';
const store = useStore();
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content {
padding-bottom: 120rpx;
}
.input_box {
position: fixed;
width: 750rpx;
height: 120rpx;
background: #FFFFFF;
bottom: 0;
left: 0;
input {
width: 467rpx;
height: 80rpx;
background: #F8F8F8;
border-radius: 8rpx;
padding: 0 30rpx;
}
.send {
width: 133rpx;
height: 80rpx;
background: #01508B;
border-radius: 8rpx;
text-align: center;
line-height: 80rpx;
font-size: 28rpx;
color: #FFFFFF;
}
}
.list {
padding: 40rpx 30rpx;
.item:not(:first-child) {
margin-top: 60rpx;
}
.item {
image {
width: 86rpx;
height: 86rpx;
border-radius: 50%;
background-color: maroon;
}
.left {
.content {
padding: 24rpx 30rpx;
background: #FFFFFF;
border-radius: 0rpx 16rpx 16rpx 16rpx;
margin-left: 24rpx;
font-size: 28rpx;
color: #333333;
}
}
.right {
justify-content: flex-end;
.content {
margin-right: 24rpx;
padding: 24rpx 30rpx;
background: #01508B;
border-radius: 16rpx 0rpx 16rpx 16rpx;
font-size: 28rpx;
color: #FFFFFF;
}
}
}
}
</style>

105
pages/talk/message_list.vue Normal file
View File

@ -0,0 +1,105 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="list">
<view class="item f-row aic">
<view class="f-row aic">
<image src="../../static/system.png" mode=""></image>
</view>
<view class="name_info">
<view class="name_time f-row aic jcb">
<view class="name">
系统通知
</view>
<view class="time">
1分钟前
</view>
</view>
<view class="info">
关于年假通知关于年假通知关于年假通知关于年假通知关于年假通知关于年假通知关于年假通知
</view>
</view>
</view>
<view class="item f-row aic" v-for="item,i in 5" :key="i" @click="jump('/pages/talk/conversation')">
<view class="f-row aic">
<image src="" mode=""></image>
</view>
<view class="name_info">
<view class="name_time f-row aic jcb">
<view class="name">
系统通知
</view>
<view class="time">
1分钟前
</view>
</view>
<view class="info">
关于年假通知
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
beforeJump
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const store = useStore();
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
</script>
<style lang="scss" scoped>
.list {
padding: 0 30rpx;
}
.item:not(:last-child) {
border-bottom: 1px solid #EFEFEF;
}
.item {
height: 150rpx;
.name_info {
flex: 1;
}
.name {
font-size: 32rpx;
color: #333333;
}
.info {
margin-top: 4rpx;
width: 540rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.time,
.info {
font-size: 28rpx;
color: #999999;
}
image {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #f8f8f8;
margin-right: 24rpx;
}
}
</style>

60
pages/talk/system.vue Normal file
View File

@ -0,0 +1,60 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="list">
<view class="item" v-for="item,i in 3" :key="i">
<view class="left f-row aic">
<view class="avatar f-row aic">
<image src="../../static/system.png" mode=""></image>
</view>
<view class="content">
你今天在干嘛呢为什么这么久不回我信息真的生气了
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
useStore
} from '@/store';
const store = useStore();
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content{
padding-bottom: 120rpx;
}
.list {
padding: 40rpx 30rpx;
.item:not(:first-child) {
margin-top: 60rpx;
}
.item {
image {
width: 86rpx;
height: 86rpx;
border-radius: 50%;
}
.left {
.content {
padding: 24rpx 30rpx;
background: #FFFFFF;
border-radius: 0rpx 16rpx 16rpx 16rpx;
margin-left: 24rpx;
font-size: 28rpx;
color: #333333;
}
}
}
}
</style>

374
pages/task/handle.vue Normal file
View File

@ -0,0 +1,374 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<customNav>
<view class="f-row aic box">
<view class="back" @click="back">
<uni-icons type="left" size="20" color="#fff"></uni-icons>
</view>
<view class="avatar">
<image :src="imgUrl(store.userinfo.avatar)" mode=""></image>
</view>
<view class="name">
{{taskInfo.processApplyUserName}}{{taskInfo.processDefinitionName}}
</view>
<view class="status" v-if="type==0">
待审批
</view>
<view class="status" v-if="type==1" style="background-color: #7AC756;">
已处理
</view>
</view>
</customNav>
<component :is="comp" :dataId="dataId"></component>
<view class="btn f-row aic jcb" v-if="type == 0">
<view class="refuse" @click="openpop(1)">
拒绝
</view>
<view class="agree" @click="openpop(2)">
同意
</view>
</view>
<uni-popup ref="popup" type="center">
<view class="popup">
<view class="title">
审批意见
</view>
<view class="f-col aic">
<view class="input f-col">
<textarea v-model="reason" name="" id="" maxlength="200" placeholder="请输入"></textarea>
<view class="">
{{reason.length}}/200
</view>
</view>
</view>
<view v-if="status==2" class="agree_operate f-row aic" @click="chooseNextPerson=!chooseNextPerson">
<image v-if="chooseNextPerson" src="../../static/login/checked.png" mode=""></image>
<image v-else src="../../static/login/nocheck.png" mode=""></image>
<view class="">
指定下一步操作人
</view>
</view>
<view class="" v-else>
<picker :value="currentnode" :range="stepNode" range-key="NAME_" @change="nodeChange">
<view class="node">{{currentnode!=null?stepNode[currentnode].NAME_:'请选择驳回节点'}}</view>
</picker>
</view>
<view class="popbtn f-row aic">
<view class="cancel" @click="closepop">
取消
</view>
<view class="confirm" @click="handleProcess">
确定
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import {
ref,
getCurrentInstance
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
getProcessNodeInfoApi,
processCompleteApi,
getProcessTaskTransInfoApi,
getHisProcessNodeInfoApi,
} from '@/api/api.js';
import {
beforeJump
} from '@/utils/index.js';
import customNav from '../../bpm/customNav.vue';
import {
imgUrl
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const store = useStore()
const {
proxy
} = getCurrentInstance()
const popup = ref(null)
const reason = ref('')
/**拒绝(1)||同意(2)*/
const status = ref(null)
const openpop = (val) => {
status.value = val
popup.value.open()
reason.value = val == 2 ? '同意' : ''
}
const closepop = () => {
popup.value.close()
}
const comp = ref(null)
const dataId = ref('')
const getProcessNodeInfo = (taskId) => {
getProcessNodeInfoApi({
taskId
}).then((res) => {
if (res.success) {
dataId.value = res.result.dataId
comp.value = res.result.formUrlMobile
}
})
}
const back = () => {
uni.navigateBack()
}
/**是否指定下一步操作人*/
const chooseNextPerson = ref(false)
let nextnode = null
/**流程办理判断*/
const handleProcess = () => {
// if (!reason.value.trim()) return proxy.$toast('')
let params = {}
if (status.value == 1) { //
if (currentnode.value == null) return proxy.$toast('请选择驳回节点')
params.processModel = 3
params.rejectModelNode = stepNode.value[currentnode.value].TASK_DEF_KEY_
processComplete(params)
} else { //
if (chooseNextPerson.value) { //
beforeJump('/pages/userlist/index', () => {
closepop()
uni.navigateTo({
url: `/pages/userlist/index?id=${taskInfo.value.id}&isradio=1&nextnode=${JSON.stringify(nextnode)}&reason=${reason.value}`
})
})
} else {
params.processModel = 1
processComplete(params)
}
}
}
/**流程办理接口*/
const processComplete = (params) => {
processCompleteApi({
taskId: taskInfo.value.id,
reason: reason.value,
...params
}).then((res) => {
if (res.success) {
proxy.$toast(res.message)
setTimeout(() => {
uni.navigateBack()
}, 2000)
}
})
}
/**审批流程节点*/
const stepNode = ref([])
/**当前选择的节点*/
const currentnode = ref(null)
/**切换节点*/
const nodeChange = (e) => {
currentnode.value = e.detail.value
}
const getProcessTaskTransInfo = (e) => {
getProcessTaskTransInfoApi({
taskId: taskInfo.value.id
}).then((res) => {
if (res.success) {
stepNode.value = res.result.histListNode
nextnode = res.result.transitionList
}
})
}
/**历史任务详情*/
const getHisProcessNodeInfo = (procInstId) => {
getHisProcessNodeInfoApi({
procInstId
}).then((res) => {
if (res.success) {
dataId.value = res.result.dataId
comp.value = res.result.formUrlMobile
}
})
}
const taskInfo = ref(null)
let type = null
onLoad((options) => {
taskInfo.value = JSON.parse(options.info)
type = options.type
if (type == 1 || type == 2) {
return getHisProcessNodeInfo(taskInfo.value.processInstanceId)
}
getProcessNodeInfo(taskInfo.value.id)
getProcessTaskTransInfo()
})
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.popup {
width: 690rpx;
background: #FFFFFF;
border-radius: 8rpx;
.node {
margin: 24rpx;
font-size: 28rpx;
color: #333333;
padding: 0 20rpx;
}
.agree_operate {
padding: 24rpx;
font-size: 28rpx;
color: #333333;
image {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
}
.title {
font-size: 32rpx;
color: #000000;
text-align: center;
padding: 40rpx 0;
}
.input {
width: 582rpx;
height: 226rpx;
background: #F8F8F8;
border-radius: 8rpx;
padding: 24rpx;
textarea {
flex: 1;
width: 100%;
}
view {
text-align: right;
font-size: 28rpx;
color: #999999;
}
}
.popbtn {
font-size: 32rpx;
border-top: 1px solid #E5E5E5;
margin-top: 40rpx;
position: relative;
&::after {
position: absolute;
content: ' ';
height: 100rpx;
width: 1px;
background-color: #E5E5E5;
left: 50%;
transform: translateX(-50%);
}
view {
flex: 1;
text-align: center;
height: 100rpx;
line-height: 100rpx;
}
.cancel {
color: #000000;
}
.confirm {
color: #007FFF;
}
}
}
.content {
// margin-top: 88rpx;
padding-bottom: 120rpx;
}
.btn {
position: fixed;
bottom: 0;
width: 690rpx;
height: 120rpx;
background: #FFFFFF;
padding: 0 30rpx;
view {
width: 330rpx;
height: 88rpx;
font-size: 28rpx;
border-radius: 16rpx;
text-align: center;
line-height: 88rpx;
}
.refuse {
box-sizing: border-box;
background: #FFFFFF;
border: 2rpx solid #01508B;
color: #01508B;
}
.agree {
background: #01508B;
color: #FFFFFF;
}
}
.box {
position: absolute;
bottom: 12rpx;
left: 0;
}
.back {
padding-left: 30rpx;
}
image {
width: 64rpx;
height: 64rpx;
border-radius: 32rpx;
background-color: #fff;
margin-right: 16rpx;
margin-left: 50rpx;
}
.name {
font-size: 28rpx;
color: #FFFFFF;
}
.status {
padding: 4rpx 8rpx;
display: inline-block;
background-color: #FE4600;
color: #FFFFFF;
font-size: 20rpx;
margin-left: 8rpx;
border-radius: 8rpx;
}
</style>

184
pages/task/index.vue Normal file
View File

@ -0,0 +1,184 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="nav">
<view class="tab_box f-row aic jca">
<view :class="{'active':i==currentIndex}" v-for="item,i in tabArr" :key="i" @click="change(i)">
{{item.text}}
</view>
</view>
</view>
<view class="tasklist">
<tasklistCom @jump="jump" :taskArr="taskArr" :currentIndex="currentIndex"></tasklistCom>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import tasklistCom from '../../bpm/tasklistCom.vue';
import { toast } from '@/utils/index.js';
import {
taskListApi,
taskHistoryListApi
} from '@/api/api.js';
import {
onLoad,
onShow,
onReachBottom,
onPullDownRefresh
} from '@dcloudio/uni-app';
import {
beforeJump
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const store = useStore()
let processDefinitionName = ''
onLoad((options) => {
currentIndex.value = +options.id
processDefinitionName = options.title
})
onShow(() => {
taskArr.value = []
pageNo = 1
pageSize = 10
loading = false
taskList()
})
const tabArr = ref([{
text: '我的任务',
id: 0
},
{
text: '历史任务',
id: 1
}])
const date = ref('')
const currentIndex = ref(0)
let pageNo = 1
let pageSize = 10
let loading = false
const taskArr = ref([])
const taskList = () => {
loading = true
uni.showLoading({
title: '加载中...'
})
let getlist = currentIndex.value == 0 ? taskListApi : taskHistoryListApi
getlist({
// createTime: date.value ? date.value + ' 00:00:00' : '',
pageNo,
pageSize,
_t: new Date().getTime(),
processDefinitionName
}).then((res) => {
if (res.success) {
if (!res.result.records.length) return toast('没有更多了~')
taskArr.value = [...taskArr.value, ...(res?.result?.records || [])]
loading = false
}
}).catch((err) => {
console.log(err);
})
}
const change = (i) => {
taskArr.value = []
pageNo = 1
pageSize = 10
loading = false
currentIndex.value = i
taskList()
}
const chooseTime = () => {
taskArr.value = []
taskList()
}
onReachBottom(() => {
if (loading) return
pageNo++
taskList()
})
onPullDownRefresh(() => {
pageNo = 1
pageSize = 10
loading = false
taskArr.value = []
taskList()
uni.stopPullDownRefresh()
})
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.tasklist {
padding-top: 100rpx;
}
.nav {
background-color: #fff;
// height: 200rpx;
height: 100rpx;
width: 100vw;
position: fixed;
top: 0;
left: 0;
z-index: 99;
.tab_box {
padding: 24rpx 0;
view {
position: relative;
font-size: 28rpx;
color: #666666;
}
.active {
font-size: 28rpx;
color: #01508B;
&::after {
position: absolute;
width: 230rpx;
height: 2rpx;
background: #01508B;
content: ' ';
bottom: -22rpx;
left: 50%;
transform: translateX(-50%);
}
}
}
.time_box {
padding: 20rpx 0;
.time {
padding: 0 30rpx;
width: 630rpx;
height: 72rpx;
background: #F8F8F8;
border-radius: 8rpx;
image {
width: 34rpx;
height: 34rpx;
}
}
}
}
</style>

79
pages/task/self.vue Normal file
View File

@ -0,0 +1,79 @@
<template>
<view :class="{'gray':store.isgray==1}">
<tasklistCom @jump="jump" :taskArr="taskArr" :currentIndex="2"></tasklistCom>
</view>
</template>
<script setup>
import {
beforeJump
} from '@/utils/index.js';
import tasklistCom from '../../bpm/tasklistCom.vue';
import {
ref
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import {
useStore
} from '@/store';
import {
myApplyProcessListApi
} from '@/api/api.js';
import { toast } from '@/utils/index.js';
const store = useStore()
const taskArr = ref([])
let processName = ''
onLoad((options) => {
processName = options.title
getmyApply()
})
let pageNo = 1
let pageSize = 10
let loading = false
const getmyApply = () => {
loading = true
uni.showLoading({
title:'加载中...'
})
myApplyProcessListApi({
pageNo,
pageSize,
_t: new Date().getTime(),
processName
}).then((res) => {
if (res.success) {
if(!res.result.records.length)return toast('没有更多了~')
let arr = res.result.records
arr.map((item) => {
item['processApplyUserName'] = item['startUserName']
item['processDefinitionName'] = item['prcocessDefinitionName']
item['taskBeginTime'] = item['startTime']
})
taskArr.value = [...taskArr.value, ...arr]
loading = false
}
}).catch((err) => {
console.log(err);
})
}
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
onReachBottom(() => {
if (loading) return
pageNo++
getmyApply()
})
</script>
<style lang="scss" scoped>
</style>

264
pages/task/todotask.vue Normal file
View File

@ -0,0 +1,264 @@
<template>
<view :class="[{'gray':store.isgray==1}]">
<view class="nav"></view>
<view class="placeholder"></view>
<view class="content">
<extendCom title="我的任务" img="process" :list="todoArr" :total="todoTotal" type="0"></extendCom>
<extendCom title="历史任务" img="done" :list="doneArr" :total="doneTotal" type="1"></extendCom>
<extendCom title="本人发起" img="self" :list="selfArr" :total="selfTotal" type="2"></extendCom>
</view>
</view>
</template>
<script setup>
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = (statusHeight + 44) + "px";
import extendCom from '../../bpm/extendCom.vue';
import {
ref
} from 'vue';
import {
taskListApi,
myApplyProcessListApi,
taskHistoryListApi
} from '@/api/api.js';
import {
onShow,
onReachBottom,
onPullDownRefresh
} from '@dcloudio/uni-app';
import {
useStore
} from '@/store'
const store = useStore()
onShow(() => {
initArr()
taskList()
taskHistoryList()
myApplyProcessList()
uni.removeTabBarBadge({ //
index: '1',
});
})
const todoArr = ref([])
const todoTotal = ref(0)
/**待办事项*/
const taskList = () => {
taskListApi({
pageNo: 1,
pageSize: 4,
_t: new Date().getTime()
}).then((res) => {
if (res?.success) {
if (res?.result?.total > 4) {
taskListApi({
pageNo: 1,
pageSize: res?.result?.total,
_t: new Date().getTime()
}).then((res1) => {
console.log('---', res1)
if (res1?.success) {
todoArr.value = [...todoArr.value, ...handleData(res1?.result?.records)]
todoTotal.value = res1?.result?.total
}
}).catch((err) => {
console.log('err', err);
})
} else {
todoArr.value = [...todoArr.value, ...handleData(res?.result?.records)]
todoTotal.value = res?.result?.total
}
}
}).catch((err) => {
console.log(err);
})
}
const doneArr = ref([])
const doneTotal = ref(0)
/**已办事项*/
const taskHistoryList = () => {
taskHistoryListApi().then((res) => {
if (res.success) {
if (res.result.total > 4) {
taskHistoryListApi({
pageNo: 1,
pageSize: res.result.total,
_t: new Date().getTime()
}).then((res1) => {
if (res1.success) {
doneArr.value = [...doneArr.value, ...handleData(res1.result.records)]
doneTotal.value = res1.result.total
}
}).catch((err) => {
console.log(err);
})
} else {
doneArr.value = [...doneArr.value, ...handleData(res.result.records)]
doneTotal.value = res.result.total
}
}
}).catch((err) => {
console.log(err);
})
}
const selfArr = ref([])
const selfTotal = ref(0)
/**本人发起*/
const myApplyProcessList = () => {
myApplyProcessListApi().then((res) => {
if (res.success) {
if (res.result.total > 4) {
myApplyProcessListApi({
pageNo: 1,
pageSize: res.result.total,
_t: new Date().getTime()
}).then((res1) => {
if (res1.success) {
selfArr.value = [...selfArr.value, ...handleData(res1.result.records)]
selfTotal.value = res1.result.total
}
}).catch((err) => {
console.log(err);
})
} else {
selfArr.value = [...selfArr.value, ...handleData(res.result.records)]
selfTotal.value = res.result.total
}
}
}).catch((err) => {
console.log(err);
})
}
const handleData = (titlearr) => {
let titleArr = titlearr.length ? titlearr.map(item => item.processDefinitionName || item
.prcocessDefinitionName) : []
let res = titleArr.reduce((obj, title) => {
if (title in obj) {
obj[title]++
} else {
obj[title] = 1
}
return obj
}, {})
return Object.entries(res).map(([k, v]) => ({
title: k,
num: v
}))
}
const initArr = () => {
todoArr.value = []
selfArr.value = []
doneArr.value = []
todoTotal.value = 0
doneTotal.value = 0
selfTotal.value = 0
}
let loading = false
onPullDownRefresh(() => {
loading = false
initArr()
taskList()
taskHistoryList()
myApplyProcessList()
uni.stopPullDownRefresh()
})
</script>
<style lang="scss" scoped>
.drag {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
margin: 24rpx 30rpx 0 30rpx;
.title {
font-size: 28rpx;
color: #333333;
padding: 30rpx 0 0 30rpx;
}
}
.inner {
image {
width: 98rpx;
height: 98rpx;
background-color: #efefef;
}
.text {
font-size: 28rpx;
color: #333333;
margin-top: 20rpx;
}
}
.placeholder {
height: v-bind(cusnavbarheight);
}
.nav {
width: calc(100% - 60rpx);
padding: 0 30rpx;
height: v-bind(cusnavbarheight);
font-size: 24rpx;
color: #FFFFFF;
position: fixed;
top: 0;
left: 0;
z-index: 99;
background-image: url('../../static/my/navbg.png');
background-repeat: no-repeat;
background-size: 750rpx 458rpx;
}
.content {
padding: 0 30rpx 20rpx 30rpx;
}
.list {
margin-bottom: 24rpx;
.item {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx 0;
margin-top: 24rpx;
.title {
font-size: 28rpx;
color: #333333;
padding-left: 30rpx;
}
}
image {
width: 98rpx;
height: 98rpx;
}
.info_box {
flex-wrap: wrap;
.info {
margin-top: 40rpx;
width: 25%;
.text {
font-size: 28rpx;
color: #333333;
margin-top: 20rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,106 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="area f-row jcb">
<view class="title topic">
所在地区
</view>
<input type="text" placeholder="省、市、区、街道" />
</view>
<view class="area f-row jcb">
<view class="title topic">
详细地址
</view>
<textarea placeholder="小区楼栋/乡村名称"></textarea>
</view>
<view class="area f-row jcb">
<view class="title">
设为默认地址
</view>
<image src="../../static/login/checked.png" mode=""></image>
<!-- <image src="../../static/login/nocheck.png" mode=""></image> -->
</view>
<view class="btn f-col aic">
<view class="">
保存
</view>
</view>
</view>
</template>
<script setup>
import {
useStore
} from '@/store'
const store = useStore()
</script>
<style>
page {
background-color: #fff;
}
</style>
<style lang="scss" scoped>
.content {
padding: 30rpx 30rpx 120rpx 30rpx;
}
.area:not(:first-child) {
margin-top: 40rpx;
}
.area {
image {
width: 38rpx;
height: 38rpx;
}
.topic {
margin-top: 28rpx;
}
.title {
font-size: 32rpx;
color: #333333;
}
input {
width: 472rpx;
height: 96rpx;
background: #F6F6F6;
border-radius: 16rpx;
padding: 0 30rpx;
}
textarea {
width: 472rpx;
height: 104rpx;
background: #F6F6F6;
border-radius: 16rpx;
padding: 28rpx 30rpx;
}
}
.btn {
position: fixed;
bottom: 0;
width: 750rpx;
height: 120rpx;
background: #FFFFFF;
justify-content: center;
left: 0;
view {
width: 690rpx;
height: 88rpx;
background: #01508B;
border-radius: 8rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
line-height: 88rpx;
}
}
</style>

143
pages/useredit/address.vue Normal file
View File

@ -0,0 +1,143 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="list">
<view class="item" v-for="item,i in 2" :key="i">
<view class="province f-row aic">
<view class="">
浙江省杭州市
</view>
<image src="../../static/my/default.png" mode=""></image>
</view>
<view class="address f-row jcb">
<view class="">
重庆 重庆市 渝北区 龙溪街道花卉园东路黄金
宝高级住宅小区
</view>
<image src="../../static/my/edit.png" mode=""></image>
</view>
<view class="set f-row aic jcb">
<view class="f-row aic">
<!-- <image src="../../static/login/checked.png" mode=""></image> -->
<image src="../../static/login/nocheck.png" mode=""></image>
设为默认地址
</view>
<view class="">
删除
</view>
</view>
</view>
</view>
<view class="btn f-col aic">
<view class="" @click="jump('/pages/useredit/add_address')">
+添加收货地址
</view>
</view>
</view>
</template>
<script setup>
import {
beforeJump
} from '@/utils/index.js';
import {
useStore
} from '@/store'
const store = useStore()
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
</script>
<style>
page {
background-color: #f8f8f8;
}
</style>
<style lang="scss" scoped>
.content {
padding-bottom: 120rpx;
}
.list {
padding: 30rpx;
.item:not(:first-child) {
margin-top: 30rpx;
}
.item {
padding: 30rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
.province {
font-size: 28rpx;
color: #333333;
margin-bottom: 10rpx;
image {
width: 56rpx;
height: 36rpx;
margin-left: 16rpx;
}
}
.address {
font-size: 24rpx;
color: #666666;
padding-bottom: 30rpx;
border-bottom: 1px solid #EFEFEF;
view {
flex: 1;
}
image {
width: 28rpx;
height: 30rpx;
margin-left: 20rpx;
}
}
.set {
margin-top: 30rpx;
font-size: 24rpx;
color: #666666;
image {
width: 38rpx;
height: 38rpx;
margin-right: 12rpx;
}
}
}
}
.btn {
position: fixed;
bottom: 0;
width: 750rpx;
height: 120rpx;
background: #FFFFFF;
justify-content: center;
view {
width: 690rpx;
height: 88rpx;
background: #01508B;
border-radius: 8rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
line-height: 88rpx;
}
}
</style>

View File

@ -0,0 +1,65 @@
<template>
<view :class="{'gray':store.isgray==1}">
<view class="list">
<view class="item f-row aic jcb" v-for="item,i in 4" :key="i">
<view class="user f-row aic">
<image src="" mode=""></image>
<view class="name_job">
<view class="name">
我是晴天
</view>
<view class="job">
销售部-销售总监
</view>
</view>
</view>
<view class="btn">
电话联系
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
useStore
} from '@/store'
const store = useStore()
</script>
<style lang="scss" scoped>
.list{
padding: 0 30rpx;
.item{
padding: 30rpx 0;
border-bottom: 1px solid #EFEFEF;
image{
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
background-color: #EFEFEF;
margin-right: 30rpx;
}
.name{
font-size: 32rpx;
color: #333333;
}
.job{
font-size: 24rpx;
color: #999999;
margin-top: 8rpx;
}
.btn{
width: 132rpx;
height: 60rpx;
background: #01508B;
border-radius: 8rpx;
text-align: center;
line-height: 60rpx;
font-size: 24rpx;
color: #FFFFFF;
}
}
}
</style>

182
pages/useredit/useredit.vue Normal file
View File

@ -0,0 +1,182 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="box">
<view>头像</view>
<view style="display: flex;align-items: center;">
<button class="head-btn" @click="chooseAvatar">
<image class="head-img" v-if="!form.avatar" :src="imgUrl(store.userinfo.avatar)" mode="">
</image>
<image class="head-img" v-else :src="imgUrl(form.avatar)"></image>
</button>
<uni-icons type="right" size="24"></uni-icons>
</view>
</view>
<view class="box" style="padding-top: 30rpx;padding-bottom: 30rpx;">
<view>姓名</view>
<input disabled style="text-align: right;" type="nickname"
placeholder-style="font-size: 32rpx;color: #999999;" v-model="store.userinfo.realname"
placeholder="请输入姓名" />
</view>
<view class="box" style="padding-top: 30rpx;padding-bottom: 30rpx;">
<view>手机号</view>
<input style="text-align: right;" type="nickname" v-model="store.userinfo.phone"
placeholder="请输入手机号" placeholder-style="font-size: 32rpx;color: #999999;" />
</view>
<view class="box" style="padding-top: 30rpx;padding-bottom: 30rpx;">
<view>劳动合同号</view>
<input style="text-align: right;" type="nickname" disabled v-model="store.userinfo.workNo"
placeholder="请输入劳动合同号" placeholder-style="font-size: 32rpx;color: #999999;" />
</view>
</view>
<view class="line">
</view>
</template>
<script setup>
import {
reactive,
ref
} from "vue";
import {
onLoad
} from '@dcloudio/uni-app';
import {
userEditApi,
} from '@/api/api.js';
import {
beforeJump,
imgUrl
} from '@/utils/index.js';
import {
useStore
} from '@/store';
const baseUrl = import.meta.env.VITE_REQUEST_BASE_URL + '/jeecg-boot/sys/common/upload'
const store = useStore()
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
const chooseAvatar = () => {
uni.chooseImage({
count: 1,
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
const photoPath = '用户头像/' + store.userinfo.realname
uni.uploadFile({
url: baseUrl, //
filePath: tempFilePaths[0],
name: 'file',
formData: {
appPath: photoPath
},
success: (res) => {
uni.showLoading({
title: '上传中...'
})
form.avatar = JSON.parse(res.data).message
userEditApi({
avatar: form.avatar,
id: store.userinfo.id
}).then((res) => {
if (res) {
uni.showToast({
title: res,
icon: 'success',
duration: 2000
})
}
}).catch((err) => {
console.log(err);
})
},
fail(err) {
console.log('图片上传出错', err);
}
});
}
});
}
const form = reactive({
avatar: '',
realname: '',
phone: ''
})
onLoad(() => {
uni.setNavigationBarColor({
frontColor: "#ffffff",
backgroundColor: '#bebebe'
})
})
</script>
<style scoped lang="scss">
.choose {
font-size: 32rpx;
color: #999999;
}
.choosed {
font-size: 32rpx;
color: #333333;
}
button::after {
display: none;
}
.content {
padding: 30rpx 30rpx 0 30rpx;
.box:not(:last-child) {
border-bottom: 1rpx solid #EFEFEF;
}
.box {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
color: #333333;
button {
background-color: #fff;
margin: 0;
padding: 0;
border: none;
image {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #f8f8f8;
}
}
.value {
color: #999999;
}
}
.out_login {
color: #ED361D;
font-size: 32rpx;
font-weight: bold;
margin-top: 60rpx;
text-align: center;
}
}
.line {
height: 10rpx;
background: #F8F8F8;
}
</style>

338
pages/userlist/index.vue Normal file
View File

@ -0,0 +1,338 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<uni-data-picker @popupclosed="popclose($event)" :step-searh="false" :map="{text:'departName',value:'id'}"
:localdata="departList" popup-title="请选择部门" placeholder="请选择部门" @nodeclick="onnodeclick">
</uni-data-picker>
<view class="search_box">
<view class="username f-row aic">
用户姓名<input v-model="realname" type="text" placeholder="请输入姓名"
placeholder-style="color: grey;font-size: 28rpx;">
</view>
<view class="username f-row aic">
用户账号<input v-model="username" type="text" placeholder="请输入账号"
placeholder-style="color: grey;font-size: 28rpx;">
</view>
<view class="btn f-row aic jca">
<view class="f-row aic" @click="search">
<uni-icons type="search" size="15" color="#fff"></uni-icons>
查询
</view>
<view class="f-row aic" @click="refresh">
<uni-icons type="refreshempty" size="15" color="#fff"></uni-icons>
重置
</view>
</view>
</view>
<view class="list">
<view class="title f-row aic box">
<view class="">
</view>
<view class="">
序号
</view>
<view class="username">
用户账号
</view>
<view class="">
用户姓名
</view>
</view>
<view class="item f-row aic box" v-for="item,i in userlist" :key="i">
<view class="f-row aic img" @click="choose(item.id)">
<image v-if="chooseArr.includes(item.id)" src="../../static/login/checked.png" mode=""></image>
<image v-else src="../../static/login/nocheck.png" mode=""></image>
</view>
<view class="order">
{{i+1}}
</view>
<view class="username f-col aic">
<view class="">
{{item.username}}
</view>
</view>
<view class="realname">
<view class="">
{{item.realname}}
</view>
</view>
</view>
</view>
<view class="confirm f-col aic">
<view class="" @click="handleprocess">
确认
</view>
</view>
</view>
</template>
<script setup>
import {
onLoad
} from '@dcloudio/uni-app';
import {
ref,
getCurrentInstance
} from 'vue';
import {
queryMyDeptTreeListApi,
queryUserByDepIdApi,
taskEntrustApi,
processCompleteApi
} from '@/api/api.js';
import {
useStore
} from '@/store';
const store = useStore()
const {
proxy
} = getCurrentInstance()
const departList = ref([])
/**部门列表*/
const queryMyDeptTreeList = () => {
queryMyDeptTreeListApi().then((res) => {
departList.value = res.result
currentId = res.result[0].id
queryUserByDepId(res.result[0].id)
}).catch((err) => {
console.log(err);
})
}
const userlist = ref([])
/**根据部门查询人员*/
const queryUserByDepId = (id, username, realname) => {
queryUserByDepIdApi({
id,
username: username || '',
realname: realname || ''
}).then((res) => {
if (res.success) {
userlist.value = res.result
}
}).catch((err) => {
console.log(err);
})
}
let currentId = null
let departArr = []
const onnodeclick = (e) => {
queryUserByDepId(e.id)
currentId = e.id
if (departArr.indexOf(e.title) != -1) {
departArr.splice(departArr.indexOf(e.title), 1, e.title)
} else {
departArr.push(e.title)
}
}
const popclose = (e) => {
console.log('qqq', e);
}
const chooseArr = ref([])
const choose = (id) => {
if (isradio) { //
if (chooseArr.value.indexOf(id) != -1) return
chooseArr.value.splice(chooseArr.value.indexOf(id), 1, id)
} else { //
if (chooseArr.value.indexOf(id) != -1) {
chooseArr.value.splice(chooseArr.value.indexOf(id), 1)
} else {
chooseArr.value.push(id)
}
}
}
/**0为多选1单选*/
let isradio = 0
/**任务id*/
let taskId = null
/**nextnode*/
let nextnode = null
/**reason*/
let reason = null
onLoad((options) => {
isradio = options.isradio
taskId = options.id
reason = options.reason
if (options.nextnode) {
nextnode = JSON.parse(options.nextnode)
}
queryMyDeptTreeList()
})
const username = ref('')
const realname = ref('')
const search = () => {
if (username.value.trim() || realname.value.trim()) {
userlist.value = []
queryUserByDepId(currentId, username.value, realname.value)
}
}
const refresh = () => {
username.value = ''
realname.value = ''
userlist.value = []
queryUserByDepId(currentId, username.value, realname.value)
}
/**委托*/
const taskEntrust = () => {
if (!chooseArr.value.length) return proxy.$toast('请选择被委托人')
taskEntrustApi({
taskAssignee: userlist.value.filter(item => item.id == chooseArr.value[0])[0].username,
taskId
}).then((res) => {
if (res.success) {
proxy.$toast(res.message)
setTimeout(() => {
uni.navigateBack()
}, 2000)
}
})
}
const handleprocess = () => {
if (nextnode) {
processComplete()
} else {
taskEntrust()
}
}
/**流程办理接口*/
const processComplete = () => {
processCompleteApi({
taskId,
reason,
processModel: 1,
nextnode: nextnode[0].nextnode,
nextUserName: userlist.value.filter(item => item.id == chooseArr.value[0])[0].realname,
nextUserId: chooseArr.value[0],
}).then((res) => {
proxy.$toast(res.message)
setTimeout(() => {
uni.navigateBack()
}, 2000)
})
}
</script>
<style lang="scss" scoped>
.content {
padding-bottom: 130rpx;
}
.confirm {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
background-color: #fff;
border-top: 1px solid #efefef;
width: 100%;
padding: 20rpx 0;
view {
width: 630rpx;
height: 88rpx;
background: #01508B;
border-radius: 44rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
line-height: 88rpx;
}
}
.search_box {
font-size: 28rpx;
.username {
padding: 0 20rpx;
border-bottom: 1px solid #e5e5e5;
height: 100rpx;
input {
flex: 1;
height: 100%;
}
}
.btn {
color: #fff;
padding: 20rpx 0;
view {
width: 178rpx;
height: 80rpx;
background-color: #01508B;
border-radius: 40rpx;
justify-content: center;
}
}
}
.list {
word-break: break-all;
font-size: 28rpx;
color: #333333;
.box {
view:first-child {
flex: 0.3;
}
view:nth-child(2) {
flex: 0.3;
}
view:nth-child(3) {
flex: 1;
}
view:nth-child(4) {
flex: 1;
}
}
.title {
text-align: center;
border-bottom: 1px solid #e5e5e5;
background-color: #f8f8f8;
height: 100rpx;
}
.item {
text-align: center;
border-bottom: 1px solid #e5e5e5;
.order {
border-right: 1px solid #e5e5e5;
height: 100rpx;
line-height: 100rpx;
}
.username {
border-right: 1px solid #e5e5e5;
height: 100rpx;
justify-content: center;
overflow-y: auto;
}
.realname {
height: 100rpx;
line-height: 100rpx;
overflow-y: auto;
justify-content: center;
}
.img {
border-right: 1px solid #e5e5e5;
height: 100rpx;
justify-content: center;
}
image {
width: 40rpx;
height: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<view>
<uni-card :is-shadow="false">
<uni-section title="台账信息" type="line">
<uni-card :is-shadow="false">
<button type="primary" @click="getTaizhang">人员台账</button>
</uni-card>
</uni-section>
<uni-section title="统计信息" type="line">
<uni-card :is-shadow="false">
<text class="uni-body">这是一个基础卡片示例内容较少此示例展示了一个没有任何属性不带阴影的卡片</text>
</uni-card>
</uni-section>
</uni-card>
</view>
</template>
<script>
export default {
components: {
},
data() {
return {
}
},
methods: {
getTaizhang() {
uni.navigateTo({
url:"/pages/views/renliziyuan/renyuanxinxi/taizhang"
})
}
},
}
</script>
<style>
</style>

View File

@ -0,0 +1,183 @@
<template>
<view>
<scroll-view :scroll-y="true">
<uni-card>
<uni-title title="" type="h1" align="center"></uni-title>
<view>
<uni-row>
<uni-col :span="11"><uni-title title="姓名 " align="left" type="h5"></uni-title></uni-col>
<uni-col :span="11" :push="2"><uni-title title="劳动合同号" align="left"
type="h5"></uni-title></uni-col>
</uni-row>
<uni-row>
<uni-col :span="11"><uni-easyinput v-model="xm" focus suffixIcon="search" placeholder="姓名模糊查询"
@change="Search" @iconClick="Search" /></uni-col>
<uni-col :span="11" :push="2">
<uni-easyinput v-model="ldhth" focus suffixIcon="search" placeholder="劳动合同号模糊查询"
@change="Search" @iconClick="Search" />
</uni-col>
</uni-row>
</view>
<view style="margin-bottom: 10rpx;">
<uni-row>
<uni-col :span="24"><uni-title title="所属单位" align="left" type="h5"></uni-title></uni-col>
</uni-row>
<uni-row>
<uni-col :span="24">
<trq-depart-select returnCodeOrID="orgCode" @change="departChange"></trq-depart-select>
</uni-col>
</uni-row>
</view>
</uni-card>
<uni-card>
{{rrr}}
<zb-table :show-header="true" :highlight="true" :columns="column" :stripe="true" :fit="false"
:border="true" :data="ryDataList"></zb-table>
</uni-card>
</scroll-view>
<uni-load-more :status="status" :content-text="contentText"></uni-load-more>
</view>
</template>
<script setup>
import {
onReady,
onLoad
} from '@dcloudio/uni-app';
import {
reactive,
ref
} from 'vue';
import {
useStore
} from '@/store';
import {
queryDepByCode,
queryZbDepByLdhth
} from '@/api/depart.js'
import {
queryRenyuanByDepartID
} from '@/api/renyuan.js'
let xm = ref("")
let ldhth = ref("")
let departID = ref("") //ID
let ryDataList = ref([])
let rrr=ref("")
let status = ref("false")
let contentText = reactive({
contentdown: '点击查看更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
})
let pageNo = ref(1)
let pageSize = ref(10)
let params = reactive({
pageNo: pageNo,
pageSize: pageSize
})
let column = ref([{
label: '序号',
width: 60,
type: 'index',
color: 'blue',
align: 'center'
},
{
name: 'xm',
label: '姓名',
width: 70,
align: 'center'
},
{
name: 'gzdw',
label: '单位',
align: 'center',
width: 150
},
{
name: 'xb_dictText',
label: '性别',
align: 'center',
width: 60
},
{
name: 'nl',
label: '年龄',
align: 'center',
width: 60
},
{
name: 'operation',
type: 'operation',
label: '操作',
align: 'center',
renders: [{
name: '详情',
func: 'detail',
size: 'mini'
}]
}
])
onLoad((e) => {
})
function detail() {
}
function departChange (e){
ryDataList = []
departID.value = e
let queryParm = {
pageNo: pageNo.value,
pageSize: pageSize.value
};
queryParm.orgCode = departID.value
queryRenyuanByDepartID(queryParm).then((res) => {
if (res.success) {
ryDataList.value = res.result.records
rrr.value=ryDataList[0].xm
console.log(ryDataList)
}
}).catch((err) => {
console.log(err);
})
}
const Search = () => {
ryDataList = [];
let queryParm = {
pageNo: pageNo.value,
pageSize: pageSize.value
};
if ((ldhth.value == '') & (xm.value == '')) {
return;
}
if (xm.value !== '') {
queryParm.xm = '*' + xm.value + '*';
}
if (ldhth.value !== '') {
queryParm.ldhth = '*' + ldhth.value + '*';
}
queryRenyuanByDepartID(queryParm).then((res) => {
if (res.success) {
ryDataList = res.result.records
console.log(ryDataList)
}
}).catch((err) => {
console.log(err);
})
}
</script>
<style scoped>
.uni-group {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,212 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<view class="list_box">
<view class="list">
<view class="title f-row aic jcb">
<view class="">
年度部门讨论会议
</view>
<text>1分钟前</text>
</view>
<view class="info">
<view class="f-row aic jcb">
<view class="">
会议状态
</view>
<text>待开始/已开始/已结束</text>
</view>
<view class="f-row aic jcb">
<view class="">
发起人
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议日期
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议地点
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议内容
</view>
<text>周如意</text>
</view>
<view class="">
<view class="">
参与人员
</view>
<view class="person f-row aic">
<view class="item f-col aic" v-for="item,i in 7" :key="i">
<image src="" mode=""></image>
<view class="name">
周如意
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="btn f-row aic jcb">
<view class="refuse">
拒绝
</view>
<view class="agree" @click="openpop">
同意
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
huiyiDetailApi
} from '@/api/api.js';
import {
onLoad
} from '@dcloudio/uni-app';
import {
useStore
} from '@/store'
const store = useStore()
onLoad(() => {
huiyiDetail()
})
const huiyiDetail = () => {
huiyiDetailApi({
mainid:1
}).then((res) => {
if (res.success) {
}
}).catch((err) => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.content{
padding-bottom: 120rpx;
}
.btn {
position: fixed;
bottom: 0;
width: 690rpx;
height: 120rpx;
background: #FFFFFF;
padding: 0 30rpx;
border-top: 1px solid #EFEFEF;
view {
width: 330rpx;
height: 88rpx;
font-size: 28rpx;
border-radius: 16rpx;
text-align: center;
line-height: 88rpx;
}
.refuse {
box-sizing: border-box;
background: #FFFFFF;
border: 2rpx solid #01508B;
color: #01508B;
}
.agree {
background: #01508B;
color: #FFFFFF;
}
}
.list_box {
.list {
padding: 30rpx;
margin-bottom: 30rpx;
.title {
border-bottom: 1px solid #efefef;
padding-bottom: 24rpx;
margin-bottom: 8rpx;
view {
font-size: 28rpx;
color: #333333;
}
text {
font-size: 28rpx;
color: #999999;
}
}
.info {
font-size: 28rpx;
color: #666666;
view {
padding-top: 16rpx;
font-size: 28rpx;
color: #666666;
}
text{
font-size: 28rpx;
color: #333333;
}
.person{
flex-wrap: wrap;
.item{
width: 16.66%;
}
image{
width: 78rpx;
height: 78rpx;
border-radius: 38rpx;
background-color: #01508B;
}
}
}
.btn {
margin-top: 30rpx;
view {
width: 300rpx;
height: 64rpx;
border-radius: 8rpx;
font-size: 28rpx;
text-align: center;
line-height: 64rpx;
}
.entrust {
background: #FFFFFF;
border: 2rpx solid #01508B;
box-sizing: border-box;
color: #01508B;
}
.handle {
background: #01508B;
color: #FFFFFF;
}
}
}
}
</style>

View File

@ -0,0 +1,247 @@
<template>
<view :class="{'gray':store.isgray==1}">
<customNav>
<view class="nav_box f-row aic jcb">
<view class="back f-row aic" @click="back">
<uni-icons type="left" size="20" color="#fff"></uni-icons>
</view>
<view class="search f-row aic">
<input type="text" v-model="searchKey" @confirm="search" @blur="showicon=true&&!searchKey"
@focus="showicon=false" />
<view class="f-row aic" v-if="showicon">
<image src="@/static/search.png" mode=""></image>
<text>搜索</text>
</view>
</view>
</view>
</customNav>
<view class="list_box">
<view class="list" v-for="item,i in 3" :key="i" @click="jump(`/pages/meeting/detail?id=1`)">
<view class="title f-row aic jcb">
<view class="">
年度部门讨论会议
</view>
<text>1分钟前</text>
</view>
<view class="info">
<view class="f-row aic jcb">
<view class="">
发起人
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议日期
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议地点
</view>
<text>周如意</text>
</view>
<view class="f-row aic jcb">
<view class="">
会议内容
</view>
<text>周如意</text>
</view>
</view>
<!-- <view class="btn f-row aic jcb">
<view class="entrust">
拒绝
</view>
<view class="handle">
同意
</view>
</view> -->
<view class="handled f-row">
<view class="refused">
已拒绝
</view>
<!-- <view class="agreed">
已同意
</view> -->
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
useStore
} from '@/store'
const store = useStore()
import {
huiyilistApi
} from '@/api/api.js';
import customNav from '@/bpm/customNav.vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
beforeJump
} from '@/utils/index.js';
const showicon = ref(true)
const searchKey = ref('')
onLoad(() => {
// huiyilist()
})
const huiyilist = () => {
huiyilistApi().then((res) => {
if (res.success) {
}
}).catch((err) => {
console.log(err);
})
}
const jump = (url) => {
beforeJump(url, () => {
uni.navigateTo({
url
})
})
}
const back = () => {
uni.navigateBack()
}
</script>
<style lang="scss" scoped>
.nav_box {
position: absolute;
bottom: 14rpx;
width: 100%;
left: 0;
}
.back {
padding: 0 30rpx;
}
.search {
position: relative;
padding-right: 30rpx;
flex: 1;
view {
position: absolute;
left: 28rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #999999;
}
input {
flex: 1;
height: 72rpx;
background: #F8F8F8;
border-radius: 44rpx;
padding: 0 28rpx;
}
image {
width: 34rpx;
height: 34rpx;
margin-right: 16rpx;
}
}
.list_box {
padding: 14rpx 30rpx 0 30rpx;
margin-top: 24rpx;
.list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.5);
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.title {
border-bottom: 1px solid #efefef;
padding-bottom: 24rpx;
margin-bottom: 8rpx;
view {
font-size: 28rpx;
color: #333333;
}
text {
font-size: 28rpx;
color: #999999;
}
}
.info {
font-size: 28rpx;
color: #666666;
view {
padding-top: 16rpx;
}
}
.btn {
margin-top: 30rpx;
view {
width: 300rpx;
height: 64rpx;
border-radius: 8rpx;
font-size: 28rpx;
text-align: center;
line-height: 64rpx;
}
.entrust {
background: #FFFFFF;
border: 2rpx solid #01508B;
box-sizing: border-box;
color: #01508B;
}
.handle {
background: #01508B;
color: #FFFFFF;
}
}
}
}
.refused {
color: #333333;
}
.agreed {
color: #01508B;
}
.handled {
justify-content: flex-end;
margin-top: 30rpx;
view {
width: 150rpx;
height: 64rpx;
background: #EFEFEF;
border-radius: 8rpx;
text-align: center;
line-height: 64rpx;
font-size: 28rpx;
}
}
</style>

View File

@ -0,0 +1,118 @@
<template>
<view :class="['f-col','aic',{'gray':store.isgray==1}]">
<picker fields="month" mode="date" @change="bindPickerChange" :value="index">
<view class="date">{{index}} 点击选择月份</view>
</picker>
<view class="info">
<view class="info_title f-row aic">
<view class="">
日期
</view>
<view class="">
带班领导
</view>
<view class="">
值班领导
</view>
<view class="">
值班干部
</view>
</view>
<view class="data_box">
<view class="data f-row aic" v-for="item,i in zhibanArr">
<view class="">
{{item.date}}
</view>
<view class="">
{{item.dbld_dictText}}
</view>
<view class="">
{{item.zbld_dictText}}
</view>
<view class="">
{{item.zbgbrealname}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
zhibanQueryApi
} from '@/api/api.js';
import {
useStore
} from '@/store';
const store = useStore()
import dayjs from 'dayjs';
const zhibanArr = ref([])
onLoad(() => {
zhibanQuery()
})
const index = ref(dayjs().format("YYYY-MM"))
const bindPickerChange = (e) => {
index.value = e.detail.value
zhibanQuery()
}
const zhibanQuery = () => {
let [year, month] = index.value.split('-')
zhibanQueryApi({
year,
month
}).then((res) => {
zhibanArr.value = res.result.records
}).catch((err) => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.date {
width: 690rpx;
padding: 20rpx 30rpx 0 30rpx;
font-size: 28rpx;
color: #333333;
}
.info {
background: #F8F8F8;
border-radius: 8rpx;
text-align: center;
width: 690rpx;
margin-top: 23rpx;
.info_title {
font-size: 24rpx;
color: #333333;
padding: 24rpx 0;
border-bottom: 1px solid #EFEFEF;
view {
flex: 1;
}
}
.data_box {
font-size: 24rpx;
padding-bottom: 24rpx;
color: #888888;
.data {
margin-top: 23rpx;
view {
flex: 1;
}
}
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/checkin/circle1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
static/checkin/circle2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
static/checkin/circle3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
static/checkin/circle4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
static/checkin/shibai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/index/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

BIN
static/index/calendar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/index/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/index/line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
static/index/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

BIN
static/index/position.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
static/index/rili.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/login/checked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/login/eye-off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
static/login/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/login/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
static/login/nocheck.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/login/phone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

BIN
static/login/pwd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/my/bg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
static/my/biao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/my/chart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
static/my/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
static/my/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
static/my/dingwei.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
static/my/done.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
static/my/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

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