修改生产页面的显示逻辑,增加可选

编写自定义组件的说明书
This commit is contained in:
廖德云 2025-03-12 21:45:06 +08:00
commit 3676301f30
164 changed files with 15495 additions and 0 deletions

4
.env.development Normal file
View File

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

3
.env.production Normal file
View File

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

65
.gitignore vendored Normal file
View File

@ -0,0 +1,65 @@
/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/views/zhongheguanli/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/.vite/deps/_metadata.json
/node_modules/.vite/deps/base-64.js
/node_modules/.vite/deps/base-64.js.map
/node_modules/.vite/deps/chunk-RSJERJUL.js
/node_modules/.vite/deps/chunk-RSJERJUL.js.map
/node_modules/.vite/deps/dayjs.js
/node_modules/.vite/deps/dayjs.js.map
/node_modules/.vite/deps/package.json
/uni_modules
/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 gongwenlistApi(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
})
}

16
api/common.js Normal file
View File

@ -0,0 +1,16 @@
import {
https
} from '@/utils/http.js';
/*
这是后端系统通用的系统类的基础性的api路径后续的大家分类建js存放
*/
export function initDictOption(dictCode) { // 获取部门所有人员信息
return https({
url: ' /sys/dict/getDictItems',
method: 'get',
data: dictCode
})
}

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
}
})
}

56
api/leaveApi.js Normal file
View File

@ -0,0 +1,56 @@
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
})
}
export function queryHisDateApi(username) { // 根据username获取最新请假结束日期
return https({
url: '/CxcQxj/cxcQxj/queryHisDate',
method: 'get',
data: {
username
}
})
}
export function queryLeaveListApi(params) { // 获取所有请假信息
return https({
url: '/CxcQxj/cxcQxj/list',
method: 'get',
data: params
})
}
export function countByOrgApi(params) { // 获取所有请假信息
return https({
url: '/CxcQxj/cxcQxj/countByOrg',
method: 'get',
data: params
})
}

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
})
}

39
api/pages.js Normal file
View File

@ -0,0 +1,39 @@
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
})
}
export function queryHisDateApi(username) { // 根据username获取最新请假结束日期
return https({
url: '/CxcQxj/cxcQxj/queryHisDate',
method: 'get',
data: {
username
}
})
}

107
api/renyuan.js Normal file
View File

@ -0,0 +1,107 @@
import {
https
} from '@/utils/http.js';
export function queryRenyuanByDepartID(orgCode) { // 获取部门所有人员信息
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/list',
method: 'get',
data: orgCode
})
}
export function queryGzjlByRyLdhth(ldhth) { // 获取人员工作经历信息
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/queryLl',
method: 'get',
data: ldhth
})
}
export function queryQzqkByRyLdhth(ldhth) { // 获取人员证件台账
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/queryZjtz',
method: 'get',
data: ldhth
})
}
export function queryJtzycyByRyLdhth(ldhth) { // 获取人员家庭主要成员
return https({
url: '/cxchrygxxtj/cxcHrYgxxtj/queryJtzycy',
method: 'get',
data: ldhth
})
}
export function queryXlxxByRyLdhth(ldhth) { // 获取人员学历信息
return https({
url: '/cxchrygxxtj/cxcHrYgxxtj/listCxcXlxwxxFbByMainId',
method: 'get',
data: ldhth
})
}
export function queryGbxxByRyLdhth(ldhth) { // 获取人员干部信息 专业技术等级信息
return https({
url: '/cxc_rlzy.gbxx/cxcRlzyGbxx/queryGbxx',
method: 'get',
data: ldhth
})
}
export function queryZyzgdjByRyLdhth(ldhth) { // 获取人员职业资格等级
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/queryZyzgdj',
method: 'get',
data: ldhth
})
}
export function queryJxkhByRyLdhth(ldhth) { // 绩效考核信息
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/listCxcRlzyJxkhByMainId',
method: 'get',
data: ldhth
})
}
export function cxcHrYgxxtj(parm) { // 获取员工信息统计
return https({
url: '/cxchrygxxtj/cxcHrYgxxtj/list',
method: 'get',
data: parm
})
}
export function cxcRyDataTongji(url, parm) { // 员工信息统计
return https({
url: url,
method: 'get',
data: parm
})
}
export function cxcRyDatAstatistics(parm) { // 员工分组统计
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/statistics',
method: 'get',
data: parm
})
}
export function cxcRyDatAstatisticsCertificate(parm) { // 员工按证件分组统计
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/getStatisticsCertificate',
method: 'get',
data: parm
})
}
export function cxcRyDatAstatisticsDetails(parm) { // 员工信息统计
return https({
url: '/cxc_rlzy.zb/cxcRlzyZb/details',
method: 'get',
data: parm
})
}

37
api/shengchan.js Normal file
View File

@ -0,0 +1,37 @@
import {
https
} from '@/utils/http.js';
export function queryJinriShengchansj(params) { // 获取今日天然气生产数据
return https({
url: '/scdt.CxcScdtChart/cxcScdtChart/list',
method: 'get',
data: params
})
}
export function queryJinriTrqShengchansj(params) { // 获取当前日期、今年以来天然气的生产数据 day gas unit
return https({
url: '/scdt.CxcScdtChart/cxcScdtChart/getStatisticsData',
method: 'get',
data: params
})
}
export function queryYearShengchansj(params) { // 获取今年以来天然气的生产数据
return https({
url: '/scdt.CxcScdtChart/cxcScdtChart/getYearStatis',
method: 'get',
data: params
})
}
export function queryJinriYuanyouShengchansj(params) { // 获取今日原油 污油产量
return https({
url: '/scdt.cxcscdtwyrb/cxcScdtWyRb/list',
method: 'get',
data: params
})
}

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,335 @@
<template>
<view class="f-col aic">
<view class="info_box">
<view class="title">
申请信息
<b style="text-align: right;color: blue;" @click="goToHis">历史查询</b>
</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>
{{examineleader}}
</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/leaveApi.js';
import {
ref,
onMounted
} from 'vue'
import {
imgUrl
} from '@/utils/index.js';
const props = defineProps({
dataId: {
type: String,
default: ''
},
})
const examineleader = ref('')
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) {
if (res.result.records[0].zwmc == '单位专家' || res.result.records[0].zwmc == '基层正职' ||
res.result.records[0].zwmc == '高级主管') {
examineleader.value = '分管领导';
} else {
examineleader.value = '审批领导';
}
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
step.value = step.value.map(item => {
if (item.name === 'start') {
item.name = '开始';
} else if (item.name === 'end') {
item.name = '结束';
}
return item;
});
}
})
}
onMounted(() => {
qjQueryById()
extActFlowData()
})
const goToHis = () => {
uni.navigateTo({
url: `/pages/views/renliziyuan/qingjiaxinxi/index?username=${info.value.username}`
});
}
</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;
display: flex;
justify-content: space-between;
}
.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

122
manifest.json Normal file
View File

@ -0,0 +1,122 @@
{
"name": "数智产销",
"appid": "__UNI__9F097F0",
"description": "",
"versionName": "1.1.11",
"versionCode": 20250303,
"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"
}
/* */

56
package-lock.json generated Normal file
View File

@ -0,0 +1,56 @@
{
"name": "cxc-szcx-uniapp",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@dcloudio/uni-ui": "^1.5.6",
"base-64": "^1.0.0",
"dayjs": "^1.11.13",
"echarts": "^5.6.0"
}
},
"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=="
},
"node_modules/echarts": {
"version": "5.6.0",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz",
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.6.1"
}
},
"node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"license": "0BSD"
},
"node_modules/zrender": {
"version": "5.6.1",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz",
"integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==",
"license": "BSD-3-Clause",
"dependencies": {
"tslib": "2.3.0"
}
}
}
}

8
package.json Normal file
View File

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

331
pages.json Normal file
View File

@ -0,0 +1,331 @@
{
"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/product",
"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/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/views/shengchan/index",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "生产数据",
// "enablePullDownRefresh": false,
// "navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/shengchan/ribaoshuju/rbsjLsxq",
"style": {
// "navigationStyle": "custom"
"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"
}
},
{
"path": "pages/views/renliziyuan/renyuanxinxi/detail",
"style": {
"navigationBarTitleText": "人员详细信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/renyuanxinxi/tongji",
"style": {
"navigationBarTitleText": "人员年龄分组统计信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/renyuanxinxi/qttongji",
"style": {
"navigationBarTitleText": "其他统计信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/qingjiaxinxi/index",
"style": {
"navigationBarTitleText": "请假信息",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/qingjiaxinxi/detail",
"style": {
"navigationBarTitleText": "请假详情",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/views/renliziyuan/qingjiaxinxi/application",
"style": {
"navigationBarTitleText": "请假申请",
"enablePullDownRefresh": false,
"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/tab/product",
"iconPath": "/static/tab/product.png",
"selectedIconPath": "/static/tab/product2.png"
},
{
"text": "办公",
"pagePath": "pages/tab/office",
"iconPath": "static/tab/OA.png",
"selectedIconPath": "static/tab/OA1.png"
}, {
"text": "任务",
"pagePath": "pages/task/todotask",
"iconPath": "static/tab/office1.png",
"selectedIconPath": "static/tab/office2.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>

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

@ -0,0 +1,322 @@
<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="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>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
watch
} from 'vue';
import {
onReachBottom,
onPullDownRefresh,
onLoad
} from '@dcloudio/uni-app';
import {
gongwenlistApi,
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
gongwenlistApi({
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>

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

@ -0,0 +1,385 @@
<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,
queryHisDateApi
} 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);
}
})
queryHisDateApi(store.userinfo.username).then((res) => { //
if (res) {
console.log('--0', res)
getTomorrowDate(res);
} else {
console.log('--1', res)
getTomorrowDate();
}
})
}
const bindType = (e) => {
typeIndex.value = e.detail.value
}
const getTomorrowDate = (e) => {
let tomorrow;
if (e) {
// Date
const dateParts = e.split('-').map(Number);
tomorrow = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
} else {
// 使
tomorrow = new Date();
}
//
tomorrow.setDate(tomorrow.getDate() + 1);
//
const year = tomorrow.getFullYear();
const month = (tomorrow.getMonth() + 1).toString().padStart(2, '0');
const day = tomorrow.getDate().toString().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>

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

@ -0,0 +1,321 @@
<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));
}
}
}
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>

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/views/zhongheguanli/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 {
gongwenlistApi,
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
gongwenlistApi({
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) {
console.log('--',res.result.records)
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>

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

@ -0,0 +1,32 @@
<template>
<view>
<view class="nav">生产经营数据</view>
<product-data></product-data>
</view>
</template>
<script setup>
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = statusHeight + 44 + 'px';
import productData from '@/pages/views/shengchan/index.vue';
</script>
<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;
}
</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>

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

@ -0,0 +1,391 @@
<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 v-if="ifShow" style="display: block; margin: 10px;">
温馨提示:目前APP暂不支持电子签章审批,请登录PC端厂综合管理平台(https://10.75.166.6),-</view>
<view class="btn f-row aic jcb" v-if="type == 0 && !ifShow">
<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 ifShow = ref(false) //20250122
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 getIfShow = () => {
if (taskInfo.value.taskId == 'task1705482211321' || taskInfo.value.taskId == 'task1705482639673' ||
taskInfo.value.taskId == 'task1714092890849' || taskInfo.value.taskId == 'task1714092955682' ||
taskInfo.value.taskId == 'task1689151174324' || taskInfo.value.taskId == 'task1677809773570' ||
taskInfo.value.taskId == 'task1689579219152')
{ //
ifShow.value = true;
} else {
ifShow.value = false;
}
}
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()
getIfShow()
})
</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>

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

@ -0,0 +1,337 @@
<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) => {
}
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,386 @@
<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" :start="startDate" :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">
<view class="f-row aic jcb box">
<view class="title">
{{examineleader}}
</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,
queryHisDateApi
} from '@/api/leaveApi.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
}
/**请假开始时间 绑定start*/
const startDate = ref('')
/**结束时间*/
const endTime = ref('')
const chooseEnd = (e) => {
endTime.value = e.detail.value
}
/**审批领导*/
const typeArr = ref([])
const typeIndex = ref(null)
/**判断显示审批 / 分管 领导*/
const examineleader = 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()
})
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 (typeIndex.value == null) { //
return proxy.$toast('请选择' + examineleader.value)
}
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 == '高级主管') {
examineleader.value = '分管领导';
}else{
examineleader.value = '审批领导';
}
} else {
proxy.$toast(res.message);
}
})
queryHisDateApi(store.userinfo.username).then((res) => { //
if (res) {
getTomorrowDate(res);
startDate.value = beginTime.value; // startDate
} else {
getTomorrowDate();
startDate.value = '1900-01-01';
}
})
}
const bindType = (e) => {
typeIndex.value = e.detail.value
}
const getTomorrowDate = (e) => {
let tomorrow;
if (e) {
// Date
const dateParts = e.split('-').map(Number);
tomorrow = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
} else {
// 使
tomorrow = new Date();
}
//
tomorrow.setDate(tomorrow.getDate() + 1);
//
const year = tomorrow.getFullYear();
const month = (tomorrow.getMonth() + 1).toString().padStart(2, '0');
const day = tomorrow.getDate().toString().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>

View File

@ -0,0 +1,174 @@
<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>
</template>
<script setup>
import {
processHistoryListApi
} from '@/api/api.js';
import {
qjQueryByIdApi
} from '@/api/leaveApi.js';
import {
ref,
onMounted
} from 'vue'
import {
imgUrl
} from '@/utils/index.js';
import {
onLoad
} from '@dcloudio/uni-app';
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 = (e) => {
qjQueryByIdApi({
id: e
}).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)
};
});
}
}
})
}
onLoad((options) => {
qjQueryById(options.id)
})
</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;
}
}
}
</style>

View File

@ -0,0 +1,284 @@
<template>
<view :class="['content',{'gray':store.isgray==1}]">
<uni-card>
<view>
<uni-row v-show="!username">
<uni-col :span="12"><uni-title title="所属单位" align="left" type="h5"></uni-title></uni-col>
<uni-col :span="12"><uni-title title="重置" align="right" type="h5" color="#666666"
@click="reset"></uni-title></uni-col>
</uni-row>
<uni-row v-show="!username">
<uni-col :span="24">
<trq-depart-select v-model="orgCode" returnCodeOrID="orgCode"
@change="departChange"></trq-depart-select>
</uni-col>
</uni-row>
<uni-row v-show="!username">
<uni-col :span="12"><uni-title title="姓名" align="left" type="h5"></uni-title></uni-col>
<uni-col :span="12"><uni-title title="劳动合同号" align="left" type="h5"></uni-title></uni-col>
</uni-row>
<uni-row v-show="!username">
<uni-col :span="12">
<uni-easyinput v-model="realname" placeholder="姓名模糊查询" @change="Search" @clear="Search"/>
</uni-col>
<uni-col :span="12">
<uni-easyinput v-model="contractNumber" placeholder="劳动合同号查询" @change="Search" @clear="Search"/>
</uni-col>
</uni-row>
<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">
<uni-datetime-picker v-model="range" type="daterange" rangeSeparator="至" @input="handleInput" />
</uni-col>
</uni-row>
<!-- ECharts图表 -->
<view class="chart-container">
<l-echart ref="chart" />
</view>
</view>
</uni-card>
<view class="list">
<view class="item" v-for="item,i in list" :key="i"
@click="jump(`/pages/views/renliziyuan/qingjiaxinxi/detail?id=${item.id}`)">
<view class="title">
{{item.username_dictText}}{{item.type}}申请
</view>
<view class="time_box f-row aic">
<view class="time">
{{item.sysOrgCode_dictText}}
</view>
<view class="f-row aic no-wrap-right">
{{item.begintime}}{{item.endtime}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
onReachBottom,
onLoad
} from '@dcloudio/uni-app';
import {
queryLeaveListApi,
countByOrgApi
} from '@/api/leaveApi.js';
import {
getCategoryItemsApi
} from '@/api/api.js';
import {
useStore
} from '@/store';
import * as echarts from 'echarts';
const chart = ref(null);
const chartOption = ref({});
const orgCode = ref('') //orgCode
const range = ref('') //
const type = ref('') //
const username = ref('') //
const realname = ref('') //
const contractNumber = ref('') //
const timeout = ref(null)
const store = useStore();
const list = ref([])
let pageNo = 1
let pageSize = 15
let loading = false
onLoad((options) => {
if (options.username) {
username.value = options.username
}
})
function departChange(e) {
orgCode.value = e
queryLeave()
}
function reset() {
orgCode.value = null
range.value = []
type.value = ''
username.value = ''
realname.value = ''
contractNumber.value = ''
queryLeave()
}
function handleInput(e) {
queryLeave()
}
function Search() {
if (timeout.value) {
clearTimeout(timeout.value);
}
timeout.value = setTimeout(() => {
queryLeave()
}, 300); // 300ms
}
function clearSearch() {
console.log('-----',realname.value)
console.log('-----',contractNumber.value)
}
const queryLeave = (e) => {
let param = {
sysOrgCode: orgCode.value,
begin: range.value[0],
end: range.value[1],
type: type.value,
username: username.value,
realname: realname.value,
contractNumbers: contractNumber.value
}
if (e == 1) { // pageNo++
pageNo++;
} else { // listpageNo1
list.value = [];
pageNo = 1;
if (e != 2) {
//
setChartOption(param);
}
}
//
queryLeaveList(param);
}
const queryLeaveList = (params = {}) => {
loading = true
queryLeaveListApi({
...params,
pageNo,
pageSize
}).then((res) => {
if (res.success) {
list.value = [...list.value, ...res.result.records]
}
loading = false
}).catch((err) => {})
}
//
const initChart = () => {
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
myChart.setOption(chartOption.value);
myChart.on('click', (params) => {
// params
type.value = params.name
queryLeave(2);
});
}, 300);
};
const setChartOption = (e) => {
countByOrgApi(e).then(res => {
chartOption.value = {
tooltip: {
trigger: 'item'
},
series: [{
type: 'pie',
radius: '50%',
data: res.result
}]
}
initChart()
})
}
const jump = (url) => {
uni.navigateTo({
url: url
});
}
const back = () => {
uni.navigateBack()
}
onReachBottom(() => {
if (loading) return
queryLeave(1); //1
})
</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 {
display: flex;
align-items: center;
justify-content: space-between;
/* 均匀分布子元素 */
font-size: 24rpx;
color: #888888;
.time {
margin-right: 62rpx;
width: 50%;
}
.no-wrap-right {
white-space: nowrap;
text-align: right;
}
}
}
}
.back {
padding: 0 30rpx;
}
</style>

View File

@ -0,0 +1,608 @@
<template>
<view>
<scroll-view :scroll-x="true" :scroll-y="true">
<view style="padding: 10px 10px 10px 10px">
<uni-title title="基本信息" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="18"><yjly-row-cell :cellData="cellData" :rowDataCount="2"></yjly-row-cell></uni-col>
<uni-col :span="6">
<view class="img">
<image mode="aspectFit" :src="'https://36.112.48.190/jeecg-boot/sys/common/static/' + imgUrl"></image>
</view>
</uni-col>
</uni-row>
<yjly-row-cell :cellData="cellData1" :rowDataCount="3"></yjly-row-cell>
<view v-if="roleDetail">
<uni-title title="年度绩效考核" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="4">
<view class="titleStyle">序号</view>
</uni-col>
<uni-col :span="10">
<view class="titleStyle">绩效考核年份</view>
</uni-col>
<uni-col :span="10">
<view class="titleStyle">绩效考核成绩</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item, index) in jxkhxxList">
<uni-col :span="4">
<view class="dataStyle1">
{{ index + 1 }}
</view>
</uni-col>
<uni-col :span="10">
<view class="dataStyle1">
{{ item.nf }}
</view>
</uni-col>
<uni-col :span="10">
<view class="dataStyle1">
{{ item.khcj + '---' + item.khcj_dictText }}
</view>
</uni-col>
</view>
</uni-row>
</view>
<uni-title title="工作简历" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="4">
<view class="titleStyle">起始时间</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">终止时间</view>
</uni-col>
<uni-col :span="11">
<view class="titleStyle">工作职务</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">岗位职务</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item, index) in gzjlList">
<uni-col :span="4">
<view class="dataStyle2">
{{ item.kssj }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2">
{{ item.jssj }}
</view>
</uni-col>
<uni-col :span="11">
<view class="dataStyle2" ref="dataView">
{{ item.jlms }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.jlms2 }}
</view>
</uni-col>
</view>
</uni-row>
<!-- <uni-segmented-control></uni-segmented-control> -->
<view>
<uni-title title="学历信息" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="4">
<view class="titleStyle">类别</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">毕业院校</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">所学专业</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">学历</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">学位</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">毕业时间</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item, index) in xlxxList">
<uni-col :span="4">
<view class="dataStyle1">
{{ item.xllb }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2">
{{ item.byyx }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2" ref="dataView">
{{ item.sxzy }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2">
{{ item.qdxl }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2">
{{ item.qdxw }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle2">
{{ item.bytime }}
</view>
</uni-col>
</view>
</uni-row>
</view>
<uni-title title="取证信息" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="6">
<view class="titleStyle">证书名称</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">证书等级</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">取证时间</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">复审时间</view>
</uni-col>
<uni-col :span="3">
<view class="titleStyle">备注</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item, index) in zjtzList">
<uni-col :span="6">
<view class="dataStyle2" ref="dataView">
{{ item.zjmc }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.zsdj }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.fzrq }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.fssj }}
</view>
</uni-col>
<uni-col :span="3">
<view class="dataStyle1">
{{ item.bz }}
</view>
</uni-col>
</view>
</uni-row>
<view v-if="roleDetail">
<uni-title title="家庭信息" type="h1" color="blue"></uni-title>
<uni-row>
<uni-col :span="4">
<view class="titleStyle">称谓</view>
</uni-col>
<uni-col :span="3">
<view class="titleStyle">姓名</view>
</uni-col>
<uni-col :span="6">
<view class="titleStyle">出生年月</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">政治面貌</view>
</uni-col>
<uni-col :span="7">
<view class="titleStyle">工作单位及职务</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item, index) in zyjtcyList">
<uni-col :span="4">
<view class="dataStyle2">
{{ item.ybrgx }}
</view>
</uni-col>
<uni-col :span="3">
<view class="dataStyle1">
{{ item.gxname }}
</view>
</uni-col>
<uni-col :span="6">
<view class="dataStyle1">
{{ item.cstime }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle1">
{{ item.cyzzmm }}
</view>
</uni-col>
<uni-col :span="7">
<view class="dataStyle2" ref="dataView">
{{ item.cygzdw }}
</view>
</uni-col>
</view>
</uni-row>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { onReady, onLoad } from '@dcloudio/uni-app';
import { reactive, ref, onMounted } from 'vue';
import { queryGzjlByRyLdhth, queryQzqkByRyLdhth, queryJtzycyByRyLdhth, queryXlxxByRyLdhth, queryGbxxByRyLdhth, queryZyzgdjByRyLdhth, queryJxkhByRyLdhth } from '@/api/renyuan.js';
import { useStore } from '@/store';
const store = useStore();
const tempCellData = ref({
title: '',
value: '',
titleSpan: 4,
valueSpan: 4
});
const roleDetail = ref(store.userinfo.realname === '廖德云' || store.userinfo.realname === '马敬朝');
const ldhth = ref('');
const imgUrl = ref('');
const renyuanData = ref({});
const cellData = ref([]);
const cellData1 = ref([]);
const gzjlList = ref([]); // -
const zjtzList = ref([]); // -
const zyjtcyList = ref([]); // -
const xlxxList = ref([]); // -
const gbxxList = ref([]); // -
const zyzgdjList = ref([]); // -
const jxkhxxList = ref([]); // -
function getChildTable() {
console.log(ldhth.value);
queryJxkhByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
jxkhxxList.value = res.result.records;
// console.log(jxkhxxList.value)
})
.catch((err) => {
console.log(err);
});
queryGbxxByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
gbxxList.value = res;
// console.log(gbxxList.value)
})
.catch((err) => {
console.log(err);
});
queryZyzgdjByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
zyzgdjList.value = res;
// console.log(zyzgdjList.value)
})
.catch((err) => {
console.log(err);
});
queryGzjlByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
if (res.length > 0) {
gzjlList.value = res;
}
})
.catch((err) => {
console.log(err);
});
queryQzqkByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
if (res.length > 0) {
zjtzList.value = res;
}
})
.catch((err) => {
console.log(err);
});
queryJtzycyByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
// console.log(res);
if (res.length > 0) {
zyjtcyList.value = res;
}
})
.catch((err) => {
console.log(err);
});
queryXlxxByRyLdhth({
ldhth: ldhth.value
})
.then((res) => {
if (res.success) {
xlxxList.value = [];
if (res.result.records.length > 0) {
var rress = res.result.records;
// console.log(rress);
for (let i = 0; i < rress.length; i++) {
if ((rress[i].onexl == 1) & (rress[i].zgxl == 1)) {
rress[i].xllb = '第一学历';
xlxxList.value.push(JSON.parse(JSON.stringify(rress[i])));
// console.log(xlxxList.value)
rress[i].xllb = '最高学历';
xlxxList.value.push(JSON.parse(JSON.stringify(rress[i])));
// console.log(xlxxList.value)
}
if ((rress[i].onexl == 1) & (rress[i].zgxl != 1)) {
rress[i].xllb = '第一学历';
xlxxList.value.push(rress[i]);
}
if ((rress[i].onexl != 1) & (rress[i].zgxl == 1)) {
rress[i].xllb = '最高学历';
xlxxList.value.push(rress[i]);
}
}
}
}
// adjustFontSize()
})
.catch((err) => {
console.log(err);
});
}
function getJbxx() {
cellData.value.push({
title: '姓名',
value: renyuanData.value.xm,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '性别',
value: renyuanData.value.xb_dictText,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '出生年月',
value: renyuanData.value.cssj,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '民族',
value: renyuanData.value.mz,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '籍贯',
value: renyuanData.value.jg,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '出生地',
value: renyuanData.value.csd,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '工作时间',
value: renyuanData.value.cjgzsj,
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle'
});
cellData.value.push({
title: '现专业',
value: '',
titleSpan: 6,
valueSpan: 6,
class: 'dataStyle1'
});
cellData.value.push({
title: '政治面貌',
value: renyuanData.value.zzmm === '群众' ? renyuanData.value.zzmm : renyuanData.value.zzmm + renyuanData.value.jrsj,
titleSpan: 5,
valueSpan: 7,
class: 'dataStyle1'
});
cellData.value.push({
title: '用工形式',
value: renyuanData.value.rylb1_dictText,
titleSpan: 5,
valueSpan: 7,
class: 'dataStyle1'
});
cellData1.value.push({
title: '所在单位',
value: renyuanData.value.orgCode_dictText,
titleSpan: 5,
valueSpan: 7,
class: 'dataStyle1'
});
cellData1.value.push({
title: '专业技术资格',
value: gbxxList.value.zc === 0 ? '/' : gbxxList.value.zc + gbxxList.value.zcsj,
titleSpan: 5,
valueSpan: 7,
class: 'dataStyle1'
});
cellData1.value.push({
title: '',
value: '',
titleSpan: 0,
valueSpan: 0,
class: 'dataStyle'
});
cellData1.value.push({
title: '职业资格等级',
value: zyzgdjList.value.ztgz === '0' ? '/' : zyzgdjList.value.ztgz + zyzgdjList.value.ztgzdj,
titleSpan: 4,
valueSpan: 4,
class: 'dataStyle1'
});
cellData1.value.push({
title: '职务(岗位)',
value: gbxxList.value.zw,
titleSpan: 4,
valueSpan: 4,
class: 'dataStyle1'
});
cellData1.value.push({
title: '职位级别',
value: gbxxList.value.zwcj,
titleSpan: 4,
valueSpan: 4,
class: 'dataStyle'
});
}
onLoad((e) => {
console.log(store.userinfo);
renyuanData.value = JSON.parse(decodeURIComponent(e.data));
imgUrl.value = renyuanData.value.zplj;
console.log(imgUrl.value, renyuanData.value);
ldhth.value = renyuanData.value.ldhth;
getChildTable();
setTimeout(function () {
getJbxx();
}, 500);
});
</script>
<style scoped>
.renyuanInfo {
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: 0;
height: 98vh;
width: 900px;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: row;
font-size: 18px;
color: #fff;
}
.titleStyle {
font-size: 12px;
color: #747474;
line-height: 35px;
height: 35px;
background: #f2f9fc;
text-align: center;
vertical-align: middle;
border-left: 1px solid #919191;
border-bottom: 1px solid #919191;
}
/* 内容样式 */
.dataStyle {
font-size: 14px;
color: #00007f;
line-height: 25px;
height: 50px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-align: center;
word-wrap: break-word;
overflow-wrap: break-word;
}
/* 内容样式 */
.dataStyle1 {
font-size: 14px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
word-wrap: break-word;
overflow-wrap: break-word;
}
/* 内容样式 */
.dataStyle2 {
font-size: 12px;
color: #00007f;
line-height: 15px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-align: center;
word-wrap: break-word;
overflow-wrap: break-word;
}
.img {
height: 154px;
border: 1px solid #ccc;
/* 仅用于展示容器范围,可根据需要移除 */
display: flex;
justify-content: center;
/* 水平居中 */
align-items: center;
/* 垂直居中 */
overflow: hidden;
/* 防止图片溢出容器 */
}
</style>

View File

@ -0,0 +1,42 @@
<template>
<view>
<uni-card :is-shadow="false">
<uni-section title="台账信息" type="line">
<uni-card :is-shadow="false">
<button type="primary" @click="toTaizhang">人员台账</button>
</uni-card>
</uni-section>
<uni-section title="统计信息" type="line">
<uni-card :is-shadow="false">
<button type="primary" @click="toTongji">年龄段统计</button>
</uni-card>
<uni-card :is-shadow="false">
<button type="primary" @click="toQtTongji">通用字段统计</button>
</uni-card>
</uni-section>
</uni-card>
</view>
</template>
<script setup>
function toTaizhang() {
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/taizhang'
});
}
function toTongji() {
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/tongji'
});
}
function toQtTongji() {
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/qttongji'
});
}
</script>
<style></style>

View File

@ -0,0 +1,985 @@
<template>
<view>
<view class="container" id="top1">
<uni-row style="margin-bottom: 10px">
<uni-col :span="5"><uni-title :title="'选择单位'" align="left" type="h4"></uni-title></uni-col>
<uni-col :span="19">
<trq-depart-select v-model="selectedOrgCode" returnCodeOrID="orgCode"
@change="onOrgCodeChange"></trq-depart-select>
</uni-col>
</uni-row>
<uni-row style="margin-bottom: 10px">
<uni-col :span="5"><uni-title :title="'选择字段'" align="left" type="h4"></uni-title></uni-col>
<uni-col :span="12">
<uni-data-select v-model="selectedField" :localdata="fieldList"
@change="onFieldChange"></uni-data-select>
</uni-col>
<uni-col style="margin-left:5px" :span="6" v-if="selectedField==='zjmc'"><button type="primary"
size="mini" @click="showPopup=!showPopup">筛选</button></uni-col>
</uni-row>
</view>
<!-- ECharts图表 -->
<view class="chart-container">
<l-echart ref="chart" @finished="initChart" />
</view>
<!-- 翻页按钮 -->
<view style="display: flex; justify-content: center; margin-top: 10px">
<button @click="prevPage" :disabled="currentPage === 1" size="mini">上一页</button>
<button @click="nextPage" :disabled="currentPage * pageSize >= chartDataCount.value"
size="mini">下一页</button>
</view>
<!-- 数据表格 -->
<uni-row style="margin-top: 10px; margin-left: 20px; margin-right: 20px" v-if="personnelList.length > 0">
<uni-col :span="2">
<view class="titleStyle">序号</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">姓名</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">基层单位</view>
</uni-col>
<uni-col :span="5" v-if="selectedField.value !== 'zjmc'">
<view class="titleStyle">基层班组</view>
</uni-col>
<uni-col :span="5" v-else>
<view class="titleStyle">岗位</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">年龄</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">操作</view>
</uni-col>
</uni-row>
<scroll-view scroll-y :style="{ height: bottomHeight + 'px' }">
<uni-row style="margin-bottom: 10px; margin-left: 20px; margin-right: 20px; font-size: 12px">
<view v-for="(item, index) in personnelList">
<uni-col :span="2">
<view class="dataStyle">
{{ index + 1 }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
{{ item.xm }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.jcdw }}
</view>
</uni-col>
<uni-col :span="5" v-if="selectedField.value != 'zjmc'">
<view class="dataStyle1">
{{ item.jcxd }}
</view>
</uni-col>
<uni-col :span="4" v-else>
<view class="dataStyle">
{{ item.sdgw }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
{{ item.nl }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
<span @click="detail(item)" style="color: red;">详情</span>
<!-- <button size="mini" type="primary" @click="detail(item)">详情</button> -->
</view>
</uni-col>
</view>
</uni-row>
</scroll-view>
<uni-popup ref="showPopup" type="bottom" border-radius="10px 10px 0 0">
<uni-card>
<uni-title :title="'已选证书:'" align="left" type="h4"></uni-title>
<view style="color: red;font-weight: 300;margin-bottom: 10px;">{{dictData}}</view>
<scroll-view scroll-y style="height: 40vh;">
<view>
<cxc-szcx-dictSelect :dictCode="dictCode" @change="dictChange"></cxc-szcx-dictSelect>
</view>
</scroll-view>
</uni-card>
</uni-popup>
</view>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
computed
} from 'vue';
import * as echarts from 'echarts/dist/echarts.min'; // EChartsH5
import {
cxcRyDatAstatistics,
cxcRyDatAstatisticsCertificate,
cxcRyDatAstatisticsDetails
} from '@/api/renyuan.js';
// tableData
const bottomHeight = ref(0);
//
const chart = ref(null);
const chartDataCount = ref(0);
const fieldList = ref([{
text: '取证情况',
value: 'zjmc',
isDict: false,
dictCode: 'gzrlzy',
},
{
text: '岗位类别',
value: 'gwlb',
isDict: false,
dictCode: ''
},
{
text: '性别',
value: 'xb',
isDict: true,
dictCode: 'sex'
},
{
text: '政治面貌',
value: 'zzmm',
isDict: true,
dictCode: 'zzmm'
},
{
text: '民族',
value: 'mz',
isDict: true,
dictCode: 'mz'
}
]); //
const dictCode = ref('');
const dictData = ref('');
const showPopup = ref(null);
const fieldisDict = ref(true);
const selectedOrgCode = ref(''); // orgCode
const selectedOrgCodeLabel = ref('请选择单位'); //
const selectedField = ref(''); //
const selectedFieldLabel = ref('请选择字段'); //
const orgCodeGroupData = ref([]); //orgcode
const chartData = ref({}); //
const personnelList = ref([]); // initChart
const fieldValues = ref([]); //
const fieldTexts = ref([]); //
const chartOption = ref({});
const orgType = ref(''); // by
const chartTitle = computed(() => {
return selectedOrgCodeLabel.value + '人员(' + selectedFieldLabel.value + ')分组统计';
});
//
const pageSize = ref(3); //
const currentPage = ref(1); //
function detail(record) {
// console.log(record)
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/detail?data=' + encodeURIComponent(JSON.stringify(record))
});
}
onMounted(() => {
getHeight();
});
const dictChange = (e) => {
console.log(e)
dictData.value = e
fetchStatisticsData()
}
const getHeight = () => {
//
const systemInfo = uni.getSystemInfoSync();
const screenHeight = systemInfo.screenHeight;
//
const query = uni.createSelectorQuery();
//
query
.select('#top1')
.boundingClientRect((rect1) => {
//
const topComponentsHeight = rect1.height;
//
bottomHeight.value = screenHeight - topComponentsHeight - 415;
})
.exec();
};
// ECharts length departChange
//
const initChart = () => {
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
myChart.setOption(chartOption.value);
}, 300);
};
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
}
updateChart(chartData.value);
};
const nextPage = () => {
if (currentPage.value * pageSize.value < chartDataCount.value) {
currentPage.value++;
//
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
updateChart(chartData.value);
// const tempChartData = temp.slice(startIndex, endIndex);
}
};
// option
const getChartOption = (ChartData) => {
// let temp = JSON.parse(JSON.stringify(tempchartData[0].children));
// chartDataCount.value = temp.length;
//
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
//
const tempChartData = ChartData.slice(startIndex, endIndex);
try {
let xData = [];
let seriesData = [];
console.log(1, tempChartData);
// transformDataForEcharts
let legendData = [];
for (let i = 0; i < fieldValues.value.length; i++) {
legendData.push(fieldValues.value[i].fieldText);
}
tempChartData.forEach((item) => {
xData.push(item.name);
});
for (let i = 0; i < fieldValues.value.length; i++) {
let tempData = [];
tempChartData.forEach((item) => {
// console.log(item);
if (item.data[i]) {
tempData.push(item.data[i]);
} else {
tempData.push(0);
}
});
seriesData.push({
name: fieldValues.value[i].fieldText,
type: 'bar',
label: {
show: true, //
position: 'top' //
},
data: tempData
});
}
console.log(2, legendData, xData, seriesData);
let tempOption = {
title: {
text: chartTitle.value,
padding: [0, 0, 0, 30]
},
toolbox: {
padding: [0, 30, 0, 0],
show: true,
feature: {
//
restore: {
show: true //
},
saveAsImage: {
show: true //
}
}
},
xAxis: {
type: 'category',
data: xData,
axisLabel: {
color: '#7F84B5',
fontWeight: 300,
interval: 0,
rotate: 0
},
padding: [0, 10, 0, 10],
axisTick: {
show: false //线
},
axisLine: {
show: false //线
}
},
yAxis: [{
show: true,
boundaryGap: false, //线
type: 'value',
// name: 'Budget (million USD)',
// data: this.yList,
minInterval: 1,
axisLabel: {
interval: 0
},
splitLine: {
show: true,
lineStyle: {
//线
type: 'dashed'
}
},
axisTick: {
show: true //线
},
axisLine: {
show: false //线
}
}],
series: seriesData,
legend: {
data: legendData,
itemGap: 1,
padding: [0, 0, 0, 0],
y: 'bottom',
itemHeight: 8, //
itemWidth: 18, //
type: 'scroll'
}
};
return tempOption;
} catch (error) {
console.log(error);
}
};
//
const updateChart = (tempchartData) => {
//
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
console.log(tempchartData);
let tempOption = getChartOption(tempchartData);
myChart.setOption(tempOption);
//
myChart.on('click', (params) => {
console.log(params.name, params.seriesIndex, params.dataIndex);
console.log(orgCodeGroupData.value);
let updateData = findRyByOrgCode(orgCodeGroupData.value.children, params.name);
console.log(updateData);
const ldhth = updateData.fieldValues[params.seriesIndex].ldhth;
console.log(ldhth);
if (ldhth && ldhth.length > 0) {
fetchPersonnelList(ldhth);
}
// updateChart(updateData);
});
}, 300);
};
//
//
function findRyByOrgCode(treeData, targetOrgCode) {
// console.log(treeData, targetOrgCode);
for (const node of treeData) {
//
if (node.orgText === targetOrgCode) {
return node;
}
//
if (node.children && node.children.length > 0) {
const found = findNodeByOrgCode(node.children, targetOrgCode);
if (found) return found;
}
}
return null;
}
/**
* 从echart图标的树状数据中根据 orgCode 获取节点及其子节点数据
* @param {Array} treeData 树状数据
* @param {string} targetOrgCode 目标 orgCode
* @returns {Object|null} 匹配的节点及其子节点数据未找到返回 null
*/
function findNodeByOrgCode(treeData, targetOrgCode) {
// console.log(treeData, targetOrgCode);
for (const node of treeData) {
//
if (node.name === targetOrgCode) {
return node;
}
//
if (node.children && node.children.length > 0) {
const found = findNodeByOrgCode(node.children, targetOrgCode);
if (found) return found;
}
}
return null;
}
//fieldValue
function collectUniqueKeyFieldValues(tree) {
const uniqueMap = new Map();
tree.forEach((item) => {
const {
fieldValue,
fieldText
} = item;
const key = `${fieldValue}-${fieldText}`;
if (!uniqueMap.has(key)) {
uniqueMap.set(key, {
fieldValue,
fieldText
});
}
});
const result = Array.from(uniqueMap.values());
return result;
}
//
class OrgCodeMapper {
constructor(data) {
//
this.orgCodeToOrgTextMap = {};
//
for (let i = 0; i < data.length; i++) {
const item = data[i];
// orgCode orgText
this.orgCodeToOrgTextMap[item.orgCode] = item.orgText;
}
}
// orgCode orgText
findOrgText(orgCode) {
return this.orgCodeToOrgTextMap[orgCode];
}
}
//
// const result = findNodeByOrgCode(echartData, "A01A01A01A01");
// console.log(result);
/**
* 转换数据为支持钻取的ECharts格式
* @param {Array} data 原始数据
* @param {string} selectOrgCode 当前选择的组织编码
* @returns {Object} 包含当前层级数据和子节点信息的对象 符合echart的格式
*/
//-----------------------------------------------------------------------------------------
function transformData(selectOrgCode, data) {
const nodes = new Map();
//fieldValue data[] fieldValue
fieldValues.value = collectUniqueKeyFieldValues(data);
// console.log(fieldValues.value);
const orgMapper = new OrgCodeMapper(data); //orgtext
// console.log(orgMapper.findOrgText('A01A01A01A01'));
// orgCode
function getHierarchy(orgCode) {
const hierarchy = [];
for (let i = selectOrgCode.length; i <= orgCode.length; i += 3) {
hierarchy.push(orgCode.substring(0, i));
}
// console.log('hierarchy', hierarchy);
return hierarchy;
}
// orgCode
function getParentCode(code) {
if (code.length <= 3) return null;
return code.substring(0, code.length - 3);
}
// series
let tempArrayValue = new Array(fieldValues.value.length).fill(0);
//
data.forEach((entry) => {
const hierarchy = getHierarchy(entry.orgCode);
// console.log(entry);
hierarchy.forEach((code) => {
// console.log(code);
let tempOrgText = orgMapper.findOrgText(code) === undefined ? '' : orgMapper.findOrgText(
code);
// console.log(tempOrgText);
if (!nodes.has(code)) {
nodes.set(code, {
orgCode: code,
name: tempOrgText,
type: 'bar',
data: JSON.parse(JSON.stringify(tempArrayValue)), // data[0, 0]
children: []
});
}
});
// console.log(nodes);
// console.log('fieldValues', fieldValues.value, fieldValues.value.length, hierarchy);
// data
const node = nodes.get(entry.orgCode);
const fieldValue = entry.fieldValue;
for (let i = 0; i < fieldValues.value.length; i++) {
if (fieldValue === fieldValues.value[i].fieldValue) {
// console.log(555, i, fieldValue, fieldValues.value[i], entry.number);
node.data[i] += entry.number;
}
}
// console.log(11, node);
//
for (let i = 0; i < hierarchy.length - 1; i++) {
const parentCode = hierarchy[i];
const childCode = hierarchy[i + 1];
const parentNode = nodes.get(parentCode);
const childNode = nodes.get(childCode);
if (!parentNode.children.some((c) => c.orgCode === childCode)) {
parentNode.children.push(childNode);
}
}
});
// data
function computeData(node) {
if (node.children.length === 0) return;
node.data = JSON.parse(JSON.stringify(tempArrayValue));
node.children.forEach((child) => {
computeData(child);
for (let i = 0; i < fieldValues.value.length; i++) {
// console.log(666, i, node.data[i], child.data[i]);
node.data[i] += child.data[i];
}
});
}
//
const rootNodes = [];
nodes.forEach((node, code) => {
const parentCode = getParentCode(code);
// console.log(parentCode);
if (!parentCode || !nodes.has(parentCode)) {
rootNodes.push(node);
}
});
// data
rootNodes.forEach((root) => computeData(root));
console.log(rootNodes)
return rootNodes;
// console.log('rootNodes', rootNodes);
// //
// function formatTree(node) {
// // console.log(node);
// return {
// orgCode: node.orgCode,
// name: node.name,
// type: 'bar',
// data: node.data,
// children: node.children.map((child) => formatTree(child))
// };
// }
// return rootNodes.map((root) => {
// console.log(root);
// formatTree(root);
// });
}
//-----------------------------------------------------------------------------------------
// orgCode children deepseek
const groupByOrgCode = (orgCode, data) => {
//
console.log("aaaa")
const filteredData = data.filter((item) => item.orgCode.startsWith(orgCode));
const orgMapper = new OrgCodeMapper(data);
// null
if (filteredData.length === 0) {
uni.showToast({
title: '过滤后数据为空',
duration: 1000
});
return null;
}
// console.log(0, filteredData);
// fieldValue
const groupedByFieldValue = {};
try {
filteredData.forEach((item) => {
// console.log(item);
if (!groupedByFieldValue[item.fieldValue]) {
groupedByFieldValue[item.fieldValue] = {
orgCode: item.orgCode,
orgText: item.orgText,
fieldText: item.fieldText,
number: 0,
ldhth: []
};
}
// console.log(item.orgCode, 22, groupedByFieldValue[item.fieldValue]);
groupedByFieldValue[item.fieldValue].number += item.number;
groupedByFieldValue[item.fieldValue].ldhth.push(...item.ldhth.split(','));
});
} catch (error) {
console.log(error);
}
// console.log(1, orgMapper.findOrgText(orgCode));
//
console.log("aaaa")
const result = {
orgCode: orgCode,
orgText: orgMapper.findOrgText(orgCode),
fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => {
const {
fieldText,
orgCode,
orgText
} = groupedByFieldValue[fieldValue] || {};
return {
fieldValue: fieldValue,
fieldText: fieldText,
orgCode: orgCode,
orgText: orgText,
number: groupedByFieldValue[fieldValue].number,
ldhth: [...new Set(groupedByFieldValue[fieldValue].ldhth)] //
};
}),
children: []
};
// console.log('', result);
// orgCode
const nextLevelOrgCodes = new Set();
try {
filteredData.forEach((item) => {
if (item.orgCode !== orgCode && item.orgCode.startsWith(orgCode)) {
const nextLevelOrgCode = item.orgCode.substring(0, orgCode.length + 3);
nextLevelOrgCodes.add(nextLevelOrgCode);
}
});
} catch (error) {
console.log(error);
}
//
try {
nextLevelOrgCodes.forEach((nextLevelOrgCode) => {
const child = groupByOrgCode(nextLevelOrgCode, data);
if (child) {
result.children.push(child);
}
});
} catch (error) {
console.log(error);
}
console.log('全部', result);
return result;
};
// then filter
const fetchStatisticsData = async () => {
console.log(selectedOrgCode)
if (!selectedOrgCode.value || !selectedField.value) return;
let res = [];
chartData.value = [];
try {
// A01A01A01 orgType by
var tempOrgType = '1';
if(selectedOrgCode.value.includes('A01A01A01')){
tempOrgType = '1';
}else{
tempOrgType = orgType
}
if (selectedField.value === 'zjmc') {
console.log(dictCode.value);
console.log(dictData.value);
res = await cxcRyDatAstatisticsCertificate({
orgCode: selectedOrgCode.value,
field: selectedField.value,
dictCode: dictCode.value,
fieldisDict: fieldisDict.value,
typeOfWorkList: dictData.value,
orgType: tempOrgType.value
});
} else {
res = await cxcRyDatAstatistics({
orgCode: selectedOrgCode.value,
field: selectedField.value,
dictCode: dictCode.value,
fieldisDict: fieldisDict.value,
orgType: tempOrgType.value
});
}
// console.log(res); //deepseek
if (res.success) {
console.log(selectedOrgCode.value, res);
if (res.result.length < 1) {
uni.showToast({
title: '查询数据为空'
});
return;
}
//
orgCodeGroupData.value = groupByOrgCode(selectedOrgCode.value, res.result);
console.log(orgCodeGroupData.value);
//echart
const temp = transformData(selectedOrgCode.value, res.result);
if (temp[0].children.length > 0) {
chartData.value = JSON.parse(JSON.stringify(temp[0].children));
chartDataCount.value = chartData.value.length;
console.log(chartData.value);
// updateChart(chartData.value);
} else {
var tempArr = [];
tempArr.push(temp[0])
chartData.value =tempArr;
}
updateChart(chartData.value);
}
} catch (error) {
console.error('获取统计数据失败:', error);
}
};
// delimiter
const fetchPersonnelList = async (ldhthList) => {
personnelList.value = [];
try {
const res = await cxcRyDatAstatisticsDetails({
ldhth: ldhthList
});
console.log(res);
if (res.success) {
personnelList.value = res.result;
}
} catch (error) {
console.error('获取人员列表失败:', error);
}
};
//
const onOrgCodeChange = (e, data) => {
personnelList.value = [];
selectedOrgCode.value = e;
console.log(e)
console.log(data);
orgType.value = data.value.orgType; // by
selectedOrgCodeLabel.value = data.value.title;
fetchStatisticsData();
};
const onFieldChange = (e) => {
personnelList.value = [];
// console.log(e);
try {
selectedField.value = e;
for (var index = 0; index < fieldList.value.length; index++) {
var element = fieldList.value[index];
// console.log(element);
if (element.value === e) {
selectedFieldLabel.value = element.text;
dictCode.value = element.dictCode;
fieldisDict.value = element.isDict;
}
}
if (selectedField.value === 'zjmc') {
showPopup.value.open()
} else {
fetchStatisticsData();
}
} catch (error) {
//TODO handle the exception
console.log(error);
}
};
const onChartClick = (e) => {
personnelList.value = [];
const {
ldhth
} = chartData.value;
if (ldhth && ldhth.length > 0) {
fetchPersonnelList(ldhth);
}
};
</script>
<style scoped>
/* 颜色变量 */
:root {
--primary-blue: #409eff;
--deep-blue: #2c7be5;
--light-blue: #ecf5ff;
--gradient-start: #6b8cff;
--gradient-end: #4364f7;
--hover-blue: #66b1ff;
}
/* 全局容器 */
.container {
margin: 10px 10px;
padding: 10px;
background: linear-gradient(145deg, #f5f9ff, var(--light-blue));
border-radius: 12px;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
border: 1px solid rgba(64, 158, 255, 0.1);
}
/* 图表容器 */
.chart-container {
height: 250px;
margin: 10px 0;
border-radius: 12px;
overflow: hidden;
background: #ffffff;
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.12);
border: 1px solid rgba(64, 158, 255, 0.08);
}
/* 表格标题行 */
.titleStyle {
font-size: 10px;
color: #747474;
line-height: 30px;
height: 30px;
background: #f2f9fc;
text-align: center;
vertical-align: middle;
border-left: 1px solid #919191;
border-bottom: 1px solid #919191;
}
/* 内容样式 */
.dataStyle {
font-size: 10px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-overflow: ellipsis;
}
/* 内容样式 */
.dataStyle1 {
font-size: 8px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-overflow: ellipsis;
}
/* 滚动区域 */
scroll-view {
background: #ffffff;
border-radius: 0 0 8px 8px;
box-shadow: 0 4px 12px rgba(0, 35, 111, 0.08);
}
/* 输入框聚焦效果 */
.trq-depart-select:focus-within {
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
border-color: var(--primary-blue);
}
/* 加载动画优化 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.container>* {
animation: fadeIn 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}
/* 自定义滚动条美化 */
::-webkit-scrollbar {
width: 4px;
background: rgba(64, 158, 255, 0.05);
}
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, var(--primary-blue), var(--deep-blue));
border-radius: 6px;
border: 1px solid white;
}
/* 筛选行间距优化 */
.filter-row {
margin: 15px 0;
padding: 10px 0;
border-radius: 8px;
}
/* 响应式调整优化 */
@media (max-width: 768px) {
.chart-container {
height: 250px;
border-radius: 10px;
}
}
/* 数据行高亮效果 */
.data-row:nth-child(even) {
background: rgba(236, 245, 255, 0.3);
}
.data-row:hover {
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.1);
}
</style>

View File

@ -0,0 +1,317 @@
<template>
<view class="container" id="top1">
<uni-card>
<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" suffixIcon="search" clearable placeholder="姓名模糊查询"
@change="Search" @iconClick="Search" /></uni-col>
<uni-col :span="11" :push="2">
<uni-easyinput v-model="ldhth" suffixIcon="search" clearable 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 v-model="departID" returnCodeOrID="orgCode"
@change="departChange"></trq-depart-select>
</uni-col>
</uni-row>
</view>
</uni-card>
</view>
<uni-card>
<!-- 数据表格 -->
<uni-row>
<uni-col :span="3">
<view class="titleStyle">序号</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">姓名</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">性别</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">年龄</view>
</uni-col>
<uni-col :span="6">
<view class="titleStyle">操作</view>
</uni-col>
</uni-row>
<scroll-view scroll-y :style="{ height: bottomHeight + 'px' }">
<uni-row v-if="ryDataList.length > 0">
<view v-for="(item, index) in ryDataList">
<uni-col :span="3">
<view class="dataStyle">
{{ index + 1 }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.xm }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.xb_dictText }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.nl }}
</view>
</uni-col>
<uni-col :span="6">
<view class="dataStyle">
<span @click="detail(item)" style="color: red;">详情</span>
<!-- <button size="mini" type="primary" @click="detail(item)">详情</button> -->
</view>
</uni-col>
</view>
</uni-row>
<view class="pagination">
<uni-pagination :current="current" :pagerCount="5" :total="total" prev-text="前一页" next-text="后一页"
:show-icon="false" @change="pagechange" />
</view>
</scroll-view>
</uni-card>
</template>
<script setup>
import {
onReady,
onLoad
} from '@dcloudio/uni-app';
import {
reactive,
ref,
onMounted
} 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
const ryDataList = ref([]);
const bottomHeight = ref(0);
let status = ref('');
let contentText = reactive({
contentdown: '点击查看更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
});
let pageNo = ref(1);
let pageSize = ref(10);
let total = ref(0);
let pages = ref(0);
let current = ref(0);
let params = reactive({
pageNo: pageNo,
pageSize: pageSize
});
onLoad((e) => {});
onMounted((e) => {
getHeight();
departID.value = '';
getRenyuanByDepID();
});
const getHeight = () => {
//
const systemInfo = uni.getSystemInfoSync();
const screenHeight = systemInfo.screenHeight;
//
const query = uni.createSelectorQuery();
//
query
.select('#top1')
.boundingClientRect((rect1) => {
//
const topComponentsHeight = rect1.height;
//
bottomHeight.value = screenHeight - topComponentsHeight;
})
.exec();
};
function detail(record) {
// console.log(record)
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/detail?data=' + encodeURIComponent(JSON.stringify(record))
});
}
function pagechange(e) {
current.value = e.current;
pageNo.value = e.current;
let params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
current: current.value
};
if (departID.value.length <= 9) {
params.orgCode = departID.value;
} else {
params.jcxd_code = departID.value;
}
getRenyuanByDepID(params);
}
function departChange(e, data) {
departID.value = e;
let params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
current: current.value
};
console.log(e);
if (e.length <= 9) {
params.orgCode = departID.value;
} else {
params.jcxd_code = departID.value;
}
getRenyuanByDepID(params);
}
function getRenyuanByDepID(queryParm) {
// ryDataList.value = [];
console.log(queryParm);
if (departID.value.length <= 6) {
console.log(123242353);
uni.showToast({
title: '全厂数据较多,请选 下一层级...',
icon: 'none',
duration: 1000
});
return;
}
if (queryParm) {
queryRenyuanByDepartID(queryParm)
.then((res) => {
console.log(res);
if (res.success) {
ryDataList.value = res.result.records;
total.value = res.result.total;
pages.value = res.result.pages;
current.value = res.result.current;
}
getHeight();
})
.catch((err) => {
console.log(err);
});
}
}
function Search() {
ryDataList.value = [];
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 + '*';
}
console.log(queryParm);
queryRenyuanByDepartID(queryParm)
.then((res) => {
if (res.success) {
ryDataList.value = res.result.records;
total.value = res.result.total;
pages.value = res.result.pages;
}
})
.catch((err) => {
console.log(err);
});
}
</script>
<style scoped>
/* 全局容器 */
.container {
/* margin: 10rpx 10rpx; */
/* padding: 10rpx; */
background: linear-gradient(145deg, #ffaaff, var(--light-blue));
border-radius: 24rpx;
box-shadow: 0 8rpx 24rpx rgba(64, 158, 255, 0.15);
border: 2rpx solid rgba(64, 158, 255, 0.1);
}
.uni-group {
display: flex;
align-items: center;
}
.titleStyle {
font-size: 12px;
color: #747474;
line-height: 30px;
height: 30px;
background: #f2f9fc;
text-align: center;
vertical-align: middle;
border-left: 1px solid #919191;
border-bottom: 1px solid #919191;
}
/* 内容样式 */
.dataStyle {
font-size: 12px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-overflow: ellipsis;
}
/* 内容样式 */
.pagination {
font-size: 16px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
text-overflow: ellipsis;
}
</style>

View File

@ -0,0 +1,535 @@
<template>
<view>
<view class="container" id="top1">
<uni-row style="margin-bottom: 10rpx; margin-left: 30rpx; margin-right: 30rpx">
<uni-col :span="24"><uni-title :title="'所选单位'" align="left" type="h4"></uni-title></uni-col>
</uni-row>
<uni-row style="margin-bottom: 20rpx; margin-left: 30rpx; margin-right: 30rpx">
<uni-col :span="24">
<trq-depart-select v-model="orgCode" returnCodeOrID="orgCode" @change="departChange"></trq-depart-select>
</uni-col>
</uni-row>
<!-- 概览统计 -->
<view class="stats-box" v-if="summary.total">
<view class="stat-item">
<text class="label">总人数</text>
<text class="value">{{ summary.total }}</text>
</view>
<view class="stat-item">
<text class="label">平均年龄</text>
<text class="value">{{ summary.avgAge.toFixed(1) }}</text>
</view>
</view>
</view>
<!-- ECharts图表 -->
<view class="chart-container">
<l-echart ref="chart" @finished="initChart" />
</view>
<!-- 数据表格 -->
<uni-row style="margin-top: 10px; margin-left: 30rpx; margin-right: 30rpx" v-if="tableData.length > 0">
<uni-col :span="3">
<view class="titleStyle">序号</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">姓名</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">性别</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">年龄</view>
</uni-col>
<uni-col :span="6">
<view class="titleStyle">操作</view>
</uni-col>
</uni-row>
<scroll-view scroll-y :style="{ height: bottomHeight + 'px' }">
<uni-row style="margin-bottom: 10rpx; margin-left: 30rpx; margin-right: 30rpx">
<view v-for="(item, index) in tableData">
<uni-col :span="3">
<view class="dataStyle">
{{ index + 1 }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.xm }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.xb_dictText }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle">
{{ item.nl }}
</view>
</uni-col>
<uni-col :span="6">
<view class="dataStyle">
<span @click="detail(item)" style="color: red">详情</span>
<!-- <button size="mini" type="primary" @click="detail(item)">详情</button> -->
</view>
</uni-col>
</view>
</uni-row>
</scroll-view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import * as echarts from 'echarts';
import { queryRenyuanByDepartID } from '@/api/renyuan.js';
//
const bottomHeight = ref(0);
//
const isLoading = ref(false);
const orgCode = ref('');
const rawData = ref([]);
const tableData = ref([]);
const summary = reactive({
total: 0,
avgAge: 0
});
const chart = ref(null);
const chartOption = ref({});
const drillPopup = ref(null);
const drillList = ref([]);
const drillTitle = ref('');
function detail(record) {
// console.log(record)
uni.navigateTo({
url: '/pages/views/renliziyuan/renyuanxinxi/detail?data=' + encodeURIComponent(JSON.stringify(record))
});
}
//
const calculateAge = (birthDate) => {
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
};
//
const departChange = async (e, data) => {
tableData.value = [];
console.log(e);
orgCode.value = e;
try {
//
isLoading.value = true;
if (orgCode.value.length <= 6) {
console.log(123242353);
uni.showToast({
title: '全厂数据较多,请选 下一层级...',
icon: 'none',
duration: 1000
});
isLoading.value = false;
return;
} else {
uni.showLoading({
title: '数据加载中...',
mask: true
});
}
let params = {
pageSize: 3000,
fields: ['xm', 'nl', 'xb', 'xb_dictText', 'orgCode', 'jcdw', 'jcxd', 'jcxdCode']
};
if (orgCode.value.length <= 9) {
params.orgCode = orgCode.value;
} else {
params.jcxd_code = orgCode.value;
}
queryRenyuanByDepartID(params)
.then((res) => {
if (res.success) {
processData(res.result.records);
//
isLoading.value = false;
uni.hideLoading();
}
})
.catch((err) => {
console.log(err);
uni.showToast({
title: '数据加载失败',
icon: 'none',
duration: 1000
});
});
} catch (error) {
console.log(error);
uni.showToast({
title: '数据加载失败',
icon: 'none',
duration: 1000
});
} finally {
//
isLoading.value = false;
uni.hideLoading();
}
};
//
const processData = (data) => {
//
const validData = data
.map((item) => ({
...item,
nl: calculateAge(item.cssj)
}))
.filter((item) => item.nl >= 21 && item.nl <= 64);
//
summary.total = validData.length;
summary.avgAge = validData.reduce((sum, cur) => sum + cur.nl, 0) / summary.total || 0;
//
// tableData.value = validData;
groupsData(validData);
//
generateChartData(validData);
};
// ...
const subOrgStaffs = ref({}); //
const ageGroupStaffs = ref({}); //
const groupsData = (data) => {
//
subOrgStaffs.value = {};
ageGroupStaffs.value = {};
data.reduce((acc, cur) => {
// console.log(cur)
let subOrg = '';
let ageRange = getAgeRange(cur.nl);
// console.log(cur.orgCode, cur.jcxdCode)
if (cur.orgCode <= 6) {
subOrg = cur.orgCode;
} else {
subOrg = cur.jcxdCode;
}
// subOrgStaffs
if (!subOrgStaffs.value[subOrg]) {
subOrgStaffs.value[subOrg] = [];
}
subOrgStaffs.value[subOrg].push(cur);
// ageGroupStaffs
if (!ageGroupStaffs.value[ageRange]) {
ageGroupStaffs.value[ageRange] = [];
}
ageGroupStaffs.value[ageRange].push(cur);
});
};
//
const getAgeRange = (age) => {
const ranges = ['21-30岁', '31-40岁', '41-50岁', '51-60岁', '61-64岁'];
const index = Math.floor((age - 21) / 10);
return ranges[index] || '其他';
};
//
const showStaffList = (subOrg, ageRange) => {
//
const targetStaffs = subOrgStaffs.value[subOrg].filter((staff) => getAgeRange(staff.nl) === ageRange);
staffList.value = targetStaffs;
popupTitle.value = `${subOrg} ${ageRange}人员列表(共${targetStaffs.length}人)`;
popup.value.open();
};
//
const getSubOrgStaffs = (subOrgCode) => {
return subOrgStaffs.value[subOrgCode] || [];
};
//
const getAgeGroupStaffs = (ageRange) => {
return ageGroupStaffs.value[ageRange] || [];
};
//
const generateChartData = (data) => {
//
const ageRanges = ['21-30岁', '31-40岁', '41-50岁', '51-60岁', '61-64岁'];
const jcdwGroups = data.reduce((acc, cur) => {
if (!acc[cur.jcdw]) {
acc[cur.jcdw] = {
ageGroups: [0, 0, 0, 0, 0] // 21-30,31-40,41-50,51-60,61-64
};
}
const ageGroup = Math.floor((cur.nl - 21) / 10);
// console.log(ageGroup, cur.jcdw)
if (ageGroup >= 0 && ageGroup <= 4) {
acc[cur.jcdw].ageGroups[ageGroup]++;
}
return acc;
}, {});
//
const xData = Object.keys(jcdwGroups);
const seriesData = ageRanges.map((range, index) => ({
name: range,
type: 'bar',
data: xData.map((jcdw) => jcdwGroups[jcdw].ageGroups[index] || 0),
itemStyle: {
color: ['#5470C6', '#91CC75', '#FAC858', '#EE6666', '#73C0DE'][index]
},
//
label: {
show: true,
position: 'top'
}
// 20
// barWidth: 20
}));
chartOption.value = {
title: {
text: '人员年龄分组统计',
padding: [0, 0, 0, 30]
},
toolbox: {
padding: [0, 30, 0, 0],
show: true,
feature: {
//
restore: {
show: true //
},
saveAsImage: {
show: true //
}
}
},
// tooltip: {
// trigger: 'axis',
// axisPointer: {
// type: 'shadow',
// label: {
// show: false
// }
// }
// },
grid: {
top: '15%',
left: '4%',
right: '4%',
bottom: '10%',
containLabel: true
},
legend: {
data: ageRanges,
itemGap: 5,
padding: [0, 15, 0, 15],
y: 'bottom',
itemHeight: 8, //
itemWidth: 8, //
type: 'scroll'
},
xAxis: {
type: 'category',
data: xData,
axisLabel: {
color: '#7F84B5',
fontWeight: 300,
interval: 0,
rotate: 0
},
padding: [0, 10, 0, 10],
axisTick: {
show: false //线
},
axisLine: {
show: false //线
}
},
yAxis: [
{
show: true,
boundaryGap: false, //线
type: 'value',
// name: 'Budget (million USD)',
// data: this.yList,
minInterval: 1,
axisLabel: {
interval: 0
},
splitLine: {
show: true,
lineStyle: {
//线
type: 'dashed'
}
},
axisTick: {
show: true //线
},
axisLine: {
show: false //线
}
}
],
series: seriesData
};
//
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
myChart.setOption(chartOption.value);
myChart.on('click', (params) => {
console.log(params.seriesName);
tableData.value = getAgeGroupStaffs(params.seriesName);
});
}, 300);
// #ifdef APP
getHeight();
// #endif
};
onMounted(() => {
// #ifdef APP
getHeight();
// #endif
});
// #ifdef APP
const getHeight = () => {
//
const systemInfo = uni.getSystemInfoSync();
const screenHeight = systemInfo.screenHeight;
//
const query = uni.createSelectorQuery();
//
query
.select('#top1')
.boundingClientRect((rect1) => {
//
const topComponentsHeight = rect1.height;
//
bottomHeight.value = screenHeight - topComponentsHeight - 415;
})
.exec();
};
// #endif
//
const initChart = () => {
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
myChart.setOption(chartOption.value);
}, 300);
};
</script>
<style scoped>
.container {
margin: 20, 20, 20, 20rpx;
}
.input-group {
display: flex;
gap: 20rpx;
margin-bottom: 30rpx;
}
.input {
flex: 1;
border: 1rpx solid #ddd;
padding: 15rpx;
border-radius: 8rpx;
}
.query-btn {
background: #007aff;
color: white;
padding: 0 40rpx;
border-radius: 8rpx;
}
.stats-box {
display: flex;
justify-content: space-around;
margin: 30rpx 0;
padding: 20rpx;
background: #f8f8f8;
border-radius: 12rpx;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
}
.label {
font-size: 24rpx;
color: #666;
}
.value {
font-size: 36rpx;
font-weight: bold;
color: #0000ff;
}
.chart-container {
height: 400rpx;
margin-top: 20rpx;
}
.titleStyle {
font-size: 12px;
color: #747474;
line-height: 30px;
height: 30px;
background: #f2f9fc;
text-align: center;
vertical-align: middle;
border-left: 1px solid #919191;
border-bottom: 1px solid #919191;
}
/* 内容样式 */
.dataStyle {
max-font-size: 14px;
/* 最大字体限制 */
min-font-size: 10px;
/* 最小字体限制 */
font-size: 12px;
color: #00007f;
line-height: 30px;
height: 30px;
font-weight: 500;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid #919191;
border-left: 1px solid #919191;
text-overflow: ellipsis;
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<view>
<view class="nav"></view>
<view class="placeholder"></view>
<view style="width: 100%; display: grid; place-items: center">
<uni-title :title="dateDate + ':生产经营情况'" type="h1" color="blue" />
</view>
<trq-data></trq-data>
<yy-data></yy-data>
</view>
</template>
<script setup>
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
import { ref, onMounted, computed, nextTick, watchEffect } from 'vue';
const res = wx.getSystemInfoSync();
const statusHeight = res.statusBarHeight; //
const cusnavbarheight = statusHeight + 44 + 'px';
const dateDate = ref('');
import trqData from './ribaoshuju/trqRbsj.vue';
import yyData from './ribaoshuju/yyRbsj.vue';
const strDate = () => {
const now = new Date();
if (now.getHours() < 11) {
return formatDate(getDateAfterDays(now, -1)); //11
} else {
return formatDate(now);
}
};
onMounted(() => {
dateDate.value = strDate();
});
</script>
<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;
}
.placeholder {
height: v-bind(cusnavbarheight);
}
</style>

View File

@ -0,0 +1,348 @@
<template>
<view>
<view class="stats-container">
<uni-title v-if="type === 'trq'" :title="name.unit + '天然气---单位(万方)'" color="blue" type="h2"></uni-title>
<uni-title v-if="type === 'yy'" :title="name.dw + '原油---单位(吨)'" color="blue" type="h2"></uni-title>
</view>
<view class="dateSelect">
<cxc-szcx-dateRangeSelect :mode="'range'" v-model="dateRange"></cxc-szcx-dateRangeSelect>
</view>
<cxc-szcx-lineChart v-if="type === 'trq'" :dataList="dataList" x-field="rqDate" y-field="rq" legend-field="unit" :reference-value="0"></cxc-szcx-lineChart>
<cxc-szcx-lineChart v-if="type === 'yy'" :dataList="dataList" x-field="scrq" y-field="rcwy" legend-field="dw" :reference-value="0"></cxc-szcx-lineChart>
<view style="margin: 0 15px">
<view class="stats-container">
<view class="stats-item">最大值: {{ dataStats.max }}</view>
<view class="stats-item">最小值: {{ dataStats.min }}</view>
<view class="stats-item">平均值: {{ dataStats.average }}</view>
</view>
<view v-if="type === 'trq'" class="table-container">
<!-- 表头 -->
<view class="tr header">
<view class="th1">序号</view>
<view class="th">名称</view>
<view class="th">日期</view>
<view class="th">日气量</view>
</view>
<scroll-view scroll-Y="true" class="scroll-wrapper">
<!-- 表格内容 -->
<view class="tr" v-for="(item, index) in dataList" :key="index" :class="{ even: index % 2 === 0 }">
<view class="td1">{{ index + 1 }}</view>
<view class="td">{{ item.unit }}</view>
<view class="td">{{ item.rqDate }}</view>
<view class="td" :class="{ negative: item.rq < 0 }">
{{ item.rq }}
</view>
</view>
<!-- 空数据提示 -->
<view v-if="!dataList.length" class="empty">暂无相关数据</view>
</scroll-view>
</view>
<view v-if="type === 'yy'" class="table-container">
<!-- 表头 -->
<view class="tr header">
<view class="th1">序号</view>
<view class="th">名称</view>
<view class="th">日期</view>
<view class="th">日油量</view>
</view>
<scroll-view scroll-Y="true" class="scroll-wrapper">
<!-- 表格内容 -->
<view class="tr" v-for="(item, index) in dataList" :key="index" :class="{ even: index % 2 === 0 }">
<view class="td1">{{ index + 1 }}</view>
<view class="td">{{ item.dw }}</view>
<view class="td">{{ item.scrq }}</view>
<view class="td" :class="{ negative: item.rcwy < 0 }">
{{ item.rcwy }}
</view>
</view>
<!-- 空数据提示 -->
<view v-if="!dataList.length" class="empty">暂无相关数据</view>
</scroll-view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, computed, nextTick, watchEffect, warn, watch } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryJinriShengchansj, queryJinriYuanyouShengchansj } from '@/api/shengchan.js';
import { formatDate, getDateAfterDays, getDateAfterMonths } from '@/utils/dateTime.js';
const name = ref({});
const type = ref('');
const dateRange = ref([]);
const dataList = ref([]);
const endDate = ref('');
const startDate = ref('');
const dataStats = ref({
min: 0,
max: 0,
avg: 0
});
const getJinriShengchansj = (tempDateRange) => {
// console.log(tempDateRange);
//
if (!tempDateRange || tempDateRange.some((date) => !convertToDate(date))) {
console.error('收到无效日期范围:', tempDateRange);
return;
}
let queryParms = {};
dataList.value = [];
queryParms.gas = name.value.gas;
queryParms.unit = name.value.unit;
queryParms.rqDate_begin = formatDate(tempDateRange[0]);
queryParms.rqDate_end = formatDate(tempDateRange[1]);
queryParms.pageSize = 500;
//
if (!queryParms.rqDate_begin || !queryParms.rqDate_end) {
console.error('参数格式化失败:', queryParms);
return;
}
// console.log(queryParms);
queryJinriShengchansj(queryParms).then((res) => {
if (res.success) {
// console.log(res);
dataList.value = res.result.records;
dataStats.value = calculateStats(dataList.value, 'rq');
}
});
};
const getJinriYuanyouShengchansj = (tempDateRange) => {
console.log(tempDateRange);
//
if (!tempDateRange || tempDateRange.some((date) => !convertToDate(date))) {
console.error('收到无效日期范围:', tempDateRange);
return;
}
let queryParms = {};
dataList.value = [];
queryParms.dw = name.value.dw;
queryParms.scrq_begin = formatDate(tempDateRange[0]);
queryParms.scrq_end = formatDate(tempDateRange[1]);
queryParms.pageSize = 500;
//
if (!queryParms.scrq_begin || !queryParms.scrq_end) {
console.error('参数格式化失败:', queryParms);
return;
}
console.log(queryParms);
queryJinriYuanyouShengchansj(queryParms).then((res) => {
if (res.success) {
console.log(res);
dataList.value = res.result.records;
dataStats.value = calculateStats(dataList.value, 'rcwy').reverse();
}
});
};
function calculateStats(data, field) {
// field null undefined
const validData = data.filter((item) => item[field] !== null && item[field] !== undefined);
if (validData.length === 0) {
return {
max: null,
min: null,
average: null
};
}
//
let max = validData[0][field];
let min = validData[0][field];
let sum = 0;
//
for (let i = 0; i < validData.length; i++) {
const value = validData[i][field];
//
if (value > max) {
max = value;
}
//
if (value < min) {
min = value;
}
//
sum += value;
}
//
const average = (sum / validData.length).toFixed(4);
return {
max: max,
min: min,
average: average
};
}
function convertToDate(str) {
try {
const date = new Date(str);
//
if (isNaN(date.getTime())) {
return false;
}
return true;
} catch (error) {
return false;
//TODO handle the exception
}
}
//
watch(
[() => type.value, dateRange], // type dateRange
([newType, newDateRange]) => {
if (!newDateRange || !convertToDate(newDateRange[0]) || !convertToDate(newDateRange[1])) {
// console.error(':', newDateRange);
return;
}
// console.log(newType, newDateRange);
switch (
newType // 使 newType
) {
case 'trq':
getJinriShengchansj(newDateRange);
break;
case 'yy':
getJinriYuanyouShengchansj(newDateRange);
break;
default:
console.warn('未知类型:', newType);
}
},
{
immediate: true,
deep: true
}
);
onMounted(() => {
// nextTick();
// getJinriShengchansj(dateRange.value);
});
onLoad((options) => {
name.value = JSON.parse(options.data);
type.value = options.type;
// console.log(name.value, type.value);
const now = new Date();
if (now.getHours() < 11) {
endDate.value = getDateAfterDays(now, -1); //11
startDate.value = getDateAfterMonths(endDate.value, -1); //11
} else {
endDate.value = now;
startDate.value = getDateAfterMonths(endDate.value, -1); //11
}
dateRange.value = [startDate.value, endDate.value];
// console.log(1111, dateRange.value);
});
</script>
<style scoped>
.table-container {
width: 100%;
height: 40vh;
overflow: hidden;
}
.scroll-wrapper {
width: 100%;
height: 35vh;
}
.tr {
display: flex;
min-height: 14px;
font-size: 12px;
border-bottom: 1px solid #e8e8e8;
}
.th,
.td {
flex: 1;
min-width: 80px;
padding: 10px;
font-size: 12px;
font-weight: bold;
color: #333;
text-align: center;
white-space: nowrap;
height: 18px;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
}
.th1,
.td1 {
flex: 1;
max-width: 40px;
padding: 10px;
font-size: 12px;
font-weight: bold;
color: #333;
text-align: center;
white-space: nowrap;
height: 14px;
vertical-align: middle;
}
.th {
background-color: #f0f0f0;
}
.td.negative {
color: #ff4444;
font-weight: 500;
}
.empty {
padding: 40px;
text-align: center;
color: #888;
font-size: 16px;
}
.stats-container {
display: flex;
justify-content: space-around;
align-items: center;
text-align: center;
background-color: #f5f5f5;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 10px;
margin: 15 15px;
}
.dateSelect {
display: flex;
justify-content: space-around;
align-items: center;
text-align: center;
background-color: #f5f5f5;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 5px;
margin: 10px;
}
.stats-item {
font-size: 12px;
color: #00aa00;
font-weight: bold;
}
.stats-item + .stats-item {
border-left: 1px solid #ccc;
padding-left: 16px;
}
</style>

View File

@ -0,0 +1,646 @@
<template>
<view :class="{ gray: store.isgray == 1 }">
<view style="padding: 0 10px">
<view class="progress-bartime">
<!-- 动态设置宽度和颜色 -->
<view class="progressTime" :style="{ width: `${timePercent}%`, 'background-color': '#00aaff' }"></view>
<!-- 显示带符号的百分比 -->
<text class="progress-text">全年时间进度:{{ timePercent }}%</text>
</view>
</view>
<view class="content">
<!-- 标题行 -->
<view class="header-row">
<view class="title">天然气产量</view>
<view class="more" @click="selectMore">更多 </view>
</view>
</view>
<view class="container">
<view v-for="(item, index) in shishiArrSelect" :key="index" class="card-item" @click="handleCardClick(item.gas)">
<view class="card">
<text class="title">{{ item.gas }}</text>
<view class="content">
<text class="label">气量</text>
<text class="value">{{ formatNumber(item.dailyVolume) || '-' }}</text>
</view>
<view class="content">
<text class="label">年累计</text>
<text class="value">{{ formatNumber(item.yearVolume) || '-' }}</text>
</view>
<view class="progress-bar">
<!-- 动态设置宽度和颜色 -->
<view class="progress" :style="{ width: `${Math.abs(item.yearPerCent)}%`, 'background-color': item.yearPerCent < 0 ? '#ff4444' : '#007aff' }"></view>
<!-- 显示带符号的百分比 -->
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')" class="progress-text">{{ item.yearPerCent }}%</text>
</view>
</view>
</view>
</view>
<uni-popup ref="popupSelect" type="top" background-color="#fff">
<view style="margin-top: 50px">
<view class="titlepopup">选择显示更多生产数据</view>
<uni-data-checkbox
style="font-size: 14px"
@change="onselectionchange"
:localdata="shishiArr"
v-model="shishiArrDisplay"
multiple
:map="{ value: 'gas', text: 'gas' }"
></uni-data-checkbox>
</view>
</uni-popup>
<!-- 数据弹窗 -->
<uni-popup ref="popup" type="bottom" background-color="#fff">
<view class="popup-content">
<view class="popup-header">
<text class="title">{{ selectedGas }}数据详情 单位(万立方米)</text>
<uni-icons type="closeempty" size="24" color="#666" @click="closePopup"></uni-icons>
</view>
<view class="table">
<!-- 表头 -->
<view class="tr header">
<view class="th1">序号</view>
<view class="th">名称</view>
<view class="th">日气量</view>
<view class="th">年累计</view>
<view class="th1">操作</view>
</view>
<scroll-view scroll-X="true" scroll-Y="true" class="table-container">
<!-- 表格内容 -->
<view class="tr" v-for="(item, index) in filteredData" :key="index" :class="{ even: index % 2 === 0 }">
<view class="td1">{{ index + 1 }}</view>
<view class="td">{{ item.unit }}</view>
<view class="td" :class="{ negative: item.rq < 0 }">
{{ formatNumber(item.rq) }}
</view>
<view class="td" :class="{ negative: item.yearVolume < 0 }">
{{ formatNumber(item.yearVolume) }}
</view>
<view class="td1" style="color: red" @click="goHistory(item)">历史</view>
</view>
<!-- 空数据提示 -->
<view v-if="!filteredData.length" class="empty">暂无相关数据</view>
</scroll-view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, onMounted, computed, nextTick, watchEffect } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryJinriShengchansj, queryYearShengchansj, queryJinriTrqShengchansj } from '@/api/shengchan.js';
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
import { beforeJump } from '@/utils/index.js';
import { useStore } from '@/store';
import { getYearProgress } from '@/utils/dateTime.js';
const store = useStore();
const shishiArr = ref([]);
const shishiArrSelect = ref([]);
const shishiArrDisplay = ref(['气井气', '站线综合输差']);
const dataJinriUnit = ref([]);
const selectedGas = ref('');
const filteredData = ref([]);
const popup = ref(null);
const popupSelect = ref(null);
const strDate = ref('');
const timePercent = ref(0);
const dataJinri = ref([]);
const dataJinriSum = ref([]);
const dataJinriSumUnit = ref([]);
//
// const handleCardClick = (gas) => {
// selectedGas.value = gas;
// let queryParms = {};
// filteredData.value = [];
// queryParms.day = strDate.value;
// queryParms.gas = gas;
// queryParms.unit = '23,';
// console.log(queryParms);
// queryJinriTrqShengchansj(queryParms).then((res) => {
// if (res.success) {
// console.log(res);
// filteredData.value = res.result;
// }
// });
// popup.value.open();
// };
function selectMore() {
popupSelect.value.open();
}
const onselectionchange = () => {
shishiArrSelect.value = [];
shishiArrDisplay.value.forEach((item) => {
shishiArrSelect.value.push(shishiArr.value.filter((item1) => item1.gas === item)[0]);
});
};
const handleCardClick = (gas) => {
selectedGas.value = gas;
filteredData.value = dataJinriSumUnit.value.filter((item) => item.gas === gas);
popup.value.open();
};
//
const closePopup = () => {
popup.value.close();
};
onMounted(() => {
getJinriTrqShengchansj();
timePercent.value = getYearProgress();
getJinriShengchansj();
});
//
const formatNumber = (num) => {
let temp = 0;
try {
temp = parseFloat(num);
} catch (error) {
//TODO handle the exception
}
return temp.toFixed(4).replace(/\.?0+$/, '');
};
//
function calcZhsc(tempArray) {
let totalJinqi = {
gas: '总进气',
dailyVolume: 0,
yearVolume: 0,
yearPlan: '100',
yearPerCent: 0
};
let totalChuqi = {
gas: '总出气',
dailyVolume: 0,
yearVolume: 0,
yearPlan: '100',
yearPerCent: 0
};
const compositeZx = {
gas: '站线综合输差',
dailyVolume: 0,
yearVolume: 0,
yearPlan: '100',
yearPerCent: 0
}; //
const compositeJc = {
gas: '进出综合输差',
dailyVolume: 0,
yearVolume: 0,
yearPlan: '100',
yearPerCent: 0
}; //
tempArray.forEach((item) => {
if (item.gas === '站输差' || item.gas === '线输差') {
compositeZx.dailyVolume += parseFloat(item.dailyVolume) || 0;
compositeZx.yearVolume += parseFloat(item.yearVolume) || 0;
}
if (item.gas === '气井气' || item.gas === '外部气' || item.gas === '返回气') {
totalJinqi.dailyVolume += parseFloat(item.dailyVolume) || 0;
totalJinqi.yearVolume += parseFloat(item.yearVolume) || 0;
}
if (item.gas === '自耗气' || item.gas === '用户气' || item.gas === '返采油厂干气') {
totalChuqi.dailyVolume += parseFloat(item.dailyVolume) || 0;
totalChuqi.yearVolume += parseFloat(item.yearVolume) || 0;
}
});
compositeZx.yearPerCent = calcPercent(compositeZx.yearPlan, compositeZx.yearVolume);
compositeJc.dailyVolume = (-totalJinqi.dailyVolume + totalChuqi.dailyVolume).toFixed(4);
compositeJc.yearVolume = (-totalJinqi.yearVolume + totalChuqi.yearVolume).toFixed(4);
compositeJc.yearPerCent = calcPercent(compositeJc.yearPlan, compositeJc.yearVolume);
tempArray.push(compositeZx);
// tempArray.push(compositeJc);
return tempArray;
// console.log(composite);
}
const getJinriTrqShengchansj = () => {
const now = new Date();
if (now.getHours() < 11) {
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11
} else {
strDate.value = formatDate(now).toString();
}
let queryParms = {};
shishiArr.value = [];
queryParms.day = strDate.value;
// // console.log(queryParms);
queryJinriTrqShengchansj(queryParms).then((res) => {
if (res.success) {
// console.log(1, res);
let temp = res.result;
temp.forEach((item) => {
if (item.gas === '气井气') {
item.yearPlan = 7500;
item.yearPerCent = calcPercent(item.yearPlan, item.yearVolume);
}
});
// console.log(2, temp);
shishiArr.value = calcZhsc(temp);
nextTick();
onselectionchange();
console.log(3, shishiArr.value);
console.log(4, shishiArrSelect.value);
}
});
};
function goHistory(val) {
uni.navigateTo({
url: '/pages/views/shengchan/ribaoshuju/rbsjLsxq?data=' + JSON.stringify(val) + '&type=trq'
});
}
function calcPercent(yearJihua, yearShiji) {
// 0
// 100
let plan = parseFloat(yearJihua === '' ? 0 : yearJihua);
let shiji = parseFloat(yearShiji);
let percent = 0;
//
if (plan > 0) {
percent = (shiji / plan) * 100;
percent = Math.min(percent, 100); // 100%
}
return parseFloat(percent.toFixed(2)); //
}
const getJinriShengchansj = () => {
const now = new Date();
if (now.getHours() < 11) {
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11
} else {
strDate.value = formatDate(now).toString();
}
let queryParms = {};
dataJinri.value = [];
dataJinriSum.value = [];
dataJinriSumUnit.value = [];
queryParms.rqDate = strDate.value;
queryParms.pageSize = 100;
// console.log(queryParms);
queryJinriShengchansj(queryParms).then((res) => {
if (res.success) {
// console.log(res);
dataJinri.value = res.result.records;
dataJinriSumUnit.value = sumByUnit(dataJinri.value); //gas unit rq cq totalGas
// console.log(dataJinriSumUnit.value);
// 使 nextTick DOM
nextTick();
getYearShengchansj(); //
}
});
};
const getYearShengchansj = () => {
const now = new Date();
let year = formatDate(now).split('-')[0];
let queryParms = {};
queryParms.yearStart = year;
queryParms.yearEnd = year;
// // console.log(2, queryParms.value);
queryYearShengchansj(queryParms).then((res) => {
if (res.success) {
try {
// // console.log(res.result);
let yearData = res.result[year];
// console.log(dataJinriSumUnit.value.length, dataJinriSumUnit.value, yearData.length,
// yearData);
dataJinriSumUnit.value.forEach((item) => {
yearData.forEach((itemYear) => {
// // console.log(item, itemYear);
if (item.unit === itemYear.unit) {
item.yearVolume = itemYear.yearSum || 0;
}
});
});
dataJinriSum.value = sumByGas(dataJinriSumUnit.value);
// console.log(dataJinriSum.value);
shishiArr.value.forEach((item) => {
dataJinriSum.value.forEach((itemjinri) => {
if (item.gas === itemjinri.gas) {
item.dailyVolume = itemjinri.rq.toFixed(4);
item.yearVolume = itemjinri.yearVolume.toFixed(4);
}
});
});
} catch (error) {
// console.log(error);
}
}
});
};
function sumByGas(records) {
// console.log(records);
const summaryMap = {};
try {
records.forEach((record) => {
const gas = record.gas;
if (!summaryMap[gas]) {
// gas
summaryMap[gas] = {
gas: gas,
rq: 0,
sq: 0,
totalGas: 0,
yearVolume: 0
};
}
// gas
summaryMap[gas].rq += record.rq || 0;
summaryMap[gas].sq += record.sq || 0;
summaryMap[gas].totalGas += record.totalGas || 0;
summaryMap[gas].yearVolume += record.yearVolume || 0;
});
return Object.values(summaryMap);
} catch (error) {
//TODO handle the exception
// console.log(error);
}
}
function sumByUnit(records) {
// console.log(records);
const summaryMap = {};
try {
records.forEach((record) => {
const unit = record.unit;
if (!unit.includes('区')) {
if (!summaryMap[unit]) {
// gas
summaryMap[unit] = {
unit: unit,
gas: record.gas,
rq: 0,
sq: 0,
totalGas: 0,
yearVolume: 0
};
}
// unit
summaryMap[unit].rq += record.rq || 0;
summaryMap[unit].sq += record.sq || 0;
summaryMap[unit].totalGas += record.totalGas || 0;
summaryMap[unit].yearVolume += record.yearVolume || 0;
}
});
return Object.values(summaryMap);
} catch (error) {
//TODO handle the exception
// console.log(error);
}
}
</script>
<style lang="scss" scoped>
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10 10rpx;
border-bottom: 1rpx solid #eee;
}
.title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.titlepopup {
font-size: 30rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-top: 20px;
margin-top: 20px;
}
.more {
font-size: 26rpx;
color: #666;
cursor: pointer;
}
.more::after {
content: '';
width: 8rpx;
height: 8rpx;
border-top: 2rpx solid #666;
border-right: 2rpx solid #666;
transform: rotate(45deg);
margin-left: 8rpx;
vertical-align: middle;
}
/* 鼠标悬停效果 */
.more:hover {
color: #007aff;
}
.container {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
gap: 20rpx;
}
.popup-content {
padding: 30rpx;
max-height: 40vh;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #eee;
.title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
}
.table-container {
width: 100%;
height: 30vh;
overflow: hidden;
}
.table {
min-width: 100%;
border: 2rpx solid #e8e8e8;
.tr {
display: flex;
border-bottom: 2rpx solid #e8e8e8;
&.header {
background-color: #fafafa;
font-weight: 600;
}
&.even {
background-color: #f8f8f8;
}
}
.th,
.td {
flex: 1;
min-width: 80rpx;
padding: 10rpx;
font-size: 22rpx;
font-weight: bold;
color: #333;
text-align: center;
white-space: nowrap;
height: 30rpx;
vertical-align: middle;
}
.th1,
.td1 {
flex: 1;
max-width: 40rpx;
padding: 10rpx;
font-size: 22rpx;
font-weight: bold;
color: #333;
text-align: center;
white-space: nowrap;
height: 30rpx;
vertical-align: middle;
}
.th {
background-color: #f0f0f0;
}
.td.negative {
color: #ff4444;
font-weight: 500;
}
}
.empty {
padding: 40rpx;
text-align: center;
color: #888;
font-size: 16rpx;
}
.card-item {
flex: 1 1 200rpx; // 300rpx selectedGas formatNumber
min-width: 240rpx;
max-width: calc(50% - 10rpx); //
@media (min-width: 768px) {
max-width: calc(33.33% - 14rpx); // 3
}
}
.card {
background: #ececec;
border-radius: 16rpx;
padding: 15rpx;
box-shadow: 0 4rpx 12rpx rgba(179, 179, 179, 0.1);
.title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 16rpx;
}
.content {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 24rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #0000ff;
font-weight: 500;
}
}
}
.progress-item {
margin-bottom: 20px;
}
.progress-bar {
position: relative;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-bartime {
position: relative;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
margin-bottom: 30rpx;
}
.progress {
height: 100%;
transition: all 0.3s;
}
.progressTime {
height: 100%;
transition: all 0.3s;
padding: 0 20px;
}
.progress-text {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: red;
/* 保持红色 */
font-size: 12px;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
/* 提升可读性 */
}
</style>

View File

@ -0,0 +1,412 @@
<template>
<view :class="{ gray: store.isgray == 1 }">
<!-- <view style="margin-left: 20rpx;"> <uni-title :title="strDate + ':生产数据'" type="h1" color="red" /> -->
<!-- </view> -->
<view class="content">
<!-- 标题行 -->
<view class="header-row">
<view class="title">原油产量</view>
<view class="more"></view>
</view>
</view>
<view class="container">
<view v-for="(item, index) in shishiArr" :key="index" class="card-item" @click="handleCardClick(item.gas)">
<view class="card">
<!-- <text class="title">{{ item.gas }}</text> -->
<view class="content">
<text class="label">日油量</text>
<text class="value">{{ item.rcwy || '-' }}</text>
</view>
<view class="content">
<text class="label">月累计</text>
<text class="value">{{ item.yl || '-' }}</text>
</view>
<view class="content">
<text class="label">年累计</text>
<text class="value">{{ item.nl || '-' }}</text>
</view>
<view class="progress-bar">
<!-- 动态设置宽度和颜色 -->
<view
class="progress"
:style="{
width: `${Math.abs(item.yearPerCent)}%`,
'background-color': item.yearPerCent < 0 ? '#ff4444' : '#007aff'
}"
></view>
<!-- 显示带符号的百分比 -->
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')" class="progress-text">{{ item.yearPerCent }}%</text>
</view>
</view>
</view>
</view>
<!-- 数据弹窗 -->
<uni-popup ref="popup" type="bottom" background-color="#fff">
<view class="popup-content">
<view class="popup-header">
<text class="title">原油数据详情 单位()</text>
<uni-icons type="closeempty" size="24" color="#666" @click="closePopup"></uni-icons>
</view>
<scroll-view scroll-X="true" scroll-Y="true" class="table-container">
<view class="table">
<!-- 表头 -->
<view class="tr header">
<view class="th1">序号</view>
<view class="th">名称</view>
<view class="th">日油量</view>
<view class="th">月累计</view>
<view class="th">年累计</view>
<view class="th1">操作</view>
</view>
<!-- 表格内容 -->
<view class="tr" v-for="(item, index) in dataJinri" :key="index" :class="{ even: index % 2 === 0 }">
<view class="td1">{{ index }}</view>
<view class="td">{{ item.dw }}</view>
<view class="td">
{{ formatNumber(item.rcwy) }}
</view>
<view class="td">{{ formatNumber(item.yl) }}</view>
<view class="td">
{{ formatNumber(item.nl) }}
</view>
<view class="td1" style="color: red" @click="goHistory(item)">历史</view>
</view>
<!-- 空数据提示 -->
<view v-if="!dataJinri.length" class="empty">暂无相关数据</view>
</view>
</scroll-view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, onMounted, computed, nextTick, watchEffect } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryJinriYuanyouShengchansj } from '@/api/shengchan.js';
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
import { beforeJump } from '@/utils/index.js';
import { useStore } from '@/store';
const store = useStore();
import dataCom from '@/bpm/dataCom.vue';
const shishiArr = ref([
{
gas: '原油产量',
rcwy: '',
yl: '',
nl: '',
yearPlan: '1500',
yearPerCent: ''
}
]);
const dataJinri = ref([]);
const dataJinriSum = ref([]);
const popup = ref(null);
//
const handleCardClick = () => {
popup.value.open();
};
//
const closePopup = () => {
popup.value.close();
};
onMounted(() => {
getJinriYuanyouShengchansj();
// getYearShengchansj();
});
const strDate = ref('');
//
const formatNumber = (num) => {
if (typeof num !== 'number') return '-';
return num.toFixed(4).replace(/\.?0+$/, '');
};
function goHistory(val) {
uni.navigateTo({
url: '/pages/views/shengchan/ribaoshuju/rbsjLsxq?data=' + JSON.stringify(val) + '&type=yy'
});
}
const getJinriYuanyouShengchansj = () => {
const now = new Date();
if (now.getHours() < 11) {
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11
} else {
strDate.value = formatDate(now).toString();
}
let queryParms = {};
dataJinri.value = [];
dataJinriSum.value = [];
queryParms.scrq = strDate.value;
queryParms.pageSize = 100;
// // console.log(queryParms);
queryJinriYuanyouShengchansj(queryParms).then((res) => {
if (res.success) {
// // console.log(res);
dataJinri.value = res.result.records;
dataJinriSum.value = sumByOil(dataJinri.value); //gas unit rq cq totalGas
// // console.log(dataJinriSum.value);
nextTick();
shishiArr.value.forEach((item) => {
dataJinriSum.value.forEach((itemjinri) => {
item.rcwy = itemjinri.rcwy.toFixed(4);
item.nl = itemjinri.nl.toFixed(4);
item.yl = itemjinri.yl.toFixed(4);
item.yearPerCent = calcPercent(item.yearPlan, item.nl);
});
});
// getYearShengchansj(); //
}
});
};
function calcPercent(yearJihua, yearShiji) {
// 0
// 100
let plan = parseFloat(yearJihua === '' ? 0 : yearJihua);
let shiji = parseFloat(yearShiji);
let percent = 0;
//
if (plan > 0) {
percent = (shiji / plan) * 100;
percent = Math.min(percent, 100); // 100%
}
return parseFloat(percent.toFixed(2)); //
}
function sumByOil(records) {
// console.log(records);
const summaryMap = {};
try {
records.forEach((record) => {
const gas = record.gas;
if (!summaryMap[gas]) {
// gas
summaryMap[gas] = {
rcwy: 0,
yl: 0,
nl: 0
};
}
// gas
summaryMap[gas].rcwy += record.rcwy || 0;
summaryMap[gas].yl += record.yl || 0;
summaryMap[gas].nl += record.nl || 0;
});
return Object.values(summaryMap);
} catch (error) {
//TODO handle the exception
// console.log(error);
}
}
</script>
<style lang="scss" scoped>
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #eee;
}
.title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.more {
font-size: 26rpx;
color: #666;
cursor: pointer;
}
.more::after {
content: '';
width: 8rpx;
height: 8rpx;
border-top: 2rpx solid #666;
border-right: 2rpx solid #666;
transform: rotate(45deg);
margin-left: 8rpx;
vertical-align: middle;
}
/* 鼠标悬停效果 */
.more:hover {
color: #007aff;
}
.container {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
gap: 20rpx;
}
.popup-content {
padding: 30rpx;
max-height: 70vh;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #eee;
.title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
}
.table-container {
width: 100%;
height: 30vh;
overflow: hidden;
}
.table {
min-width: 100%;
border: 2rpx solid #e8e8e8;
.tr {
display: flex;
border-bottom: 2rpx solid #e8e8e8;
&.header {
background-color: #fafafa;
font-weight: 600;
}
&.even {
background-color: #f8f8f8;
}
}
.th,
.td {
flex: 1;
min-width: 80rpx;
padding: 10rpx;
font-size: 20rpx;
font-weight: 500;
color: #333;
text-align: center;
white-space: nowrap;
}
.th1,
.td1 {
flex: 1;
max-width: 40rpx;
padding: 10rpx;
font-size: 22rpx;
font-weight: bold;
color: #333;
text-align: center;
white-space: nowrap;
height: 30rpx;
vertical-align: middle;
}
.th {
background-color: #f0f0f0;
}
.td.negative {
color: #ff4444;
font-weight: 500;
}
}
.empty {
padding: 40rpx;
text-align: center;
color: #888;
font-size: 16rpx;
}
.card-item {
flex: 1 1 200rpx; // 300rpx selectedGas formatNumber
min-width: 200rpx;
max-width: calc(50% - 10rpx); //
@media (min-width: 768px) {
max-width: calc(33.33% - 14rpx); // 3
}
}
.card {
background: #ececec;
border-radius: 16rpx;
padding: 15rpx;
box-shadow: 0 4rpx 12rpx rgba(197, 197, 197, 0.1);
.title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 16rpx;
}
.content {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 24rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #0000ff;
font-weight: 500;
}
}
}
.progress-item {
margin-bottom: 20px;
}
.progress-bar {
position: relative;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress {
height: 100%;
transition: all 0.3s;
}
.progress-text {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: red; /* 保持红色 */
font-size: 12px;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); /* 提升可读性 */
}
</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,169 @@
<template>
<view :class="[{'gray':store.isgray==1}]">
<view style="margin-top: 10px;margin-bottom: 10px;">
<picker fields="month" mode="date" @change="bindPickerChange" :value="index">
<view class="date">{{index}} 点击选择月份</view>
</picker>
</view>
<uni-row>
<uni-col :span="7">
<view class="titleStyle">
日期
</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">
带班领导
</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">
值班领导
</view>
</uni-col>
<uni-col :span="9">
<view class="titleStyle">
值班干部
</view>
</uni-col>
</uni-row>
<uni-row>
<view v-for="(item,index) in zhibanArr">
<uni-col :span="7">
<view class="dataStyle">
{{item.date}}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
{{item.dbld_dictText}}
</view>
</uni-col><uni-col :span="4">
<view class="dataStyle">
{{item.zbld_dictText}}
</view>
</uni-col><uni-col :span="9">
<view class="dataStyle">
{{item.zbgbrealname}}
</view>
</uni-col>
</view>
</uni-row>
</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';
let column = ref([{
name: 'date',
label: '日期',
width: 70,
align: 'center'
},
{
name: 'dbld_dictText',
label: '带班领导',
align: 'center',
width: 60
},
{
name: 'zbld_dictText',
label: '值班领导',
align: 'center',
width: 60
},
{
name: 'zbgbrealname',
label: '值班干部',
align: 'center',
width: 150
}
])
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>
// 使便
$primary-color: #0056b3;
$secondary-color: #f2f9fc;
$border-color: #d1e7ff;
$text-color: #333;
.date {
width: 100%; //
padding: 20rpx 30rpx;
font-size: 28rpx;
color: $text-color;
text-align: center; //
background: $secondary-color; // 使
border-bottom: 1px solid $border-color; //
}
.titleStyle {
font-size: 14px; //
color: $primary-color; //
line-height: 2;
height: auto; //
background: $secondary-color;
text-align: center; //
vertical-align: middle;
border-left: 1px solid $border-color;
border-bottom: 1px solid $border-color;
}
/* 内容样式 */
.dataStyle {
font-size: 14px;
color: $text-color;
line-height: 1.5; //
height: auto; //
font-weight: normal; //
text-align: center; //
vertical-align: middle;
border-bottom: 1px solid $border-color;
border-left: 1px solid $border-color;
padding: 10rpx; //
//
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</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

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