Compare commits

..

38 Commits

Author SHA1 Message Date
lcw
883416417f lcw 2026-04-29 02:23:59 +08:00
lcw
cd8347d3d1 lcw 2026-04-28 11:26:26 +08:00
lcw
9fa073546b lcw 2026-04-23 09:28:13 +08:00
lcw
836bcf196c Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-22 21:07:09 +08:00
lcw
a1e247c2e3 lcw 2026-04-22 21:06:37 +08:00
a2a7335536 更新 2026-04-21 23:20:00 +08:00
dbc6ecf62d 更新 2026-04-21 23:17:28 +08:00
cf455216f9 更新 2026-04-21 20:50:56 +08:00
e4a044944d 更新 2026-04-21 19:42:00 +08:00
lcw
ebdd319f9f Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-21 19:23:13 +08:00
lcw
92c1f0be41 lcw 2026-04-21 19:23:00 +08:00
c4cc33bee3 更新 2026-04-21 19:22:56 +08:00
lcw
96e97de237 lcw 2026-04-21 19:22:32 +08:00
5bb7ca0515 Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-21 19:08:32 +08:00
00c9f1e07f 更新 2026-04-21 19:08:23 +08:00
lcw
76df2bc42c Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-21 17:01:37 +08:00
aa1af80bdf 调整 2026-04-21 17:00:48 +08:00
lcw
0020d383bf lcw 2026-04-21 17:00:46 +08:00
571e149313 修改bug 2026-04-20 20:36:59 +08:00
6b563f728f Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-20 16:53:32 +08:00
52095b5fb9 Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-20 16:52:53 +08:00
f31be82805 更新 2026-04-20 16:52:45 +08:00
lcw
35c6849b43 lcw 2026-04-20 16:52:01 +08:00
lcw
baa818153f Merge branch 'main' of http://61.139.16.27:26684/zy_oyj/sgxt_web 2026-04-17 21:42:39 +08:00
lcw
70ed05c67a lcw 2026-04-17 21:41:30 +08:00
f4747be3bc 更新代码 2026-04-17 18:12:29 +08:00
e676fc9000 更新 2026-04-17 17:30:53 +08:00
04cedbc438 更新页面 2026-04-17 17:16:51 +08:00
a3464a53cb 更新需求 2026-04-16 17:14:19 +08:00
lcw
f09a8a0083 lcw 2026-04-16 15:44:42 +08:00
lcw
fbf259663b lcw 2026-04-15 16:04:50 +08:00
763057ed9f 更新 2026-04-07 18:46:30 +08:00
970596f922 更新代码 2026-04-07 17:18:19 +08:00
lcw
ef3c23a03a lcw 2026-04-07 11:12:09 +08:00
lcw
582b8677fc lcw 2026-04-01 00:14:43 +08:00
lcw
af838854fa lcw 2026-03-29 19:46:50 +08:00
lcw
60de16032f lcw 2026-03-24 12:18:39 +08:00
lcw
c181530639 lcw 2026-03-18 11:07:40 +08:00
298 changed files with 44541 additions and 20501 deletions

View File

@ -1 +1 @@
src/
# 取消忽略 src 目录,让 ESLint 正常检查源代码

View File

@ -1,6 +1,7 @@
{
"semi":true,
"semi": true,
"singleQuote": false,
"trailingComma": "none",
"spaced-comment":2
}
"spacedComment": 2,
"quoteProps": "preserve"
}

View File

@ -1,2 +0,0 @@
<!-- 拖拽组件 -->
// npm install vue-draggable-plus --save

94
check_unused_dicts.js Normal file
View File

@ -0,0 +1,94 @@
const fs = require('fs');
const path = require('path');
const baseDir = path.join(__dirname, 'src/views/backOfficeSystem');
// Find all .vue files with proxy.$dict
function findVueFiles(dir) {
let results = [];
const files = fs.readdirSync(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
results = results.concat(findVueFiles(filePath));
} else if (file.endsWith('.vue')) {
const content = fs.readFileSync(filePath, 'utf-8');
if (content.includes('proxy.$dict')) {
results.push(filePath);
}
}
}
return results;
}
// Parse dict variables and their usage
function analyzeFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
// Find the dict destructuring pattern
// Pattern: const { VAR1, VAR2, ... } = proxy.$dict("KEY1", "KEY2", ...)
// Extract the destructured variable names
const destructMatch = content.match(/const\s*\{([^}]+)\}\s*=\s*proxy\.\$dict\s*\(/);
if (!destructMatch) return null;
const varsStr = destructMatch[1];
const dictVars = varsStr.split(',').map(v => v.trim().replace(/\/\/.*$/, '').trim()).filter(v => v && !v.startsWith('//'));
// Extract the dict keys
const dictCallMatch = content.match(/proxy\.\$dict\s*\(([^)]+)\)/s);
if (!dictCallMatch) return null;
const dictKeysStr = dictCallMatch[1];
const dictKeys = dictKeysStr.split(',').map(k => k.trim().replace(/['"]/g, '').replace(/\/\/.*$/, '').trim()).filter(k => k && !k.startsWith('//'));
// Now check which dict vars are actually used in the file
// Remove the dict declaration part first
const scriptContent = content.replace(/const\s*\{[^}]+\}\s*=\s*proxy\.\$dict\s*\([^)]+\)[^;\n]*;?/s, '');
const unusedVars = [];
const usedVars = [];
for (const varName of dictVars) {
if (!varName) continue;
// Check if the variable name appears elsewhere in the file (outside the dict declaration)
// Look for: varName in template, searchConfiger, getMultiDictVal, DictTag :options, :dict= etc.
const regex = new RegExp('\\b' + varName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b');
const matches = scriptContent.match(regex);
if (matches && matches.length > 0) {
usedVars.push(varName);
} else {
unusedVars.push(varName);
}
}
return {
filePath,
dictVars,
dictKeys,
unusedVars,
usedVars
};
}
const vueFiles = findVueFiles(baseDir);
console.log(`Found ${vueFiles.length} files with proxy.$dict\n`);
let totalUnused = 0;
const filesWithUnused = [];
for (const filePath of vueFiles) {
const result = analyzeFile(filePath);
if (result && result.unusedVars.length > 0) {
const relPath = path.relative(__dirname, filePath).replace(/\\/g, '/');
console.log(`\n${relPath}:`);
console.log(` Unused: ${result.unusedVars.join(', ')}`);
filesWithUnused.push(result);
totalUnused += result.unusedVars.length;
}
}
console.log(`\n\n=== Summary ===`);
console.log(`Total files with unused dicts: ${filesWithUnused.length}`);
console.log(`Total unused dict variables: ${totalUnused}`);

View File

@ -0,0 +1,129 @@
# 首页导航跳转问题分析与解决方案
## 问题现象
接口请求完成之前,首页的导航菜单无法跳转;接口请求完成后,导航跳转正常。
---
## 问题根源
### 核心问题SideBarMenu.vue 的页面刷新逻辑
```javascript
// 问题代码(已修复)
if (router.getRoutes().length <= 7 && store.state.permission.routeReady <= 1) {
setTimeout(() => {
router.go(0); // 触发页面刷新!
}, 200);
}
```
当动态路由还没添加完成时,这个条件会触发页面不断刷新,导致导航不可用。
---
## 已完成的修复
### 1. 修改 `src/store/modules/permission.js`
**修改内容**:优化 `routeReady` 状态管理0: 未开始 → 1: 进行中 → 2: 完成)
```javascript
actions: {
filterRoutes(context, menus) {
// 开始处理,标记为进行中
context.commit('setRouteReady', 1);
let routes = [];
if (menus && menus.length > 0) {
routes = filter(privateRoutes, menus);
}
routes.push({ path: '/:catchAll(.*)', redirect: '/404' });
context.commit('setRoutes', routes);
// 处理完成,标记为已完成
context.commit('setRouteReady', 2); // ← 新增:完成时设为 2
return routes;
}
}
```
### 2. 修改 `src/permission.js`
**修改内容**:移除了在路由守卫开始时设置 `setRouteReady(1)` 的代码,让 `filterRoutes` action 统一管理状态。
### 3. 修改 `src/layout/components/SideBar/SideBarMenu.vue`
**修改内容**:移除自动刷新页面的逻辑,改为监听路由加载状态
```javascript
// 原代码(已移除):
// if (router.getRoutes().length <= 7 && store.state.permission.routeReady <= 1) {
// store.commit("user/setIsReady", {});
// setTimeout(() => {
// router.go(0);
// }, 200);
// }
// 新代码:监听路由加载完成状态
if (store.state.permission.routeReady !== 2) {
const unwatch = watch(
() => store.state.permission.routeReady,
(val) => {
if (val === 2) {
unwatch();
}
},
{ immediate: true }
);
}
```
### 4. 修改 `src/utils/route.js`
**修改内容**:添加空值安全检查,避免 `deptId``roleList` 为空时报错
```javascript
// 原代码(可能报错):
// const { deptBizType, deptLevel } = getItem('deptId')[0]
// 新代码(安全):
const deptIdData = getItem('deptId');
const deptInfo = deptIdData && deptIdData.length > 0 ? deptIdData[0] : {};
const deptBizType = deptInfo.deptBizType || '';
const deptLevel = deptInfo.deptLevel || '';
const roleListData = getItem('roleList') || [];
const roleList = roleListData.filter(item => item.roleCode == 'JS_666666').length > 0;
const xjLsit = roleListData.filter(item => item.roleCode == 'JS_999999').length > 0;
```
---
## 修复后的流程
```
登录成功 → window.location.href = '/' → 页面加载
permission.js 路由守卫执行
filterRoutes 开始执行 → routeReady = 1进行中
动态路由添加完成 → routeReady = 2完成
SideBarMenu.vue 监听到 routeReady === 2
导航菜单正常渲染,可以跳转
```
---
## 修复文件列表
| 文件路径 | 修改内容 |
|---------|---------|
| `src/store/modules/permission.js` | 优化 routeReady 状态管理0→1→2 |
| `src/permission.js` | 移除重复的 setRouteReady 调用 |
| `src/layout/components/SideBar/SideBarMenu.vue` | 移除自动刷新逻辑,改为监听状态 |
| `src/utils/route.js` | 添加空值安全检查 |

View File

@ -0,0 +1,463 @@
# 菜单权限逻辑文档
## 概述
本项目采用**动态路由注册**方案实现权限控制。用户登录后,系统根据后端返回的菜单权限码动态注册路由,无权限的路由**根本不会注册**到 Vue Router从根本上杜绝了越权访问的可能。
---
## 整体流程图
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 用户登录 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 调用登录接口 │
│ 返回jwtToken、menuList、menuCodeSet、deptList 等 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 存储权限数据 │
│ - localStorage.menusPermission = menuCodeSet菜单权限码集合
│ - Vuex: user.userInfo.permission.menus = menuCodeSet │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 路由守卫permission.js
│ 首次进入时:获取 menusPermission → 调用 filterRoutes 动态注册路由 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ Vuex: permission/filterRoutes │
│ 1. 根据 menusPermission 过滤 privateRoutes │
│ 2. 通过 router.addRoute() 动态注册有权限的路由 │
│ 3. 最后注册 404 兜底路由 │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ SideBarMenu.vue 组件 │
│ 从已注册的路由中筛选并渲染侧边栏菜单 │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 核心文件说明
| 文件路径 | 作用 |
|---------|------|
| `src/router/index.js` | 路由配置,定义 `publicRoutes`(公开路由)和 `privateRoutes`(私有路由) |
| `src/store/modules/permission.js` | 权限模块,处理路由过滤和动态注册逻辑 |
| `src/store/modules/user.js` | 用户模块,处理登录和退出登录 |
| `src/permission.js` | 路由守卫,控制路由初始化时机 |
| `src/utils/route.js` | 路由工具函数,处理菜单生成 |
| `src/layout/components/SideBar/SideBarMenu.vue` | 侧边栏菜单组件,渲染权限菜单 |
| `src/views/error/404.vue` | 无权限/页面不存在页面 |
| `src/directives/permission.js` | 按钮级权限指令 |
---
## 路由分类
### 公开路由publicRoutes
应用启动时静态注册,所有用户都能访问:
| 路由路径 | 说明 |
|---------|------|
| `/login` | 登录页 |
| `/oatuh_login` | OAuth 登录页 |
| `/zeroTrust_login` | 零信任登录页 |
| `/` | 首页 |
| `/401` | 无权限页(保留) |
| `/404` | 页面不存在/无权限页 |
| `/mapNavigation` | 地图导航 |
| `/KeyPopulations` | 重点人详情 |
| `/deploymentApproval` | 布控审核 |
| `/clueVerification` | 线索核实 |
| 其他特殊路由... | 无需菜单权限校验的业务路由 |
### 私有路由privateRoutes
登录后根据权限动态注册,包含所有业务功能页面。
---
## 详细逻辑分析
### 1. 登录阶段 - 获取并存储权限
**文件**: `src/store/modules/user.js`
```javascript
// 登录成功后存储权限数据
this.commit("user/setToken", data.jwtToken);
this.commit("user/setMenuList", data.menuList);
setItem("menusPermission", data.menuCodeSet); // 核心:菜单权限码集合
this.commit("user/setUserInfo", {
token: data.jwtToken,
permission: {
buttonPermission: ["removeTest", "viewTest"],
menus: data.menuCodeSet
},
menuList: data.menuList,
deptList: data.deptList
});
```
**权限码示例**
```javascript
["FourColorWarning", "YjData", "IntelligentControl", "userList", "departmentList", ...]
```
---
### 2. 路由守卫 - 控制初始化
**文件**: `src/permission.js`
```javascript
const whiteList = ['/login', '/oatuh_login', '/404', '/401', '/zeroTrust_login',
'/focusExploration', '/clueVerification', '/deploymentApproval'];
let routesInitialized = false;
router.beforeEach(async (to, from, next) => {
if (store.getters.token) {
if (!routesInitialized) {
// ★ 首次进入:动态注册路由
routesInitialized = true;
const afterMenuList = getItem('menusPermission');
// 根据权限动态注册路由
await store.dispatch('permission/filterRoutes', afterMenuList);
// 重新导航,确保刚注册的路由能正确匹配
next({ ...to, replace: true });
return;
}
next();
} else {
// 未登录:白名单放行,否则跳转登录
if (whiteList.indexOf(to.path) > -1) {
next();
} else {
// 跳转登录逻辑...
}
}
});
```
---
### 3. 权限过滤与动态注册
**文件**: `src/store/modules/permission.js`
```javascript
import router from '@/router'
import { publicRoutes, privateRoutes } from '@/router'
/**
* 递归过滤路由(保留 component 引用)
* 规则:
* 1. 路由有 name 且在权限列表中 → 保留
* 2. 路由无 name 但有子路由 → 检查子路由权限,有权限子路由则保留父路由
*/
function filter(data, menus) {
const result = []
data.forEach(route => {
const newRoute = { ...route } // 浅拷贝,保留 component 引用
if (route.name && menus?.includes(route.name)) {
// 有权限:递归处理子路由
if (route.children && route.children.length > 0) {
newRoute.children = filter(route.children, menus)
}
result.push(newRoute)
} else if (!route.name && route.children && route.children.length > 0) {
// 父路由无 name检查子路由
const filteredChildren = filter(route.children, menus)
if (filteredChildren.length > 0) {
newRoute.children = filteredChildren
result.push(newRoute)
}
}
})
return result
}
actions: {
filterRoutes(context, menus) {
let routes = []
if (menus && menus.length > 0) {
routes = filter(privateRoutes, menus)
}
// ★★★ 关键:动态添加路由到 Vue Router ★★★
routes.forEach(route => {
router.addRoute(route)
})
// 404 兜底路由必须最后添加
router.addRoute({
path: '/:catchAll(.*)',
redirect: '/404'
})
context.commit('setRoutes', routes)
return routes
}
}
```
**重要说明**
- 不能使用 `JSON.parse(JSON.stringify())` 深拷贝,会丢失 `component` 函数引用导致页面空白
- 使用 `{ ...route }` 浅拷贝保留 `component` 引用
---
### 4. 侧边栏菜单渲染
**文件**: `src/layout/components/SideBar/SideBarMenu.vue`
```javascript
// 从已注册的路由中获取并过滤
const routes = computed(() => {
const fRoutes = filterRoutes(router.getRoutes());
const data = fRoutes.filter((item) => !EXCLUDE_NAMES.includes(item.name));
const menusPermission = getItem("menusPermission");
if (menusPermission === null || menusPermission === undefined) {
return [];
}
const menusSet = new Set(menusPermission.map((item) => `${item}`));
const permissionFiltered = menusSet.size
? filterRoutesByMenusPermission(data, menusSet)
: [];
return generateMenus(permissionFiltered);
});
```
---
### 5. 404 无权限页面
**文件**: `src/views/error/404.vue`
无权限访问时统一跳转此页面,显示提示信息和操作按钮:
```vue
<template>
<div class="error-page">
<div class="error-content">
<h1>404</h1>
<h2>无权限访问</h2>
<p>您没有权限访问此页面请联系上级部门添加相关权限</p>
<el-button type="primary" @click="goHome">返回首页</el-button>
<el-button @click="logout">退出登录</el-button>
</div>
</div>
</template>
<script setup>
const logout = () => {
window.opener = null;
window.open('', '_self');
window.close();
store.commit("app/clearTag", null, { immediate: true });
store.commit("permission/deleteRouter", { immediate: true });
store.commit("user/deleteKeepLiiveRoute", "home");
}
</script>
```
---
### 6. 退出登录
**文件**: `src/store/modules/user.js`
```javascript
async logout(ctx) {
const res = await loginOut();
if (res) {
// 重置动态路由
resetRouter();
// 重置路由守卫初始化标记
resetRoutesInit();
// 清除权限模块状态
ctx.dispatch("permission/resetRoutes");
// 清除用户状态
ctx.commit("user/setToken", "");
ctx.commit("user/setUserName", "admin");
ctx.commit("user/setUserInfo", {});
// 清除本地存储
removeAllItem();
// 跳转统一门户
window.location.href = `https://tyyy.lz.dsj.xz/portal/home`;
}
}
```
---
## 权限判断核心
### 匹配公式
```
用户权限码menusPermission = ["FourColorWarning", "YjData", "userList", ...]
路由配置:
{
path: "/FourColorWarning",
name: "FourColorWarning", // ← 必须与权限码一致
meta: { title: "预警中心", icon: "article-ranking" },
children: [...]
}
判断逻辑:
menusPermission.includes(route.name) ? 有权限 : 无权限
```
### 关键点
| 要素 | 说明 |
|-----|------|
| **权限来源** | 后端登录接口返回的 `menuCodeSet` |
| **存储位置** | `localStorage.menusPermission` |
| **匹配字段** | 路由的 `name` 属性 |
| **匹配方式** | 数组 `includes` 检查 |
| **父路由处理** | 无 `name` 时检查子路由,有权限子路由则保留父路由 |
---
## 权限控制层级
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 权限控制层级 │
├─────────────────────────────────────────────────────────────────────────┤
│ 第一层:路由守卫 │
│ - 控制登录状态 │
│ - 未登录跳转登录页 │
│ - 白名单路由直接放行 │
├─────────────────────────────────────────────────────────────────────────┤
│ 第二层:动态路由注册 │
│ - 根据权限码筛选路由 │
│ - 无权限路由不注册 → 用户输入 URL 直接 404 │
│ - 只在登录时计算一次,性能最优 │
├─────────────────────────────────────────────────────────────────────────┤
│ 第三层:侧边栏菜单过滤 │
│ - 从已注册路由中筛选 │
│ - 只显示有权限的菜单项 │
│ - 支持特殊部门/角色的额外过滤 │
├─────────────────────────────────────────────────────────────────────────┤
│ 第四层:按钮级权限 │
│ - 使用 v-permission 指令控制按钮显示 │
│ - 根据用户的功能权限动态移除无权限元素 │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 安全特性
### 动态路由方案的安全优势
| 特性 | 说明 |
|-----|------|
| **路由不存在** | 无权限路由不会注册到 Vue Router从根本上杜绝越权访问 |
| **URL 直接访问** | 用户输入无权限 URL 直接跳转 404 |
| **性能最优** | 只在登录时计算一次,后续跳转无需校验 |
| **业界标准** | Vue 官方推荐的权限控制方案 |
### 无权限访问流程
```
用户访问无权限 URL如 /user/userList
路由是否已注册?
┌─────┴─────┐
│ 否 │ 是
▼ ▼
跳转 404 正常访问(但不会发生,因为无权限路由不会注册)
```
---
## 特殊权限处理
### 部门类型 + 角色组合
系统根据部门类型(`deptBizType`)和角色(`roleList`)进行特殊路由控制:
| 条件 | 排除的路由 |
|-----|----------|
| `deptBizType == '23'` 且有 `JS_666666` 角色 | 不排除任何路由 |
| `deptBizType == '23'` 且有 `JS_999999` 角色 | 排除 `/internalAuditor` |
| 其他情况 | 排除 `/internalAuditor``/auditList` |
---
## 常见问题
### Q1: 页面空白?
检查项:
1. 是否使用了 `JSON.parse(JSON.stringify())` 深拷贝路由(会丢失 component
2. 路由的 `name` 是否与权限码一致
3. 控制台是否有报错
### Q2: 菜单不显示?
检查项:
1. `localStorage.menusPermission` 是否存在
2. 路由是否包含 `meta.title``meta.icon`
3. 路由是否在 `EXCLUDE_NAMES` 列表中
### Q3: 刷新后 404
检查项:
1. `localStorage.menusPermission` 是否存在
2. 路由守卫是否正确重新初始化
### Q4: 退出登录后无法重新登录?
检查项:
1. 是否正确调用了 `resetRoutesInit()` 重置初始化标记
2. 是否正确清除了 localStorage
---
## 相关文件索引
| 文件 | 说明 |
|-----|------|
| `src/router/index.js` | 路由配置publicRoutes / privateRoutes |
| `src/store/modules/permission.js` | 权限路由模块(过滤 + 动态注册) |
| `src/store/modules/user.js` | 用户模块(登录/退出) |
| `src/permission.js` | 路由守卫 |
| `src/utils/route.js` | 路由工具函数 |
| `src/layout/components/SideBar/SideBarMenu.vue` | 侧边栏菜单 |
| `src/layout/components/NavBar.vue` | 导航栏(退出登录) |
| `src/views/error/404.vue` | 无权限/404 页面 |
| `src/directives/permission.js` | 按钮级权限指令 |

View File

@ -0,0 +1,209 @@
# 麒麟系统浏览器文件下载兼容性修复方案
## 一、问题现象
**下载成功,但文件打不开**。文件已保存到本地,但用对应软件打开时提示损坏或格式错误。
## 二、根因分析
### 可能原因 1`URL.revokeObjectURL` 释放过早(文件内容损坏)
当前代码第300-313行
```javascript
function downloadFile(url, filename) {
fetch(url)
.then((response) => response.blob())
.then((blob) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href); // 同步释放,可能过早
})
}
```
`link.click()` 在麒麟浏览器中是异步的,同步调用 `revokeObjectURL` 会在 Blob 数据写入磁盘前就销毁它,导致文件内容不完整。
---
### 可能原因 2文件名无后缀 / 后缀被篡改
分析文件名传递链路:
**上传时**`handlerSuccess` 保存的是 `{ id, name }``name` 来自浏览器原始文件名(带后缀),这部分没问题。
**但回显时**watch 中第183-188行存在一个关键问题
```javascript
// 当 modelValue 元素是字符串(非对象)时:
} else {
return {
url: String(`/mosty-api/mosty-base/minio/image/download/` + el || ""),
id: el
// ← 没有 name 属性!
};
}
```
此时 `file.name``undefined`,传入 `downloadFile(file.url, file.name)`
```javascript
link.download = undefined; // 文件名丢失
```
**麒麟浏览器的行为**:当 `download` 属性为空或 `undefined` 时,浏览器会:
- 从 URL 路径提取文件名(如 `/minio/image/download/abc123` → 文件名变成 `abc123`**无后缀**
- 或根据 Blob 的 `type` 自动添加后缀(如服务端返回的 Content-Type 是 `application/json` → 强制加 `.json` 后缀)
**结果**:一个 `.docx` 文件下载后变成了 `.json` 或无后缀文件,自然打不开。
**验证方法**:在麒麟系统上下载一个文件,查看下载后的文件名是否和原始文件名一致(包括后缀)。
---
### 可能原因 3麒麟系统安全机制拦截
麒麟系统(基于 Linux自带安全中心可能触发以下行为
| 安全机制 | 行为 | 结果 |
|----------|------|------|
| 文件隔离 | 将下载的文件标记为不可信,移到隔离区 | 文件存在但被锁,其他程序无法读取 |
| 执行权限 | 给文件添加可执行标记,或删除可执行标记 | 程序拒绝打开带危险标记的文件 |
| 杀毒扫描 | 实时扫描下载文件,误报则隔离 | 文件被移动或内容被修改 |
| WINE 兼容层 | 试图用 WINE 打开 Windows 格式文件 | 文件关联错误,打开方式不对 |
**验证方法**
1. 在麒麟系统终端执行 `ls -la` 查看下载文件是否有特殊权限标记
2. 检查 `/tmp` 或隔离区目录是否有被拦截的文件
3. 暂时关闭麒麟安全中心,重新下载测试
---
## 三、修复方案
### 方案 A综合修复推荐
同时解决原因1和原因2并在下载失败时给出明确提示
```javascript
import { saveAs } from 'file-saver'
// 补全文件名后缀
function ensureFilename(file) {
if (file.name) return file.name
// name 丢失时,从 URL 中尝试提取,或使用默认名
const urlId = file.url?.split('/').pop()
return urlId ? `文件_${urlId}` : '未命名文件'
}
function downloadFile(url, filename) {
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`下载失败: ${response.status}`)
}
return response.blob()
})
.then((blob) => {
// saveAs 内部处理了 Blob 释放时序,不会过早 revoke
saveAs(blob, filename)
})
.catch((error) => {
console.error('下载失败:', error)
ElMessage.error('文件下载失败,请重试')
})
}
const handleDownload = (file) => {
if (file?.response?.data) {
window.open(file.response.data)
} else if (file?.url) {
const filename = ensureFilename(file)
downloadFile(file.url, filename)
}
}
```
**改动内容**
1. 引入 `file-saver`(项目已有依赖)→ 解决 Blob 释放过早
2. `ensureFilename` 补全文件名 → 解决后缀丢失
3. 响应状态校验 → 发现服务端错误时提示用户
---
### 方案 B仅修复 Blob 释放时序(最小改动)
```javascript
function downloadFile(url, filename) {
fetch(url)
.then((response) => response.blob())
.then((blob) => {
const blobUrl = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = blobUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 延迟释放,确保浏览器完成 Blob 数据拷贝
setTimeout(() => URL.revokeObjectURL(blobUrl), 3000);
})
.catch((error) => console.error("下载失败:", error));
}
```
**改动量**1 行。但未修复文件名丢失问题。
---
### 方案 Cwindow.open 直接下载
```javascript
const handleDownload = (file) => {
if (file?.url) {
window.open(file.url, "_blank");
}
};
```
**前提**:后端接口需设置 `Content-Disposition: attachment; filename="xxx.docx"` 响应头,浏览器才能正确处理文件名和下载行为。
---
## 四、排查步骤
建议按以下顺序验证,定位到底是哪个原因:
1. **检查文件名**:在麒麟系统下载后,文件名是否带正确后缀(如 `.docx``.pdf`
- 后缀丢失/被改 → **原因2文件名问题**
- 后缀正确 → 排除原因2
2. **检查文件大小**:下载的文件大小是否和服务端一致?
- 文件明显偏小或0字节 → **原因1Blob 释放过早)**
- 大小一致 → 排除原因1
3. **关闭安全中心测试**:暂时关闭麒麟安全中心,重新下载
- 能正常打开 → **原因3安全拦截**
- 仍打不开 → 排除原因3
---
## 五、方案对比
| | 方案 A 综合修复 | 方案 B 延迟释放 | 方案 C window.open |
|---|---|---|---|
| 修复原因1Blob释放 | ✅ | ✅ | 不涉及 |
| 修复原因2文件名后缀 | ✅ | ❌ | 取决于后端 |
| 处理原因3安全拦截 | ❌ 需系统配置 | ❌ | ❌ |
| 改动量 | ~15行 | 1行 | 最小 |
**建议**先执行排查步骤确认根因再选择对应方案。如果原因1和2同时存在直接用方案A。
---
**文档版本**: v3.0
**创建日期**: 2026-04-24

BIN
gsxt.zip Normal file

Binary file not shown.

25540
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,10 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@babel/core": "^7.29.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/preset-env": "^7.29.2",
"@element-plus/icons": "^0.0.11",
"@toast-ui/editor": "^3.0.2",
"@vue/cli-plugin-babel": "~4.5.0",
@ -79,14 +83,5 @@
"sass-loader": "^8.0.2",
"svg-sprite-loader": "^6.0.9",
"vue-cli-plugin-element-plus": "0.0.13"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
}
}

View File

@ -45,7 +45,6 @@ onMounted(() => {
/**
*@Descripttion:图片页面初始化
*@Author: PengShuai

View File

@ -620,7 +620,7 @@ export const idCardNoLogin = (data) => {
method: "POST",
data
});
}
};
// 通过身份证号获取会话信息
export const getSessionForSfzh = (params) => {
return request({
@ -636,7 +636,7 @@ export const idCardNoLoginPcs = (data) => {
method: "POST",
data
});
}
};
// 通过身份证号获取会话信息
export const getSessionForSfzhPcs = (params) => {
return request({

View File

@ -1,5 +1,15 @@
import request from "@/utils/request";
const api = "/mosty-api/mosty-gsxt";
// 情报采集关注
export const xxcjCare = (data) => {
return request({
url: api + "/xxcj/cjgz",
method: "POST",
data
});
}
// 情报采集新增
export const xxcjAddEntity = (data) => {
return request({
@ -65,6 +75,14 @@ export const xxcjSelectCzlcList = (params) => {
})
}
// 情报采集指令更新
export const xxcjPlsb = (data) => {
return request({
url: api + `/xxcj/plsb`,
method: "post",
data
})
}
// 情报采集指令更新
export const xxcjUpdateCzlc = (data) => {
return request({
url: api + `/xxcj/updateCzlc`,
@ -236,3 +254,12 @@ export const xxcjXxcjSh = (data) => {
data
})
}
// 上报区厅
export const xxcjReportGat = (data) => {
return request({
url: api + `/xxcj/reportGat`,
method: "post",
data
})
}

View File

@ -155,7 +155,7 @@ header {
}
&::v-deep .el-form-item--default {
width: 23%;
// width: 23%;
padding-bottom: 20px;
margin: 0 1%;
}

View File

@ -241,6 +241,10 @@
align-items: center;
}
.vam {
vertical-align: middle;
}
/**********文本省略***********/
.nowrap {
white-space: nowrap;
@ -287,6 +291,10 @@
margin-top: 10px;
}
.mb10 {
margin-bottom: 10px;
}
/**********字体大小和边距***********/
@for $i from 1 through 100 {
.f#{$i} {
@ -345,7 +353,7 @@
}
.ww#{$i} {
width: #{$i}+"%";
width: #{$i * 1%};
}
.hh#{$i} {
@ -430,10 +438,13 @@
// 警情闪速动画
@keyframes alert-flash {
0%, 100% {
0%,
100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.3;
transform: scale(1.05);
@ -444,19 +455,25 @@
0% {
box-shadow: 0 0 0 0 rgba(255, 77, 79, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(255, 77, 79, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(255, 77, 79, 0);
}
}
@keyframes alert-blink {
0%, 49% {
0%,
49% {
opacity: 1;
}
50%, 100% {
50%,
100% {
opacity: 0;
}
}
@ -489,3 +506,9 @@
color: #df6c07;
animation: alert-flash 1s ease-in-out infinite;
}
.margTop {
padding: 10px;
margin-top: 10px;
background-color: #fff;
}

BIN
src/assets/images/01.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/02.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/03.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/04.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/05.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/06.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/07.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/08.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/09.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/10.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/11.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/12.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/13.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/14.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/15.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/16.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/17.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/18.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/19.mp3 Normal file

Binary file not shown.

BIN
src/assets/images/jqjc.mp3 Normal file

Binary file not shown.

View File

@ -88,7 +88,11 @@
import { qcckGet } from "@/api/qcckApi.js";
import { defineProps, ref, getCurrentInstance, watch } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_BQ_DJ, D_GS_SSYJ,D_GS_BQ_LB,D_GS_BQ_LX } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ","D_GS_BQ_LB","D_GS_BQ_LX"); //获取字典数据
const { D_GS_BQ_DJ, D_GS_SSYJ,
// D_GS_BQ_LB, D_GS_BQ_LX
} = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"
// ,"D_GS_BQ_LB","D_GS_BQ_LX"
); //获取字典数据
const props = defineProps({
modelValue: {
type: Boolean,

View File

@ -7,9 +7,17 @@
@close="closed"
>
<div>
<div class="flex" style="margin-bottom: 10px;">
<el-button :type="bqLb === '01' ? 'success' : 'info'" @click="qihuan('01')">标签大类</el-button>
<el-button :type="bqLb === '02' ? 'success' : 'info'" @click="qihuan('02')"> 标签小类 </el-button>
<div class="mark-tabs">
<span class="label">标签类型</span>
<el-radio-group v-model="bqLx" @change="changeBqLx">
<el-radio-button label="02">行为标签</el-radio-button>
<el-radio-button label="01">身份标签</el-radio-button>
</el-radio-group>
<span class="label" style="margin-left: 20px;">类别</span>
<el-radio-group v-model="bqLb" @change="qihuan">
<el-radio-button label="01">大类</el-radio-button>
<el-radio-button label="02">小类</el-radio-button>
</el-radio-group>
</div>
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
<el-form-item label="标签名称">
@ -83,7 +91,7 @@
<script setup>
import { qcckGet } from "@/api/qcckApi.js";
import { defineProps, ref, getCurrentInstance, watch } from "vue";
import { defineProps, ref, getCurrentInstance, watch, nextTick } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
const props = defineProps({
@ -107,6 +115,11 @@ const props = defineProps({
roleIds: {
type: Array,
default: []
},
// 标签类型02-行为标签01-身份标签
bqLx: {
type: String,
default: "02"
}
});
const loading = ref(false);
@ -120,6 +133,8 @@ const keyVal = ref();
const multipleUserRef = ref(null);
const multipleSelectionUser = ref([]);
const tableData = ref([]);
const bqLx = ref(props.bqLx);
const bqLb = ref("01");
const emits = defineEmits(["update:modelValue", "choosed"]);
const keyid = (row) => {
return row.id;
@ -148,9 +163,9 @@ const onComfirm = () => {
closed();
};
const qihuan = (val) => {
bqLb.value = val
getListData()
}
listQuery.value.pageCurrent = 1;
getListData();
};
/**
* pageSize 改变触发
*/
@ -168,7 +183,7 @@ const handleCurrentChange = (currentPage) => {
const getListData = () => {
keyVal.value++;
loading.value = true;
const params = { ...listQuery.value, bqLx: "02",bqLb:bqLb.value };
const params = { ...listQuery.value, bqLx: bqLx.value, bqLb: bqLb.value };
qcckGet(params, "/mosty-gsxt/tbGsxtBqgl/selectPage")
.then((res) => {
loading.value = false;
@ -183,23 +198,25 @@ const getListData = () => {
//列表回显 - 优化版,确保已选择数据正确回显
function multipleUser() {
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
return;
}
nextTick(() => {
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
return;
}
// 先清除所有选中状态
tableData.value.forEach((item) => {
multipleUserRef.value.toggleRowSelection(item, false);
});
// 再根据roleIds重新设置选中状态
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
// 先清除所有选中状态
tableData.value.forEach((item) => {
if (props.roleIds.some((id) => id == item.id)) {
multipleUserRef.value.toggleRowSelection(item, true);
}
multipleUserRef.value.toggleRowSelection(item, false);
});
}
// 再根据roleIds重新设置选中状态
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
tableData.value.forEach((item) => {
if (props.roleIds.some((id) => id == item.id)) {
multipleUserRef.value.toggleRowSelection(item, true);
}
});
}
});
}
const handleFilter = () => {
@ -218,7 +235,11 @@ const handleSelectionChange = (val) => {
multipleSelectionUser.value = val;
}
};
const bqLb=ref('01')
const changeBqLx = (val) => {
listQuery.value.pageCurrent = 1;
multipleUserRef.value?.clearSelection();
getListData();
};
// 监听弹窗打开状态,打开时重新加载数据
watch(
() => props.modelValue,
@ -233,19 +254,40 @@ watch(
// 监听roleIds变化确保数据回显正确
watch(
() => props.roleIds,
(newRoleIds) => {
// 使用setTimeout确保在表格数据加载完成后再进行选择
setTimeout(() => {
() => {
nextTick(() => {
multipleUser();
}, 100);
});
},
{ deep: true }
);
// 监听外部传入的 bqLx 变化
watch(
() => props.bqLx,
(newVal) => {
bqLx.value = newVal;
}
);
</script>
<style lang="scss" scoped>
@import "@/assets/css/layout.scss";
@import "@/assets/css/element-plus.scss";
.mark-tabs {
display: flex;
align-items: center;
margin-bottom: 15px;
padding: 10px 15px;
background: #f5f7fa;
border-radius: 6px;
.label {
font-weight: 500;
color: #606266;
}
}
</style>
<style>
.tabBoxRadio .el-checkbox__inner {

View File

@ -67,13 +67,14 @@
</template>
<script setup>
import { getItem } from "@/utils/storage";
import { timeValidate } from '@/utils/tools'
import { ref,defineEmits, onMounted } from 'vue'
const props = defineProps({
modelValue:Boolean,
})
const emit = defineEmits(['update:modelValue','save'])
const baseInfo = localStorage.getItem('rhInfo') ? JSON.parse(localStorage.getItem('rhInfo')) : {};
const baseInfo = getItem('rhInfo') || {};
const formData = ref({
alarm:1,
duration:'30',

View File

@ -34,6 +34,7 @@
</template>
<script setup>
import { getItem } from "@/utils/storage";
import useCallModule from '@/components/Consultation/sdk/call';
import useRecorder from '@/components/Consultation/hooks/recorder';
import DraggableResizableVue from "draggable-resizable-vue3";
@ -43,7 +44,7 @@ const props = defineProps({
modelValue:Boolean,
})
const emit = defineEmits(['update:modelValue'])
const baseInfo = localStorage.getItem('rhInfo') ? JSON.parse(localStorage.getItem('rhInfo')) : {};
const baseInfo = getItem('rhInfo') || {};
let waveContainer;
let audioWave = SiriWave || undefined;
const element = ref({

View File

@ -9,6 +9,7 @@
</template>
<script setup>
import { getItem } from "@/utils/storage";
import { timeValidate } from '@/utils/tools'
import DraggerAble from './components/draggerAble.vue'
import useConfernceEvent from './components/js/useConfernceEvent';
@ -21,8 +22,9 @@ import { useStore } from "vuex";
const emit = defineEmits(['update']);
const modleType = ref('')
const store = useStore();
const inDustRialId = getItem('inDustRialId'); // 当前用户的警号
const sdkBDModule = useBaseDataModule();
const baseInfo = localStorage.getItem('rhInfo') ? JSON.parse(localStorage.getItem('rhInfo')) : {};
const baseInfo = ref(getItem('rhInfo') || {});
const showVideo = ref(false)//拖动视频
const showDailog = ref(false)//showDailog
const openMeeting = ref(false) //打开会议
@ -95,8 +97,8 @@ const handleTime = (n=10) =>{
// 创建会议
const conferenceActionSDK = async (record ) => {
const createRes = await lemon.conference.createConference({
subject: record.glxsmc, //主题
let data = {
subject: record.hsbt, //主题
type: 1, //会议类型 0=即时会议1=预约会议
emergency_flag: 0, //会议紧急标识 0 = 非紧急会议1 = 紧急会议
duration: 60, //预计时长 (分钟)
@ -105,14 +107,14 @@ const conferenceActionSDK = async (record ) => {
appointment: handleTime(), // start_date 和 start_time 对应的 UTC 时间
members:[
{
alias:baseInfo.dispatcher_name,
basedata_id:baseInfo.basedata_id,
guid:baseInfo.user_guid,
number:baseInfo.user_id,
alias:baseInfo.value.dispatcher_name,
basedata_id:baseInfo.value.basedata_id,
guid:baseInfo.value.user_guid,
number:baseInfo.value.user_id,
}
],//当前创建人
});
console.log(createRes,'===========创建的会议');
}
const createRes = await lemon.conference.createConference(data);
if (createRes.result === 0) {
ElMessage.success(jsonData.value['data']['conference.book.result.ok']);
record.number = createRes.meeting.number;
@ -135,7 +137,7 @@ const enterConferenceByNumber = (it) =>{
"camera_status": 1
}
lemon.conference.enterConferenceByNumber(params).then(res=> {
console.log(res,'加入会议......');
console.log(res,'=======加入会议=======');
}).catch(err=> {
console.log(err,' 加入会议失败......');
})
@ -145,7 +147,6 @@ const enterConferenceByNumber = (it) =>{
// 获取会议
const fetchConferences = (it) =>{
lemon.conference.fetchConferences().then(res=> {
console.log(res.conferenceList,'获取会议');
meetList.value = res.conferenceList;
let obj = meetList.value.find(v=>v.number == it.number);
// 会议存在 ? 进入会议 : 创建会议 ;
@ -153,58 +154,20 @@ const fetchConferences = (it) =>{
}).catch(err=> {})
}
const Init = () => {
let token = window.localStorage.getItem("rhToken");
if (!token) {
let userInfo = {
username: "sgxtcs",
password: "123456",
realm: "puc.com",
webpucUrl: "https://89.40.9.95:16888"
};
lemon.login.login(userInfo).then((esacpe) => {
token = esacpe.token;
window.localStorage.setItem("rhToken", esacpe.token);
listenerEvents()
});
} else {
ConnectWebsocket(token);
}
};
const ConnectWebsocket = (token) => {
lemon.login.reConnectWebsocket({
username: "sgxtcs",
realm: "puc.com",
webpucUrl: "https://89.40.9.95:16888",
token: token
}).then((resp) => {
if(resp.result != 0){
localStorage.removeItem('rhToken')
localStorage.removeItem('user_basedata_id')
let messge = jsonData.value['errorCode'][resp.result] +',请重新刷新页面'
ElMessage.error(messge);
lemon.login.logout().then(res=> {}).catch(err=> {})
}else{
listenerEvents();
}
});
};
// 初始化后需要监听的方法
const listenerEvents = () =>{
getLoginAccountInfo() //前账号的登录信息
useConfernceEvent()// 注册会议管理相关事件
// 无人机对讲机的监听时事件
window.lemon.call.addMediaStream((call_id, stream, type) => {
console.log(call_id, stream, type,'=======无人机对讲机的监听时事件==');
// console.log(call_id, stream, type,'=======无人机对讲机的监听时事件==');
});
}
const getLoginAccountInfo =() =>{
lemon.login.getLoginAccountInfo().then(res => {
let info = JSON.stringify(res.account_info)
baseInfo.value = res.account_info;
window.localStorage.setItem("rhInfo",info);
window.localStorage.setItem("user_basedata_id",res.account_info.basedata_id);
}).catch(err => {
@ -226,7 +189,6 @@ const openInit = (it,type) =>{
// 会议号存在 ? 获取会议列表里面是否包含该条会议 : 创建会议 ;
it.number ? fetchConferences(it) : conferenceActionSDK(it);
}).catch(()=>{ })
}
if(['对讲机','无人机'].includes(type)){
@ -236,7 +198,45 @@ const openInit = (it,type) =>{
})
}
}
const Init = () => {
let token = window.localStorage.getItem("rhToken");
if (!token || 'undefined' == token || token == 'null') {
let userInfo = {
username: inDustRialId, //用户名
password: "123456",
realm: "puc.com",
webpucUrl: "https://89.40.9.95:16888"
};
lemon.login.login(userInfo).then((esacpe) => {
token = esacpe.token;
window.localStorage.setItem("rhToken", esacpe.token);
listenerEvents()
})
} else {
ConnectWebsocket(token);
}
};
const ConnectWebsocket = (token) => {
lemon.login.reConnectWebsocket({
username: inDustRialId, //用户名
realm: "puc.com",
webpucUrl: "https://89.40.9.95:16888",
token: token
}).then((resp) => {
if(resp.result != 0){
localStorage.removeItem('rhToken')
localStorage.removeItem('user_basedata_id')
let messge = jsonData.value['errorCode'][resp.result] +',请重新刷新页面'
ElMessage.error(messge);
lemon.login.logout().then(res=> {}).catch(err=> {})
}else{
listenerEvents();
}
});
};
onMounted(()=>{
jsonData.value = require('./components/zh_CN.json');
@ -250,7 +250,7 @@ onUnmounted(()=>{
lemon.login.removeLoginStatusChangeListener(loginStatusCallbackId.value);
})
defineExpose({openInit});
defineExpose({openInit,Init});
</script>
<style lang="scss" scoped>

View File

@ -1,7 +1,13 @@
<template>
<div :id="mapid" class="map"></div>
<div class="changeMap_box" v-if="props.isShow">
<!-- <el-switch v-model="conditionRoute" @change="handleSwitch" active-text="打开路况" inactive-text="关闭路况" style="--el-switch-color:#13ce66;--el-switch-off-color:#ff4949;" /> -->
<el-switch
v-model="conditionRoute"
@change="handleSwitch"
active-text="打开路况"
inactive-text="关闭路况"
style="--el-switch-color: #13ce66; --el-switch-off-color: #ff4949"
/>
<!-- <el-carousel type="card" height="75px" :autoplay="false" indicator-position="none" :initial-index="3" @change="onMapImageChange">
<el-carousel-item>
<div class="mapImageItem">
@ -30,8 +36,14 @@
</el-carousel> -->
<!-- 地图缩放 -->
<div class="zoomTargetBox">
<el-input-number :min="7" :max="18" v-model="zoomTarget" :step="1" step-strictly @change="handleZoom">
</el-input-number>
<el-input-number
:min="7"
:max="18"
v-model="zoomTarget"
:step="1"
step-strictly
@change="handleZoom"
></el-input-number>
</div>
</div>
</template>
@ -44,7 +56,7 @@ import { getItem } from "@/utils/storage";
const conditionRoute = ref(true); //路况
const mMap = ref(null); //地图对象
const mapUtil = ref(null); //地图工具对象
const zoomTarget = ref(6);
const zoomTarget = ref(15);
const props = defineProps({
mapid: {
@ -70,8 +82,7 @@ const props = defineProps({
isShowDraw: {
type: Boolean,
default: false
},
}
});
try {
const userInfo = getItem("deptId")[0].deptCode;
@ -89,66 +100,40 @@ onMounted(() => {
map = new EliMap({
id: props.mapid,
crs: "EPSG:3857",
crs: "EPSG:4490",
style: {
glyphs: "./fonts/{fontstack}/{range}.pbf",
center: [94.36,29.65],
zoom: 11
center: [94.36057012, 29.64276831],
zoom: 15
},
minZoom: 7,
maxZoom: 18,
transformRequest: (url) => {
if (url.indexOf("TileMatrix=") != -1) {
const arr = url.split("TileMatrix=");
const arr1 = arr[1].split("&");
const nurl = `${arr[0]}&TileMatrix=${Number(arr1[0])}&${arr1[1]}&${arr1[2]}`;
}
}
minZoom: 5,
maxZoom: 20
});
window.map = map;
map.mapboxGLMap.on("load", () => {
map.addGaudLayer({
url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
})
zoomTarget.value = map.mapboxGLMap.getZoom();
// 地图加载完成后发出事件
// emit('mapLoaded')
map.addWMTSLayer(
"/PGIS_S_TileMapServer/Maps/XZDJ_DJ/EzMap",
{
Service: "getImage",
Type: "RGB",
ZoomOffset: "0",
V: "0.3",
Zoom: "{z}",
Row: "{y}",
Col: "{x}"
},
{
tileSize: 300
}
);
// WMTS图层加载完成后延时设置zoom
setTimeout(() => {
map.mapboxGLMap.setZoom(18);
zoomTarget.value = 18;
}, 500);
});
mapUtil.value = new MapUtil(map);
// map = new EliMap({
// id: props.mapid,
// crs: "EPSG:4490",
// style: {
// glyphs: "./fonts/{fontstack}/{range}.pbf",
// center: [94.36057012, 29.64276831],
// zoom: 15
// },
// minZoom: 7,
// maxZoom: 18,
// });
// window.map = map;
// map.mapboxGLMap.on("load", () => {
// map.addWMTSLayer(
// "/PGIS_S_TileMapServer/Maps/XZDJ_SL/EzMap"
// ,
// {
// Service: "getImage",
// Type: "RGB",
// ZoomOffset: "0",
// V: "0.3",
// Zoom: "{z}",
// Row: "{y}",
// Col: "{x}"
// },
// {
// tileSize: 300
// }
// );
// zoomTarget.value = map.mapboxGLMap.getZoom();
// });
// mapUtil.value = new MapUtil(map);
mapUtil.value.Drawplot(); //初始化加载绘制工具
// 设置地图中心点及图层
@ -184,6 +169,10 @@ onMounted(() => {
emitter.on("showSquire", (obj) => {
mapUtil.value.zdySquire(obj);
});
// 展示气泡框
emitter.on("makerPopup", (obj) => {
mapUtil.value.makerPopup(obj);
});
// 绘制图形 - 回显区域
emitter.on("drawShape", (res) => {
@ -289,7 +278,6 @@ const mapSetLayer = (id, source) => {
//获取地图绘制的数据
const resFun = (coord, type, flag, data) => {
emitter.emit("coordString", {
coord: coord,
type: type,
@ -303,12 +291,6 @@ const handleZoom = (val) => {
map.mapboxGLMap.setZoom(val);
};
emitter.on("map-resize", () => {
if (map && map.mapboxGLMap) {
map.mapboxGLMap.resize();
}
});
// 是否打开或者关闭路况
const handleSwitch = (val) => {
if (val) {
@ -325,6 +307,7 @@ onUnmounted(() => {
emitter.off("showPoint");
emitter.off("deletePointArea");
emitter.off("deletePointAreaOne");
emitter.off("makerPopup");
emitter.off("drawShape");
emitter.off("echoPlane");
emitter.off("removeEara");
@ -338,7 +321,6 @@ onUnmounted(() => {
emitter.off("diffusionCircle");
emitter.off("SsCircle");
emitter.off("ClearssCircle");
emitter.off("map-resize");
});
</script>
@ -361,29 +343,35 @@ onUnmounted(() => {
right: 398px;
bottom: 4px;
z-index: 9;
.mapImageItem {
border: 1px solid #08aae8;
background: rgb(9, 26, 70);
& > img {
width: 100%;
height: 50px;
}
& > div {
text-align: center;
position: relative;
top: -3px;
}
}
.zoomTargetBox {
margin-top: 10px;
margin-left: 23px;
}
::v-deep .el-input-number__decrease,
::v-deep .el-input-number__increase {
background: #133362;
color: #fff;
border: none;
}
::v-deep .el-input__inner {
background: #0c1641;
}

View File

@ -1,8 +1,7 @@
<template>
<div :id="mapid" class="map"></div>
<div class="changeMap_box" v-if="props.isShow">
<el-switch v-model="conditionRoute" @change="handleSwitch" active-text="打开路况" inactive-text="关闭路况"
style="--el-switch-color: #13ce66; --el-switch-off-color: #ff4949" />
<!-- <el-switch v-model="conditionRoute" @change="handleSwitch" active-text="打开路况" inactive-text="关闭路况" style="--el-switch-color:#13ce66;--el-switch-off-color:#ff4949;" /> -->
<!-- <el-carousel type="card" height="75px" :autoplay="false" indicator-position="none" :initial-index="3" @change="onMapImageChange">
<el-carousel-item>
<div class="mapImageItem">
@ -31,7 +30,15 @@
</el-carousel> -->
<!-- 地图缩放 -->
<div class="zoomTargetBox">
<el-input-number :min="7" :max="18" v-model="zoomTarget" :step="1" step-strictly @change="handleZoom"></el-input-number>
<el-input-number
:min="7"
:max="18"
v-model="zoomTarget"
:step="1"
step-strictly
@change="handleZoom"
>
</el-input-number>
</div>
</div>
</template>
@ -44,7 +51,7 @@ import { getItem } from "@/utils/storage";
const conditionRoute = ref(true); //
const mMap = ref(null); //
const mapUtil = ref(null); //
const zoomTarget = ref(15);
const zoomTarget = ref(6);
const props = defineProps({
mapid: {
@ -74,7 +81,7 @@ const props = defineProps({
});
try {
const userInfo = getItem("deptId")[0].deptCode;
} catch (error) { }
} catch (error) {}
let map;
let mapLayer;
let mapLayer1;
@ -88,37 +95,67 @@ onMounted(() => {
map = new EliMap({
id: props.mapid,
crs: "EPSG:4490",
crs: "EPSG:3857",
style: {
glyphs: "./fonts/{fontstack}/{range}.pbf",
center: [94.36057012, 29.64276831],
center: [94.36, 29.65],
zoom: 15
},
minZoom: 5,
minZoom: 7,
maxZoom: 18,
transformRequest: (url) => {
if (url.indexOf("TileMatrix=") != -1) {
const arr = url.split("TileMatrix=");
const arr1 = arr[1].split("&");
const nurl = `${arr[0]}&TileMatrix=${Number(arr1[0])}&${arr1[1]}&${
arr1[2]
}`;
}
}
});
window.map = map;
map.mapboxGLMap.on("load", () => {
map.addWMTSLayer(
"/PGIS_S_TileMapServer/Maps/XZDJ_DJ/EzMap"
,
{
Service: "getImage",
Type: "RGB",
ZoomOffset: "0",
V: "0.3",
Zoom: "{z}",
Row: "{y}",
Col: "{x}"
},
{
tileSize: 300
}
);
map.addGaudLayer({
url: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
});
zoomTarget.value = map.mapboxGLMap.getZoom();
//
// emit('mapLoaded')
});
mapUtil.value = new MapUtil(map);
// map = new EliMap({
// id: props.mapid,
// crs: "EPSG:4490",
// style: {
// glyphs: "./fonts/{fontstack}/{range}.pbf",
// center: [94.36057012, 29.64276831],
// zoom: 15
// },
// minZoom: 7,
// maxZoom: 18,
// });
// window.map = map;
// map.mapboxGLMap.on("load", () => {
// map.addWMTSLayer(
// "/PGIS_S_TileMapServer/Maps/XZDJ_SL/EzMap"
// ,
// {
// Service: "getImage",
// Type: "RGB",
// ZoomOffset: "0",
// V: "0.3",
// Zoom: "{z}",
// Row: "{y}",
// Col: "{x}"
// },
// {
// tileSize: 300
// }
// );
// zoomTarget.value = map.mapboxGLMap.getZoom();
// });
// mapUtil.value = new MapUtil(map);
mapUtil.value.Drawplot(); //
//
@ -154,10 +191,6 @@ onMounted(() => {
emitter.on("showSquire", (obj) => {
mapUtil.value.zdySquire(obj);
});
//
emitter.on("makerPopup", (obj) => {
mapUtil.value.makerPopup(obj);
});
// -
emitter.on("drawShape", (res) => {
@ -276,6 +309,12 @@ const handleZoom = (val) => {
map.mapboxGLMap.setZoom(val);
};
emitter.on("map-resize", () => {
if (map && map.mapboxGLMap) {
map.mapboxGLMap.resize();
}
});
//
const handleSwitch = (val) => {
if (val) {
@ -292,7 +331,6 @@ onUnmounted(() => {
emitter.off("showPoint");
emitter.off("deletePointArea");
emitter.off("deletePointAreaOne");
emitter.off("makerPopup");
emitter.off("drawShape");
emitter.off("echoPlane");
emitter.off("removeEara");
@ -306,6 +344,7 @@ onUnmounted(() => {
emitter.off("diffusionCircle");
emitter.off("SsCircle");
emitter.off("ClearssCircle");
emitter.off("map-resize");
});
</script>
@ -328,35 +367,29 @@ onUnmounted(() => {
right: 398px;
bottom: 4px;
z-index: 9;
.mapImageItem {
border: 1px solid #08aae8;
background: rgb(9, 26, 70);
&>img {
& > img {
width: 100%;
height: 50px;
}
&>div {
& > div {
text-align: center;
position: relative;
top: -3px;
}
}
.zoomTargetBox {
margin-top: 10px;
margin-left: 23px;
}
::v-deep .el-input-number__decrease,
::v-deep .el-input-number__increase {
background: #133362;
color: #fff;
border: none;
}
::v-deep .el-input__inner {
background: #0c1641;
}

View File

@ -0,0 +1,55 @@
<template>
<div class="form-item-box zj-packageSelect-wrap" :style="{ width: width }">
<el-select v-bind="$attrs" :model-value="modelValue" @change="hanlderSelect"
:popper-class="selectOption.length > 20 ? 'nation-select' : ''" :placeholder="placeholder">
<el-option v-for="item in selectOption" :key="item.dm" :label="item.zdmc" :value="item.dm">
</el-option>
</el-select>
</div>
</template>
<script setup>
import { COMPONENT_WIDTH } from '@/constant';
import { nextTick, onBeforeMount, ref } from "vue";
import { getDictInfoByDictEnum } from "@/api/sysDict";
const emits = defineEmits(["handleChange"]); //子组件向父组件事件传递
const props = defineProps({
//获取组件传值
placeholder: {
default: "请选择",
type: String
},
modelValue: {
default: "",
type: String
},
dictEnum: {
default: "",
type: String
},
width: {
default: COMPONENT_WIDTH,
type: String
}
});
const selectOption = ref([]);
onBeforeMount(async () => {
const res = await getDictInfoByDictEnum({ dictElementEnum: props.dictEnum });
//正常下拉结构
if (res.zdlx === 1) {
selectOption.value = [...res.itemList];
} else {
//树形结构数据
}
});
const hanlderSelect = (data) => {
emits("handleChange", data);
};
</script>
<style lang="scss" scoped>
.zj-packageSelect-wrap {
::v-deep .el-select {
width: 100%;
}
}
</style>

View File

@ -3,8 +3,8 @@
</template>
<script setup>
import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
import { defineComponent, onMounted, onBeforeUnmount, ref, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
data: {
type: Array,
@ -12,137 +12,141 @@ const props = defineProps({
},
color: {
type: Array,
default:() => []
default: () => []
}
})
const chartRef = ref(null)
let chart = null
});
const chartRef = ref(null);
let chart = null;
// 保存 resize 处理函数的引用
const handleResize = () => {
chart && chart.resize();
};
const initChart = () => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value)
if (!chartRef.value) return;
chart = echarts.init(chartRef.value);
const option = {
// backgroundColor: '#1a213c',
tooltip: {
formatter: '{b}: {c} ({d}%)',
backgroundColor: 'rgba(0,0,0,0.7)',
borderColor: '#1a213c',
formatter: "{b}: {c} ({d}%)",
backgroundColor: "rgba(0,0,0,0.7)",
borderColor: "#1a213c",
textStyle: {
color: '#fff'
color: "#fff"
}
},
legend: {
type: 'scroll', // 启用滚动图例
selectedMode: 'multiple',
orient: 'vertical',
right: '0%',
top: 'center',
type: "scroll", // 启用滚动图例
selectedMode: "multiple",
orient: "vertical",
right: "0%",
top: "center",
textStyle: {
color: '#fff'
color: "#fff"
},
formatter: function (name) {
const data = option.series[0].data
const total = data.reduce((sum, item) => sum + item.value, 0)
const target = data.find(item => item.name === name)
const percentage = ((target.value / total) * 100).toFixed(0)
return `${name} ${target.value}`
const data = option.series[0].data;
const total = data.reduce((sum, item) => sum + item.value, 0);
const target = data.find((item) => item.name === name);
const percentage = ((target.value / total) * 100).toFixed(0);
return `${name} ${target.value}`;
},
// 图例翻页配置
pageIconColor: '#fff', // 翻页按钮颜色
pageTextStyle: { color: '#fff' }, // 翻页文字颜色
pageIconColor: "#fff", // 翻页按钮颜色
pageTextStyle: { color: "#fff" }, // 翻页文字颜色
pageIconSize: 12, // 翻页按钮大小
pageButtonItemGap: 5, // 分页按钮之间的间距
pageButtonGap: 10, // 分页按钮与图例项之间的间距
pageIconInactiveColor: '#555', // 不激活的翻页按钮颜色
pageButtonPosition: 'end' // 翻页按钮的位置
pageIconInactiveColor: "#555", // 不激活的翻页按钮颜色
pageButtonPosition: "end" // 翻页按钮的位置
},
series: [{
type: 'pie',
radius: ['30%', '55%'],
center: ['40%', '50%'],
roseType: false,
zlevel: 10,
startAngle: 35,
selectedMode: 'single',
selectedOffset: 10,
data:[...props.data],
label: {
show: true,
formatter: '{d}%',
color: '#fff',
position: 'outside',
fontSize: 14,
fontWeight: 'bold'
},
emphasis: {
focus: 'self',
scaleSize: 10,
series: [
{
type: "pie",
radius: ["30%", "55%"],
center: ["40%", "50%"],
roseType: false,
zlevel: 10,
startAngle: 35,
selectedMode: "single",
selectedOffset: 10,
data: [...props.data],
label: {
show: true,
formatter: "{d}%",
color: "#fff",
position: "outside",
fontSize: 14,
fontWeight: "bold"
},
emphasis: {
focus: "self",
scaleSize: 10,
itemStyle: {
shadowBlur: 20,
shadowOffsetX: 5,
shadowOffsetY: 5,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
},
itemStyle: {
shadowBlur: 20,
shadowOffsetX: 5,
shadowOffsetY: 5,
shadowColor: 'rgba(0, 0, 0, 0.5)'
borderRadius: 4,
borderColor: "#1a213c",
borderWidth: 2
},
// 启用全局动画控制器
animation: true,
// 关键设置animationDelayUpdate确保数据更新时也有动画
animationDelayUpdate: function (idx) {
return idx * 300;
},
// 逐个显示的动画效果 - 改为从透明到不透明的过渡效果
animationType: "opacity",
animationEasing: "cubicOut",
// 关键:设置初始样式,让每个扇形从透明状态开始
// 使用动画帧序列来控制动画过程
animation: true,
animationDuration: 1000,
animationDelay: function (idx) {
// 按照索引顺序依次显示,设置更明显的延迟
return idx * 400;
},
// 动画开始前的回调,确保动画效果
animationBegin: function () {
// 可以在这里进行额外的动画初始化
return 0;
},
// 动画帧序列,控制每个关键帧的样式
animationFrame: function (idx, percent) {
// percent参数是从0到1的动画进度
return {
opacity: percent,
scale: 0.8 + percent * 0.2 // 从0.8放大到1
};
}
},
itemStyle: {
borderRadius: 4,
borderColor: '#1a213c',
borderWidth: 2
},
// 启用全局动画控制器
animation: true,
// 关键设置animationDelayUpdate确保数据更新时也有动画
animationDelayUpdate: function (idx) {
return idx * 300;
},
// 逐个显示的动画效果 - 改为从透明到不透明的过渡效果
animationType: 'opacity',
animationEasing: 'cubicOut',
// 关键:设置初始样式,让每个扇形从透明状态开始
// 使用动画帧序列来控制动画过程
animation: true,
animationDuration: 1000,
animationDelay: function (idx) {
// 按照索引顺序依次显示,设置更明显的延迟
return idx * 400;
},
// 动画开始前的回调,确保动画效果
animationBegin: function() {
// 可以在这里进行额外的动画初始化
return 0;
},
// 动画帧序列,控制每个关键帧的样式
animationFrame: function (idx, percent) {
// percent参数是从0到1的动画进度
return {
opacity: percent,
scale: 0.8 + percent * 0.2 // 从0.8放大到1
};
}
}],
media: [
{
query: { minAspectRatio: 1 },
option: {
series: [
{ center: ['36%', '50%'] },
]
],
media: [
{
query: { minAspectRatio: 1 },
option: {
series: [{ center: ["36%", "50%"] }]
}
}
}
]
}
]
};
chart.setOption(option);
};
chart.setOption(option)
}
onMounted(() => {
initChart()
window.addEventListener('resize', () => {
chart && chart.resize()
})
})
initChart();
window.addEventListener("resize", handleResize);
});
// 监听数据变化,确保动画在数据更新时也能触发
watch(
@ -150,30 +154,21 @@ watch(
(newData) => {
if (chart && newData && newData.length > 0) {
// 使用clear方法强制重新渲染并触发动画
chart.clear()
initChart()
chart.clear();
initChart();
}
},
{ deep: true }
)
);
// 组件卸载时清理资源
const cleanup = () => {
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
if (chart) {
chart.dispose()
chart = null
chart.dispose();
chart = null;
}
window.removeEventListener('resize', () => {
chart && chart.resize()
})
}
// 组件卸载时执行清理
onUnmounted(() => {
cleanup()
})
});
</script>
<style scoped>

View File

@ -1,45 +1,103 @@
<template>
<div class="form-item-box" :class="props.showBtn ? 'showBtn-upload' : ''" :style="{ width: width }">
<div
class="form-item-box"
:class="props.showBtn ? 'showBtn-upload' : ''"
:style="{ width: width }"
>
<!-- 列表模式按钮在上文件列表在下 -->
<div v-if="props.showBtn" class="upload-wrapper">
<el-upload
v-bind="$attrs"
:headers="headers"
:multiple="false"
class="avatar-uploader upload-btn-only"
:limit="props.limit"
:action="actionUrl"
:file-list="fileList"
:show-file-list="false"
:on-exceed="handleExceed"
:on-success="handlerSuccess"
:before-upload="beforeImgUpload"
>
<el-button size="small" type="primary">上传文件</el-button>
</el-upload>
<!-- 文件列表 -->
<div v-if="showFileList" class="upload-file-list">
<div v-for="(file, index) in fileList" :key="file.id || index" class="upload-list-item">
<span class="upload-list-item__name" @click="handleDownload(file)">
<el-icon class="upload-list-item__icon"><Document /></el-icon>
{{ file.name }}
</span>
<span class="upload-list-item__actions">
<el-icon class="upload-list-item__download" @click="handleDownload(file)"><Download /></el-icon>
<el-icon v-if="!disabled" class="upload-list-item__delete" @click="handleRemove(file, fileList)"><Close /></el-icon>
</span>
</div>
</div>
</div>
<!-- 卡片模式 -->
<el-upload
v-else
v-bind="$attrs"
:headers="headers"
:multiple="false"
class="avatar-uploader"
:limit="props.limit"
:action="actionUrl"
:list-type="props.showBtn ? '' : 'picture-card'"
list-type="picture-card"
:file-list="fileList"
:show-file-list="showFileList"
:before-remove="beforeRemove"
:on-exceed="handleExceed"
:on-success="handlerSuccess"
:before-upload="beforeImgUpload">
:before-upload="beforeImgUpload"
>
<template #default>
<el-button v-if="props.showBtn" size="small" type="primary">上传文件</el-button>
<el-icon v-else><Plus /></el-icon>
<el-icon><Plus /></el-icon>
</template>
<template #file="{ file }" v-if="!props.showBtn">
<template #file="{ file }">
<!-- 图片卡片模式 -->
<div v-if="props.isImg">
<img class="el-upload-list__item-thumbnail" :src="file.url || ''" alt="" />
<img
class="el-upload-list__item-thumbnail"
:src="file.url || ''"
alt=""
/>
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<el-icon> <zoom-in /></el-icon>
</span>
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file, fileList)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
<!-- 文件卡片模式 -->
<div v-else>
<div class="file-wrap">
<span><svg-icon :icon="getSuffix(file.name)" /></span>
<span class="file-name">{{ file.name }}</span>
</div>
<span class="el-upload-list__item-actions">
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDownload(file)">
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleDownload(file)"
>
<el-icon><Download /></el-icon>
</span>
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file, fileList)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
@ -54,8 +112,17 @@
<script setup>
import { COMPONENT_WIDTH } from "@/constant";
import { ref, defineProps, defineEmits, computed, watch, onMounted, onUnmounted } from "vue";
import {
ref,
defineProps,
defineEmits,
computed,
watch,
onMounted,
onUnmounted
} from "vue";
import { ElMessage } from "element-plus";
import { saveAs } from "file-saver";
import { useStore } from "vuex";
const props = defineProps({
//获取组件传值
@ -98,35 +165,42 @@ const headers = ref({
});
const fileList = ref([]);
watch(() => props.modelValue,(val) => {
let arr = val ? (Array.isArray(val) ? val :[val]): [];
if(arr.length == 0 ) return fileList.value = [];
fileList.value = arr.map((el) => {
if (Object.prototype.toString.call(el) === "[object Object]") {
// 确保file.url始终是字符串URL
const fileUrl = props.isAll ? `/mosty-api/mosty-base/minio/image/download/` + el.id : el.url;
return {
...el,
url: String(fileUrl || ''),
name: el.name || '',
};
} else {
return {
url: String(`/mosty-api/mosty-base/minio/image/download/` + el || ''),
id: el
};
}
});
console.log(fileList.value, "fileList.value");
},{ immediate: true,deep:true });
watch(
() => props.modelValue,
(val) => {
let arr = val ? (Array.isArray(val) ? val : [val]) : [];
if (arr.length == 0) return (fileList.value = []);
fileList.value = arr.map((el) => {
if (Object.prototype.toString.call(el) === "[object Object]") {
// 确保file.url始终是字符串URL
const fileUrl = props.isAll
? `/mosty-api/mosty-base/minio/image/download/` + el.id
: el.url;
return {
...el,
url: String(fileUrl || ""),
name: el.name || ""
};
} else {
return {
url: String(`/mosty-api/mosty-base/minio/image/download/` + el || ""),
id: el,
name: el
};
}
});
console.log(fileList.value, "fileList.value");
},
{ immediate: true, deep: true }
);
const actionUrl = computed(() => {
if (props.isAll) {
return "/mosty-api/mosty-base/minio/image/upload/id";
} else {
return props.isImg ? "/mosty-api/mosty-base/minio/image/upload/id": "/mosty-api/mosty-base/minio/file/uploadObj";
return props.isImg
? "/mosty-api/mosty-base/minio/image/upload/id"
: "/mosty-api/mosty-base/minio/file/uploadObj";
}
});
@ -158,7 +232,17 @@ const getSuffix = (fileName) => {
//pdf
if (suffix === "pdf") return "PDF";
//视频 音频
var videolist = ["mp4","m2v","mkv","rmvb","wmv","avi","flv","mov","m4v"];
var videolist = [
"mp4",
"m2v",
"mkv",
"rmvb",
"wmv",
"avi",
"flv",
"mov",
"m4v"
];
if (videolist.includes(suffix)) return "VIDEO";
var musiclist = ["mp3", "wav", "wmv"];
if (musiclist.includes(suffix)) return "MUSIC";
@ -177,19 +261,19 @@ const handlerSuccess = (res, file) => {
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
file.id = res.data;
fileList.value.push(file);
let arr = []
if(props.isImg){
arr = fileList.value.map((el) => el.id)
let arr = [];
if (props.isImg) {
arr = fileList.value.map((el) => el.id);
} else {
console.log(fileList,"测试");
console.log(fileList, "测试");
arr = fileList.value.map((el) => {
console.log(el,'xunhuan');
console.log(el, "xunhuan");
return {
id: el.id, name: el.name
}
})
console.log(arr,"测试2222");
id: el.id,
name: el.name
};
});
console.log(arr, "测试2222");
}
emits("update:modelValue", arr);
};
@ -201,7 +285,7 @@ const handleExceed = (files, fileList) => {
const beforeImgUpload = (file) => {
if (props.isImg) {
let isIMG = false;
if (getSuffix(file.name) === "IMG") isIMG = true;
if (getSuffix(file.name) === "IMG") isIMG = true;
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isIMG) ElMessage.error("上传图片只能是jpg/png/jpeg/bmp/gif格式!");
if (!isLt5M) ElMessage.error("上传图片大小不能超过 5MB!");
@ -212,28 +296,38 @@ const beforeImgUpload = (file) => {
};
//查询图片
const handlePictureCardPreview = (file) => {
dialogImageUrl.value = file.url || '';
dialogImageUrl.value = file.url || "";
dialogVisible.value = true;
};
function downloadFile(url, filename) {
fetch(url)
.then((response) => response.blob())
.then((blob) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
})
.catch((error) => console.error("下载失败:", error));
// 补全文件名:确保文件名有效且有后缀
const ensureFilename = (file) => {
if (file.name) return file.name;
// name 丢失时,从 URL 或 ID 提取
const urlId = file.url?.split('/').pop() || file.id;
return urlId ? `文件_${urlId}` : '未命名文件';
};
async function downloadFile(url, filename) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`下载失败: ${response.status}`);
}
const blob = await response.blob();
// 使用 file-saver 处理下载,内部处理了 Blob 释放时序,兼容各系统
saveAs(blob, filename);
} catch (error) {
console.error("下载失败:", error);
ElMessage.error("文件下载失败,请重试");
}
}
const handleDownload = (file) => {
if (file?.response?.data) {
window.open(file.response.data);
} else if (file?.url) {
downloadFile(file.url, file.name);
const filename = ensureFilename(file);
downloadFile(file.url, filename);
}
};
// const handleDownload = (file) => {
@ -247,7 +341,7 @@ const beforeRemove = (file) => {
});
props.modelValue.splice(index, 1);
emits("update:modelValue", props.modelValue);
}
};
const handleRemove = (file) => {
let index = fileList.value.findIndex(function (item) {
@ -257,7 +351,6 @@ const handleRemove = (file) => {
props.modelValue.splice(index, 1);
emits("update:modelValue", props.modelValue);
};
</script>
<style lang="scss" scoped>
@ -312,4 +405,90 @@ const handleRemove = (file) => {
-webkit-line-clamp: 2;
}
}
/* 列表模式容器 */
.upload-wrapper {
display: flex;
flex-direction: column;
width: 100%;
.upload-btn-only {
:deep(.el-upload-list) {
display: none;
}
}
}
/* 文件列表 */
.upload-file-list {
width: 100%;
margin-top: 10px;
}
/* 列表模式样式 */
.upload-list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
background: #f5f7fa;
border-radius: 4px;
margin-bottom: 8px;
transition: background-color 0.3s;
&:hover {
background: #e9ecf0;
.upload-list-item__actions {
opacity: 1;
}
}
.upload-list-item__name {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
cursor: pointer;
color: #606266;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: #409eff;
}
}
.upload-list-item__icon {
margin-right: 8px;
font-size: 18px;
color: #909399;
flex-shrink: 0;
}
.upload-list-item__actions {
display: flex;
align-items: center;
flex-shrink: 0;
opacity: 0;
transition: opacity 0.3s;
.el-icon {
cursor: pointer;
font-size: 16px;
margin-left: 12px;
color: #606266;
&:hover {
color: #409eff;
}
}
.upload-list-item__delete:hover {
color: #f56c6c;
}
}
}
</style>

View File

@ -18,6 +18,7 @@ import MarkdownEdit from "./MarkdownEdit/index.vue";
import FileUpload from "./FileUpload/index.vue";
import Date from "./Date/index.vue";
import Empty from "./Empty/index.vue";
import PackageSelect from "./PackageSelect/index.vue";
export {
AddressSelect,
FrameWork,
@ -38,5 +39,6 @@ export {
MarkdownEdit,
FileUpload,
Date,
Empty
Empty,
PackageSelect
};

View File

@ -108,7 +108,7 @@ import {
reactive,
ref,
watch,
watchEffect
shallowRef
} from "vue";
const props = defineProps({
tableConfiger: {
@ -200,10 +200,14 @@ let getConfiger = reactive({
});
const radioChoose = ref("");
watchEffect(() => {
getConfiger = { ...getConfiger, ...props.tableConfiger };
// 使用 watch 替代 watchEffect,避免无限循环
// 只有当 tableConfiger 的 JSON 字符串表示变化时才触发
watch(() => JSON.stringify(props.tableConfiger), () => {
Object.keys(props.tableConfiger).forEach(key => {
getConfiger[key] = props.tableConfiger[key];
});
setDefaultChoose();
});
}, { immediate: true });
onMounted(() => {
setDefaultChoose();

View File

@ -1,7 +1,7 @@
<template>
<el-form ref="elform" :model="listQuery" :label-width="props.labelWidth" :rules="props.rules" :inline="props.inline" label-position="right" :disabled="props.disabled">
<el-form-item v-for="(item, idx) in props.formList" :style="item.width && { width: item.width }" :prop="item.prop" :label="item.label" :label-width="item.labelWidth" :key="idx">
<el-form-item v-for="(item, idx) in props.formList" v-show="item.show !== false" :style="item.width && { width: item.width }" :prop="item.prop" :label="item.label" :label-width="item.labelWidth" :key="idx">
<!-- input表单 input-->
<MOSTY.Other v-if="item.type == 'input'" width="100%" clearable v-model="listQuery[item.prop]" :placeholder="`请输入${item.label}`" :disabled="item.disabled" :readonly="item.readonly" @blur="inputBlur($event,item)" />
@ -12,7 +12,7 @@
<el-input-number v-model="listQuery[item.prop]" v-else-if="item.type == 'number'" :step="item.step || 1" style="width: 100%" :min="item.min || 0" :max="item.max || 1000" :disabled="item.disabled" />
<!--选择 select-->
<MOSTY.Select v-else-if="item.type == 'select'" filterable :multiple="item.multiple" v-model="listQuery[item.prop]" :dictEnum="item.options" width="100%" clearable :placeholder="`请选择${item.label}`" :disabled="item.disabled" />
<MOSTY.Select v-else-if="item.type == 'select'" :filterable="item.filterable" :multiple="item.multiple" v-model="listQuery[item.prop]" :dictEnum="item.options" width="100%" clearable :placeholder="`请选择${item.label}`" :disabled="item.disabled" />
<!-- 部门department -->
<template v-else-if="item.type === 'department'">

View File

@ -49,7 +49,7 @@
</template>
<script setup>
import { nextTick, onMounted, reactive, ref, watch, watchEffect } from "vue";
import { nextTick, onMounted, reactive, ref, watch, shallowRef } from "vue";
const props = defineProps({
tableConfiger: {
type: Object,
@ -117,10 +117,14 @@ let getConfiger = reactive({
radioChoose: "", // 单选时选中的值------------- 待完成
rowHeight: "41" // 每行的高度
});
watchEffect(() => {
getConfiger = { ...getConfiger, ...props.tableConfiger };
// 使用 watch 替代 watchEffect,避免无限循环
// 只有当 tableConfiger 的 JSON 字符串表示变化时才触发
watch(() => JSON.stringify(props.tableConfiger), () => {
Object.keys(props.tableConfiger).forEach(key => {
getConfiger[key] = props.tableConfiger[key];
});
setDefaultChoose();
});
}, { immediate: true });
onMounted(() => {
setDefaultChoose();
});

View File

@ -0,0 +1,553 @@
<template>
<div v-loading="loadingPage" class="pageSearch searchBox main-container"
:style="`margin-bottom: ${marginBottom}px;background-color: ${backgroundColor}`">
<div class="filter-title">
<span class="filter-label"><el-icon>
<Filter />
</el-icon>筛选条件</span>
</div>
<div class="content-container">
<div class="box">
<div v-for="(item, index) in getArr" :key="index" class="item">
<div class="label" v-if="item.label">{{ item.label }}</div>
<!-- select -->
<el-select v-if="item.showType === 'select'" v-model="searchObj[item.prop]" :multiple="item.multiple"
:clearable="item.clearable" :filterable="item.filterable" :placeholder="item.placeholder" collapse-tags
collapse-tags-tooltip>
<el-option v-for="obj in getOptions[item.prop]" :key="obj.value" :label="obj.label || obj.lable"
:value="obj.value" />
</el-select>
<!-- input -->
<el-input v-else-if="item.showType === 'input'" class="input" v-model="searchObj[item.prop]"
:clearable="item.clearable" :placeholder="item.placeholder" />
<!-- input -->
<el-input v-else-if="item.showType === 'number'" class="input" v-model="searchObj[item.prop]"
:clearable="item.clearable" :placeholder="item.placeholder" type="number" />
<!-- 日期段选择器 -->
<el-date-picker v-else-if="item.showType === 'daterange'" v-model="searchObj[item.prop]" type="daterange"
unlink-panels :range-separator="item.rangeSeparator" :start-placeholder="item.startPlaceholder"
:end-placeholder="item.endPlaceholder" :shortcuts="item.shortcuts" :disabledDate="disabledDate"
value-format="YYYY-MM-DD" />
<el-date-picker v-else-if="item.showType === 'datetimerange'" v-model="searchObj[item.prop]"
type="datetimerange" unlink-panels :range-separator="item.rangeSeparator || ''"
:start-placeholder="item.startPlaceholder || '开始日期'" :end-placeholder="item.endPlaceholder || '结束日期'"
:shortcuts="item.shortcuts" value-format="YYYY-MM-DD HH:mm:ss" />
<el-date-picker v-else-if="item.showType === 'date'" v-model="searchObj[item.prop]" type="date"
:placeholder="item.placeholder" :disabled-date="disabledDate" :shortcuts="item.shortcuts"
value-format="YYYY-MM-DD">
</el-date-picker>
<el-date-picker v-else-if="item.showType === 'datetime'" v-model="searchObj[item.prop]" type="datetime"
:placeholder="item.placeholder" value-format="YYYY-MM-DD HH:mm:ss">
</el-date-picker>
<!-- checkbox -->
<template v-else-if="item.showType === 'department'">
<MOSTY.Department clearable v-model="searchObj[item.prop]" />
</template>
<!-- checkbox -->
<template v-else-if="item.showType === 'checkbox'">
<el-checkbox v-if="item.showSelectAll" v-model="item.checkAll" :indeterminate="item.isIndeterminate"
@change="
(val) => {
handleCheckAllChange(val, item);
}
">全选</el-checkbox>
<el-checkbox-group v-model="searchObj[item.prop]" @change="
(val) => {
handleCheckedCitiesChange(val, item);
}
">
<el-checkbox v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-checkbox>
</el-checkbox-group>
</template>
<!-- radio -->
<el-radio-group v-else-if="item.showType === 'radio'" v-model="searchObj[item.prop]" @change="
(val) => {
handleRadioChange(val, item);
}
">
<el-radio v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-radio>
</el-radio-group>
<!-- 级联选择 -->
<el-cascader v-else-if="item.showType === 'cascader'" v-model="searchObj[item.prop]" :props="item.props"
:show-all-levels="item.showAllLevels" :clearable="item.clearable" :options="getOptions[item.prop]"
:placeholder="item.placeholder" />
<div v-if="item.showType === 'Slot'">
<slot :name="item.prop"></slot>
</div>
<div v-if="item.showType === 'defaultSlot'">
<slot name="defaultSlot"></slot>
</div>
<div v-if="item.showType === 'nameSlot'">
<slot name="nameSlot"></slot>
</div>
</div>
</div>
<div class="button-container">
<div class="flex">
<el-button type="primary" @click="submit" size="small">确定</el-button>
<el-button type="" @click="reset" size="small">重置</el-button>
<slot> </slot>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {
ref,
reactive,
watchEffect,
getCurrentInstance,
watch,
computed
} from "vue";
import * as MOSTY from "@/components/MyComponents/index";
const { proxy } = getCurrentInstance();
const props = defineProps({
searchArr: {
type: Array,
default: () => {
return [
{
showType: "select",
prop: "selectKey",
options: [
{
value: 1,
label: "选择1"
}
],
defaultVal: "",
label: "选择",
dict: "" // 字典编码
},
{
showType: "input",
prop: "inputKey",
defaultVal: "",
label: "输入"
},
{
showType: "department",
prop: "deptKey",
defaultVal: "",
label: "输入"
},
{
showType: "daterange",
prop: "daterangeKey",
defaultVal: "",
label: "输入"
},
{
showType: "date",
prop: "date",
defaultVal: ""
},
{
showType: "checkbox",
prop: "checkboxKey1",
options: [
{
value: 1,
label: "选择1"
}
],
defaultVal: ""
},
{
showType: "cascader",
prop: "cascaderKey",
label: "级联选择",
checkStrictly: false, //点击任意选中
defaultVal: ""
},
{
showType: "radio",
defaultVal: ""
},
{
showType: "defaultTime",
prop: "timeField",
options: []
}
];
}
},
marginBottom: {
type: Number,
default: 0
},
backgroundColor: {
type: String,
default: "rgb(255, 255, 255, 1)"
},
bool: {
type: Boolean,
default: true
}
});
let loadingPage = ref(false);
const emit = defineEmits(["submit", "reset"]);
let searchObj = reactive({});
// select 的一些默认配置
const selectDefault = {
clearable: true, // 是否可以清空
filterable: true, // 是否可以筛选
multiple: false, // 是否多选
placeholder: "请选择"
};
// 重新定义下拉框的选项
let getOptions = reactive({});
// input 的一些默认配置
const inputDefault = {
clearable: true, // 是否可以清空
placeholder: "请输入"
};
const shortcuts = [
{
text: "今天",
value: () => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 0);
return [start, end];
}
},
{
text: "昨天",
value: () => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
end.setTime(end.getTime() - 3600 * 1000 * 24 * 1);
return [start, end];
}
},
{
text: "最近7天",
value: () => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
return [start, end];
}
},
{
text: "最近30天",
value: () => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
return [start, end];
}
},
{
text: "最近90天",
value: () => {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
return [start, end];
}
}
];
// daterange 的一些默认配置
const daterangeDefault = {
rangeSeparator: "",
startPlaceholder: "开始日期",
endPlaceholder: "结束日期",
shortcuts: [], // 快捷选择
defaultShortcuts: true // 是否显示快捷选择 如果要自定义快捷选择传入一个shortcuts就可以了
};
// date 的一些默认配置
const defaultDate = {
clearable: true, // 是否可以清空
placeholder: "请输入",
shortcuts: [], // 快捷选择
defaultShortcuts: true // 是否显示快捷选择 如果要自定义快捷选择传入一个shortcuts就可以了
};
const dateShortcuts = [
{
text: "今天",
value: new Date()
},
{
text: "昨天",
value: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
return date;
}
},
{
text: "7天前",
value: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
return date;
}
},
{
text: "30天前",
value: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30);
return date;
}
},
{
text: "90天前",
value: () => {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 90);
return date;
}
}
];
// 设置不可选的日期
const disabledDate = (time) => {
return time.getTime() > Date.now();
};
// checkbox 的一些默认配置
const defaultCheckbox = reactive({
defaultVal: [],
checkAll: false, // 全选的值
isIndeterminate: false, // 控制全选按钮样式
showSelectAll: true // 是否显示全选
});
// 全选复选框的选中与不选中
const handleCheckAllChange = (val, obj) => {
searchObj[obj.prop] = val ? obj.checkboxValueArr : [];
obj.isIndeterminate = false;
};
// 单个复选框的选中与不选中
const handleCheckedCitiesChange = (value, obj) => {
const checkedCount = value.length;
obj.checkAll = checkedCount === obj.checkboxValueArr.length;
obj.isIndeterminate =
checkedCount > 0 && checkedCount < obj.checkboxValueArr.length;
};
//单选
const handleRadioChange = (val, obj) => {
console.log(val, obj);
};
// cascader 的一些默认配置
let defaultCascader = {
filterable: true, // 是否可以搜索
clearable: true, // 是否可以清空
placeholder: "请选择",
checkStrictly: true, // 控制是否父子联动(是否可以选择任意节点)
showAllLevels: false, // 是否显示完整路径
lazy: false, // 是否懒加载 当设置为false时就要传入options
portUrl: "", // 这里必须写 接口地址
props: {
label: "label",
value: "value",
children: "children"
},
options: []
};
// 在懒加载状态下cascader 的props的一些配置
const cascaderLazyProps = reactive({
value: "value",
label: "label",
lazy: false,
lazyLoad(node, resolve) {
// 这里要根据实际情况修改
const { level } = node;
let options = [];
switch (level) {
case 0:
options = [
{
value: 1,
label: "选择1",
leaf: false // 表示有下一级 必须有这个表示 不然获取不到值
},
{
value: 2,
label: "选择2",
leaf: false // 表示有下一级
},
{
value: 3,
label: "选择3",
leaf: false // 表示有下一级
},
{
value: 4,
label: "选择4",
leaf: true // 表示没有下一级了
}
];
break;
case 1:
options = [
{
value: 11,
label: "选择1_1",
leaf: true // 表示没有下一级了
},
{
value: 21,
label: "选择2_1",
leaf: true // 表示没有下一级了
},
{
value: 31,
label: "选择3_1",
leaf: true // 表示没有下一级了
},
{
value: 41,
label: "选择4_1",
leaf: true // 表示没有下一级了
}
];
}
resolve(options);
}
});
// 获取到传过来的参数
let getArr = reactive([]);
const submit = () => {
emit("submit", searchObj);
};
const reset = () => {
getArr.forEach((item) => {
searchObj[item.prop] = item.defaultVal;
});
emit("reset", true);
emit("submit", searchObj);
};
// 暴露searchObj给父组件
defineExpose({
searchObj,
submit,
reset
});
watchEffect(() => {
loadingPage.value = true;
let arr = JSON.parse(JSON.stringify(props.searchArr));
getArr = arr.map((item) => {
switch (item.showType) {
case "select":
item = { ...selectDefault, ...item };
item.options = reactive(item.options);
getOptions[item.prop] = item.options;
break;
case "input":
item = { ...inputDefault, ...item };
break;
case "daterange":
item = { ...daterangeDefault, ...item };
if (item.defaultShortcuts) item.shortcuts = shortcuts;
break;
case "date":
item = { ...defaultDate, ...item };
if (item.defaultShortcuts) {
item.shortcuts = dateShortcuts;
}
break;
case "checkbox":
item = reactive({ ...defaultCheckbox, ...item });
item.checkboxValueArr = item.options.map((obj) => {
return obj.value;
});
break;
case "cascader":
item = { ...defaultCascader, ...item };
if (item.lazy) {
cascaderLazyProps.checkStrictly = item.checkStrictly;
item.props = { ...cascaderLazyProps, ...(item.props || {}) };
delete item.options;
} else {
item.props = {
...defaultCascader.props,
...(item.props || {}),
...{ checkStrictly: item.checkStrictly }
};
getOptions[item.prop] = reactive(item.options);
}
break;
}
loadingPage.value = false;
searchObj[item.prop] = item.defaultVal;
return item;
});
});
</script>
<style lang="scss" scoped>
.pageSearch {
.main-container {
padding: 0;
}
.content-container {
display: flex;
padding: 0 15px;
}
.button-container {
display: flex;
flex-direction: column-reverse;
margin-bottom: 10px;
}
.filter-title {
display: flex;
align-items: center;
margin-bottom: 10px;
width: 100%;
background: linear-gradient(to right, #9ed7ff, #e6f0f8);
padding: 5px 15px;
.filter-label {
display: flex;
align-items: center;
font-weight: bold;
color: #000;
margin-right: 10px;
white-space: nowrap;
}
.filter-line {
flex: 1;
height: 1px;
background-color: #ccc;
}
}
.box {
flex: 1;
display: flex;
flex-wrap: wrap;
.item {
display: flex;
margin-right: 12px;
margin-bottom: 15px;
}
.label {
margin: auto;
margin-right: 5px;
white-space: nowrap;
color: #000;
}
}
}
::v-deep .el-date-editor .el-range-separator {
color: #333;
}
</style>

View File

@ -1,77 +1,74 @@
<template>
<div v-loading="loadingPage" class="pageSearch searchBox main-container"
:style="`margin-bottom: ${marginBottom}px;background-color: ${backgroundColor}`">
<div class="filter-title">
<span class="filter-label"><el-icon>
<Filter />
</el-icon>筛选条件</span>
</div>
<div class="content-container">
<div class="box">
<div v-for="(item, index) in getArr" :key="index" class="item">
<div class="label" v-if="item.label">{{ item.label }}</div>
<div v-loading="loadingPage" class="query-wrap">
<div class="query-title">查询条件</div>
<div class="query-grid">
<div v-for="(item, index) in getArr" :key="index" class="query-cell">
<div class="cell-label">{{ item.label }}</div>
<div class="cell-control">
<!-- select -->
<el-select v-if="item.showType === 'select'" v-model="searchObj[item.prop]" :multiple="item.multiple"
:clearable="item.clearable" :filterable="item.filterable" :placeholder="item.placeholder" collapse-tags
collapse-tags-tooltip>
<el-option v-for="obj in getOptions[item.prop]" :key="obj.value" :label="obj.label || obj.lable"
collapse-tags-tooltip class="control-select">
<el-option v-for="obj in (getOptions[item.prop] || [])" :key="obj.value" :label="obj.label || obj.lable"
:value="obj.value" />
</el-select>
<!-- input -->
<el-input v-else-if="item.showType === 'input'" class="input" v-model="searchObj[item.prop]"
:clearable="item.clearable" :placeholder="item.placeholder" />
<!-- input -->
<el-input v-else-if="item.showType === 'number'" class="input" v-model="searchObj[item.prop]"
<el-input v-else-if="item.showType === 'input'" class="control-input" v-model="searchObj[item.prop]"
:clearable="item.clearable" :placeholder="item.placeholder" />
<!-- input -->
<el-input v-else-if="item.showType === 'number'" class="control-input" v-model="searchObj[item.prop]"
:clearable="item.clearable" :placeholder="item.placeholder" type="number" />
<!-- 日期段选择器 -->
<el-date-picker v-else-if="item.showType === 'daterange'" v-model="searchObj[item.prop]" type="daterange"
unlink-panels :range-separator="item.rangeSeparator" :start-placeholder="item.startPlaceholder"
:end-placeholder="item.endPlaceholder" :shortcuts="item.shortcuts" :disabledDate="disabledDate"
value-format="YYYY-MM-DD" />
value-format="YYYY-MM-DD" class="control-date" />
<el-date-picker v-else-if="item.showType === 'datetimerange'" v-model="searchObj[item.prop]"
type="datetimerange" unlink-panels :range-separator="item.rangeSeparator || ''"
:start-placeholder="item.startPlaceholder || '开始日期'" :end-placeholder="item.endPlaceholder || '结束日期'"
:shortcuts="item.shortcuts" value-format="YYYY-MM-DD HH:mm:ss" />
:shortcuts="item.shortcuts" value-format="YYYY-MM-DD HH:mm:ss" class="control-date" />
<el-date-picker v-else-if="item.showType === 'date'" v-model="searchObj[item.prop]" type="date"
:placeholder="item.placeholder" :disabled-date="disabledDate" :shortcuts="item.shortcuts"
value-format="YYYY-MM-DD">
value-format="YYYY-MM-DD" class="control-date">
</el-date-picker>
<el-date-picker v-else-if="item.showType === 'datetime'" v-model="searchObj[item.prop]" type="datetime"
:placeholder="item.placeholder" value-format="YYYY-MM-DD HH:mm:ss">
:placeholder="item.placeholder" value-format="YYYY-MM-DD HH:mm:ss" class="control-date">
</el-date-picker>
<!-- checkbox -->
<template v-else-if="item.showType === 'department'">
<MOSTY.Department clearable v-model="searchObj[item.prop]" />
<MOSTY.Department clearable v-model="searchObj[item.prop]" class="control-select" />
</template>
<!-- checkbox -->
<template v-else-if="item.showType === 'checkbox'">
<el-checkbox v-if="item.showSelectAll" v-model="item.checkAll" :indeterminate="item.isIndeterminate"
@change="
<div class="checkbox-wrap">
<el-checkbox v-if="item.showSelectAll" v-model="item.checkAll" :indeterminate="item.isIndeterminate"
@change="
(val) => {
handleCheckAllChange(val, item);
}
">全选</el-checkbox>
<el-checkbox-group v-model="searchObj[item.prop]" @change="
(val) => {
handleCheckAllChange(val, item);
handleCheckedCitiesChange(val, item);
}
">全选</el-checkbox>
<el-checkbox-group v-model="searchObj[item.prop]" @change="
(val) => {
handleCheckedCitiesChange(val, item);
}
">
<el-checkbox v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-checkbox>
</el-checkbox-group>
" class="checkbox-group">
<el-checkbox v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-checkbox>
</el-checkbox-group>
</div>
</template>
<!-- radio -->
<el-radio-group v-else-if="item.showType === 'radio'" v-model="searchObj[item.prop]" @change="
(val) => {
handleRadioChange(val, item);
}
">
" class="radio-group">
<el-radio v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-radio>
</el-radio-group>
<!-- 级联选择 -->
<el-cascader v-else-if="item.showType === 'cascader'" v-model="searchObj[item.prop]" :props="item.props"
:show-all-levels="item.showAllLevels" :clearable="item.clearable" :options="getOptions[item.prop]"
:placeholder="item.placeholder" />
:placeholder="item.placeholder" class="control-select" />
<div v-if="item.showType === 'Slot'">
<slot :name="item.prop"></slot>
</div>
@ -82,16 +79,16 @@
<slot name="nameSlot"></slot>
</div>
</div>
</div>
<div class="button-container">
<div class="flex">
<el-button type="primary" @click="submit" size="small">确定</el-button>
<el-button type="" @click="reset" size="small">重置</el-button>
<slot> </slot>
</div>
</div>
<div class="query-action">
<div>
<slot> </slot>
</div>
<div>
<el-button type="primary" @click="submit" size="small">查询</el-button>
<el-button type="default" @click="reset" size="small">重置</el-button>
</div>
</div>
</div>
</template>
@ -415,12 +412,12 @@ const cascaderLazyProps = reactive({
}
});
// 获取到传过来的参数
let getArr = reactive([]);
let getArr = ref([]);
const submit = () => {
emit("submit", searchObj);
};
const reset = () => {
getArr.forEach((item) => {
getArr.value.forEach((item) => {
searchObj[item.prop] = item.defaultVal;
});
emit("reset", true);
@ -433,121 +430,228 @@ defineExpose({
submit,
reset
});
watchEffect(() => {
// 监听 searchArr 变化,同时监听内部 options 的异步更新
watch(() => props.searchArr, (newArr) => {
loadingPage.value = true;
let arr = JSON.parse(JSON.stringify(props.searchArr));
getArr = arr.map((item) => {
switch (item.showType) {
case "select":
item = { ...selectDefault, ...item };
item.options = reactive(item.options);
getOptions[item.prop] = item.options;
break;
case "input":
item = { ...inputDefault, ...item };
break;
case "daterange":
item = { ...daterangeDefault, ...item };
if (item.defaultShortcuts) item.shortcuts = shortcuts;
break;
case "date":
item = { ...defaultDate, ...item };
if (item.defaultShortcuts) {
item.shortcuts = dateShortcuts;
}
break;
case "checkbox":
item = reactive({ ...defaultCheckbox, ...item });
item.checkboxValueArr = item.options.map((obj) => {
return obj.value;
});
break;
case "cascader":
item = { ...defaultCascader, ...item };
if (item.lazy) {
cascaderLazyProps.checkStrictly = item.checkStrictly;
item.props = { ...cascaderLazyProps, ...(item.props || {}) };
delete item.options;
} else {
item.props = {
...defaultCascader.props,
...(item.props || {}),
...{ checkStrictly: item.checkStrictly }
};
getOptions[item.prop] = reactive(item.options);
}
break;
}
try {
// 不再深拷贝,保留响应式引用
getArr.value = newArr.map((item) => {
const itemCopy = { ...item }; // 浅拷贝即可
switch (itemCopy.showType) {
case "select":
Object.assign(itemCopy, { ...selectDefault, ...itemCopy });
// 直接引用原 options保持响应式
getOptions[itemCopy.prop] = itemCopy.options || [];
break;
case "input":
Object.assign(itemCopy, { ...inputDefault, ...itemCopy });
break;
case "daterange":
Object.assign(itemCopy, { ...daterangeDefault, ...itemCopy });
if (itemCopy.defaultShortcuts) itemCopy.shortcuts = shortcuts;
break;
case "date":
Object.assign(itemCopy, { ...defaultDate, ...itemCopy });
if (itemCopy.defaultShortcuts) {
itemCopy.shortcuts = dateShortcuts;
}
break;
case "checkbox":
Object.assign(itemCopy, { ...defaultCheckbox, ...itemCopy });
itemCopy.checkboxValueArr = (itemCopy.options || []).map((obj) => {
return obj.value;
});
break;
case "cascader":
Object.assign(itemCopy, { ...defaultCascader, ...itemCopy });
if (itemCopy.lazy) {
cascaderLazyProps.checkStrictly = itemCopy.checkStrictly;
itemCopy.props = { ...cascaderLazyProps, ...(itemCopy.props || {}) };
delete itemCopy.options;
} else {
itemCopy.props = {
...defaultCascader.props,
...(itemCopy.props || {}),
...{ checkStrictly: itemCopy.checkStrictly }
};
getOptions[itemCopy.prop] = itemCopy.options || [];
}
break;
}
searchObj[itemCopy.prop] = itemCopy.defaultVal;
return itemCopy;
});
} catch (e) {
console.error('Search组件解析searchArr失败:', e);
} finally {
loadingPage.value = false;
searchObj[item.prop] = item.defaultVal;
return item;
});
});
}
}, { immediate: true, deep: true }); // 开启深度监听,检测 options 变化
</script>
<style lang="scss" scoped>
.pageSearch {
.main-container {
padding: 0;
}
.content-container {
display: flex;
padding: 0 15px;
}
.button-container {
display: flex;
flex-direction: column-reverse;
margin-bottom: 10px;
}
.filter-title {
display: flex;
align-items: center;
margin-bottom: 10px;
width: 100%;
background: linear-gradient(to right, #9ed7ff, #e6f0f8);
padding: 5px 15px;
.filter-label {
display: flex;
align-items: center;
font-weight: bold;
color: #000;
margin-right: 10px;
white-space: nowrap;
}
.filter-line {
flex: 1;
height: 1px;
background-color: #ccc;
}
}
.box {
flex: 1;
display: flex;
flex-wrap: wrap;
.item {
display: flex;
margin-right: 12px;
margin-bottom: 15px;
}
.label {
margin: auto;
margin-right: 5px;
white-space: nowrap;
color: #000;
}
}
<style scoped lang="scss">
.query-wrap {
border: 1px solid #b8d3ff;
background: #fff;
}
::v-deep .el-date-editor .el-range-separator {
color: #333;
.query-title {
height: 32px;
background: linear-gradient(to right, #9ed7ff, #e6f0f8);
line-height: 32px;
padding-left: 10px;
font-size: 16px;
font-weight: 700;
color: #0d2148;
border-bottom: 1px solid #b8d3ff;
}
.query-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.query-cell {
display: flex;
min-height: 40px;
border-right: 1px solid #b8d3ff;
border-bottom: 1px solid #b8d3ff;
}
.query-cell:nth-child(4n) {
border-right: 0;
}
.cell-label {
width: 130px;
flex-shrink: 0;
border-right: 1px solid #b8d3ff;
font-size: 14px;
color: #0d2148;
display: flex;
align-items: center;
justify-content: center;
white-space: nowrap;
}
.cell-control {
flex: 1;
min-width: 0;
padding: 4px 8px;
display: flex;
align-items: center;
overflow: hidden;
}
.cell-control.is-checkbox {
justify-content: center;
padding: 0;
}
.control-input,
.control-select,
.control-date {
width: 100%;
max-width: 100%;
min-width: 0;
}
:deep(.control-input .el-input__wrapper),
:deep(.control-select .el-select__wrapper),
:deep(.control-date .el-input__wrapper) {
width: 100%;
max-width: 100%;
min-height: 28px;
border-radius: 0;
box-shadow: 0 0 0 1px #b8d3ff inset;
}
:deep(.control-date.el-date-editor) {
width: 100%;
max-width: 100%;
min-width: 0;
}
:deep(.control-date.el-date-editor .el-range-input) {
min-width: 0;
}
:deep(.control-input .el-input__inner),
:deep(.control-select .el-select__placeholder),
:deep(.control-date .el-input__inner) {
font-size: 14px;
color: #0d2148;
}
:deep(.control-date .el-range-input) {
font-size: 14px;
color: #0d2148;
}
:deep(.control-date .el-range__icon),
:deep(.control-date .el-range__close-icon) {
line-height: 1;
}
.checkbox-wrap {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.radio-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
:deep(.checkbox-wrap .el-checkbox) {
margin-right: 0;
height: 100%;
display: flex;
align-items: center;
}
:deep(.checkbox-wrap .el-checkbox__inner) {
width: 14px;
height: 14px;
}
.query-action {
height: 36px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 8px;
}
:deep(.el-button--primary) {
background-color: #0f5bbd;
border-color: #0f5bbd;
}
:deep(.el-button--primary:hover) {
background-color: #1a73e8;
border-color: #1a73e8;
}
:deep(.el-button--default) {
background-color: #ffffff;
border-color: #dcdfe6;
color: #606266;
}
:deep(.el-button--default:hover) {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
</style>

View File

@ -26,6 +26,7 @@ const checkAll = ref(false);
const isIndeterminate = ref(true);
const hasChecked = ref([]); //已经全选的数据
const checkedList = ref([]);
const isInit = ref(true); // 标记是否为初始化
watch(
() => props.data,
(val) => {
@ -38,16 +39,28 @@ watch(
immediate: true
}
);
// 监听hasChecked变化初始化完成后才触发changeData
watch(
hasChecked,
(val) => {
if (isInit.value) {
isInit.value = false;
return;
}
emits("changeData", val);
},
{ deep: true }
);
// 全选
function handleCheckAll(val) {
hasChecked.value = val ? checkedList.value : [];
isIndeterminate.value = false;
emits("changeData", hasChecked.value);
// emits 由 watch 处理
}
// 处理多选框改变
function handleCheckedChange(val) {
handleChange(val);////判断是否全选
emits("changeData", hasChecked.value);
// emits 由 watch 处理
}
//判断是否全选
function handleChange(val) {
@ -68,4 +81,4 @@ function handleChange(val) {
margin: 0 20px 0 4px;
}
}
</style>
</style>

View File

@ -17,147 +17,201 @@
<script setup>
// 测试div组件用于在后台和大屏页面都显示
import { ref, onMounted, onUnmounted } from 'vue'
import { Close } from '@element-plus/icons-vue'
import { ref, onMounted, onUnmounted } from "vue";
import { Close } from "@element-plus/icons-vue";
import emitter from "@/utils/eventBus.js"; // 导入事件总线
import { qcckGet } from '@/api/qcckApi'
import Item from './item.vue'
import { AudioPlayerClass } from '@/utils/audioPlayer.js'
import {getItem} from '@/utils/storage.js'
const dataList = ref([])
const timekeeping = ref(null)
const countdown = ref(0) // 倒计时时间(秒)
import { qcckGet } from "@/api/qcckApi";
import Item from "./item.vue";
import { AudioPlayerClass } from "@/utils/audioPlayer.js";
import { getItem } from "@/utils/storage.js";
const dataList = ref([]);
const timekeeping = ref(null);
const countdown = ref(0); // 倒计时时间(秒)
// 音频播放器实例映射
const audioPlayers = ref({
'02': null, // 信息上报
'03': null, // 研判审批
'04': null, // 研判指令
'05': null // 线索下发
})
const audioPlayers = new Map();
// 预加载音频播放器(仅加载 playAudioByType 中实际用到的类型)
const initAudioPlayers = async () => {
const usedTypes = ["03", "09", "10", "11", "12", "13", "16", "17", "18", "19"];
await Promise.all(
usedTypes.map(
(type) =>
new Promise((resolve) => {
const player = new AudioPlayerClass();
audioPlayers.set(type, player);
player.init(audioPaths[type], false).then(resolve).catch(resolve);
})
)
);
};
// 获取指定类型的音频播放器
const getAudioPlayer = (type) => {
return audioPlayers.get(type);
};
// 音频文件路径映射
const audioPaths = {
'02': require('@/assets/images/cjyp.mp3'),
'03': require('@/assets/images/ypbg.mp3'),
'04': require('@/assets/images/ypzl.mp3'),
'05': require('@/assets/images/xsyp.mp3')
}
// 初始化音频播放器
const initAudioPlayers = () => {
Object.keys(audioPaths).forEach(type => {
try {
audioPlayers.value[type] = new AudioPlayerClass()
audioPlayers.value[type].init(audioPaths[type], false)
} catch (error) {
console.error(`初始化类型${type}的音频播放器失败:`, error)
}
})
}
"01": require("@/assets/images/01.mp3"), //高级预计信息前置
"02": require("@/assets/images/02.mp3"), //一般预警信息前置
"03": require("@/assets/images/03.mp3"), //信息前置
"04": require("@/assets/images/04.mp3"), //红色预警
"05": require("@/assets/images/05.mp3"), //新的重点人
"06": require("@/assets/images/06.mp3"), //一级临控预警
"07": require("@/assets/images/07.mp3"), //有新的布控预警情
"08": require("@/assets/images/08.mp3"), //有新的标签预警
"09": require("@/assets/images/09.mp3"), //信息汇聚系统有新信息
"10": require("@/assets/images/10.mp3"), //林安码
"11": require("@/assets/images/11.mp3"), //发布了新的"线索"
"12": require("@/assets/images/12.mp3"), //有新的研判指令
"13": require("@/assets/images/13.mp3"), //有新的研判约稿通知
"14": require("@/assets/images/14.mp3"), //有新的公文发布
"15": require("@/assets/images/15.mp3"), //有新的警情监测预警,请注意查收
"16": require("@/assets/images/16.mp3"), //有新的一级临控预警,请及时签收处理!
"17": require("@/assets/images/17.mp3"), //有新的紧急预警信息,请及时签收处理!
"18": require("@/assets/images/18.mp3"), //滴滴滴~~~叮~~~~
"19": require("@/assets/images/19.mp3") //有新的预警信息,请您注意查收
};
// 根据类型播放音频
const playAudioByType = (type) => {
if (audioPlayers.value[type]) {
try {
audioPlayers.value[type].play()
} catch (error) {
console.error(`播放类型${type}的音频失败:`, error)
}
const playAudioByType = (val) => {
switch (val.typeMasgeLx) {
case "01": //预警
// 01 布控预警、02 七类重点人、03 政保
switch (val.yjlb) {
case "01":
case "02":
if (val.sfQs == '1') return
if (val.yjJb == "01") {
getAudioPlayer("18")?.play();
getAudioPlayer("17")?.play();
} else {
getAudioPlayer("19")?.play();
}
break;
}
break;
case "02": //信息汇聚
getAudioPlayer("03")?.play();
getAudioPlayer("09")?.play();
break;
case "03": //约稿
getAudioPlayer("03")?.play();
getAudioPlayer("13")?.play();
break;
case "04": //指令
getAudioPlayer("03")?.play();
getAudioPlayer("12")?.play();
break;
case "05": //新线索
getAudioPlayer("03")?.play();
getAudioPlayer("11")?.play();
break;
case "06": //检测警情
if (val.jqdjdm == "01") {
getAudioPlayer("18")?.play();
getAudioPlayer("17")?.play();
} else {
getAudioPlayer("19")?.play();
}
break;
case "08": //林安码
getAudioPlayer("03")?.play();
getAudioPlayer("10")?.play();
break;
case "11":
getAudioPlayer("03")?.play();
getAudioPlayer("19")?.play();
break;
default:
break;
}
}
};
// 手动关闭
const handleClose = () => {
if (timekeeping.value) {
clearInterval(timekeeping.value)
timekeeping.value = null
clearInterval(timekeeping.value);
timekeeping.value = null;
}
dataList.value = []
}
dataList.value = [];
};
// 重置倒计时
const resetCountdown = () => {
if (timekeeping.value) {
clearInterval(timekeeping.value)
clearInterval(timekeeping.value);
}
countdown.value = 15
countdown.value = 15;
timekeeping.value = setInterval(() => {
countdown.value--
countdown.value--;
if (countdown.value <= 0) {
clearInterval(timekeeping.value)
dataList.value = []
timekeeping.value = null
clearInterval(timekeeping.value);
dataList.value = [];
timekeeping.value = null;
}
}, 1000)
}
}, 1000);
};
// 做一个定时器15s一次
const checkNews = ref(null)
const checkNewsInterval = 15000 // 15秒
checkNews.value = setInterval(() => {
dataModel()
}, checkNewsInterval)
const checkNews = ref(null);
const checkNewsInterval = 15000; // 15秒
const idEntityCard = ref(getItem("idEntityCard"));
onMounted(() => {
// 初始化音频播放器
initAudioPlayers()
emitter.on('webSocketMessage', (newsDate) => {
if (newsDate) {
dataList.value = newsDate
// dataList.value.unshift({...newsDate.data,typeMasgeLx:newsDate.type})
// 根据消息类型播放音频
playAudioByType(newsDate[0].typeMasgeLx)
resetCountdown()
}
})
})
const idEntityCard = ref(getItem('idEntityCard'))
// 音频初始化在后台进行,不阻塞组件渲染
initAudioPlayers().then(() => {
// 音频预加载完成后再启动轮询
checkNews.value = setInterval(() => {
dataModel();
}, checkNewsInterval);
});
// 注册事件监听(需在 onUnmounted 中精确解绑)
emitter.on("webSocketMessage", handleWebSocketMessage);
});
// 处理 WebSocket 消息事件(需在 onUnmounted 中解绑,提取到模块作用域)
const handleWebSocketMessage = (newsDate) => {
if (newsDate) {
dataList.value = newsDate;
playAudioByType(newsDate[0]);
resetCountdown();
}
};
const dataModel = () => {
qcckGet({}, '/mosty-gsxt/dsjJbxx/message').then(res => {
qcckGet({}, "/mosty-gsxt/dsjJbxx/message").then((res) => {
if (res) {
const yjmasg = res.filter(item => item.type === '01')
if (yjmasg.length > 0) {
emitter.emit('openYp', yjmasg[0].obj); // 触发音频播放
} else {
const data=res.filter(item=>item.sfzList.includes(idEntityCard.value))
const infoMasge =data.map(item => {
return {
...item.obj,
typeMasgeLx: item.type
}
})
console.log(infoMasge);
emitter.emit('webSocketMessage', infoMasge)
}
const data = res.filter((item) =>
item.sfzList.includes(idEntityCard.value)
);
const infoMasge = data.map((item) => {
return {
...item.obj,
typeMasgeLx: item.type
};
});
emitter.emit("webSocketMessage", infoMasge);
}
})
});
};
}
// if (newsDate.type === '01') {
// // 触发音频播放
// console.log('触发音频播放');
// emitter.emit('openYp', newsDate.data); // 传递消息数据
// } else {
onUnmounted(() => {
emitter.off('webSocketMessage')
emitter.off("webSocketMessage", handleWebSocketMessage);
if (timekeeping.value) {
clearInterval(timekeeping.value)
clearInterval(timekeeping.value);
}
// 销毁所有音频播放器实例
Object.values(audioPlayers.value).forEach(player => {
if (player) {
player.destroy()
}
})
audioPlayers.forEach((player) => {
player.destroy();
});
audioPlayers.clear();
// 清除定时器
if (checkNews.value) {
clearInterval(checkNews.value)
checkNews.value = null
clearInterval(checkNews.value);
checkNews.value = null;
}
// 组件卸载时执行的操作
console.log('组件卸载时执行的操作')
})
});
</script>
<style scoped lang="scss">
@ -207,7 +261,7 @@ onUnmounted(() => {
text-shadow: 0 0 10px rgba(0, 255, 255, 0.7);
&::before {
content: '';
content: "";
display: inline-block;
width: 8px;
height: 8px;

View File

@ -1,79 +1,150 @@
<template>
<div class="test-item" v-if="item.typeMasgeLx == '02'" @click="goDetail(item.id, item.typeMasgeLx)">
<div
class="test-item"
v-if="item.typeMasgeLx == '01' || item.typeMasgeLx == '11'"
@click="goDetail(item.id, item.typeMasgeLx, item)"
>
<div class="item-header">
<div class="item-title">{{ item.qbmc || '' }}</div>
<div class="item-title">{{ item.yjBt || "" }}</div>
<div class="item-type">
{{
item.yjlb == "01"
? "布控预警"
: item.yjlb == "02"
? "七类重点人"
: "政保"
}}
</div>
</div>
<div class="item-message">{{ item.yjNr }}</div>
<div class="item-time">{{ item.yjSj || "" }}</div>
</div>
<div
class="test-item"
v-if="item.typeMasgeLx == '02'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.qbmc || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message">{{ item.qbnr }}</div>
<div class="item-time">{{ item.xtCjsj || '' }}</div>
<div class="item-time">{{ item.xtCjsj || "" }}</div>
</div>
<div class="test-item" v-if="item.typeMasgeLx == '03'" @click="goDetail(item.id, item.typeMasgeLx)">
<div
class="test-item"
v-if="item.typeMasgeLx == '03'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.bgmc || '' }}</div>
<div class="item-title">{{ item.ypyt || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message" v-html="item.bgnr"></div>
<div class="item-time">{{ item.xtCjsj || '' }}</div>
<div class="item-message">{{ item.ssbm }}</div>
<div class="item-time">{{ item.ypsj || "" }}</div>
</div>
<div class="test-item" v-if="item.typeMasgeLx == '04'" @click="goDetail(item.id, item.typeMasgeLx)">
<div
class="test-item"
v-if="item.typeMasgeLx == '04'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.zlbt || '' }}</div>
<div class="item-title">{{ item.zlbt || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message" v-html="item.zlnr"></div>
<div class="item-time">{{ item.xtCjsj || '' }}</div>
<div class="item-time">{{ item.xtCjsj || "" }}</div>
</div>
<div class="test-item" v-if="item.typeMasgeLx == '05'" @click="goDetail(item.id, item.typeMasgeLx)">
<div
class="test-item"
v-if="item.typeMasgeLx == '05'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.zlbt || '' }}</div>
<div class="item-title">{{ item.zlbt || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message" v-html="item.zlnr"></div>
<div class="item-time">{{ item.xtCjsj || '' }}</div>
<div class="item-time">{{ item.xtCjsj || "" }}</div>
</div>
<div
class="test-item"
v-if="item.typeMasgeLx == '06'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.gxdwmc || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message">{{ item.bcjjnr }}</div>
<div class="item-time">{{ item.bjsj || "" }}</div>
</div>
<div
class="test-item"
v-if="item.typeMasgeLx == '08'"
@click="goDetail(item.id, item.typeMasgeLx)"
>
<div class="item-header">
<div class="item-title">{{ item.qbmc || "" }}</div>
<div class="item-type">{{ informationMap[item.typeMasgeLx] }}</div>
</div>
<div class="item-message">{{ item.qbnr }}</div>
<div class="item-time">{{ item.sxsbsj || "" }}</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
import { useRouter } from "vue-router";
import emitter from "@/utils/eventBus.js"; // 导入
const router = useRouter();
const props = defineProps({
item: {
type: Object,
default: () => ({})
}
})
});
const informationMap = {
'01': '报警信息',
'02': '信息上报',
'03': '研判审批',
'04': '研判指令',
'05': '线索下发',
}
const emit=defineEmits(['goDetail'])
const goDetail = (id, lx) => {
let path = ''
"01": "预警信息",
"02": "信息上报",
"03": "研判约稿",
"04": "研判指令",
"05": "线索下发",
"06": "警情监测",
"08": "林安码信息"
};
const emit = defineEmits(["goDetail"]);
const goDetail = (id, lx, val) => {
let path = "";
switch (lx) {
case '02':
path = '/InfoCollection'
case "01":
case "11":
emitter.emit("openYp", val);
break;
case '03':
path = '/strategicResearchs'
case "02":
path = "/InfoCollection";
break;
default:
case '04':
path = '/judgmentCommand'
case "03":
path = "/dataReduction";
break;
case "04":
path = "/judgmentCommand";
break;
case "05":
path = "/InstructionInformation";
break;
case "06":
path = "/policeReport";
break;
case "08":
path = "/lamXs";
break;
case '05':
path = '/InstructionInformation'
break;
}
router.push({
path: path,
query: {
id: id
}
})
}
});
};
</script>
<style lang="scss" scoped>
.test-item {

View File

@ -26,14 +26,14 @@
<!-- </div> -->
</div>
<div class="container-box" v-else>
<div v-for="(item, index) in userList" :key="item.id">
<div v-for="item in userList" :key="item.id">
<div v-if="checkList.includes(item.nodeId)">
<el-divider content-position="left">{{ item.nodeName }}</el-divider>
<template v-if="Array.isArray(item.userList)">
<div class="reloBox" v-for="items in item.userList">
<div class="reloBox" v-for="(items,idx) in item.userList" :key="idx">
<div class="orgName">{{ items.name }}</div>
<el-checkbox-group v-model="items.checkList">
<el-checkbox :label="it.userid" v-for="(it, index) in items.users" :key="it.id">{{
<el-checkbox :label="it.userid" v-for="it in items.users" :key="it.id">{{
it.username }}</el-checkbox>
</el-checkbox-group>
</div>

View File

@ -21,8 +21,13 @@
</template>
</el-dialog>
<SelectingPeople v-model="showDialog" :createProcess="createProcess" @close="close" :radioData="radioData"
:path="path" @getList="emit('getList')" :userData="userData" />
<SelectingPeople
v-model="showDialog"
:createProcess="createProcess"
@close="close" :radioData="radioData"
:path="path"
@getList="emit('getList')"
:userData="userData" />
</template>
<script setup>

View File

@ -75,10 +75,10 @@ const handleClick = () => {
xxlx: ""
}
queryWdxxPageList({ ...promes, xxlx: 100 }).then((res) => {
xxListData.xtxxNumber = res.total
xxListData.xtxxNumber = res?.total || 0
});
queryWdxxPageList({ ...promes, xxlx: 200 }).then((res) => {
xxListData.tztgNumber = res.total
xxListData.tztgNumber = res?.total || 0
});
}
@ -115,28 +115,29 @@ onMounted(() => {
} else {
showFxq.value = true
}
emitter.on("handleClick", () => {
idEntityCard.value = getItem('idEntityCard')
emitter.on("handleClick", handleClickHandler);
// 清除旧定时器,避免多个定时器同时运行
if (intTime.value) {
clearInterval(intTime.value)
}
intTime.value = setInterval(() => {
handleClick()
// 清除旧定时器,避免多个定时器同时运行
if (intTime.value) {
clearInterval(intTime.value)
}
intTime.value = setInterval(() => {
handleClick()
}, 60000)
});
}, 60000)
})
const handleClickHandler = () => {
idEntityCard.value = getItem('idEntityCard')
handleClick()
}
onUnmounted(() => {
clearInterval(intTime.value)
emitter.off("handleClick")
emitter.off("handleClick", handleClickHandler)
})
</script>
<style lang="scss" scoped>
// 蜂群组件样式
.fxqx {
border-radius: 34px;
border-radius: 34px;
width: 34px;
background-color: rgb(1, 127, 245);
margin-bottom: 18px;

View File

@ -1,11 +1,7 @@
<template>
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<el-avatar
shape="circle"
:size="28"
:src="require('@/assets/images/ly-person-icon.png')"
></el-avatar>
<el-avatar shape="circle" :size="28" :src="require('@/assets/images/ly-person-icon.png')"></el-avatar>
</div>
<template #dropdown>
<el-dropdown-menu class="user-dropdown">
@ -17,7 +13,7 @@
</template>
<script setup>
import { useRouter, useRoute,onBeforeRouteLeave } from "vue-router";
import { useRouter, useRoute, onBeforeRouteLeave } from "vue-router";
import { ref } from "vue";
import { useStore } from "vuex";
import UpdatePwdDialog from "./UpdatePwdDialog.vue";
@ -28,12 +24,7 @@ const updatePwd = () => {
const store = useStore();
const logout = () => {
window.opener = null;
window.open('', '_self');
window.close();
store.commit("app/clearTag", null, { immediate: true });
store.commit("permission/deleteRouter", { immediate: true });
store.commit("user/deleteKeepLiiveRoute", "home");
store.dispatch("user/logout");
};
</script>
@ -52,6 +43,7 @@ const logout = () => {
cursor: pointer;
// hover 动画
transition: background 0.5s;
&:hover {
background: rgba(0, 0, 0, 0.1);
}
@ -86,9 +78,11 @@ const logout = () => {
::v-deep .avatar-container {
cursor: pointer;
.avatar-wrapper {
margin-top: 5px;
position: relative;
.el-avatar {
--el-avatar-background-color: none;
margin-right: 12px;

View File

@ -0,0 +1,83 @@
<template>
<el-menu class="el-menu-vertical-demo" :collapse="!$store.getters.sidebarOpened" :default-active="activeMenu"
:unique-opened="true" background-color="rgba(0, 0, 0, 0)" :text-color="$store.getters.cssVar.menuText"
:active-text-color="$store.getters.cssVar.menuActiveText" router>
<SideBarItem v-for="item in routes" :key="item.path" :route="item"></SideBarItem>
</el-menu>
</template>
<script setup>
import { computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useStore } from "vuex";
import { filterRoutes, generateMenus } from "@/utils/route";
import { getItem } from "@/utils/storage";
import SideBarItem from "./SideBarItem.vue";
const store = useStore();
const router = useRouter();
const EXCLUDE_NAMES = ["warningLists", "behaviorWarnings", "identityWarnings", "combinedWarnings", "DeploymentAreas", "mpvPeos", "myControls"];
const filterRoutesByMenusPermission = (routes, menusSet) => {
return routes.reduce((result, route) => {
const children = Array.isArray(route.children) ? filterRoutesByMenusPermission(route.children, menusSet) : [];
const routeName = route.name ? `${route.name}` : "";
const selfMatched = routeName && menusSet.has(routeName);
if (selfMatched || children.length > 0) {
result.push({ ...route, children });
}
return result;
}, []);
};
const routes = computed(() => {
const fRoutes = filterRoutes(router.getRoutes());
const data = fRoutes.filter((item) => !EXCLUDE_NAMES.includes(item.name));
const menusPermission = getItem("menusPermission");
const menusSet = new Set(Array.isArray(menusPermission) ? menusPermission.map((item) => `${item}`) : []);
const permissionFiltered = menusSet.size ? filterRoutesByMenusPermission(data, menusSet) : data;
return generateMenus(permissionFiltered);
});
if (!store.getters.token) {
router.push("/login");
}
if (router.getRoutes().length <= 7 && store.state.permission.routeReady <= 1) {
store.commit("user/setIsReady", {});
setTimeout(() => {
router.go(0);
}, 200);
}
//默认激活项
const route = useRoute();
const activeMenu = computed(() => {
const { path } = route;
return path;
});
</script>
<style lang="scss" scoped>
::v-deep .el-menu-item {
height: 48px;
}
::v-deep .el-sub-menu__title {
height: 48px;
color: rgb(255, 255, 255);
background-color: rgb(20, 46, 78);
}
::v-deep .el-menu-item.is-active {
background-image: linear-gradient(to right, #2356d4 0%, #8efbde 100%);
margin: 0 14px;
border-radius: 4px;
// padding-left: 46px !important;
}
::v-deep .el-sub-menu .el-menu-item {
height: 48px;
line-height: 48px;
}
</style>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 240px;
min-height: 400px;
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<el-menu class="el-menu-vertical-demo" :collapse="!$store.getters.sidebarOpened" :default-active="activeMenu"
:unique-opened="true" background-color="rgba(0, 0, 0, 0)" :text-color="$store.getters.cssVar.menuText"
:active-text-color="$store.getters.cssVar.menuActiveText" router>
<SideBarItem v-for="item in routes" :key="item.path" :route="item"></SideBarItem>
</el-menu>
</template>
<script setup>
import { computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useStore } from "vuex";
import { filterRoutes, generateMenus } from "@/utils/route";
import SideBarItem from "./SideBarItem.vue";
const store = useStore();
const router = useRouter();
const routes = computed(() => {
const fRoutes = filterRoutes(router.getRoutes());
const data = fRoutes.filter(item => {
if (item.name != "warningLists"
&& item.name != "behaviorWarnings"
&& item.name != "identityWarnings"
&& item.name != "combinedWarnings"
&& item.name != "DeploymentAreas"
&& item.name != "mpvPeos"
&& item.name != "myControls") {
return item;
}
}
)
return generateMenus(data);
});
if (!store.getters.token) {
router.push("/login");
}
if (router.getRoutes().length <= 7 && store.state.permission.routeReady <= 1) {
store.commit("user/setIsReady", {});
setTimeout(() => {
router.go(0);
}, 200);
}
//默认激活项
const route = useRoute();
const activeMenu = computed(() => {
const { path } = route;
return path;
});
</script>
<style lang="scss" scoped>
::v-deep .el-menu-item {
height: 48px;
}
::v-deep .el-sub-menu__title {
height: 48px;
color: rgb(255, 255, 255);
background-color: rgb(20, 46, 78);
}
::v-deep .el-menu-item.is-active {
background-image: linear-gradient(to right, #2356d4 0%, #8efbde 100%);
margin: 0 14px;
border-radius: 4px;
// padding-left: 46px !important;
}
::v-deep .el-sub-menu .el-menu-item {
height: 48px;
line-height: 48px;
}
</style>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 240px;
min-height: 400px;
}
</style>

View File

@ -1,43 +1,108 @@
<template>
<el-menu class="el-menu-vertical-demo" :collapse="!$store.getters.sidebarOpened" :default-active="activeMenu"
:unique-opened="true" background-color="rgba(0, 0, 0, 0)" :text-color="$store.getters.cssVar.menuText"
:active-text-color="$store.getters.cssVar.menuActiveText" router>
<SideBarItem v-for="item in routes" :key="item.path" :route="item"></SideBarItem>
<el-menu
class="el-menu-vertical-demo"
:collapse="!$store.getters.sidebarOpened"
:default-active="activeMenu"
:unique-opened="true"
background-color="rgba(0, 0, 0, 0)"
:text-color="$store.getters.cssVar.menuText"
:active-text-color="$store.getters.cssVar.menuActiveText"
router
>
<SideBarItem
v-for="item in routes"
:key="item.path"
:route="item"
></SideBarItem>
</el-menu>
</template>
<script setup>
import { computed } from "vue";
import { computed, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useStore } from "vuex";
import { filterRoutes, generateMenus } from "@/utils/route";
import { getItem } from "@/utils/storage";
import SideBarItem from "./SideBarItem.vue";
const store = useStore();
const router = useRouter();
const EXCLUDE_NAMES = [
"warningLists",
"behaviorWarnings",
"identityWarnings",
"combinedWarnings",
"DeploymentAreas",
"mpvPeos",
"myControls"
];
const filterRoutesByMenusPermission = (routes, menusSet) => {
return routes.reduce((result, route) => {
const children = Array.isArray(route.children)
? filterRoutesByMenusPermission(route.children, menusSet)
: [];
const routeName = route.name ? `${route.name}` : "";
const selfMatched = routeName && menusSet.has(routeName);
if (selfMatched || children.length > 0) {
result.push({ ...route, children });
}
return result;
}, []);
};
const routes = computed(() => {
const fRoutes = filterRoutes(router.getRoutes());
const data = fRoutes.filter(item => {
if (item.name != "warningLists"
&& item.name != "behaviorWarnings"
&& item.name != "identityWarnings"
&& item.name != "combinedWarnings"
&& item.name != "DeploymentAreas"
&& item.name != "mpvPeos"
&& item.name != "myControls") {
return item;
}
// 排除不需要显示的菜单,包括 forumPost单独处理
const data = fRoutes.filter((item) =>
!EXCLUDE_NAMES.includes(item.name) && item.name !== 'forumPost'
);
const menusPermission = getItem("menusPermission");
// 情报论坛菜单(所有人可见,始终显示在最后)
const forumMenu = {
path: '/forumPost',
meta: { title: '情报论坛', icon: 'article-ranking' },
children: []
};
// 如果 menusPermission 为 null 或 undefined只显示情报论坛菜单
if (menusPermission === null || menusPermission === undefined) {
return [forumMenu];
}
)
return generateMenus(data);
const menusSet = new Set(
Array.isArray(menusPermission)
? menusPermission.map((item) => `${item}`)
: []
);
// 先按权限过滤
let permissionFiltered = menusSet.size
? filterRoutesByMenusPermission(data, menusSet)
: [];
// 生成菜单
const menus = generateMenus(permissionFiltered);
// 最后添加情报论坛菜单(所有人可见,放到最后)
menus.push(forumMenu);
return menus;
});
if (!store.getters.token) {
router.push("/login");
}
if (router.getRoutes().length <= 7 && store.state.permission.routeReady <= 1) {
store.commit("user/setIsReady", {});
setTimeout(() => {
router.go(0);
}, 200);
// 路由未完成加载时,等待加载完成,不再刷新页面
if (store.state.permission.routeReady !== 2) {
const unwatch = watch(
() => store.state.permission.routeReady,
(val) => {
if (val === 2) {
unwatch();
}
},
{ immediate: true }
);
}
//默认激活项
const route = useRoute();

View File

@ -9,62 +9,55 @@ import {
import {
getCookie
} from "@/utils/cookie";
// 白名单
// 白名单路由(无需登录即可访问)
const whiteList = ['/login', '/oatuh_login', '/404', '/401', '/zeroTrust_login', '/focusExploration', '/clueVerification', '/deploymentApproval']
// 标记路由是否已初始化
let routesInitialized = false;
/**
* 路由前置守卫
* to 去哪里
* from 来自哪
* next 往下走
*/
router.beforeEach(async (to, from, next) => {
// 存在 token ,进入主页
// if (store.state.user.token) {
// 快捷访问
// console.log(store.getters.token);
console.log('[permission.js] 路由守卫触发:', from.path, '->', to.path, '时间:', Date.now());
if (store.getters.token) {
// console.log("路由1");
// 已登录
if (!routesInitialized) {
// 首次进入:根据权限动态注册路由
console.log('[permission.js] 首次初始化路由...');
routesInitialized = true;
const afterMenuList = getItem('menusPermission');
console.log('[permission.js] menusPermission:', afterMenuList?.length);
// 判断用户资料是否获取
// 若不存在用户信息,则需要获取用户信息
// 触发获取用户信息的 action并获取用户当前权限
store.commit('permission/setRouteReady', 1)
// 添加完动态路由之后,需要在进行一次主动跳转
const afterMenuList = getItem('menusPermission');
// 处理用户权限,筛选出需要添加的权限
// console.log(store.state.permission.routes);
// 动态注册有权限的路由
await store.dispatch('permission/filterRoutes', afterMenuList);
console.log('[permission.js] 路由初始化完成');
if (store.state.permission.routes.length === 0) {
const filterRoutes = await store.dispatch('permission/filterRoutes', afterMenuList)
filterRoutes.forEach(item => {
router.addRoute(item)
})
// console.log("已添加动态路由");
next({
...to,
replace: true
})
} else {
// console.log('已存在路由');
next()
// 重新导航到目标路由,确保刚注册的路由能正确匹配
next({ ...to, replace: true });
return;
}
// 利用 addRoute 循环添加
// 处理 keep-alive 缓存(使用组件名称,而非路由名称)
if (to.meta.keepAlive && to.meta.componentName) {
store.commit('user/setKeepLiiveRoute', to.meta.componentName);
}
console.log('[permission.js] 放行跳转');
next();
} else {
// 没有token的情况下可以进入白名单
// 未登录:白名单放行,否则跳转登录
if (whiteList.indexOf(to.path) > -1) {
// console.log("路由2");
next()
} else {
const cookie = getCookie("clientKey");
if (cookie) {
// console.log("路由3");
next(`/zeroTrust_login`)
} else {
// console.log("路由4");
const isOatuh = getItem('isOatuh')
// 没有token的情况下可以进入白名单
if (isOatuh) {
// console.log("路由5");
const idEntityCard = getItem('idEntityCard')
next(`/oatuh_login?token=${Base64.encode(idEntityCard)}`)
} else {
@ -74,3 +67,15 @@ router.beforeEach(async (to, from, next) => {
}
}
})
// 添加路由后置守卫,确认路由变化
router.afterEach((to, from) => {
console.log('[permission.js] 路由跳转完成:', from.path, '->', to.path, '时间:', Date.now());
})
/**
* 重置路由初始化状态(退出登录时调用)
*/
export function resetRoutesInit() {
routesInitialized = false;
}

View File

@ -1,26 +1,24 @@
import { createRouter, createWebHashHistory } from "vue-router";
import layout from "@/layout/index"; //layout直接引用 其他使用路由懒加载
import layout from "@/layout/index";
import store from "@/store";
// import Home from '../views/Home.vue'
/**
* 关于路由配置描述
* 1.meta && meta.title && meta.icon 则在菜单栏显示
* 2.如果存在children , 则以el-sub-menu子菜单显示
* 否则不在menu菜单显示
* 如果只展示单级别菜单 需要像developer这样配置
* 路由配置说明
*
* 1. publicRoutes公开路由- 所有用户都能访问,应用启动时静态注册
* 包括:登录页、首页、错误页等
*
* 2. privateRoutes私有路由- 需要权限才能访问,登录后动态注册
* 包括:所有业务功能路由
*
* 3. 路由的 name 属性必须与后端返回的菜单权限码menuCodeSet一致
*/
/**
* 私有路由表
*/
export const privateRoutes = [];
/**
* 公开路由表
* 公开路由表 - 所有人都能访问
*/
export const publicRoutes = [
// 登录相关路由
{
path: "/oatuh_login",
name: "oatuh_login",
@ -36,44 +34,57 @@ export const publicRoutes = [
name: "zeroTrust_login",
component: () => import("@/views/login/zeroTrust_login")
},
// 错误页面
{
path: "/401",
name: "401",
component: () => import("@/views/error/401.vue")
},
{
path: "/404",
name: "404",
component: () => import("@/views/error/404.vue")
},
// 首页(所有登录用户都可访问)
{
path: "/",
name: "home",
component: () => import("@/views/home/index") //系统登录
component: () => import("@/views/home/index"),
meta: { keepAlive: true, componentName: 'HomePage' }
},
// 公共访问页面(无需权限校验)
{
path: "/mapNavigation",
name: "mapNavigation",
component: () => import("@/views/home/model/mapNavigation.vue") //系统登录
component: () => import("@/views/home/model/mapNavigation.vue")
},
{
path: "/KeyPopulations",
name: "KeyPopulations",
component: () => import("@/views/KeyPopulations/index") //系统登录
component: () => import("@/views/KeyPopulations/index")
},
// 布控审核信息
// 以下路由虽然在白名单中,但仍需要登录才能访问
// 它们是特殊业务路由,登录后所有人都能访问(不依赖菜单权限)
{
path: "/deploymentApproval",
name: "deploymentApproval",
component: () => import("@/views/backOfficeSystem/ApprovalInformation/deploycontrol/deploymentApproval.vue"),
},
// 标签布控审核
{
path: "/shym",
name: "shym",
component: () => import("@/views/backOfficeSystem/IntelligentControl/marksControl/components/shym.vue"),
},
// 布控审核信息
{
path: "/information",
name: "information",
component: () => import("@/views/backOfficeSystem/JudgmentHome/internalAuditor/information.vue"),
}, {
},
{
path: "/Spdloyment",
name: "Spdloyment",
component: () => import("@/views/backOfficeSystem/HumanIntelligence/auditList/components/spdloyment.vue"),
},
// 线索
{
path: "/clueVerification",
name: "clueVerification",
@ -84,13 +95,40 @@ export const publicRoutes = [
name: "ReviewListSH",
component: () => import("@/views/backOfficeSystem/JudgmentHome/ReviewList/detail.vue"),
},
// 重点人发掘
{
path: "/focusExploration",
name: "focusExploration",
component: () => import("@/views/backOfficeSystem/ApprovalInformation/FocusExploration/index.vue"),
},
//开放到派出所路由
// 情报论坛(所有登录用户都可访问)
{
path: "/forumPost",
name: "forumPost",
component: layout,
meta: {
title: "情报论坛",
icon: "article-ranking"
},
children: [
{
path: "",
name: "forumPostPage",
component: () => import("@/views/backOfficeSystem/luntan/index.vue"),
meta: {
title: "情报论坛",
icon: "article-ranking"
}
}
]
},
];
/**
* 私有路由表 - 需要权限才能访问
* 登录后根据用户的 menuCodeSet 动态注册
*/
export const privateRoutes = [
// 派出所开放路由(特殊权限,不在菜单显示)
{
path: "/warningLists",
name: "warningLists",
@ -100,7 +138,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/behaviorWarnings",
name: "behaviorWarnings",
@ -127,7 +164,8 @@ export const publicRoutes = [
title: "重点人管理",
icon: "article-create"
}
}, {
},
{
path: "/myControls",
name: "myControls",
component: () => import("@/views/backOfficeSystem/IntelligentControl/myControl/index"),
@ -135,7 +173,8 @@ export const publicRoutes = [
title: "我的布控",
icon: "article-create"
}
}, {
},
{
path: "/DeploymentAreas",
name: "DeploymentAreas",
component: () => import("@/views/backOfficeSystem/IntelligentControl/DeploymentArea/index"),
@ -144,8 +183,9 @@ export const publicRoutes = [
icon: "article-create"
}
},
// 主业务路由(带 layout
{
path: "/editPassword", // 注意:带有路径“/”的记录中的组件“默认”是一个不返回 Promise 的函数
path: "/editPassword",
redirect: "/IdentityManage",
component: layout,
children: [
@ -154,125 +194,51 @@ export const publicRoutes = [
name: "FourColorWarning",
meta: { title: "预警中心", icon: "article-ranking" },
children: [
// {
// path: "/centerHome",
// name: "centerHome",
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/centerHome/index"),
// meta: { title: "预警中心大屏", icon: "article-create" },
// },
// {
// path: "/warningBk",
// name: "warningBk",
// meta: { title: "布控预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/warningBk/index"),
// },
{
path: "/YjData",
name: "YjData",
meta: { title: "预警列表", icon: "article-create" },
component: () => import("@/views/backOfficeSystem/fourColorManage/YjData/index.vue"),
},
// {
// path: "/fouColorWarning",
// name: "fouColorWarning",
// meta: { title: "预警数据整合", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/fouColorWarning/index"),
// },
// {
// path: "/sevenWarning",
// name: "sevenWarning",
// meta: { title: "七类重点人员", icon: "article" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/sevenWarning/index.vue"),
// },
// {
// path: "/identityWarning",
// name: "identityWarning",
// meta: { title: "身份预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/identityWarning/index"),
// },
// {
// path: "/behaviorWarning",
// name: "behaviorWarning",
// meta: { title: "行为预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/behaviorWarning/index"),
// },
// {
// path: "/combinedWarning",
// name: "combinedWarning",
// meta: { title: "组合预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/combinedWarning/index"),
// },
// {
// path: "/warningList",
// name: "warningList",
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningList/index"),
// meta: {
// title: "布控预警",
// icon: "article-create"
// }
// },
// {
// path: "/portraitWarning",
// name: "portraitWarning",
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningList/portraitWarning/index"),
// meta: {
// title: "人像预警",
// icon: "article-create"
// }
// },
// {
// path: "/vehicleWarning",
// name: "vehicleWarning",
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningList/vehicleWarning/index"),
// meta: {
// title: "车辆预警",
// icon: "article-create"
// }
// },
// {
// path: "/controlWarning",
// name: "controlWarning",
// meta: { title: "布控预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/controlWarning/index"),
// },
// {
// path: "/regionalControl",
// name: "regionalControl",
// meta: { title: "区域布控预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/regionalControl/index"),
// },
// {
// path: "/fouColorWarning",
// name: "fouColorWarning",
// meta: { title: "四色预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/fouColorWarning/index"),
// },
{
path: "/jqjc",
name: "jqjc",
meta: { title: "警情监测", icon: "article-create" },
children: [
{
path: "/policeReport",
name: "policeReport",
component: () => import("@/views/backOfficeSystem/policeReport/index.vue"),
meta: {
title: "警情信息",
icon: "article-create"
}
},
{
path: "/policeSituations",
name: "policeSituations",
component: () => import("@/views/backOfficeSystem/PoliceIncidentMonitoring/index.vue"),
meta: {
title: "警情预警监测",
icon: "article-create"
}
},
]
},
{
path: "/scoreRanking",
name: "scoreRanking",
meta: { title: "积分排名", icon: "article-create" },
component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/scoreRanking/index"),
},
{
path: "/sevenWarningFail",
name: "sevenWarningFail",
meta: { title: "报错列表", icon: "article" },
component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/sevenWarningFail/index.vue"),
},
// {
// path: "/modelWarning",
// name: "modelWarning",
// meta: { title: "模型预警", icon: "article-create" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/modelWarning/index"),
// },
]
},
{
path: "/IntelligentControl",
name: "IntelligentControl",
@ -314,24 +280,15 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/DeploymentAudit",
// name: "DeploymentAudit",
// component: () => import("@/views/backOfficeSystem/IntelligentControl/DeploymentAudit/index"),
// meta: {
// title: "我的审核",
// icon: "article-create"
// }
// },
// {
// path: "/ControlApproval",
// name: "ControlApproval",
// component: () => import("@/views/backOfficeSystem/IntelligentControl/ControlApproval/index"),
// meta: {
// title: "我的审批",
// icon: "article-create"
// }
// }
{
path: "/ReviewListControl",
name: "ReviewListControl",
component: () => import("@/views/backOfficeSystem/IntelligentControl/ReviewListControl/index"),
meta: {
title: "审核列表",
icon: "article-create"
}
},
]
},
{
@ -356,29 +313,13 @@ export const publicRoutes = [
name: "openSourceList",
component: () => import("@/views/backOfficeSystem/HumanIntelligence/listView/index"),
meta: { title: "共享列表", icon: "article-create", qbjbList: '01' },
}, {
},
{
path: "/auditList",
name: "auditList",
component: () => import("@/views/backOfficeSystem/HumanIntelligence/auditList/index"),
meta: { title: "审批列表", icon: "article-create" },
},
// {
// path: "/socialInformationCrculated",
// name: "changeTheClue",
// component: () => import("@/views/backOfficeSystem/HumanIntelligence/FollowLeads/index"),
// meta: { title: "转线索列表", icon: "article-create" },
// },
// {
// path: "/CollectPoints",
// name: "CollectPoints",
// component: () => import("@/views/backOfficeSystem/HumanIntelligence/CollectPoints/index"),
// meta: {
// title: "采集积分",
// icon: "article-create"
// }
// },
{
path: "/supplementReportList",
name: "supplementReportList",
@ -397,24 +338,15 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/InformationReporting",
// name: "InformationReporting",
// component: () => import("@/views/backOfficeSystem/InformationReporting/index.vue"),
// meta: {
// title: "蜂群信息",
// icon: "article-create"
// }
// },
// {
// path: "/MakeAcomment",
// name: "MakeAcomment",
// component: () => import("@/views/backOfficeSystem/MakeAcomment/index"),
// meta: {
// title: "情报评一评",
// icon: "article-create"
// }
// }
{
path: "/InformationReporting",
name: "InformationReporting",
component: () => import("@/views/backOfficeSystem/InformationReporting/index.vue"),
meta: {
title: "蜂群信息",
icon: "article-create"
}
},
]
},
{
@ -434,19 +366,6 @@ export const publicRoutes = [
component: () => import("@/views/backOfficeSystem/HumanIntelligence/lamXs/index"),
meta: { title: "林安码线索", icon: "article" },
},
// 暂时不要
// {
// path: "/MoralAnalysis",
// name: "MoralAnalysis",
// component: () => import("@/views/backOfficeSystem/ResearchJudgment/MoralAnalysis/index"),
// meta: {
// title: "情报语义分析",
// icon: "article-create"
// }
// },
{
path: "/InstructionInformation",
name: "InstructionInformation",
@ -456,21 +375,8 @@ export const publicRoutes = [
icon: "article"
}
},
// {
// path: "/InformationFlows",
// name: "InformationFlows",
// meta: { title: "情报流转", icon: "article-create" },
// // redirect: "/InformationFlow",
// // children: [
// // ]
// },
]
},
{
path: "/JudgmentHome",
name: "JudgmentHome",
@ -480,15 +386,6 @@ export const publicRoutes = [
icon: "article-ranking"
},
children: [
{
path: "/policeReport",
name: "policeReport",
component: () => import("@/views/backOfficeSystem/policeReport/index.vue"),
meta: {
title: "警情管理",
icon: "article-create"
}
},
{
path: "/policeManagement",
name: "policeManagement",
@ -516,16 +413,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/situationHome",
// name: "situationHome",
// component: () => import("@/views/backOfficeSystem/JudgmentHome/situationHome/index"),
// meta: {
// title: "战略研判",
// icon: "article-create"
// }
// },
// 后面写的研判
{
path: "/strategicResearchs",
name: "strategicResearchs",
@ -562,15 +449,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/analysisReport",
// name: "AnalysisReport",
// component: () => import("@/views/backOfficeSystem/AnalysisReport/index"),
// meta: {
// title: "研判报告",
// icon: "article-create"
// }
// },
{
path: "/MeetingRoom",
name: "MeetingRoom",
@ -618,7 +496,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/mpvGroup",
name: "mpvGroup",
@ -628,7 +505,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/mpvCar",
name: "mpvCar",
@ -647,24 +523,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/mpvPeoSh",
// name: "mpvPeoSh",
// component: () => import("@/views/backOfficeSystem/DeploymentDisposal/mpvPeoSh/index"),
// meta: {
// title: "重点人审批",
// icon: "article-create"
// }
// },
// {
// path: "/mpvGroupSh",
// name: "mpvGroupSh",
// component: () => import("@/views/backOfficeSystem/DeploymentDisposal/mpvGroupSh/index"),
// meta: {
// title: "重点群体审核",
// icon: "article-create"
// }
// },
]
},
{
@ -685,7 +543,8 @@ export const publicRoutes = [
name: "goingJob",
meta: { title: "工作情况", icon: "article-ranking" },
component: () => import("@/views/backOfficeSystem/goingJob/index.vue")
}, {
},
{
path: "/workLogInfo",
name: "workLogInfo",
meta: { title: "值班信息", icon: "article-ranking" },
@ -693,80 +552,15 @@ export const publicRoutes = [
}
]
},
{
path: "/Cspz",
name: "Cspz",
component: () =>
import(
"@/views/backOfficeSystem/fourColorManage/Cspz/index"
),
component: () => import("@/views/backOfficeSystem/fourColorManage/Cspz/index"),
meta: {
title: "参数配置",
icon: "article-create"
}
},
// {
// path: "/IntegralCoefficient",
// name: "IntegralCoefficient",
// component: () =>
// import(
// "@/views/backOfficeSystem/fourColorManage/IntegralCoefficient/index"
// ),
// meta: {
// title: "积分系数配置",
// icon: "article-create"
// }
// },
// {
// path: "/IdentityManage",
// name: "IdentityManage",
// component: () =>
// import(
// "@/views/backOfficeSystem/fourColorManage/IdentityManage/index"
// ),
// meta: {
// title: "身份标签管理",
// icon: "article-create"
// }
// },
// {
// path: "/BehaviorLabels",
// name: "BehaviorLabels",
// component: () =>
// import(
// "@/views/backOfficeSystem/fourColorManage/BehaviorLabels/index"
// ),
// meta: {
// title: "行为标签管理",
// icon: "article-create"
// }
// },
// {
// path: "/tagManage",
// name: "tagManage",
// component: () =>
// import(
// "@/views/backOfficeSystem/fourColorManage/tagManage/index"
// ),
// meta: {
// title: "标签组合管理",
// icon: "article-create"
// }
// },
// {
// path: "/tsypHome",
// name: "tsypHome",
// component: () => import("@/views/backOfficeSystem/JudgmentHome/tsypHome/index"),
// meta: {
// title: "模型管理",
// icon: "article-create"
// }
// },
{
path: "/permissionApply",
name: "permissionApply",
@ -785,7 +579,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/FileData",
name: "FileData",
@ -795,24 +588,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/fileTransfer",
// name: "fileTransfer",
// component: () => import("@/views/backOfficeSystem/HumanIntelligence/fileTransfer/index"),
// meta: {
// title: "文件中转",
// icon: "article-create"
// }
// },
// {
// path: "/fileOrientation",
// name: "fileOrientation",
// component: () => import("@/views/backOfficeSystem/HumanIntelligence/fileOrientation/index"),
// meta: {
// title: "点对点",
// icon: "article-create"
// }
// },
{
path: "/ssemanticAnalysis",
name: "semanticAnalysis",
@ -839,7 +614,8 @@ export const publicRoutes = [
title: "操作记录",
icon: "article-create"
}
}, {
},
{
path: "/dataMonitor",
name: "dataMonitor",
meta: { title: "数据监控", icon: "article-ranking" },
@ -866,57 +642,9 @@ export const publicRoutes = [
},
]
},
// {
// path: "/BasicManagement",
// name: "BasicManagement",
// meta: {
// title: "基础管理",
// icon: "article-create"
// },
// children: [
// // {
// // path: "/surveillanceControl",
// // name: "surveillanceControl",
// // component: () =>
// // import(
// // "@/views/backOfficeSystem/BasicManagement/surveillanceControl/index"
// // ),
// // meta: {
// // title: "布控监视",
// // icon: "article-create"
// // }
// // },
// // {
// // path: "/experienceShare",
// // name: "experienceShare",
// // component: () =>
// // import("@/views/backOfficeSystem/BasicManagement/experienceShare/index"),
// // meta: {
// // title: "经验分享",
// // icon: "article-create"
// // }
// // },
// ]
// },
{
path: "/forumPost",
name: "forumPost",
component: () => import("@/views/forumPost/index.vue"),
meta: {
title: "情报论坛",
icon: "article-ranking"
}
},
{
path: "/systemConfig",
// component: layout,
name: "systemConfigModel",
// redirect: "/dict/index",
meta: {
title: "系统管理",
icon: "article-ranking"
@ -931,12 +659,10 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/user/userList",
name: "userList",
component: () =>
import("@/views/backOfficeSystem/systemConfig/user-list/index"),
component: () => import("@/views/backOfficeSystem/systemConfig/user-list/index"),
meta: {
title: "用户管理",
icon: "article-create"
@ -945,8 +671,7 @@ export const publicRoutes = [
{
path: "/user/role",
name: "userRoleIndex",
component: () =>
import("@/views/backOfficeSystem/systemConfig/role-list/index"),
component: () => import("@/views/backOfficeSystem/systemConfig/role-list/index"),
meta: {
title: "角色列表",
icon: "article-create"
@ -955,19 +680,16 @@ export const publicRoutes = [
{
path: "/user/menuList",
name: "menuList",
component: () =>
import("@/views/backOfficeSystem/systemConfig/menu-list/index"),
component: () => import("@/views/backOfficeSystem/systemConfig/menu-list/index"),
meta: {
title: "菜单管理",
icon: "article-create"
}
},
{
path: "/dict/detail",
name: "dictDetail",
component: () =>
import("@/views/backOfficeSystem/systemConfig/dict/detail"),
component: () => import("@/views/backOfficeSystem/systemConfig/dict/detail"),
meta: {
title: "字典数据"
}
@ -975,21 +697,16 @@ export const publicRoutes = [
{
path: "/dict/index",
name: "dictIndex",
component: () =>
import("@/views/backOfficeSystem/systemConfig/dict/index"),
component: () => import("@/views/backOfficeSystem/systemConfig/dict/index"),
meta: {
title: "字典列表",
icon: "article-create"
}
},
{
path: "/user/deptAllocationUser/:id",
name: "deptAllocationUser",
component: () =>
import(
"@/views/backOfficeSystem/systemConfig/department-list/deptAllocationUser"
),
component: () => import("@/views/backOfficeSystem/systemConfig/department-list/deptAllocationUser"),
meta: {
title: "管理用户"
}
@ -997,27 +714,21 @@ export const publicRoutes = [
{
path: "/user/allocationUser/:id",
name: "allocationUser",
component: () =>
import(
"@/views/backOfficeSystem/systemConfig/role-list/allocationUser"
),
component: () => import("@/views/backOfficeSystem/systemConfig/role-list/allocationUser"),
meta: {
title: "分配用户"
}
},
{
path: "/user/systemConfig",
name: "systemConfig",
component: () =>
import(
"@/views/backOfficeSystem/systemConfig/system-config-list/index"
),
component: () => import("@/views/backOfficeSystem/systemConfig/system-config-list/index"),
meta: {
title: "系统配置",
icon: "article-create"
}
}, {
},
{
path: "/calendar",
name: "calendar",
component: () => import("@/views/backOfficeSystem/calendar/index.vue"),
@ -1074,26 +785,20 @@ export const publicRoutes = [
name: "CollectCrculate",
component: () => import("@/views/backOfficeSystem/HumanIntelligence/CollectCrculate/index"),
meta: { title: "情报采集", icon: "article-create" },
}, {
},
{
path: "/RlStatisticalAnalysis",
name: "RlStatisticalAnalysis",
component: () =>
import(
"@/views/backOfficeSystem/HumanIntelligence/RlStatisticalAnalysis/index"
),
component: () => import("@/views/backOfficeSystem/HumanIntelligence/RlStatisticalAnalysis/index"),
meta: {
title: "上报统计分析",
icon: "article-create"
}
},
{
path: "/TaskScheduling",
name: "TaskScheduling",
component: () =>
import(
"@/views/backOfficeSystem/HumanIntelligence/TaskScheduling/index"
),
component: () => import("@/views/backOfficeSystem/HumanIntelligence/TaskScheduling/index"),
meta: {
title: "上报任务调度",
icon: "article-create"
@ -1102,10 +807,7 @@ export const publicRoutes = [
{
path: "/ConstructionManagement",
name: "ConstructionManagement",
component: () =>
import(
"@/views/backOfficeSystem/HumanIntelligence/ConstructionManagement/index"
),
component: () => import("@/views/backOfficeSystem/HumanIntelligence/ConstructionManagement/index"),
meta: {
title: "力量建设管理",
icon: "article-create"
@ -1152,14 +854,10 @@ export const publicRoutes = [
name: "ExcavationResearch",
meta: { title: "重点人发掘", icon: "article-ranking" },
children: [
{
path: "/PreliminaryExcavations",
name: "PreliminaryExcavations",
component: () =>
import(
"@/views/backOfficeSystem/ExcavationResearch/PreliminaryExcavations/index"
),
component: () => import("@/views/backOfficeSystem/ExcavationResearch/PreliminaryExcavations/index"),
meta: {
title: "重点人员初步发掘",
icon: "article-create"
@ -1168,10 +866,7 @@ export const publicRoutes = [
{
path: "/ZdryFjyp",
name: "ZdryFjyp",
component: () =>
import(
"@/views/backOfficeSystem/ExcavationResearch/ZdryFjyp/index"
),
component: () => import("@/views/backOfficeSystem/ExcavationResearch/ZdryFjyp/index"),
meta: {
title: "重点人员深度发掘",
icon: "article-create"
@ -1180,15 +875,13 @@ export const publicRoutes = [
{
path: "/LandingAudit",
name: "LandingAudit",
component: () =>
import(
"@/views/backOfficeSystem/ExcavationResearch/LandingAudit/index"
),
component: () => import("@/views/backOfficeSystem/ExcavationResearch/LandingAudit/index"),
meta: {
title: "重点人员落地审核",
icon: "article-create"
}
}, {
},
{
path: "/tacticalResearch",
name: "tacticalResearch",
component: () => import("@/views/backOfficeSystem/JudgmentHome/tacticalResearch/index.vue"),
@ -1207,7 +900,8 @@ export const publicRoutes = [
}
},
]
}, {
},
{
path: "/tacticalResearch",
name: "tacticalResearch",
component: () => import("@/views/backOfficeSystem/JudgmentHome/tacticalResearch/index.vue"),
@ -1216,7 +910,6 @@ export const publicRoutes = [
icon: "article-create"
}
},
{
path: "/strategicResearch",
name: "strategicResearch",
@ -1235,43 +928,26 @@ export const publicRoutes = [
icon: "article-create"
}
},
// {
// path: "/ResearchHome",
// name: "ResearchHome",
// component: () => import("@/views/backOfficeSystem/JudgmentHome/ResearchHome/index"),
// meta: {
// title: "战术研判",
// icon: "article-create"
// }
// },
// {
// path: "/situationHome",
// name: "situationHome",
// component: () => import("@/views/backOfficeSystem/JudgmentHome/situationHome/index"),
// meta: {
// title: "战略研判",
// icon: "article-create"
// }
// },
]
},
]
}
];
// 创建路由实例,只注册公开路由
const router = createRouter({
history: createWebHashHistory(),
routes: publicRoutes
});
//初始化路由表
// 重置路由(退出登录时调用)
export function resetRouter() {
if (store.getters?.routeReady && store.getters?.userInfo?.permission?.menus) {
const menus = store.getters.userInfo.permission.menus;
menus.forEach((menu) => {
router.removeRoute(menu);
});
}
// 移除所有动态添加的路由
router.getRoutes().forEach(route => {
if (route.name && !publicRoutes.find(r => r.name === route.name)) {
router.removeRoute(route.name);
}
});
}
export default router;

View File

@ -1,23 +1,60 @@
// 专门处理权限路由的模块
import router from '@/router'
import { publicRoutes, privateRoutes } from '@/router'
/**
* 递归过滤路由(保留 component 引用)
* 规则:
* 1. 如果路由有 name 且在权限列表中,保留
* 2. 如果路由没有 name 但有子路由,检查子路由是否有权限
* 3. 子路由有权限时保留父路由
*
* @param {Array} data - 路由数据
* @param {Array} menus - 菜单权限码集合
* @returns {Array} - 过滤后的路由
*/
function filter(data, menus) {
var newData = data.filter(x => menus?.includes(x.name))
newData.forEach(x => x.children && (x.children = filter(x.children, menus)))
return newData
const result = []
data.forEach(route => {
// 创建新路由对象,保留原有属性(包括 component
const newRoute = { ...route }
// 如果有 name 且在权限列表中,保留此路由
if (route.name && menus?.includes(route.name)) {
// 递归处理子路由
if (route.children && route.children.length > 0) {
newRoute.children = filter(route.children, menus)
}
result.push(newRoute)
return
}
// 如果没有 name 但有 children检查子路由是否有权限
if (!route.name && route.children && route.children.length > 0) {
const filteredChildren = filter(route.children, menus)
// 只要子路由有匹配项,就保留父路由
if (filteredChildren.length > 0) {
newRoute.children = filteredChildren
result.push(newRoute)
}
}
})
return result
}
export default {
namespaced: true,
state: {
routes: [],// 路由表:初始拥有静态路由权限
routeReady: 0
routes: [], // 最终路由表:公开路由 + 有权限的私有路由
routeReady: 0 // 0: 未开始, 1: 进行中, 2: 完成
},
mutations: {
/**
* 增加路由
* 设置路由
*/
setRoutes(state, newRoutes) {
// 永远在静态路由的基础上增加新路由
state.routes = [...publicRoutes, ...newRoutes]
},
setRouteReady(state, num) {
@ -32,9 +69,14 @@ export default {
},
actions: {
/**
* 根据权限筛选路由
* 根据权限过滤并动态注册路由
* @param {Object} context - Vuex context
* @param {Array} menus - 用户菜单权限码集合
*/
filterRoutes(context, menus) {
// 开始处理,标记为进行中
context.commit('setRouteReady', 1);
let routes = []
/**
@ -45,16 +87,36 @@ export default {
routes = filter(privateRoutes, menus)
}
// 最后添加 不匹配路由进入 404
routes.push({
// ★★★ 关键:动态添加路由到 Vue Router ★★★
routes.forEach(route => {
router.addRoute(route)
})
// 404 兜底路由必须最后添加(否则动态路由会匹配到 404
router.addRoute({
path: '/:catchAll(.*)',
redirect: '/404'
})
context.commit('setRoutes', routes);
context.commit('setRouteReady', 1);
// 处理完成,标记为已完成
context.commit('setRouteReady', 2);
return routes
},
/**
* 重置路由(退出登录时调用)
*/
resetRoutes(context) {
// 移除所有动态添加的路由
router.getRoutes().forEach(route => {
if (route.name && !publicRoutes.find(r => r.name === route.name)) {
router.removeRoute(route.name);
}
});
context.commit('deleteRouter');
context.commit('resetrouteReady');
}
}
}

View File

@ -5,27 +5,14 @@ import {
refreshToken,
loginOut
} from "@/api/sys";
import {
unifiedLogin
} from "@/api/user-manage";
import { unifiedLogin } from "@/api/user-manage";
import Base64 from "base-64";
import {
setItem,
getItem,
removeAllItem
} from "@/utils/storage";
import {
TOKEN
} from "@/constant";
import router, {
resetRouter
} from "@/router";
import {
setTimeStamp
} from "@/utils/auth";
import {
TAGS_VIEW
} from "@/constant/index.js";
import { setItem, getItem, removeAllItem } from "@/utils/storage";
import { TOKEN } from "@/constant";
import router, { resetRouter } from "@/router";
import { setTimeStamp } from "@/utils/auth";
import { TAGS_VIEW } from "@/constant/index.js";
import { resetRoutesInit } from "@/permission";
export default {
namespaced: true,
state: () => ({
@ -37,7 +24,7 @@ export default {
isReady: 0,
userName: getItem("USERNAME") || "",
keepLiiveRoute: [], //需要缓存的路由
activeId: '',//警组点击的唯一标识
activeId: "" //警组点击的唯一标识
}),
mutations: {
setToken(state, token) {
@ -69,14 +56,16 @@ export default {
},
//保存路由
setKeepLiiveRoute(state, val) {
// state.keepLiiveRoute.push(val);
if (!state.keepLiiveRoute.includes(val)) {
state.keepLiiveRoute.push(val);
}
},
//删除缓存路由
deleteKeepLiiveRoute(state, val) {
// state.keepLiiveRoute = state.keepLiiveRoute.filter((item) => {
// return item != val;
// });
},
state.keepLiiveRoute = state.keepLiiveRoute.filter((item) => {
return item != val;
});
}
},
actions: {
/*
@ -84,37 +73,43 @@ export default {
*/
login(ctx, userInfo) {
const { userName, password, kaptcha } = userInfo;
return new Promise((resolve, reject) => {
login({ userName, password: Base64.encode(password), kaptcha }).then((data) => {
if (data.deptList.length === 1) {
this.commit("user/setToken", data.jwtToken);
this.commit("user/setDeptId", data.deptList);
this.commit("user/setUserName", data.userName);
setItem('isOatuh', 0)
setItem('fzUserId', data.fzUserId)
setItem("USERNAME", data.userName);
setItem("roleList", data.sysRole ? data.sysRole : []);
setItem("SFRH", data.sfrh);
setItem("USERID", data.userId);
setItem("PermissionsInfo", data.permissionsInfo);
this.commit("user/setMenuList", data.menuList);
setItem("menusPermission", data.menuCodeSet);
setItem("idEntityCard", data.idEntityCard);
this.commit("user/setUserInfo", {
token: data.jwtToken,
permission: {
buttonPermission: ["removeTest", "viewTest"],
menus: data.menuCodeSet
},
menuList: data.menuList,
deptList: data.deptList
});
}
// 保存登录时间
setTimeStamp();
resolve(data);
login({
userName,
password: Base64.encode(password),
kaptcha,
ssxt: "sgxt"
})
.then((data) => {
if (data.deptList.length === 1) {
this.commit("user/setToken", data.jwtToken);
this.commit("user/setDeptId", data.deptList);
this.commit("user/setUserName", data.userName);
setItem("isOatuh", 0);
setItem("fzUserId", data.fzUserId);
setItem("inDustRialId", data.inDustRialId);
setItem("USERNAME", data.userName);
setItem("roleList", data.sysRole ? data.sysRole : []);
setItem("SFRH", data.sfrh);
setItem("USERID", data.userId);
setItem("PermissionsInfo", data.permissionsInfo);
this.commit("user/setMenuList", data.menuList);
setItem("menusPermission", data.menuCodeSet);
setItem("idEntityCard", data.idEntityCard);
this.commit("user/setUserInfo", {
token: data.jwtToken,
permission: {
buttonPermission: ["removeTest", "viewTest"],
menus: data.menuCodeSet
},
menuList: data.menuList,
deptList: data.deptList
});
}
// 保存登录时间
setTimeStamp();
resolve(data);
})
.catch((err) => {
reject(err);
});
@ -124,21 +119,22 @@ export default {
*单点登录
*/
oatuhLogin(ctx, userInfo) {
const { token, systemId, } = userInfo;
const { token, systemId } = userInfo;
return new Promise((resolve, reject) => {
unifiedLogin({ token, systemId }).then((data) => {
unifiedLogin({ token, systemId, ssxt: "sgxt" }).then((data) => {
if (data.deptList.length === 1) {
this.commit("user/setToken", data.jwtToken);
this.commit("user/setDeptId", data.deptList);
this.commit("user/setUserName", data.userName);
setItem("USERNAME", data.userName);
setItem('fzUserId', data.fzUserId)
setItem("fzUserId", data.fzUserId);
setItem("inDustRialId", data.inDustRialId);
setItem("SFRH", data.sfrh);
setItem("USERID", data.userId);
setItem("PermissionsInfo", data.permissionsInfo);
this.commit("user/setMenuList", data.menuList);
setItem("menusPermission", data.menuCodeSet);
setItem('isOatuh', 1)
setItem("isOatuh", 1);
setItem("idEntityCard", data.idEntityCard);
this.commit("user/setUserInfo", {
token: data.jwtToken,
@ -153,10 +149,9 @@ export default {
// 保存登录时间
setTimeStamp();
resolve(data);
})
.catch((err) => {
reject(err);
});
}).catch((err) => {
reject(err);
});
});
},
@ -214,20 +209,20 @@ export default {
async logout(ctx) {
const res = await loginOut();
if (res) {
// 重置动态路由
resetRouter();
// 重置路由守卫初始化标记
resetRoutesInit();
// 清除权限模块状态
this.dispatch("permission/resetRoutes");
// 清除用户状态
this.commit("user/setToken", "");
this.commit("user/setUserName", "admin");
this.commit("user/setUserInfo", {});
this.commit("permission/resetrouteReady", 0);
const isOatuh = getItem('isOatuh')
this.commit("permission/deleteRouter");
// 清除本地存储
removeAllItem();
// 待补充 清理权限相关的配置
// if (isOatuh) {
// 跳转到统一门户
window.location.href = `https://tyyy.lz.dsj.xz/portal/home`;
// } else {
// router.push("/login");
// }
}
}
}

View File

@ -23,29 +23,18 @@ class AudioPlayerClass {
this.audioPlayer = new Audio(audioPath);
this.audioPlayer.loop = loop; // 设置循环播放
// 监听音频加载完成事件
this.audioPlayer.addEventListener('canplaythrough', () => {
console.log('音频加载完成,可以播放');
this.isLoaded = true;
resolve(true);
});
// 监听错误事件
this.audioPlayer.addEventListener('error', (error) => {
console.error('音频加载错误:', error);
console.error('错误代码:', error.code);
console.error('音频网络状态:', this.audioPlayer.networkState);
console.error('音频就绪状态:', this.audioPlayer.readyState);
reject(error);
});
// 预加载音频
console.log('开始预加载音频...');
this.audioPlayer.load();
console.log('音频预加载请求已发送');
} catch (error) {
console.error('初始化音频播放器失败:', error);
console.error('错误详情:', error.stack);
reject(error);
}
});
@ -79,26 +68,19 @@ class AudioPlayerClass {
this.audioPlayer.play()
.then(() => {
this.isPlaying = true;
console.log('音频播放成功');
resolve(true);
})
.catch(error => {
if (error.name === 'NotAllowedError') {
console.error('播放被浏览器自动播放策略阻止,需要用户交互后才能播放');
}
reject(error);
});
.catch(error => reject(error));
}, 0);
} else {
this.audioPlayer.play()
.then(() => {
this.isPlaying = true;
console.log('音频播放成功');
resolve(true);
})
.catch(error => {
if (error.name === 'NotAllowedError') {
console.error('播放被浏览器自动播放策略阻止,需要用户交互后才能播放');
// 浏览器自动播放策略阻止,静默忽略
}
reject(error);
});
@ -117,7 +99,6 @@ class AudioPlayerClass {
if (this.audioPlayer) {
this.audioPlayer.pause();
this.isPlaying = false;
console.log('音频已暂停');
}
}
@ -167,7 +148,6 @@ class AudioPlayerClass {
this.audioPlayer = null;
this.isLoaded = false;
this.isPlaying = false;
console.log('音频播放器已销毁');
}
}
}

View File

@ -1,11 +1,11 @@
import { ref, toRefs, isRef } from 'vue';
import { getSysDictByCode, fzdict } from '@/api/sysDict' //引入封装数字字典接口
import { ref, toRefs, isRef } from "vue";
import { getSysDictByCode, fzdict } from "@/api/sysDict"; //引入封装数字字典接口
import { getLocalDic } from "@/utils/localDic/index.js"
import { getLocalDic } from "@/utils/localDic/index.js";
/**
* 获取字典数据
*/
let list = []
let list = [];
/** 是否取本地字典 (需要本地加载就加这里,不需要就删除) */
export function isLocalDict(dictCode) {
let localDicObj = {
@ -14,10 +14,9 @@ export function isLocalDict(dictCode) {
D_GS_BQ_DJ: true, // "岗哨系统标签管理标签等级"
D_GS_SSYJ: true, // "岗哨系统四色预警"
D_BZ_SF: true, // "是否"
BD_BK_CLYJBQ: true, // "车辆预警标签"
D_YJXX_CZCSLX: true, //常控处置措施类型
}
return localDicObj[dictCode]
BD_BK_CLYJBQ: true // "车辆预警标签"
};
return localDicObj[dictCode];
}
export function getDict(...args) {
const res = ref({});
@ -26,32 +25,32 @@ export function getDict(...args) {
res.value[d] = [];
// 本地字典拦截,如果本地字典存在,则使用本地字典,否则使用远程字典
if (isLocalDict(d) && getLocalDic(d)) {
res.value[d] = getLocalDic(d)
res.value[d] = getLocalDic(d);
} else {
getSysDictByCode({
dictCode: d
}).then(result => {
result = result || {}
result.itemList = Array.isArray(result.itemList) ? result.itemList : []
result.itemList.forEach(p => {
p.label = p.zdmc
p.value = p.dm
p.id = p.dm
p.elTagType = p.dictType
}).then((result) => {
result = result || {};
result.itemList = Array.isArray(result.itemList)
? result.itemList
: [];
result.itemList.forEach((p) => {
p.label = p.zdmc;
p.value = p.dm;
p.id = p.dm;
p.elTagType = p.dictType;
if (p?.itemList && p.itemList?.length > 0) {
getChildren(p)
getChildren(p);
}
p.children = p.itemList
})
res.value[d] = result.itemList
p.children = p.itemList;
});
res.value[d] = result.itemList;
//
})
});
}
})
});
return toRefs(res.value);
})()
})();
}
export function getFzDict(...args) {
const res = ref({});
@ -64,7 +63,7 @@ export function getFzDict(...args) {
} else {
fzdict({
dictLabel: d
}).then(result => {
}).then((result) => {
result = result || {};
// result.itemList = Array.isArray(result.itemList) ? result.itemList : [];
// result.itemList.forEach(p => {
@ -79,26 +78,25 @@ export function getFzDict(...args) {
// });
// console.log(res.value);
res.value[d] = result
res.value[d] = result;
});
}
});
// 使用toRefs确保返回的是响应式对象
return toRefs(res.value);
})()
})();
}
export function getChildren(item) {
item.label = item.zdmc
item.value = item.dm
item.id = item.dm
item.label = item.zdmc;
item.value = item.dm;
item.id = item.dm;
if (item.itemList && item.itemList.length > 0) {
item.itemList.forEach(v => {
getChildren(v)
})
item.itemList.forEach((v) => {
getChildren(v);
});
}
item.children = item.itemList
item.children = item.itemList;
}
/**
* 设置级联选择器回显
@ -106,17 +104,17 @@ export function getChildren(item) {
* @param {*} array 级联数据树
* @param {*} childDeptList 子集变量
*/
export function setCascader(id, array, childDeptList = 'childDeptList', fun) {
export function setCascader(id, array, childDeptList = "childDeptList", fun) {
if (array) {
array.forEach(item => {
array.forEach((item) => {
if (item.childDeptList && item.id != id) {
setCascader(id, item.childDeptList, childDeptList, fun)
setCascader(id, item.childDeptList, childDeptList, fun);
} else if (item.childDeptList && item.id == id) {
fun(item)
fun(item);
} else if (!item.childDeptList && item.id == id) {
fun(item)
fun(item);
}
})
});
}
}
/**
@ -127,58 +125,64 @@ export function setCascader(id, array, childDeptList = 'childDeptList', fun) {
*/
export function IdCard(IdCard, type) {
let user = {
birthday: '',
sex: '',
age: ''
}
if (type === 1 || type == 'all') {
birthday: "",
sex: "",
age: ""
};
if (type === 1 || type == "all") {
//获取出生日期
let birthday = IdCard.substring(6, 10) + "-" + IdCard.substring(10, 12) + "-" + IdCard.substring(12, 14)
if (type == 'all') {
user.birthday = birthday
let birthday =
IdCard.substring(6, 10) +
"-" +
IdCard.substring(10, 12) +
"-" +
IdCard.substring(12, 14);
if (type == "all") {
user.birthday = birthday;
} else {
return birthday
return birthday;
}
}
if (type === 2 || type == 'all') {
if (type === 2 || type == "all") {
//获取性别
if (parseInt(IdCard.substr(16, 1)) % 2 === 1) {
if (type == 'all') {
user.sex = '男'
if (type == "all") {
user.sex = "男";
} else {
return "男"
return "男";
}
} else {
if (type == 'all') {
user.sex = '女'
if (type == "all") {
user.sex = "女";
} else {
return "女"
return "女";
}
}
}
if (type === 3 || type == 'all') {
if (type === 3 || type == "all") {
//获取年龄
var ageDate = new Date()
var month = ageDate.getMonth() + 1
var day = ageDate.getDate()
var age = ageDate.getFullYear() - IdCard.substring(6, 10) - 1
if (IdCard.substring(10, 12) < month || IdCard.substring(10, 12) === month && IdCard.substring(12, 14) <= day) {
age++
var ageDate = new Date();
var month = ageDate.getMonth() + 1;
var day = ageDate.getDate();
var age = ageDate.getFullYear() - IdCard.substring(6, 10) - 1;
if (
IdCard.substring(10, 12) < month ||
(IdCard.substring(10, 12) === month && IdCard.substring(12, 14) <= day)
) {
age++;
}
if (age <= 0) {
age = 1
age = 1;
}
if (type == 'all') {
user.age = age
if (type == "all") {
user.age = age;
} else {
return age
return age;
}
}
return user
return user;
}
/**
*翻译字典数据
* @export
@ -186,14 +190,14 @@ export function IdCard(IdCard, type) {
* @param {*} array
*/
export function getDictValue(dm, array) {
let item = array.value.find(item => {
let item = array.value.find((item) => {
if (item.value) {
return item.value == dm;
} else if (item.dm) {
return item.dm == dm;
}
})
return item ? item.label : ""
});
return item ? item.label : "";
}
/** 获取多个字典值(一个值也可以) 字典内容 value-label
@ -201,15 +205,15 @@ export function getDictValue(dm, array) {
* @param {Array} dict 字典内容
*/
export function getMultiDictVal(values, dict) {
if (typeof values === 'string' && values?.length) values = values.split(',')
if (!Array.isArray(values)) return ''
if (isRef(dict)) dict = dict.value
if (!Array.isArray(dict)) return ''
if (typeof values === "string" && values?.length) values = values.split(",");
if (!Array.isArray(values)) return "";
if (isRef(dict)) dict = dict.value;
if (!Array.isArray(dict)) return "";
return values.map(v => {
const item = dict.find(item => item.value === v);
return item ? item.label : v;
}).join(',');
return values
.map((v) => {
const item = dict.find((item) => item.value === v);
return item ? item.label : v;
})
.join(",");
}

View File

@ -6,10 +6,62 @@ export function getLocalDic(key) {
let dicobj = {
/** "岗哨系统重点人员预警等级" */
D_GS_ZDR_YJDJ: [
{ "itemList": null, "id": "01", "zdId": 59588112, "zdbh": "D_GS_ZDR_YJDJ", "zdmc": "一级", "dm": "01", "py": "YJ", "px": 1, "bz": "", "label": "一级", "value": "01", "children": null },
{ "itemList": null, "id": "02", "zdId": 59588112, "zdbh": "D_GS_ZDR_YJDJ", "zdmc": "二级", "dm": "02", "py": "EJ", "px": 2, "bz": "", "label": "二级", "value": "02", "children": null },
{ "itemList": null, "id": "03", "zdId": 59588112, "zdbh": "D_GS_ZDR_YJDJ", "zdmc": "三级", "dm": "03", "py": "SJ", "px": 3, "bz": "", "label": "三级", "value": "03", "children": null },
{ "itemList": null, "id": "04", "zdId": 59588112, "zdbh": "D_GS_ZDR_YJDJ", "zdmc": "四级", "dm": "04", "py": "SJ", "px": 4, "bz": "", "label": "四级", "value": "04", "children": null }
{
"itemList": null,
"id": "01",
"zdId": 59588112,
"zdbh": "D_GS_ZDR_YJDJ",
"zdmc": "一级",
"dm": "01",
"py": "YJ",
"px": 1,
"bz": "",
"label": "一级",
"value": "01",
"children": null
},
{
"itemList": null,
"id": "02",
"zdId": 59588112,
"zdbh": "D_GS_ZDR_YJDJ",
"zdmc": "二级",
"dm": "02",
"py": "EJ",
"px": 2,
"bz": "",
"label": "二级",
"value": "02",
"children": null
},
{
"itemList": null,
"id": "03",
"zdId": 59588112,
"zdbh": "D_GS_ZDR_YJDJ",
"zdmc": "三级",
"dm": "03",
"py": "SJ",
"px": 3,
"bz": "",
"label": "三级",
"value": "03",
"children": null
},
{
"itemList": null,
"id": "04",
"zdId": 59588112,
"zdbh": "D_GS_ZDR_YJDJ",
"zdmc": "四级",
"dm": "04",
"py": "SJ",
"px": 4,
"bz": "",
"label": "四级",
"value": "04",
"children": null
}
],
/** 性别 */
D_BZ_XB: [
@ -235,66 +287,8 @@ export function getLocalDic(key) {
"value": "1",
"children": null
}
],
]
/** 常控处置措施类型 */
D_YJXX_CZCSLX: [
{
"itemList": null,
"id": "01",
"zdId": 59589206,
"zdbh": "D_YJXX_CZCSLX",
"zdmc": "抓捕",
"dm": "01",
"py": "ZP",
"px": 1,
"bz": "",
"label": "抓捕",
"value": "01",
"children": null
},
{
"itemList": null,
"id": "02",
"zdId": 59589206,
"zdbh": "D_YJXX_CZCSLX",
"zdmc": "管控",
"dm": "02",
"py": "GK",
"px": 2,
"bz": "",
"label": "管控",
"value": "02",
"children": null
},
{
"itemList": null,
"id": "03",
"zdId": 59589206,
"zdbh": "D_YJXX_CZCSLX",
"zdmc": "经营",
"dm": "03",
"py": "JY",
"px": 3,
"bz": "",
"label": "经营",
"value": "03",
"children": null
},
{
"itemList": null,
"id": "04",
"zdId": 59589206,
"zdbh": "D_YJXX_CZCSLX",
"zdmc": "关注",
"dm": "04",
"py": "GZ",
"px": 4,
"bz": "",
"label": "关注",
"value": "04",
"children": null
}
],
}
return dicobj[key]
};
return dicobj[key];
}

View File

@ -43,34 +43,50 @@ service.interceptors.response.use(
(response) => {
const { success, code, msg, message, data, model } = response.data;
// 需要判断当前请求是否成功
if (success && code === 10000) {
return data || [null,0,undefined,''].includes(data) ? data : response.data; // 成功后返回解析后的数据
// return data ? data : response.data; // // 成功后返回解析后的数据
if (code == 403 || code == 402) {
ElMessage({ message: message || msg || '登录已过期,请关闭浏览器,重新登录', grouping: true, type: 'error' });
} else if (success && code === 10000) {
return data || [null, 0, undefined, ''].includes(data) ? data : response.data;
} else if (code === 200 || code == "00000" || code == "10000" || msg == 'success' || model || response.data.success == true) {
return data || [null,0,undefined,''].includes(data) ? data : response.data; // 成功后返回解析后的数据
// return data ? data : response.data; // // 成功后返回解析后的数据
return data || [null, 0, undefined, ''].includes(data) ? data : response.data;
} else if (code === 401) {
store.dispatch('user/logout');
ElMessage.error(message); // 提示错误信息
ElMessage({ message: message || msg, grouping: true, type: 'error' })
ElMessage({ message: message || msg || '登录已过期,请重新登录', grouping: true, type: 'error' });
return Promise.reject(new Error('登录已过期'));
} else {
// 失败(请求成功 ,业务失败) 弹出消息提示
ElMessage({ message: message || msg, grouping: true, type: 'error' })
return Promise.reject(new Error(message + '数据格式错误'));
// 失败(请求成功,业务失败)弹出消息提示
ElMessage({ message: message || msg || '请求失败', grouping: true, type: 'error' });
return Promise.reject(new Error(message || msg || '数据格式错误'));
}
},
// 请求失败处理
// 请求失败处理(网络错误、服务器错误等)
(error) => {
//token过期
if (
error.response &&
error.response.data &&
error.response.data.code === 401
) {
console.log("Xxxxx");
// token过期
if (error.response && error.response.data && error.response.data.code === 401) {
store.dispatch('user/logout');
ElMessage({ message: '登录已过期,请重新登录', grouping: true, type: 'error' });
} else if (error.response) {
// 服务器返回了错误响应500、404、403等
const status = error.response.status;
const msg = error.response.data?.message || error.response.data?.msg;
if (status === 500) {
ElMessage({ message: msg || '服务器内部错误', grouping: true, type: 'error' });
} else if (status === 404) {
ElMessage({ message: msg || '请求资源不存在', grouping: true, type: 'error' });
} else if (status === 403) {
ElMessage({ message: msg || '没有权限访问', grouping: true, type: 'error' });
} else {
ElMessage({ message: msg || `请求错误(${status})`, grouping: true, type: 'error' });
}
} else if (error.code === 'ECONNABORTED') {
// 请求超时
ElMessage({ message: '请求超时,请稍后重试', grouping: true, type: 'error' });
} else {
// 网络错误或其他错误
ElMessage({ message: error.message || '网络连接异常', grouping: true, type: 'error' });
}
// 关键:返回 Promise.reject让调用方能捕获到错误
return Promise.reject(error);
}
);

View File

@ -5,69 +5,40 @@ import { getItem } from '@/utils/storage'
*/
const getChildrenRoutes = (routes) => {
const result = [];
const { deptBizType, deptLevel } = getItem('deptId')[0]
const roleList = getItem('roleList') ? getItem('roleList').filter(item => item.roleCode == 'JS_666666').length > 0 : false
const xjLsit = getItem('roleList') ? getItem('roleList').filter(item => item.roleCode == 'JS_999999').length > 0 : false
console.log(roleList, xjLsit);
const deptIdData = getItem('deptId');
const deptInfo = deptIdData && deptIdData.length > 0 ? deptIdData[0] : {};
const deptBizType = deptInfo.deptBizType || '';
const deptLevel = deptInfo.deptLevel || '';
const roleListData = getItem('roleList') || [];
const roleList = roleListData.filter(item => item.roleCode == 'JS_666666').length > 0;
const xjLsit = roleListData.filter(item => item.roleCode == 'JS_999999').length > 0;
// 需要从子路由中排除的路径
const excludePaths = ['/internalAuditor', '/auditList'];
// deptBizType 为 23 且有特定角色时,不排除 /auditList
const excludePathsForBiz23WithRole = ['/internalAuditor'];
routes.forEach((route) => {
if (route.children && route.children.length > 0) {
if (deptBizType == '23') {
let filteredChildren;
if (deptBizType == '23') {
if (roleList) {
result.push(...route.children);
// 有 JS_666666 角色:不排除任何路由
filteredChildren = route.children;
} else if (xjLsit) {
if (route.path == '/JudgmentHome') {
route.children.splice(route.children.findIndex(item => item.path == '/internalAuditor'), 1)
result.push(...route.children);
} else {
result.push(...route.children);
}
// 有 JS_999999 角色:只排除 /internalAuditor
filteredChildren = route.children.filter(child => !excludePathsForBiz23WithRole.includes(child.path));
} else {
if (route.path == '/HumanIntelligence') {
route.children.splice(route.children.findIndex(item => item.path == '/auditList'), 1)
result.push(...route.children);
} else {
result.push(...route.children);
}
if (route.path == '/JudgmentHome') {
route.children.splice(route.children.findIndex(item => item.path == '/internalAuditor'), 1)
result.push(...route.children);
} else {
result.push(...route.children);
}
// 其他:排除 /internalAuditor 和 /auditList
filteredChildren = route.children.filter(child => !excludePaths.includes(child.path));
}
} else {
if (route.path == '/HumanIntelligence') {
route.children.splice(route.children.findIndex(item => item.path == '/auditList'), 1)
result.push(...route.children);
} else {
result.push(...route.children);
}
if (route.path == '/JudgmentHome') {
route.children.splice(route.children.findIndex(item => item.path == '/internalAuditor'), 1)
result.push(...route.children);
} else {
result.push(...route.children);
}
// 非 23 类型:排除 /internalAuditor 和 /auditList
filteredChildren = route.children.filter(child => !excludePaths.includes(child.path));
}
// if (deptBizType == '23' && (roleList || xjLsit)) {
// // 在这个条件分支中也需要过滤掉/internalAuditor路由
// result.push(...route.children);
// } else {
// if (route.path == '/JudgmentHome' && xjLsit) {
// route.children.splice(route.children.findIndex(item => item.path == '/internalAuditor'), 1)
// result.push(...route.children);
// } else {
// result.push(...route.children);
// }
// }
result.push(...filteredChildren);
}
});
return result;
@ -82,6 +53,8 @@ export const filterRoutes = (routes) => {
const childrenRoutes = getChildrenRoutes(routes);
const data = routes.filter((route) => {
//根据route在childrenRoutes中进行查重把所有重复路由表 剔除
// 但保留 forumPost 路由
if (route.name === 'forumPost') return true;
return !childrenRoutes.find((childrenRoute) => {
return childrenRoute.path === route.path;
});
@ -135,5 +108,3 @@ export function generateMenus(routes, basePath = "") {
});
return result;
}

View File

@ -1,5 +1,3 @@
import ImageCompressor from "image-compressor.js";
// 生成10位数的随机数
@ -13,23 +11,34 @@ export function generateRandom10Digits() {
// 随机颜色 - 把16进制的颜色换成rgba格式
export function choseRbgb(color, opcity) {
if (color) {
return 'rgba(' + parseInt('0x' + color.slice(1, 3)) + ',' + parseInt('0x' + color.slice(3, 5)) + ',' + parseInt('0x' + color.slice(5, 7)) + ',' + opcity + ')'
return (
"rgba(" +
parseInt("0x" + color.slice(1, 3)) +
"," +
parseInt("0x" + color.slice(3, 5)) +
"," +
parseInt("0x" + color.slice(5, 7)) +
"," +
opcity +
")"
);
} else {
let r = Math.floor(Math.random() * 256)
let g = Math.floor(Math.random() * 256)
let b = Math.floor(Math.random() * 256)
let a = opcity ? opcity : 1
return `rgba(${r},${g},${b},${a})`
let r = Math.floor(Math.random() * 256);
let g = Math.floor(Math.random() * 256);
let b = Math.floor(Math.random() * 256);
let a = opcity ? opcity : 1;
return `rgba(${r},${g},${b},${a})`;
}
}
// 随机十六进制颜色
export function randomHexColor() { // 随机生成十六进制颜色
export function randomHexColor() {
// 随机生成十六进制颜色
var hex = Math.floor(Math.random() * 16777216).toString(16);
while (hex.length < 6) {
hex = '0' + hex;
hex = "0" + hex;
}
return '#' + hex;
return "#" + hex;
}
/**
@ -47,23 +56,30 @@ export function compressImage(file, quality = 0.6) {
},
error(e) {
reject("图片压缩失败,请稍后再试");
},
}
});
});
};
}
// 今天周几
export function weekValidate() {
let week = new Date().getDay()
let weekenday = ''
let week = new Date().getDay();
let weekenday = "";
switch (week) {
case 0: return weekenday = '星期日'
case 1: return weekenday = '星期一'
case 2: return weekenday = '星期二'
case 3: return weekenday = '星期三'
case 4: return weekenday = '星期四'
case 5: return weekenday = '星期五'
case 6: return weekenday = '星期六'
case 0:
return (weekenday = "星期日");
case 1:
return (weekenday = "星期一");
case 2:
return (weekenday = "星期二");
case 3:
return (weekenday = "星期三");
case 4:
return (weekenday = "星期四");
case 5:
return (weekenday = "星期五");
case 6:
return (weekenday = "星期六");
}
}
@ -86,45 +102,44 @@ export function formatDuring(mss) {
// 转换时间格式
export function timeValidate(date, type) {
const time = date ? new Date(date) : new Date()
const yyyy = time.getFullYear()
const MM = (time.getMonth() + 1).toString().padStart(2, 0)
const dd = time.getDate().toString().padStart(2, '0')
const hh = time.getHours().toString().padStart(2, '0')
const mm = time.getMinutes().toString().padStart(2, '0')
const ss = time.getSeconds().toString().padStart(2, '0')
const time = date ? new Date(date) : new Date();
const yyyy = time.getFullYear();
const MM = (time.getMonth() + 1).toString().padStart(2, 0);
const dd = time.getDate().toString().padStart(2, "0");
const hh = time.getHours().toString().padStart(2, "0");
const mm = time.getMinutes().toString().padStart(2, "0");
const ss = time.getSeconds().toString().padStart(2, "0");
if (type == 'ymd') {
if (type == "ymd") {
return `${yyyy}-${MM}-${dd}`;
}
if (type == 'md') {
return `${MM}.${dd}`
if (type == "md") {
return `${MM}.${dd}`;
}
if (type == 'td') {
return `${yyyy}${MM}${dd}`
if (type == "td") {
return `${yyyy}${MM}${dd}`;
}
if (type == 'ny') {
return `${yyyy}${MM}`
if (type == "ny") {
return `${yyyy}${MM}`;
}
if (type == 'yd') {
return `${yyyy}`
if (type == "yd") {
return `${yyyy}`;
}
if (type == 'ym') {
return MM
if (type == "ym") {
return MM;
}
if (type == 'rm') {
return dd
if (type == "rm") {
return dd;
}
if (type == 'mm') {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`
if (type == "mm") {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`;
}
if (type == 'ydm') {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`
if (type == "ydm") {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`;
}
return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`
return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`;
}
export function timeSlotChange(val) {
let startTime, endTime;
let now = new Date(); //当前日期
@ -132,89 +147,93 @@ export function timeSlotChange(val) {
let nowDay = now.getDate(); //当前日
let nowMonth = now.getMonth(); //当前月
let nowYear = now.getFullYear(); //当前年
let jd = Math.ceil((nowMonth + 1) / 3)
let jd = Math.ceil((nowMonth + 1) / 3);
switch (val) {
case '天':
case '日':
case "天":
case "日":
// 设置当天的开始时间00:00:00
const startDate = new Date();
startDate.setHours(0, 0, 0, 0);
startTime = timeValidate(startDate, 'ymd');
startTime = timeValidate(startDate, "ymd");
// 设置当天的结束时间23:59:59
const endDate = new Date();
endDate.setHours(23, 59, 59, 999);
endTime = timeValidate(endDate, 'ymd');
endTime = timeValidate(endDate, "ymd");
console.log(startTime, endTime);
break;
case "本周":
case "周":
startTime = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek)
endTime = new Date(nowYear, nowMonth, nowDay + 6 - nowDayOfWeek)
startTime = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek);
endTime = new Date(nowYear, nowMonth, nowDay + 6 - nowDayOfWeek);
break;
case "本月":
case "月":
startTime = new Date(nowYear, nowMonth, 1)
endTime = new Date(nowYear, nowMonth + 1, 0)
startTime = new Date(nowYear, nowMonth, 1);
endTime = new Date(nowYear, nowMonth + 1, 0);
console.log(startTime, endTime);
break;
case "本季度":
case "季度":
startTime = new Date(nowYear, (jd - 1) * 3, 1)
endTime = new Date(nowYear, jd * 3, 0)
break
startTime = new Date(nowYear, (jd - 1) * 3, 1);
endTime = new Date(nowYear, jd * 3, 0);
break;
case "本年":
case "年":
startTime = new Date(nowYear, 0, 1)
endTime = new Date(nowYear, 11, 31)
break
startTime = new Date(nowYear, 0, 1);
endTime = new Date(nowYear, 11, 31);
break;
}
return [timeValidate(startTime, 'ymd'), timeValidate(endTime, 'ymd')]
return [timeValidate(startTime, "ymd"), timeValidate(endTime, "ymd")];
}
// 获取当前近多少天 7后7天 -7 前五天
export function getRecentDay(n) {
var currentDate = new Date();
var preDate = new Date(currentDate.getTime() + n * 24 * 3600 * 1000)
let year = preDate.getFullYear()
let mon = preDate.getMonth() + 1
let day = preDate.getDate()
let s = year + '-' + (mon < 10 ? ('0' + mon) : mon) + '-' + (day < 10 ? ('0' + day) : day)
return s
var preDate = new Date(currentDate.getTime() + n * 24 * 3600 * 1000);
let year = preDate.getFullYear();
let mon = preDate.getMonth() + 1;
let day = preDate.getDate();
let s =
year +
"-" +
(mon < 10 ? "0" + mon : mon) +
"-" +
(day < 10 ? "0" + day : day);
return s;
}
// 获取n近7月 7后7 -7 前
export function getnRencebtMonth(n) {
let date = new Date();
date.setMonth(date.getMonth() - n)
date.toLocaleDateString()
let y = date.getFullYear()
let m = date.getMonth() + 1
m = m < 10 ? ('0' + m) : m + ''
return y + m
date.setMonth(date.getMonth() - n);
date.toLocaleDateString();
let y = date.getFullYear();
let m = date.getMonth() + 1;
m = m < 10 ? "0" + m : m + "";
return y + m;
}
/**
* 数据去重 相同数据值累加
* @param {Object} array 数据
*/
export function setArray(array) {
let newArr = []
array.forEach(item => {
const res = newArr.findIndex(ol => {
let newArr = [];
array.forEach((item) => {
const res = newArr.findIndex((ol) => {
//组织机构代码相同 并且报警类别相同
return item.ssbmdm == ol.ssbmdm && item.bjlb == ol.bjlb
})
return item.ssbmdm == ol.ssbmdm && item.bjlb == ol.bjlb;
});
if (res !== -1) {
newArr[res].sl = newArr[res].sl + item.sl
newArr[res].sl = newArr[res].sl + item.sl;
} else {
newArr.push(item)
newArr.push(item);
}
})
});
return newArr
return newArr;
}
/**
@ -222,44 +241,49 @@ export function setArray(array) {
* @param {Object} array 数据
*/
export function hbArray(array, item1, item2, item3) {
let newArr = []
array.forEach(item => {
const res = newArr.findIndex(ol => {
let newArr = [];
array.forEach((item) => {
const res = newArr.findIndex((ol) => {
//组织机构代码相同 并且报警类别相同
return item.product == ol.product
})
return item.product == ol.product;
});
if (res !== -1) {
newArr[res][item1] = newArr[res][item1] + item[item1]
newArr[res][item2] = newArr[res][item2] + item[item2]
newArr[res][item3] = newArr[res][item3] + item[item3]
newArr[res][item1] = newArr[res][item1] + item[item1];
newArr[res][item2] = newArr[res][item2] + item[item2];
newArr[res][item3] = newArr[res][item3] + item[item3];
} else {
newArr.push(item)
newArr.push(item);
}
})
});
return newArr
return newArr;
}
//时间格式
export function dateFormat(type, time) {
let date
let date;
if (time) {
date = new Date(time);
} else {
date = new Date();
}
let year = date.getFullYear();
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
let month =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1;
let hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
let day
let minutes =
date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let seconds =
date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
let day;
if (type == 'z') {
if (type == "z") {
//前一天日期
day = date.getDate() - 1;
day = day < 10 ? "0" + day : day;
return `${year}-${month}-${day}`;
} else if (type == 'all') {
} else if (type == "all") {
//格式化日期时间
day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
@ -269,42 +293,78 @@ export function dateFormat(type, time) {
day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
return `${year}-${month}-${day}`;
}
return day
return day;
}
//数字超长处理
export function handleNum(num) {
var data = 0
var data = 0;
if (num) {
try {
if (num * 1 > 100000) {
data = (num / 10000).toFixed(0) + '万'
data = (num / 10000).toFixed(0) + "万";
} else {
data = (num * 1).toFixed(0)
data = (num * 1).toFixed(0);
}
} catch (error) {
data = 0
data = 0;
}
}
return data
return data;
}
/**
* 文件是否是图片
* @param {*} val
*/
export function IS_PNG(val) {
return ['bmp', 'jpg', 'png', 'tif', 'gif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo',
'eps', 'ai', 'raw', 'wmf', 'webp', 'avif', 'apng'
].indexOf(val.toLowerCase()) !== -1
return (
[
"bmp",
"jpg",
"png",
"tif",
"gif",
"pcx",
"tga",
"exif",
"fpx",
"svg",
"psd",
"cdr",
"pcd",
"dxf",
"ufo",
"eps",
"ai",
"raw",
"wmf",
"webp",
"avif",
"apng"
].indexOf(val.toLowerCase()) !== -1
);
}
/**
* 文件是否是音频
* @param {*} val
*/
export function IS_MP3(val) {
return ['mp3', 'wav', 'wma', 'mp2', 'flac', 'midi', 'ra', 'ape', 'aac', 'cda', 'mov'].indexOf(val.toLowerCase()) !==
-1
return (
[
"mp3",
"wav",
"wma",
"mp2",
"flac",
"midi",
"ra",
"ape",
"aac",
"cda",
"mov"
].indexOf(val.toLowerCase()) !== -1
);
}
/**
@ -312,26 +372,39 @@ export function IS_MP3(val) {
* @param {*} val
*/
export function IS_MP4(val) {
return ['avi', 'wmv', 'mpeg', 'mp4', 'm4v', 'mov', 'asf', 'fiv', 'f4v', 'mvb', 'rm', '3gp', 'vob'].indexOf(val
.toLowerCase()) !== -1
return (
[
"avi",
"wmv",
"mpeg",
"mp4",
"m4v",
"mov",
"asf",
"fiv",
"f4v",
"mvb",
"rm",
"3gp",
"vob"
].indexOf(val.toLowerCase()) !== -1
);
}
function handelArr(arr) {
let brr = []
let brr = [];
if (arr && arr.length > 0) {
let obj = {}
let obj = {};
let coords = "";
for (let i = 0; i < arr.length; i++) {
coords += arr[i] + ","
coords += arr[i] + ",";
}
obj.coords = coords
brr.push(obj)
obj.coords = coords;
brr.push(obj);
}
return brr
return brr;
}
/**
* 时间 天数
* @param {*} val
@ -341,29 +414,31 @@ export function setEchartTime(val) {
let arrTime = [];
if (val == 0) {
for (let i = 0; i < 24; i++) {
arrTime.push(i)
arrTime.push(i);
}
} else {
for (let i = 0; i < val; i++) {
let date1 = new Date(date.getTime() - i * 24 * 60 * 60 * 1000)
arrTime.push(_setTime(date1))
let date1 = new Date(date.getTime() - i * 24 * 60 * 60 * 1000);
arrTime.push(_setTime(date1));
}
arrTime.reverse()
arrTime.reverse();
}
return arrTime
return arrTime;
}
//设置时间
function _setTime(date) {
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
let month =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1;
let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
return `${month}-${day}`;
}
//拼接地址
export function setAddress(val) {
const url = '/mosty-api/mosty-base/minio/image/download/'
return url + val
const url = "/mosty-api/mosty-base/minio/image/download/";
return url + val;
}
export function getUUid() {
var list = [];
@ -379,27 +454,31 @@ export function getUUid() {
}
// 预警等级颜色
export const bqYs = (val) => {
if (val == '01') {
return '#ff0202'
} else if (val == '02') {
return '#ff8c00'
} else if (val == '03') {
return '#ffd208ff'
} else if (val == '04') {
return '#0000ff'
if (val == "01") {
return "#ff0202";
} else if (val == "02") {
return "#ff8c00";
} else if (val == "03") {
return "#ffd208ff";
} else if (val == "04") {
return "#0000ff";
}
}
};
/** 全息档案跳转
* @param {string} szhm 身证号
*/
export function holographicProfileJump(lx, val) {
if (!val) return
if (lx == 1 || !lx) {
const sfzh = val.sfzh || val.rysfzh || val.yjRysfzh
window.open(`https://tyyy.lz.dsj.xz/profile/people/person-manage?sfzhm=${sfzh}&from=portal`)
if (!val) return;
if (lx == 1 || !lx || lx == "01") {
const sfzh = val.sfzh || val.rysfzh || val.yjRysfzh;
window.open(
`https://tyyy.lz.dsj.xz/profile/people/person-manage?sfzhm=${sfzh}&from=portal`
);
} else {
const cph = val.cph || val.yjClcph
window.open(`https://tyyy.lz.dsj.xz/profile/car/car-manage?cphm=${cph}&from=portal`)
const cph = val.cph || val.yjClcph;
window.open(
`https://tyyy.lz.dsj.xz/profile/car/car-manage?cphm=${cph}&from=portal`
);
}
}
/**
@ -416,6 +495,6 @@ export function getErrMsg(fields, msgObj) {
if (!firstErrorField) return;
/** 第一个错误字段的内容 @type{<Array>Object} - [message, field, fieldValue] */
let firstErrorFieldObj = fields?.[firstErrorField];
let errMsg = firstErrorFieldObj?.[0]?.message
return errMsg
let errMsg = firstErrorFieldObj?.[0]?.message;
return errMsg;
}

View File

@ -42,7 +42,7 @@ const btns = ref(['重点人','重点群体'])
const active = ref('重点人');
const keywords = ref(''); // 搜索关键字
const { proxy } = getCurrentInstance();
const { D_GS_ZDQT_ZT,D_BZ_RYBQ,D_GS_ZDQT_FXDJ } = proxy.$dict('D_GS_ZDQT_ZT','D_BZ_RYBQ','D_GS_ZDQT_FXDJ') //获取字典数据
const { D_GS_ZDQT_ZT,/* D_BZ_RYBQ, */D_GS_ZDQT_FXDJ } = proxy.$dict('D_GS_ZDQT_ZT',/* 'D_BZ_RYBQ', */'D_GS_ZDQT_FXDJ') //获取字典数据
const pageData = reactive({
tableData: [],
keyCount: 0,

View File

@ -49,8 +49,16 @@ import { onMounted, getCurrentInstance, ref, reactive } from 'vue'
import { useRoute } from 'vue-router'
import { setAddress } from '@/utils/tools'
const { proxy } = getCurrentInstance();
const { D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
proxy.$dict("D_BZ_SF", "D_BZ_XB", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX"); //获取字典数据
const {
// D_BZ_SF,
D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX,
// D_GS_XS_QTLX
} =
proxy.$dict(
// "D_BZ_SF",
"D_BZ_XB", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX"
// , "D_GS_XS_QTLX"
); //获取字典数据
// 基础信息
const basicInformation = ref(

View File

@ -4,13 +4,8 @@
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- <PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<el-button type="primary" size="small" @click="addEdit('add')">新增</el-button>
</template>
</PageTitle> -->
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
@ -91,7 +86,22 @@ import PageTitle from "@/components/aboutTable/PageTitle.vue";
import { qcckGet, qcckPost,qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_ZDQT_ZT,D_GS_ZDR_RYJB, D_BZ_XB,BD_BK_CLYJBQ, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_BK_SQLX, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } = proxy.$dict("D_GS_ZDQT_ZT","D_GS_ZDR_RYJB","D_BZ_XB","D_BZ_MZ","D_BZ_XZQHDM","D_GS_ZDR_BK_ZT","D_GS_ZDR_CZZT","D_GS_BQ_ZL","D_GS_BQ_LB","D_GS_BQ_LX","D_GS_BK_SSJZ","D_GS_BK_SQLX","D_BZ_SF","D_GS_XS_LY","D_BZ_SSZT","D_GS_XS_LX","D_GS_XS_QTLX","BD_BK_CLYJBQ","D_GS_ZDR_YJDJ");
const {
D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, BD_BK_CLYJBQ, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ,
// D_GS_BK_SQLX,
// D_BZ_SF,
// D_GS_XS_LY,
// D_BZ_SSZT,
// D_GS_XS_LX,
// D_GS_XS_QTLX
} = proxy.$dict("D_GS_ZDQT_ZT","D_GS_ZDR_RYJB","D_BZ_XB","D_BZ_MZ","D_BZ_XZQHDM","D_GS_ZDR_BK_ZT","D_GS_ZDR_CZZT","D_GS_BQ_ZL","D_GS_BQ_LB","D_GS_BQ_LX","D_GS_BK_SSJZ"
// ,"D_GS_BK_SQLX"
// ,"D_BZ_SF"
// ,"D_GS_XS_LY"
// ,"D_BZ_SSZT"
// ,"D_GS_XS_LX"
// ,"D_GS_XS_QTLX"
,"BD_BK_CLYJBQ","D_GS_ZDR_YJDJ");
const obj = ref({});
const showzxs = ref(false);
const zxsDilof = ref();

View File

@ -2,16 +2,13 @@
<div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<el-button type="primary" size="small" @click="addEdit('add')">新增</el-button>
<!-- <el-button type="danger" size="small" @click="handleRow()">批量删除</el-button> -->
</template>
</PageTitle>
<Search :searchArr="searchConfiger" @submit="onSearch" >
<el-button type="primary" size="small" @click="addEdit('add')">新增</el-button>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
@ -68,7 +65,26 @@ import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import { getItem } from "@/utils/storage.js";
const { proxy } = getCurrentInstance();
const { D_GS_ZDR_CZZT,D_GS_BK_SQLX, D_GS_ZDQT_FXDJ, D_GS_ZDR_RYJB, D_GS_ZDQT_LB, D_GS_ZDR_BK_ZT, D_GS_BQ_LX, D_GS_ZDQT_ZT, D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } = proxy.$dict("D_GS_ZDR_CZZT","D_GS_BK_SQLX", "D_GS_ZDQT_FXDJ", "D_GS_ZDR_RYJB", "D_GS_ZDQT_LB", "D_GS_ZDR_BK_ZT", "D_GS_BQ_LX", "D_GS_ZDQT_ZT", "D_BZ_SF", "D_BZ_XB", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX"); //获取字典数据
const {
D_GS_ZDR_CZZT,
// D_GS_BK_SQLX,
D_GS_ZDQT_FXDJ, D_GS_ZDR_RYJB, D_GS_ZDQT_LB, D_GS_ZDR_BK_ZT, D_GS_BQ_LX, D_GS_ZDQT_ZT,
// D_BZ_SF,
D_BZ_XB,
// D_GS_XS_LY,
// D_BZ_SSZT,
// D_GS_XS_LX,
// D_GS_XS_QTLX
} = proxy.$dict("D_GS_ZDR_CZZT"
// ,"D_GS_BK_SQLX"
, "D_GS_ZDQT_FXDJ", "D_GS_ZDR_RYJB", "D_GS_ZDQT_LB", "D_GS_ZDR_BK_ZT", "D_GS_BQ_LX", "D_GS_ZDQT_ZT"
// , "D_BZ_SF"
, "D_BZ_XB"
// , "D_GS_XS_LY"
// , "D_BZ_SSZT"
// , "D_GS_XS_LX"
// , "D_GS_XS_QTLX"
); //获取字典数据
const showzxs = ref(false);
const queryFrom = ref({});
const ids = ref([]);
@ -273,7 +289,7 @@ const deleteRow = (id) =>{
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 240;
window.onresize = function () {
tabHeightFn();
};

View File

@ -2,20 +2,14 @@
<div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<Search :searchArr="searchConfiger" @submit="onSearch">
<el-button type="primary" size="small" @click="addEdit('add')">新增</el-button>
<!-- <el-button type="danger" size="small" @click="handleRow()">批量删除</el-button> -->
</template>
</PageTitle>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<div class="margTop" style="padding: 0;">
<WarnDataTable :data="pageData.tableData" :columns="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:loading="pageData.tableConfiger.loading" @selection-change="chooseData">
<template #bqList="{ row }">
<ul>
<li class="one_text_detail marks mb4" :key="index" v-for="(item, index) in row.bqList">{{ item.bqMc }}({{
@ -25,9 +19,7 @@
<template #ryXb="{ row }">
<DictTag :tag="false" :value="row.ryXb" :options="D_BZ_XB" />
</template>
<template #ryJg="{ row }">
<DictTag :tag="false" :value="row.ryJg" :options="D_BZ_XZQHDM" />
</template>
<template #ryMz="{ row }">
<DictTag :tag="false" :value="row.ryMz" :options="D_BZ_MZ" />
</template>
@ -52,12 +44,13 @@
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="success" @click="handleSend(row.id)">移入</el-link>
<el-link size="small" type="success" @click="handleSend(row.id)">移入重点人</el-link>
<el-link size="small" type="success" @click="handleMoveToFocus(row.id)">移入关注库</el-link>
<el-link size="small" type="primary" @click="addEdit('edit', row)">编辑</el-link>
<el-link size="small" type="danger" @click="deleteRow(row.id)" v-if="isShiQzDelet">删除</el-link>
<el-link size="small" type="primary" @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
</WarnDataTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
@ -73,7 +66,7 @@
import { ElMessage } from "element-plus";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import AddForm from "@/views/backOfficeSystem/DeploymentDisposal/mpvPeo/components/addForm.vue";
@ -81,8 +74,23 @@ import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
import { getItem } from "@/utils/storage.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_BK_SQLX, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
proxy.$dict("D_GS_ZDQT_ZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_GS_ZDR_BK_ZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ", "D_GS_BK_SQLX", "D_BZ_SF", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX");
const {
D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ,
// D_GS_BK_SQLX,
// D_BZ_SF,
// D_GS_XS_LY,
// D_BZ_SSZT,
// D_GS_XS_LX,
// D_GS_XS_QTLX
} =
proxy.$dict("D_GS_ZDQT_ZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_GS_ZDR_BK_ZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ"
// , "D_GS_BK_SQLX"
// , "D_BZ_SF"
// , "D_GS_XS_LY"
// , "D_BZ_SSZT"
// , "D_GS_XS_LX"
// , "D_GS_XS_QTLX"
);
const obj = ref({});
const show = ref(false);
const addFormDiloag = ref();
@ -132,24 +140,25 @@ const pageData = reactive({
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 150,
controlsWidth: 340,
tableColumn: [
{ label: "姓名", prop: "ryXm", width: 150 },
{ label: "性别", prop: "ryXb", showSolt: true, width: 100 },
{ label: "籍贯", prop: "ryJg", showSolt: true, width: 100 },
{ label: "性别", prop: "ryXb", slotName: "ryXb" },
{ label: "籍贯", prop: "ryJg", width: 100 },
{ label: "身份证", prop: "rySfzh", width: 200 },
{ label: "民族", prop: "ryMz", showSolt: true, width: 100 },
{ label: "户籍地区划", prop: "hjdQh", showSolt: true, width: 150 },
{ label: "户籍派出所", prop: "hjdPcsmc", width: 200 },
{ label: "民族", prop: "ryMz", slotName: "ryMz" },
{ label: "户籍地区划", prop: "hjdQh", width: 150, slotName: "hjdQh" },
{ label: "户籍派出所", prop: "hjdPcsmc" },
{ label: "户籍地详址", prop: "hjdXz", width: 200 },
{ label: "审核状态", prop: "zdrZt", showSolt: true },
{ label: "审核状态", prop: "zdrZt", slotName: "zdrZt" },
{ label: "操作", prop: "controls", slotName: "controls", width: 280 },
]
});
const isShiQzDelet = ref(false)
onMounted(() => {
getList();
tabHeightFn();
const isShiQz = getItem('roleList').find(item => item.roleCode == 'JS_777777') != undefined
const isShiQz = getItem('roleList').find(item => item.roleCode == 'JS_777777') != undefined
if (isShiQz) isShiQzDelet.value = true
});
@ -193,7 +202,14 @@ const handleSend = (id) => {
})
};
const handleMoveToFocus = (id) => {
proxy.$confirm("确定要移至关注库?", "警告", { type: "warning" }).then(() => {
qcckPost({ id, rylx: '03' }, "/mosty-gsxt/tbGsxtZdry/rylxyd").then(() => {
proxy.$message({ type: "success", message: "移除成功" });
getList();
});
})
}
const chooseData = (data) => {
ids.value = Array.isArray(data) ? data.map((item) => item.id) : [];
choosList.value = Array.isArray(data) ? data : [];
@ -263,7 +279,7 @@ const addEdit = (type, row) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 270;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};

View File

@ -19,7 +19,7 @@ import { generateRandom10Digits } from '@/utils/tools'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
const { proxy } = getCurrentInstance();
const { D_ZFNR_MBLX } = proxy.$dict("D_ZFNR_MBLX")
// const { D_ZFNR_MBLX } = proxy.$dict("D_ZFNR_MBLX") // 未使用,已注释
const props = defineProps({
data: {
type: Object,

View File

@ -20,8 +20,8 @@
:class="activeSection === 'character-section' ? 'active' : ''">背景信息</li>
<li @click="scrollToSection('controlInfo-section')"
:class="activeSection === 'controlInfo-section' ? 'active' : ''" v-if="!butShow">管控信息</li>
<li @click="scrollToSection('featinfo-section')"
:class="activeSection === 'featinfo-section' ? 'active' : ''" v-if="!butShow">全要素布控</li>
<li @click="scrollToSection('featinfo-section')" :class="activeSection === 'featinfo-section' ? 'active' : ''"
v-if="!butShow">全要素布控</li>
<li @click="scrollToSection('demandsInfo-section')"
:class="activeSection === 'demandsInfo-section' ? 'active' : ''" v-if="!butShow">密切联系人</li>
<li @click="scrollToSection('requestInfo-section')"
@ -69,13 +69,13 @@
<div id="judgmentRecord-section" v-if="!butShow">
<VisitRecord ref="visitRecord" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
</div>
<div id="historyAssembly-section" v-if="!butShow" >
<div id="historyAssembly-section" v-if="!butShow">
<CaseInfo ref="caseInfo" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
</div>
<div id="joblogging-section" v-if="!butShow">
<ActualPerformance ref="actualPerformance" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
</div>
<div id="joblogging-joblog" v-if="!butShow" >
<div id="joblogging-joblog" v-if="!butShow">
<CzModel ref="czModel" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
</div>
</div>
@ -114,7 +114,7 @@ const showBut = ref(false)
const listQuery = ref({});
const butShow = ref(false)
const title = ref('新增')
const showData=ref(false)
const showData = ref(false)
// 初始化数据
const init = (type, row) => {
dialogForm.value = true;
@ -207,7 +207,7 @@ const submit = async () => {
info.value.throwData()
// personnelTags.value.throwData(),
]);
tbGsxtZdrySave({...infoData,rylx:'03'}).then(res => {
tbGsxtZdrySave({ ...infoData, rylx: '03' }).then(res => {
proxy.$message({
message: '新增成功',
type: 'success',
@ -221,7 +221,7 @@ const submit = async () => {
// 关闭
const close = () => {
if (route.query.id) {
if (route.query.id) {
const query = { ...route.query };
delete query.id;
router.replace({ query });

View File

@ -1,48 +1,21 @@
<template>
<div>
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<!-- <el-popover placement="bottom" :visible="visible" :width="400" trigger="click">
<template #reference>
<el-button type="primary" @click="(visible = !visible), (visiblefp = false)" size="small">布控申请</el-button>
</template>
<div class="flex just-center">
<el-button size="small" type="primary" v-for="it in D_GS_BK_SQLX" :key="it.dm"
@click="handleApplication(it)">{{ it.zdmc }}</el-button>
</div>
</el-popover> -->
<!-- <el-popover placement="bottom" :visible="visiblefp" :width="400" trigger="click">
<template #reference>
<el-button size="small" type="primary" @click="(visiblefp = !visiblefp), (visible = false)">指定分配</el-button>
</template>
<div>
<el-input readonly v-model="obj.fpmc" @click="chooseUserVisible = true" placeholder="请选择民警"></el-input>
<div class="flex just-center mt10">
<el-button @click="(visiblefp = false), (obj = {})" size="small">取消</el-button>
<el-button type="primary" @click="handlefp" size="small">分配</el-button>
</div>
</div>
</el-popover> -->
<!-- <el-button size="small" type="primary" @click="handleZxs">转线索</el-button> -->
<!-- <el-button size="small" type="primary" @click="handleMove">移交管控</el-button> -->
<!-- <el-button size="small" type="primary">导入</el-button> -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch">
<el-button type="primary" size="small" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</template>
</PageTitle>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<div class="margTop" style="padding: 0;">
<WarnDataTable :data="pageData.tableData" :columns="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:loading="pageData.tableConfiger.loading" @selection-change="chooseData">
<template #bqList="{ row }">
<ul>
<li class="one_text_detail marks mb4" :key="index" v-for="(item, index) in row.bqList">{{ item.bqMc }}({{
@ -80,7 +53,8 @@
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="success" @click="handleremove(row.id)"></el-link>
<el-link size="small" type="success" @click="handleremove(row.id)">入基础库</el-link>
<el-link size="small" type="success" @click="handleZdr(row.id)">移入重点人</el-link>
<el-link size="small" type="success" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@click="handleSend(row.id)">送审</el-link>
<el-link size="small" type="primary" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@ -88,14 +62,14 @@
<el-link size="small" type="primary" @click="addEdit('detail', row)">详情</el-link>
<el-link size="small" type="danger" @click="deleteRow(row.id)">删除</el-link>
</template>
</MyTable>
</WarnDataTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<!-- 详情 -->
<AddForm ref="addFormDiloag" @updateDate="getList"
<AddForm ref="addFormDiloag" @updateDate="getList" rylx="03"
:dic="{ D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ }" />
<!-- 选择用户 -->
<ChooseUser v-model="chooseUserVisible" @choosedUsers="handleUserSelected" :roleIds="roleIds" />
@ -110,18 +84,20 @@ import { ElMessage } from "element-plus";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import ZxsForm from "./components/zxsForm.vue";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import AddForm from "./components/addForm.vue";
// import AddForm from "./components/addForm.vue";
import AddForm from "@/views/backOfficeSystem/DeploymentDisposal/mpvPeo/components/addForm.vue";
// src\views\backOfficeSystem\DeploymentDisposal\mpvPeo\components\addForm.vue
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const { proxy } = getCurrentInstance();
const { D_ZDRGK_GKZT,D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_BK_SQLX, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
proxy.$dict('D_ZDRGK_GKZT',"D_GS_ZDQT_ZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_GS_ZDR_BK_ZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ", "D_GS_BK_SQLX", "D_BZ_SF", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX");
const { D_ZDRGK_GKZT, D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
proxy.$dict('D_ZDRGK_GKZT', "D_GS_ZDQT_ZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_GS_ZDR_BK_ZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ", "D_BZ_SF", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX");
const obj = ref({});
const showzxs = ref(false);
const zxsDilof = ref();
@ -174,28 +150,29 @@ const pageData = reactive({
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 250,
controlsWidth: 280,
tableColumn: [
{ label: "姓名", prop: "ryXm",width: 100 },
{ label: "性别", prop: "ryXb", showSolt: true, width: 80 },
{ label: "姓名", prop: "ryXm", width: 100 },
{ label: "性别", prop: "ryXb", slotName: "ryXb", width: 80 },
{ label: "身份证", prop: "rySfzh", width: 170 },
{ label: "民族", prop: "ryMz", showSolt: true, width: 80 },
{ label: "民族", prop: "ryMz", slotName: "ryMz", width: 80 },
{ label: "户籍派出所", prop: "hjdPcsmc" },
{ label: "标签", prop: "bqList", showSolt: true, showOverflowTooltip: true },
{ label: "标签", prop: "bqList", slotName: "bqList", showOverflowTooltip: true },
{ label: "管辖单位", prop: "gxSsbmmc" },
{ label: "管控状态", prop: "zdrBkZt", showOverflowTooltip: true,showSolt: true, width: 100 },
{ label: "审核状态", prop: "zdrZt", showSolt: true, width: 100 },
{ label: "管控状态", prop: "zdrBkZt", showOverflowTooltip: true, slotName: "zdrBkZt", width: 100 },
{ label: "审核状态", prop: "zdrZt", slotName: "zdrZt", width: 100 },
{ label: "入库时间", prop: "zdrRkkssj", },
{ label: "操作", prop: "controls", slotName: "controls", width: 300 },
]
});
onMounted(() => {
tabHeightFn();
tabHeightFn();
if (route.query.id) {
addEdit('x', {
id: route.query.id
})
}else{
} else {
getList();
}
});
@ -221,7 +198,7 @@ const getList = () => {
pageData.tableConfiger.loading = true;
// 人员类型D_ZDRY_RYLX(01 重点 02 普通〉
// rylx: '01',
let data = {...pageData.pageConfiger, ...queryFrom.value,rylx: '03' };
let data = { ...pageData.pageConfiger, ...queryFrom.value, rylx: '03' };
qcckGet(data, "/mosty-gsxt/tbGsxtZdry/selectPage").then((res) => {
pageData.tableData = res.records || [];
pageData.total = res.total;
@ -250,6 +227,14 @@ const handleremove = (id) => {
})
}
const handleZdr = (id) => {
proxy.$confirm("确定要移至重点人?", "警告", { type: "warning" }).then(() => {
qcckPost({ id, rylx: '01' }, "/mosty-gsxt/tbGsxtZdry/rylxyd").then(() => {
proxy.$message({ type: "success", message: "移除成功" });
getList();
});
})
}
const chooseData = (data) => {
ids.value = Array.isArray(data) ? data.map((item) => item.id) : [];
@ -328,7 +313,7 @@ const addEdit = (type, row) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};

View File

@ -40,7 +40,7 @@ import { ref, getCurrentInstance, onMounted } from 'vue'
import GdMap from "@/components/GdMap/index.vue";
const { proxy } = getCurrentInstance();
const { D_BZ_ZJLX } = proxy.$dict("D_BZ_ZJLX")
// const { D_BZ_ZJLX } = proxy.$dict("D_BZ_ZJLX") // 未使用,已注释
// 搜索表单
const searchForm = ref({

View File

@ -25,7 +25,7 @@ import CaseLodig from "../component/caseLodig.vue";
import { tbGsxtZdryAjxxSaveOrUpdateAjxx, tbGsxtZdryAjxx, tbGsxtZdryAjxxselectAjxx } from '@/api/zdr.js'
import { ElMessage, ElMessageBox } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_BZ_CLLX, D_BZ_CLYS, D_BZ_CLPP } = proxy.$dict("D_BZ_CLLX", "D_BZ_CLYS", "D_BZ_CLPP"); //获取字典数据
// const { D_BZ_CLLX, D_BZ_CLYS, D_BZ_CLPP } = proxy.$dict("D_BZ_CLLX", "D_BZ_CLYS", "D_BZ_CLPP"); // 未使用,已注释
const chooseMarksVisible = ref(false)
const props = defineProps({
dataList: {

View File

@ -2,10 +2,21 @@
<div>
<div class="headClass" style="">
<h3>密切联系人</h3>
<el-button type="primary" @click="openDialog('新增密切联系人', {}, true)" v-if="showBut">新增</el-button>
<el-button
type="primary"
@click="openDialog('新增密切联系人', {}, true)"
v-if="showBut"
>新增</el-button
>
</div>
<div class="headSelect">
<el-form :model="formData" :inline="true" ref="formRef" :rules="rulesForm" class="form-inline">
<el-form
:model="formData"
:inline="true"
ref="formRef"
:rules="rulesForm"
class="form-inline"
>
<el-form-item label="身份证号码">
<el-input v-model="formData.rySfzh" placeholder="请输入身份证号码" />
</el-form-item>
@ -16,177 +27,216 @@
</el-form-item>
</el-form>
</div>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="pageData.keyCount"
:tableConfiger="pageData.tableConfiger"
:controlsWidth="pageData.controlsWidth"
>
<template #dygx="{ row }">
<DictTag :tag="false" :value="row.dygx" :options="D_BZ_QSGXDM" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="danger" @click="delDictItem(row.id)">删除</el-link>
<el-link type="danger" @click="openDialog('修改密切联系人', row, false)">修改</el-link>
<el-link type="danger" @click="openDialog('修改密切联系人', row, false)"
>修改</el-link
>
</template>
</MyTable>
<diaLogForm v-model="dialogVisible" :data="diaLogRuleForm" @submit="addPersonOrModifica" :title="Tips"
:dict="{ D_BZ_QSGXDM }">
<diaLogForm
v-model="dialogVisible"
:data="diaLogRuleForm"
@submit="addPersonOrModifica"
:title="Tips"
:dict="{ D_BZ_QSGXDM }"
>
</diaLogForm>
</div>
</template>
<script setup>
import { identityCardRule } from "@/utils/rules"
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted, onUnmounted } from "vue";
import { identityCardRule } from "@/utils/rules";
import {
ref,
reactive,
watch,
toRaw,
getCurrentInstance,
onMounted,
onUnmounted
} from "vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import diaLogForm from "../component/diaLogForm.vue";
import { tbZdryClxxUpdate, tbGsxtZdryLxrsaveOrUpdateLxr,tbGsxtZdryLxrselectLxrBy ,tbGsxtZdryLxr} from '@/api/zdr.js'
import {
tbZdryClxxUpdate,
tbGsxtZdryLxrsaveOrUpdateLxr,
tbGsxtZdryLxrselectLxrBy,
tbGsxtZdryLxr
} from "@/api/zdr.js";
import { ElMessage, ElMessageBox } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_BZ_QSGXDM } = proxy.$dict("D_BZ_QSGXDM"); //获取字典数据
const props = defineProps({
dataList: {
type: Object,
default: () => { },
}, disabled: {
default: () => {}
},
disabled: {
type: Boolean,
default: false
},
showBut: {
type: Boolean,
default: false
},
})
const dialogVisible = ref(false)
const listData = ref({})
const Tips = ref("密切联系人")
}
});
const dialogVisible = ref(false);
const listData = ref({});
const Tips = ref("密切联系人");
// 表格数据
const pageData = reactive({
tableData: [],
tableColumn: [{
prop: 'ryXm',
label: '人员姓名',
}, {
prop: 'rySfzh',
label: '身份证号码',
}, {
prop: 'dygx',
label: '关系',
showSolt: true,
}, {
prop: 'lxrDh',
label: '联系电话',
}],
tableHeight: '200px',
tableColumn: [
{
prop: "ryXm",
label: "人员姓名"
},
{
prop: "rySfzh",
label: "身份证号码"
},
{
prop: "dygx",
label: "关系",
showSolt: true
},
{
prop: "lxrDh",
label: "联系电话"
}
],
tableHeight: "200px",
keyCount: 0,
tableConfiger: {
border: true,
stripe: true,
showHeader: true,
showIndex: true,
indexLabel: '序号',
indexLabel: "序号",
indexWidth: 60,
align: 'center',
align: "center",
showOverflowTooltip: true,
haveControls: !props.disabled
},
controlsWidth: 200,
})
controlsWidth: 200
});
// 表单数据
const formData = ref({
username: "",
ID: ""
})
const touchIn = ref(true)
const rulesForm = ref(identityCardRule({ validator: true }, 'rySfzh'))
const diaLogRuleForm = ref({})
watch(() => props.dataList, (val) => {
if (val) {
listData.value = val
getContact()
}
}, { deep: true })
});
const touchIn = ref(true);
const rulesForm = ref(identityCardRule({ validator: true }, "rySfzh"));
const diaLogRuleForm = ref({});
watch(
() => props.dataList,
(val) => {
if (val) {
listData.value = val;
getContact();
}
},
{ deep: true }
);
// 弹出增加或者修改弹窗
const openDialog = (type, formVal, bool) => {
touchIn.value = bool
dialogVisible.value = true
Tips.value = type
diaLogRuleForm.value = { ...formVal }
}
touchIn.value = bool;
dialogVisible.value = true;
Tips.value = type;
diaLogRuleForm.value = { ...formVal };
};
// 提交表单
const addPersonOrModifica = (val) => {
if (touchIn.value) {
const item = pageData.tableData.findIndex(item => item.rySfzh == val.rySfzh)
console.log(pageData.tableData);
const item = pageData.tableData.findIndex(
(item) => item.rySfzh == val.rySfzh
);
if (item != -1) {
proxy.$message({
message: '该人员已存在',
type: 'warning'
})
return
message: "该人员已存在",
type: "warning"
});
return;
}
}
const promes = {
...val,
zdryId: listData.value.id
}
tbGsxtZdryLxrsaveOrUpdateLxr(promes).then((res) => {
proxy.$message({
message: '操作成功',
type: 'success'
})
getContact()
}).catch((err) => {
proxy.$message({
message: '操作失败',
type: 'error'
})
});
}
const delDictItem = (val) => {
ElMessageBox.confirm(
'是否删除该联系人',
'提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
tbGsxtZdryLxr(val).then((res) => {
proxy.$message({
message: '删除成功',
type: 'success'
})
getContact()
}).catch((err) => {
};
tbGsxtZdryLxrsaveOrUpdateLxr(promes)
.then((res) => {
proxy.$message({
message: "操作成功",
type: "success"
});
getContact();
})
.catch((err) => {
proxy.$message({
message: "操作失败",
type: "error"
});
});
};
const delDictItem = (val) => {
ElMessageBox.confirm("是否删除该联系人", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
tbGsxtZdryLxr(val)
.then((res) => {
proxy.$message({
message: "删除成功",
type: "success"
});
getContact();
})
.catch((err) => {});
})
.catch(() => {
proxy.$message({
message: '删除失败',
type: 'info',
})
})
}
message: "删除失败",
type: "info"
});
});
};
const getContact = () => {
const promes = { zdryId: listData.value.id }
const promes = { zdryId: listData.value.id };
tbGsxtZdryLxrselectLxrBy(promes).then((res) => {
pageData.tableData = res
})
}
pageData.tableData = res;
});
};
const resetForm = () => {
formData.value = {}
getContact()
}
formData.value = {};
getContact();
};
const check = () => {
if (formData.value.rySfzh) {
// 模糊查询:检查身份证号码是否包含输入的内容
pageData.tableData = pageData.tableData.filter(item => item.rySfzh && item.rySfzh.includes(formData.value.rySfzh))
pageData.tableData = pageData.tableData.filter(
(item) => item.rySfzh && item.rySfzh.includes(formData.value.rySfzh)
);
} else {
// 如果输入为空,显示所有数据
getContact()
getContact();
}
}
};
// 抛出数据并验证标签列表不为空
const throwData = () => {
@ -197,10 +247,10 @@ const throwData = () => {
// }
resolve(pageData.tableData);
});
}
};
defineExpose({
throwData
})
});
</script>
<style lang="scss" scoped>
@ -211,8 +261,6 @@ defineExpose({
padding: 10px;
}
.left_box {
width: 200px;
border: 1px solid #c8c8c89a;
@ -287,8 +335,6 @@ defineExpose({
}
}
// .headClass::after {
// content: '';
// position: absolute;

View File

@ -76,37 +76,37 @@ const chooseMarksVisible = ref(false); // 控制标签选择弹窗显示
const roleIds = ref([]); // 已选择的标签ID
const formData = ref([
{ label: "人员照片", prop: "ryzp", type: "slot", width: "100%" },
{ label: "姓名", prop: "ryXm", type: "input" },
{ label: "性别", prop: "ryXb", type: "select", options: D_BZ_XB },
{ label: "身份证号", prop: "rySfzh", type: "input" },
{ label: "籍贯", prop: "ryJg", type: "select", options: D_BZ_XZQHDM },
{ label: "曾用名", prop: "cym", type: "input" },
{ label: "文化程度", prop: "whcdBm", type: "select", options: D_BZ_WHCD },
{ label: "民族", prop: "ryMz", type: "select", options: D_BZ_MZ },
{ label: "政治面貌", prop: "zzmm", type: "select", options: D_BZ_ZZMM },
{ label: "职业", prop: "zyBm", type: "select", options: D_ZDRY_ZYLB },
{ label: "人员级别", prop: "zdrRyjb", type: "select", options: D_GS_ZDR_RYJB },
{ label: "预警等级", prop: "zdrYjdj", type: "select", options: D_GS_ZDR_YJDJ },
{ label: "出生日期", prop: "ryCsrq", type: "date" },
{ label: "户籍地区划", prop: "hjdQh", type: "select", options: D_BZ_XZQHDM },
{ label: "户籍地详址", prop: "hjdXz", type: "input" },
{ label: "户籍地派出所", prop: "hjdPcsdm",depMc:"hjdPcsmc" ,type: "department" },
{ label: "现住地区划", prop: "xzdQh", type: "select", options: D_BZ_XZQHDM },
{ label: "现住地详址", prop: "xzdXz", type: "input" },
{ label: "现住地派出所", prop: "xzdPcsdm",depMc:"xzdPcsmc" ,type: "department" },
{ label: "管辖单位", prop: "gxSsbmdm", depMc: 'gxSsbmmc', type: "department" },
{ label: "诉求单位", prop: "sqSsbmdm", depMc: 'sqSsbmmc', type: "department" },
{ label: "责任单位", prop: "zrSsbmdm", depMc: 'zrSsbmmc', type: "department" },
{ label: "所属警种", prop: "zdrSsjz", type: "select", options: D_GS_BK_SSJZ },
{ label: "涉及警种", prop: "zdrSjjz", type: "select", options: D_GS_BK_SSJZ, multiple: true },
{ label: "婚姻状态", prop: "hyzk", type: "select", options: D_BZ_HYZK },
{ label: "姓名", prop: "ryXm", type: "input", width: "30%" },
{ label: "性别", prop: "ryXb", type: "select", options: D_BZ_XB, width: "30%" },
{ label: "身份证号", prop: "rySfzh", type: "input", width: "30%" },
{ label: "籍贯", prop: "ryJg", type: "select", options: D_BZ_XZQHDM, width: "30%" },
{ label: "曾用名", prop: "cym", type: "input", width: "30%" },
{ label: "文化程度", prop: "whcdBm", type: "select", options: D_BZ_WHCD, width: "30%" },
{ label: "民族", prop: "ryMz", type: "select", options: D_BZ_MZ, width: "30%" },
{ label: "政治面貌", prop: "zzmm", type: "select", options: D_BZ_ZZMM, width: "30%" },
{ label: "职业", prop: "zyBm", type: "select", options: D_ZDRY_ZYLB, width: "30%" },
{ label: "人员级别", prop: "zdrRyjb", type: "select", options: D_GS_ZDR_RYJB, width: "30%" },
{ label: "预警等级", prop: "zdrYjdj", type: "select", options: D_GS_ZDR_YJDJ, width: "30%" },
{ label: "出生日期", prop: "ryCsrq", type: "date", width: "30%" },
{ label: "户籍地区划", prop: "hjdQh", type: "select", options: D_BZ_XZQHDM, width: "30%" },
{ label: "户籍地详址", prop: "hjdXz", type: "input", width: "30%" },
{ label: "户籍地派出所", prop: "hjdPcsdm", depMc: "hjdPcsmc", type: "department", width: "30%" },
{ label: "现住地区划", prop: "xzdQh", type: "select", options: D_BZ_XZQHDM, width: "30%" },
{ label: "现住地详址", prop: "xzdXz", type: "input", width: "30%" },
{ label: "现住地派出所", prop: "xzdPcsdm", depMc: "xzdPcsmc", type: "department", width: "30%" },
{ label: "管辖单位", prop: "gxSsbmdm", depMc: 'gxSsbmmc', type: "department", width: "30%" },
{ label: "诉求单位", prop: "sqSsbmdm", depMc: 'sqSsbmmc', type: "department", width: "30%" },
{ label: "责任单位", prop: "zrSsbmdm", depMc: 'zrSsbmmc', type: "department", width: "30%" },
{ label: "所属警种", prop: "zdrSsjz", type: "select", options: D_GS_BK_SSJZ, width: "30%" },
{ label: "涉及警种", prop: "zdrSjjz", type: "select", options: D_GS_BK_SSJZ, multiple: true, width: "30%" },
{ label: "婚姻状态", prop: "hyzk", type: "select", options: D_BZ_HYZK, width: "30%" },
// { label: "处置状态", prop: "zdrCzzt", type: "select", options: D_GS_ZDR_CZZT },
// { label: "布控状态", prop: "zdrBkZt", type: "select", options: D_BZ_RCBKZT },
// { label: "人员类型", prop: "rylx", type: "select", options: D_ZDRY_RYLX },
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime" },
{ label: "入库结束时间", prop: "zdrRkjssj", type: "datetime" },
{ label: "Mac地址", prop: "macDz", type: "input" },
{ label: "联系电话", prop: "ryLxdh", type: "slot", width: "100%" },
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime", width: "30%" },
{ label: "入库结束时间", prop: "zdrRkjssj", type: "datetime", width: "30%" },
{ label: "Mac地址", prop: "macDz", type: "input", width: "30%" },
{ label: "联系电话", prop: "ryLxdh", type: "slot", width: "30%" },
// { label: "标签选择", prop: "tags", type: "slot", width: "100%" },
{ label: "管控原因", prop: "zdrLkyy", type: "textarea", width: "100%" },
]);
@ -171,17 +171,17 @@ const gettbGsxtZdryUpdate = () => {
}
elform.value.submit((data) => {
tbGsxtZdryUpdate(promes).then((res) => {
listQuery.value.ryzp = []
proxy.$message({
message: '更新成功',
type: 'success',
})
}).catch((err) => {
listQuery.value.ryzp = []
proxy.$message({
message: '更新成功',
type: 'success',
})
}).catch((err) => {
}).finally(() => {
loading.value = false
});
})
}).finally(() => {
loading.value = false
});
})

View File

@ -10,7 +10,6 @@
<div class="form_cnt">
<FormMessage :disabled="disabled" v-model="listQuery" :formList="formData" labelWidth="100px" ref="elform"
:rules="rules">
</FormMessage>
</div>
</div>
@ -124,9 +123,9 @@ const getDataById = (id) => {
// 提交
const submit = () => {
elform.value.submit((data) => {
data.fjdz = data.fjdz?.join(",");
let url = title.value == "新增" ? "/mosty-gsxt/tbGsxtZdcl/add" : "/mosty-gsxt/tbGsxtZdcl/update";
let params = { ...data };
params.fjdz = data.fjdz?.join(",");
loading.value = true;
qcckPost(params, url).then(() => {
loading.value = false;

View File

@ -3,10 +3,17 @@
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
<Search :searchArr="searchConfiger" @submit="onSearch">
<el-button type="primary" size="small" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</Search>
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<!-- <PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left> -->
<!-- <el-popover placement="bottom" :visible="visible" :width="400" trigger="click">
<template #reference>
<el-button type="primary" @click="(visible = !visible), (visiblefp = false)" size="small">布控申请</el-button>
@ -30,16 +37,11 @@
</el-popover>
<el-button size="small" type="primary" @click="handleZxs">转线索</el-button>
<el-button size="small" type="primary" @click="handleMove">移交管控</el-button> -->
<el-button type="primary" size="small" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</template>
</PageTitle>
<!-- </template>
</PageTitle> -->
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
@ -191,8 +193,8 @@ const pageData = reactive({
{ label: "车架号", prop: "clCjh" },
{ label: "车辆颜色", prop: "clYs", showOverflowTooltip: true },
{ label: "车辆所有人", prop: "clSyr" },
{ label: "管辖单位", prop: "gxSsbmmc", showSolt: true },
{ label: "管控民警姓名", prop: "gkMjXm", showSolt: true },
{ label: "管辖单位", prop: "gxSsbmmc"},
{ label: "管控民警姓名", prop: "gkMjXm"},
// { label: "状态", prop: "xtSjzt", showSolt: true },
// { label: "审核状态", prop: "zdrZt", showSolt: true },
]
@ -315,7 +317,7 @@ const addEdit = (type, row) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};

View File

@ -17,7 +17,7 @@
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { reactive, ref,getCurrentInstance } from 'vue';
const { proxy } = getCurrentInstance();
const { D_BZ_XB } = proxy.$dict("D_BZ_XB"); // 获取字典数据
// const { D_BZ_XB } = proxy.$dict("D_BZ_XB"); // 未使用,已注释
const elform = ref()
const showDialog = ref(false)
const emit = defineEmits(['change'])

View File

@ -3,46 +3,17 @@
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<!-- <el-popover placement="bottom" :visible="visible" :width="400" trigger="click">
<template #reference>
<el-button type="primary" @click="(visible = !visible), (visiblefp = false)" size="small">布控申请
</el-button>
</template>
<div class="flex just-center">
<el-button size="small" type="primary" v-for="it in D_GS_BK_SQLX" :key="it.dm"
@click="handleApplication(it)">{{ it.zdmc }}</el-button>
</div>
</el-popover>
<el-popover placement="bottom" :visible="visiblefp" :width="400" trigger="click">
<template #reference>
<el-button size="small" type="primary" @click="(visiblefp = !visiblefp), (visible = false)">指定分配</el-button>
</template>
<div>
<el-input readonly v-model="obj.fpmc" @click="chooseUserVisible = true" placeholder="请选择民警"></el-input>
<div class="flex just-center mt10">
<el-button @click="(visiblefp = false), (obj = {})" size="small">取消</el-button>
<el-button type="primary" @click="handlefp" size="small">分配</el-button>
</div>
</div>
</el-popover>
<el-button size="small" type="primary" @click="handleZxs">转线索</el-button>
<el-button size="small" type="primary" @click="handleMove">移交管控</el-button> -->
<!-- <el-button size="small" type="primary" >导入</el-button> -->
<el-button type="primary" size="small" @click="addEdit('add', null)">
<Search :searchArr="searchConfiger" @submit="onSearch" >
<el-button type="primary" size="small" @click="addEdit('add', null)">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</template>
</PageTitle>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData" fixed="right">
@ -99,7 +70,7 @@ import { ElMessage } from "element-plus";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { getItem } from "@/utils/storage.js";
const { proxy } = getCurrentInstance();
const { D_GS_ZDR_CZZT, D_GS_BK_SQLX, D_GS_ZDQT_FXDJ, D_GS_ZDR_RYJB, D_GS_ZDQT_LB, D_GS_ZDR_BK_ZT, D_GS_BQ_LX, D_GS_ZDQT_ZT, D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } = proxy.$dict("D_GS_ZDR_CZZT", "D_GS_BK_SQLX", "D_GS_ZDQT_FXDJ", "D_GS_ZDR_RYJB", "D_GS_ZDQT_LB", "D_GS_ZDR_BK_ZT", "D_GS_BQ_LX", "D_GS_ZDQT_ZT", "D_BZ_SF", "D_BZ_XB", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX"); //获取字典数据
const { D_GS_ZDR_CZZT, /* D_GS_BK_SQLX, */ D_GS_ZDQT_FXDJ, D_GS_ZDR_RYJB, D_GS_ZDQT_LB, D_GS_ZDR_BK_ZT, D_GS_BQ_LX, D_GS_ZDQT_ZT, D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } = proxy.$dict("D_GS_ZDR_CZZT", /* "D_GS_BK_SQLX", */ "D_GS_ZDQT_FXDJ", "D_GS_ZDR_RYJB", "D_GS_ZDQT_LB", "D_GS_ZDR_BK_ZT", "D_GS_BQ_LX", "D_GS_ZDQT_ZT", "D_BZ_SF", "D_BZ_XB", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX"); //获取字典数据
const showzxs = ref(false);
const queryFrom = ref({});
const ids = ref([]);
@ -317,7 +288,7 @@ const deleteRow = (id) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};

View File

@ -3,10 +3,17 @@
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
<Search :searchArr="searchConfiger" @submit="onSearch" >
<el-button type="primary" size="small" @click="addEdit('add', null)">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</Search>
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<!-- <PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left> -->
<!-- <el-popover placement="bottom" :visible="visible" :width="400" trigger="click">
<template #reference>
<el-button type="primary" @click="(visible = !visible), (visiblefp = false)" size="small">布控申请
@ -30,16 +37,11 @@
</el-popover>
<el-button size="small" type="primary" @click="handleZxs">转线索</el-button>
<el-button size="small" type="primary" @click="handleMove">移交管控</el-button> -->
<el-button type="primary" size="small" @click="addEdit('add', null)">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</template>
</PageTitle>
<!-- </template>
</PageTitle> -->
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"

View File

@ -3,80 +3,239 @@
<div class="head_box">
<span class="title">{{ title }}重点人管理</span>
<div>
<el-button type="primary" size="small" v-if="butShow" :loading="loading" @click="submit">保存</el-button>
<el-button
type="primary"
size="small"
v-if="butShow"
:loading="loading"
@click="submit"
>保存</el-button
>
<el-button
type="primary"
size="small"
v-if="showAuditShBtn && showButData"
@click="openAuditDialog('sh')"
>审核</el-button
>
<el-button
type="primary"
size="small"
v-if="showAuditSpBtn && showButData"
@click="openAuditDialog('sp')"
>审批</el-button
>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<AuditDialog
v-model="auditDialogVisible"
:title="auditTitle"
:formData="auditForm"
:rules="auditRules"
:reasonProp="auditReasonProp"
:loading="auditLoading"
:dictEnum="D_BZ_SF"
@cancel="handleAuditCancel"
@submit="handleAuditSubmit"
/>
<div class="form_cnt flex just-between">
<div class="left_box">
<ul class="anchor-list">
<li @click="scrollToSection('info-section')" :class="activeSection === 'info-section' ? 'active' : ''">人员信息
<li
@click="scrollToSection('info-section')"
:class="activeSection === 'info-section' ? 'active' : ''"
>
人员信息
</li>
<li
@click="scrollToSection('backinfo-section')"
:class="activeSection === 'backinfo-section' ? 'active' : ''"
>
人员标签
</li>
<li
@click="scrollToSection('groupLabels-section')"
:class="activeSection === 'groupLabels-section' ? 'active' : ''"
v-if="!butShow"
>
关联车辆
</li>
<li
@click="scrollToSection('character-section')"
:class="activeSection === 'character-section' ? 'active' : ''"
>
背景信息
</li>
<li
@click="scrollToSection('controlInfo-section')"
:class="activeSection === 'controlInfo-section' ? 'active' : ''"
v-if="!butShow"
>
管控信息
</li>
<li
@click="scrollToSection('featinfo-section')"
:class="activeSection === 'featinfo-section' ? 'active' : ''"
v-if="!butShow"
>
全要素布控
</li>
<li
@click="scrollToSection('demandsInfo-section')"
:class="activeSection === 'demandsInfo-section' ? 'active' : ''"
v-if="!butShow"
>
密切联系人
</li>
<li
@click="scrollToSection('requestInfo-section')"
:class="activeSection === 'requestInfo-section' ? 'active' : ''"
v-if="!butShow"
>
动态轨迹
</li>
<li
@click="scrollToSection('personnel-section')"
:class="activeSection === 'personnel-section' ? 'active' : ''"
v-if="!butShow"
>
行为信息
</li>
<li
@click="scrollToSection('judgmentRecord-section')"
:class="activeSection === 'judgmentRecord-section' ? 'active' : ''"
v-if="!butShow"
>
走访记录
</li>
<li
@click="scrollToSection('historyAssembly-section')"
:class="activeSection === 'historyAssembly-section' ? 'active' : ''"
v-if="!butShow"
>
案件信息
</li>
<li
@click="scrollToSection('joblogging-section')"
:class="activeSection === 'joblogging-section' ? 'active' : ''"
v-if="!butShow"
>
现实表现
</li>
<li
@click="scrollToSection('joblogging-joblog')"
:class="activeSection === 'joblogging-joblog' ? 'active' : ''"
v-if="!butShow"
>
操作日志
</li>
<li @click="scrollToSection('backinfo-section')"
:class="activeSection === 'backinfo-section' ? 'active' : ''">人员标签</li>
<li @click="scrollToSection('groupLabels-section')"
:class="activeSection === 'groupLabels-section' ? 'active' : ''" v-if="!butShow">关联车辆</li>
<li @click="scrollToSection('character-section')"
:class="activeSection === 'character-section' ? 'active' : ''">背景信息</li>
<li @click="scrollToSection('controlInfo-section')"
:class="activeSection === 'controlInfo-section' ? 'active' : ''" v-if="!butShow">管控信息</li>
<li @click="scrollToSection('featinfo-section')"
:class="activeSection === 'featinfo-section' ? 'active' : ''" v-if="!butShow">全要素布控</li>
<li @click="scrollToSection('demandsInfo-section')"
:class="activeSection === 'demandsInfo-section' ? 'active' : ''" v-if="!butShow">密切联系人</li>
<li @click="scrollToSection('requestInfo-section')"
:class="activeSection === 'requestInfo-section' ? 'active' : ''" v-if="!butShow">动态轨迹</li>
<li @click="scrollToSection('personnel-section')"
:class="activeSection === 'personnel-section' ? 'active' : ''" v-if="!butShow">行为信息</li>
<li @click="scrollToSection('judgmentRecord-section')"
:class="activeSection === 'judgmentRecord-section' ? 'active' : ''" v-if="!butShow">走访记录</li>
<li @click="scrollToSection('historyAssembly-section')"
:class="activeSection === 'historyAssembly-section' ? 'active' : ''" v-if="!butShow">案件信息</li>
<li @click="scrollToSection('joblogging-section')"
:class="activeSection === 'joblogging-section' ? 'active' : ''" v-if="!butShow">现实表现</li>
<li @click="scrollToSection('joblogging-joblog')"
:class="activeSection === 'joblogging-joblog' ? 'active' : ''" v-if="!butShow">操作日志</li>
</ul>
</div>
<div class="right_box" ref="rightBox">
<div id="info-section">
<Info ref="info" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<Info
ref="info"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
@close="close"
/>
</div>
<div id="backinfo-section">
<PersonnelTags ref="personnelTags" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<PersonnelTags
ref="personnelTags"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="groupLabels-section" v-if="!butShow">
<Vehicle ref="vehicle" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<Vehicle
ref="vehicle"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="character-section">
<BackInfo ref="backInfo" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<BackInfo
ref="backInfo"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="controlInfo-section" v-if="!butShow">
<ControlInfo ref="controlInfo" title="重点人" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<ControlInfo
ref="controlInfo"
title="重点人"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="featinfo-section" v-if="!butShow">
<Deployment ref="deployment" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<Deployment
ref="deployment"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="demandsInfo-section" v-if="!butShow">
<Contact ref="contact" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<Contact
ref="contact"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="requestInfo-section" v-if="!butShow">
<DynamicTrajectory ref="dynamicTrajectory" :disabled="disabled" :showBut="showBut" />
<DynamicTrajectory
ref="dynamicTrajectory"
:disabled="disabled"
:showBut="showBut"
/>
</div>
<div id="personnel-section" v-if="!butShow">
<BehaviorInfo ref="behaviorInfo" :disabled="disabled" :showBut="showBut" />
<BehaviorInfo
ref="behaviorInfo"
:disabled="disabled"
:showBut="showBut"
/>
</div>
<div id="judgmentRecord-section" v-if="!butShow">
<VisitRecord ref="visitRecord" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<VisitRecord
ref="visitRecord"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="historyAssembly-section" v-if="!butShow" >
<CaseInfo ref="caseInfo" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<div id="historyAssembly-section" v-if="!butShow">
<CaseInfo
ref="caseInfo"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="joblogging-section" v-if="!butShow">
<ActualPerformance ref="actualPerformance" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<ActualPerformance
ref="actualPerformance"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
<div id="joblogging-joblog" v-if="!butShow" >
<CzModel ref="czModel" :disabled="disabled" :showBut="showBut" :dataList="listQuery" />
<div id="joblogging-joblog" v-if="!butShow">
<CzModel
ref="czModel"
:disabled="disabled"
:showBut="showBut"
:dataList="listQuery"
/>
</div>
</div>
</div>
@ -87,73 +246,107 @@
import { getItem } from "@/utils/storage";
import { qcckGet, qcckPost, qcckPut } from "@/api/qcckApi.js";
import { tbGsxtZdrySelectVoById, tbGsxtZdrySave } from "@/api/zdr.js";
import ControlInfo from '../../mpvGroup/model/controlInfo.vue'
import AuditDialog from "./auditDialog.vue";
import ControlInfo from "../../mpvGroup/model/controlInfo.vue";
import Info from "../model/info.vue";
import PersonnelTags from '../model/personnelTags.vue'
import Vehicle from '../model/vehicle.vue'
import BackInfo from '../model/bakInfo.vue'
import Deployment from '../model/deployment.vue'
import Contact from '../model/contact.vue'
import DynamicTrajectory from '../model/dynamicTrajectory.vue'
import BehaviorInfo from '../model/behaviorInfo.vue'
import VisitRecord from '../model/visitRecord.vue'
import CaseInfo from '../model/caseInfo.vue'
import ActualPerformance from '../model/actualPerformance.vue'
import CzModel from '../model/czModel.vue'
import { useRouter, useRoute } from 'vue-router'
import { ref, onUnmounted, getCurrentInstance } from "vue";
const router = useRouter()
const route = useRoute()
import PersonnelTags from "../model/personnelTags.vue";
import Vehicle from "../model/vehicle.vue";
import BackInfo from "../model/bakInfo.vue";
import Deployment from "../model/deployment.vue";
import Contact from "../model/contact.vue";
import DynamicTrajectory from "../model/dynamicTrajectory.vue";
import BehaviorInfo from "../model/behaviorInfo.vue";
import VisitRecord from "../model/visitRecord.vue";
import CaseInfo from "../model/caseInfo.vue";
import ActualPerformance from "../model/actualPerformance.vue";
import CzModel from "../model/czModel.vue";
import { useRouter, useRoute } from "vue-router";
import { ref, onUnmounted, getCurrentInstance, computed, reactive } from "vue";
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
const { D_BZ_SF } = proxy.$dict("D_BZ_SF");
const emit = defineEmits(["updateDate"]);
const chooseMarksVisible = ref(false);
const dialogForm = ref(false); //弹窗
const loading = ref(false);
const disabled = ref(false)
const showBut = ref(false)
const disabled = ref(false);
const showBut = ref(false);
const listQuery = ref({});
const butShow = ref(false)
const title = ref('新增')
const showData = ref(false)
const butShow = ref(false);
const title = ref("新增");
const showData = ref(false);
const modeType = ref("detail");
const currentRowId = ref("");
const auditDialogVisible = ref(false);
const auditLoading = ref(false);
const auditForm = reactive({
id: "",
sftg: undefined,
shBtgyy: "",
spBtgyy: ""
});
const auditRules = reactive({
sftg: [{ required: true, message: "请选择是否通过", trigger: "change" }],
shBtgyy: [{ required: true, message: "请输入不通过原因", trigger: "blur" }],
spBtgyy: [{ required: true, message: "请输入不通过原因", trigger: "blur" }]
});
const auditTitle = computed(() => (modeType.value === "sp" ? "审批" : "审核"));
const auditReasonProp = computed(() =>
modeType.value === "sp" ? "spBtgyy" : "shBtgyy"
);
const showAuditShBtn = computed(
() => modeType.value === "detail" && dataListQuery.value?.zdrZt == "02"
);
const showAuditSpBtn = computed(
() => modeType.value === "detail" && dataListQuery.value?.zdrZt == "04"
);
const props = defineProps({
rylx: {
type: String,
default: '01'
default: "01"
},
showButData: {
type: Boolean,
default: false
}
})
});
const dataListQuery = ref({});
// 初始化数据
const init = (type, row) => {
dialogForm.value = true;
if (type == 'add') {
butShow.value = true
title.value = '新增'
disabled.value = false
showBut.value = false
modeType.value = type;
currentRowId.value = row?.id || "";
if (type == "add") {
butShow.value = true;
title.value = "新增";
disabled.value = false;
showBut.value = false;
listQuery.value = {};
} else {
butShow.value = false
tbGsxtZdrySelectVoById({ id: row.id }).then(res => {
listQuery.value = { ...res }
})
if (type == 'edit') {
showBut.value = true
disabled.value = false
title.value = '编辑'
butShow.value = false;
dataListQuery.value = { ...row };
tbGsxtZdrySelectVoById({ id: row.id }).then((res) => {
listQuery.value = { ...res };
});
if (type == "edit") {
showBut.value = true;
disabled.value = false;
title.value = "编辑";
} else if (type == "del") {
disabled.value = true
showBut.value = false
title.value = '删除'
}
else {
disabled.value = true
showBut.value = false
title.value = '详情'
disabled.value = true;
showBut.value = false;
title.value = "删除";
} else {
disabled.value = true;
showBut.value = false;
title.value = "详情";
}
}
};
const activeSection = ref('info-section')
const rightBox = ref(null)
const activeSection = ref("info-section");
const rightBox = ref(null);
// 滚动到指定区域
const scrollToSection = (sectionId) => {
const element = document.getElementById(sectionId);
@ -162,21 +355,30 @@ const scrollToSection = (sectionId) => {
const elementTop = element.offsetTop;
rightBox.value.scrollTo({
top: elementTop - 150, // 减去一些偏移量,让内容更好看
behavior: 'smooth' // 平滑滚动
behavior: "smooth" // 平滑滚动
});
activeSection.value = sectionId;
}
}
};
// 监听滚动,更新当前激活的锚点
const handleScroll = () => {
if (!rightBox.value) return;
const scrollPosition = rightBox.value.scrollTop + 50;
const sections = [
'info-section', 'backinfo-section', 'groupLabels-section',
'character-section', 'controlInfo-section', 'featinfo-section',
'demandsInfo-section', 'requestInfo-section', 'personnel-section',
'judgmentRecord-section', 'historyAssembly-section', 'joblogging-section', "czModel-section"
"info-section",
"backinfo-section",
"groupLabels-section",
"character-section",
"controlInfo-section",
"featinfo-section",
"demandsInfo-section",
"requestInfo-section",
"personnel-section",
"judgmentRecord-section",
"historyAssembly-section",
"joblogging-section",
"czModel-section"
];
for (let i = sections.length - 1; i >= 0; i--) {
@ -186,26 +388,26 @@ const handleScroll = () => {
break;
}
}
}
};
// 监听右侧区域的滚动事件
if (typeof window !== 'undefined') {
window.addEventListener('load', () => {
if (typeof window !== "undefined") {
window.addEventListener("load", () => {
if (rightBox.value) {
rightBox.value.addEventListener('scroll', handleScroll);
rightBox.value.addEventListener("scroll", handleScroll);
}
});
// 组件卸载时移除事件监听
onUnmounted(() => {
if (rightBox.value) {
rightBox.value.removeEventListener('scroll', handleScroll);
rightBox.value.removeEventListener("scroll", handleScroll);
}
});
}
const info = ref()
const personnelTags = ref()
const info = ref();
const personnelTags = ref();
// 提交
const submit = async () => {
// 使用Promise.all处理所有子组件的验证和数据获取
@ -213,21 +415,62 @@ const submit = async () => {
info.value.throwData()
// personnelTags.value.throwData(),
]);
tbGsxtZdrySave({...infoData,rylx:props.rylx}).then(res => {
tbGsxtZdrySave({ ...infoData, rylx: props.rylx }).then((res) => {
proxy.$message({
message: '新增成功',
type: 'success',
})
close()
})
message: "新增成功",
type: "success"
});
close();
});
console.log(infoData);
};
const butzt = ref();
const openAuditDialog = (type) => {
// modeType.value = type;
butzt.value = type;
auditForm.id = currentRowId.value || listQuery.value?.id || "";
auditForm.sftg = undefined;
auditForm.shBtgyy = "";
auditForm.spBtgyy = "";
auditDialogVisible.value = true;
};
const handleAuditCancel = () => {
auditDialogVisible.value = false;
auditLoading.value = false;
// modeType.value = "detail";
auditForm.id = "";
auditForm.sftg = undefined;
auditForm.shBtgyy = "";
auditForm.spBtgyy = "";
};
const handleAuditSubmit = () => {
auditLoading.value = true;
const url =
butzt.value === "sp"
? "/mosty-gsxt/tbGsxtZdry/updateSp"
: "/mosty-gsxt/tbGsxtZdry/updateSh";
const successMsg = modeType.value === "sp" ? "审批成功" : "审核成功";
qcckPost(auditForm, url)
.then(() => {
proxy.$message({
message: successMsg,
type: "success"
});
auditDialogVisible.value = false;
modeType.value = "detail";
close();
})
.catch(() => {
auditLoading.value = false;
});
};
// 关闭
const close = () => {
if (route.query.id) {
if (route.query.id) {
const query = { ...route.query };
delete query.id;
router.replace({ query });
@ -235,7 +478,15 @@ const close = () => {
dialogForm.value = false;
loading.value = false;
emit('updateDate')
auditLoading.value = false;
auditDialogVisible.value = false;
modeType.value = "detail";
currentRowId.value = "";
auditForm.id = "";
auditForm.sftg = undefined;
auditForm.shBtgyy = "";
auditForm.spBtgyy = "";
emit("updateDate");
};
defineExpose({ init });
@ -246,7 +497,6 @@ defineExpose({ init });
@import "~@/assets/css/element-plus.scss";
.behaviorInfo {
margin: 0 0 10px 0;
// padding-bottom: 10px;
border-bottom: 2px solid #409eff;
@ -257,7 +507,6 @@ defineExpose({ init });
font-weight: 600;
color: #303133;
}
}
.textContent {
@ -346,7 +595,7 @@ defineExpose({ init });
scrollbar-color: #999 #f1f1f1;
}
::v-deep .el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
::v-deep .el-tabs--card > .el-tabs__header .el-tabs__item.is-active {
color: #0072ff;
background: rgba(0, 114, 255, 0.3);
}
@ -428,7 +677,7 @@ defineExpose({ init });
}
.anchor-list li.active::before {
content: '';
content: "";
position: absolute;
left: 0;
top: 0;
@ -446,7 +695,7 @@ defineExpose({ init });
// border: 1px solid #ebeef5;
border-radius: 6px;
.right_box>div {
.right_box > div {
background-color: #f8f9fa;
border-radius: 6px;
padding: 20px;
@ -454,7 +703,7 @@ defineExpose({ init });
margin-bottom: 10px;
}
.right_box>div:hover {
.right_box > div:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
@ -469,7 +718,7 @@ defineExpose({ init });
}
.right_box h3::after {
content: '';
content: "";
position: absolute;
left: 0;
bottom: -2px;
@ -527,6 +776,6 @@ defineExpose({ init });
}
::v-deep .avatar-uploader {
display: flex
display: flex;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<el-dialog :model-value="modelValue" :title="title" width="500px" @update:model-value="handleModelValueChange"
@close="handleCancel">
<el-form :model="formData" ref="elAuditForm" label-width="100px" :rules="rules" style="width: 100%;">
<el-form-item label="是否通过" prop="sftg" class="mt10 mb10">
<MOSTY.Select filterable v-model="formData.sftg" :dictEnum="dictEnum" style="width: 100%;" clearable
placeholder="请选择是否通过" />
</el-form-item>
<el-form-item label="不通过原因" :prop="reasonProp" v-if="formData.sftg == 0">
<MOSTY.Other style="width: 100%;" clearable v-model="formData[reasonProp]" type="textarea"
placeholder="请输入不通过原因" />
</el-form-item>
</el-form>
<template #footer>
<div class="flex just-center">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit" v-loading="loading">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index";
import { ref } from "vue";
defineProps({
modelValue: {
type: Boolean,
default: false
},
title: {
type: String,
default: "审核"
},
formData: {
type: Object,
default: () => ({})
},
rules: {
type: Object,
default: () => ({})
},
reasonProp: {
type: String,
default: "shBtgyy"
},
loading: {
type: Boolean,
default: false
},
dictEnum: {
type: Array,
default: () => []
}
});
const emit = defineEmits(["update:modelValue", "cancel", "submit"]);
const elAuditForm = ref();
const handleModelValueChange = (val) => {
emit("update:modelValue", val);
};
const handleCancel = () => {
emit("cancel");
};
const handleSubmit = () => {
elAuditForm.value.validate((valid) => {
if (!valid) return;
emit("submit");
});
};
</script>

View File

@ -1,52 +1,36 @@
<template>
<div>
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<!-- <el-popover placement="bottom" :visible="visible" :width="400" trigger="click">
<template #reference>
<el-button type="primary" @click="(visible = !visible), (visiblefp = false)" size="small">布控申请</el-button>
</template>
<div class="flex just-center">
<el-button size="small" type="primary" v-for="it in D_GS_BK_SQLX" :key="it.dm"
@click="handleApplication(it)">{{ it.zdmc }}</el-button>
</div>
</el-popover> -->
<!-- <el-popover placement="bottom" :visible="visiblefp" :width="400" trigger="click">
<template #reference>
<el-button size="small" type="primary" @click="(visiblefp = !visiblefp), (visible = false)">指定分配</el-button>
</template>
<div>
<el-input readonly v-model="obj.fpmc" @click="chooseUserVisible = true" placeholder="请选择民警"></el-input>
<div class="flex just-center mt10">
<el-button @click="(visiblefp = false), (obj = {})" size="small">取消</el-button>
<el-button type="primary" @click="handlefp" size="small">分配</el-button>
</div>
</div>
</el-popover> -->
<!-- <el-button size="small" type="primary" @click="handleZxs">转线索</el-button> -->
<!-- <el-button size="small" type="primary" @click="handleMove">移交管控</el-button> -->
<!-- <el-button size="small" type="primary">导入</el-button> -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch">
<el-button type="primary" size="small" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</template>
</PageTitle>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<div class="margTop" style="padding: 0">
<WarnDataTable
:data="pageData.tableData"
:columns="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:loading="pageData.tableConfiger.loading"
@selection-change="chooseData"
>
<template #bqList="{ row }">
<ul>
<li class="one_text_detail marks mb4" :key="index" v-for="(item, index) in row.bqList">{{ item.bqMc }}({{
item.bqFz || 0 }} ) </li>
<li
:style="{ background: Bqys(item.bqYs) }"
class="one_text_detail marks mb4"
:key="index"
v-for="(item, index) in row.bqList"
>
{{ item.bqMc }}({{ item.bqFz || 0 }} )
</li>
</ul>
</template>
<template #ryXb="{ row }">
@ -65,7 +49,7 @@
<DictTag :tag="false" :value="row.zdrRyjb" :options="D_GS_ZDR_RYJB" />
</template>
<template #zdrBkZt="{ row }">
<DictTag :tag="false" :value="row.zdrBkZt" :options="D_ZDRGK_GKZT" />
<DictTag :tag="false" :value="row.zdrBkZt" :options="D_BZ_RCBKZT" />
</template>
<template #zdrCzzt="{ row }">
<DictTag :tag="false" :value="row.zdrCzzt" :options="D_GS_ZDR_CZZT" />
@ -73,35 +57,101 @@
<template #zdrZt="{ row }">
<DictTag :tag="false" :value="row.zdrZt" :options="D_GS_ZDQT_ZT" />
</template>
<template #zdrSsjz="{ row }">
<DictTag :tag="false" :value="row.zdrSsjz" :options="D_GS_BK_SSJZ" />
</template>
<template #zdrSjjz="{ row }">
<DictTag :tag="false" :value="row.zdrSjjz" :options="D_GS_BK_SSJZ" />
</template>
<template #xtSjzt="{ row }">
<div> {{ row.xtSjzt == 0 ? "注销" : row.xtSjzt == 1 ? "正常" : "封存" }}</div>
<div>
{{ row.xtSjzt == 0 ? "注销" : row.xtSjzt == 1 ? "正常" : "封存" }}
</div>
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="success" @click="handleremove(row.id)"></el-link>
<el-link size="small" type="success" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@click="handleSend(row.id)">送审</el-link>
<el-link size="small" type="primary" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@click="addEdit('edit', row)">编辑</el-link>
<el-link size="small" type="primary" @click="addEdit('detail', row)">详情</el-link>
<el-link size="small" type="danger" @click="deleteRow(row.id)">删除</el-link>
<!-- <el-link size="small" type="success" @click="handleremove(row.id)">至关注库</el-link> -->
<el-link
size="small"
type="success"
@click="handleMoveToFocus(row.id)"
>移入关注库</el-link
>
<el-link size="small" type="success" @click="handleremove(row.id)"
>移入基础库</el-link
>
<el-link
size="small"
type="success"
v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@click="handleSend(row.id)"
>送审</el-link
>
<el-link
size="small"
type="primary"
v-if="row.zdrZt == '01' || row.zdrZt == '03'"
@click="addEdit('edit', row)"
>编辑</el-link
>
<el-link size="small" type="primary" @click="addEdit('detail', row)"
>详情</el-link
>
<el-link size="small" type="danger" @click="deleteRow(row.id)"
>删除</el-link
>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</WarnDataTable>
<Pages
@changeNo="changeNo"
@changeSize="changeSize"
:tableHeight="pageData.tableHeight"
:pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"
></Pages>
</div>
<!-- 详情 -->
<AddForm ref="addFormDiloag" @updateDate="getList"
:dic="{ D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_ZDRGK_GKZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ }" />
<AddForm
ref="addFormDiloag"
@updateDate="getList"
:dic="{
D_GS_ZDR_RYJB,
D_BZ_XB,
D_BZ_MZ,
D_BZ_XZQHDM,
D_ZDRGK_GKZT,
D_GS_ZDR_CZZT,
D_GS_BQ_ZL,
D_GS_BQ_LB,
D_GS_BQ_LX,
D_GS_ZDR_YJDJ,
D_GS_BK_SSJZ
}"
/>
<!-- 选择用户 -->
<ChooseUser v-model="chooseUserVisible" @choosedUsers="handleUserSelected" :roleIds="roleIds" />
<ChooseUser
v-model="chooseUserVisible"
@choosedUsers="handleUserSelected"
:roleIds="roleIds"
/>
<!-- 转线索 -->
<ZxsForm v-if="showzxs" ref="zxsDilof" @change="getList"
:dic="{ D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX }"></ZxsForm>
<ZxsForm
v-if="showzxs"
ref="zxsDilof"
@change="getList"
:dic="{
D_BZ_SF,
D_BZ_XB,
D_GS_XS_LY,
D_BZ_SSZT,
D_GS_XS_LX,
D_GS_XS_QTLX
}"
></ZxsForm>
</div>
</template>
@ -110,19 +160,58 @@ import { ElMessage } from "element-plus";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import ZxsForm from "./components/zxsForm.vue";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import AddForm from "./components/addForm.vue";
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { useRouter, useRoute } from 'vue-router'
import { useRouter, useRoute } from "vue-router";
import { getItem } from "@/utils/storage.js";
const router = useRouter()
const route = useRoute()
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
const { D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_ZDRGK_GKZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_BK_SQLX, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
proxy.$dict("D_GS_ZDQT_ZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_ZDRGK_GKZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ", "D_GS_BK_SQLX", "D_BZ_SF", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX");
const {
D_GS_ZDQT_ZT,
D_GS_ZDR_RYJB,
D_BZ_XB,
D_BZ_MZ,
D_BZ_RCBKZT,
D_BZ_XZQHDM,
D_ZDRGK_GKZT,
D_GS_ZDR_CZZT,
D_GS_BQ_ZL,
D_GS_BQ_LB,
D_GS_BQ_LX,
D_GS_ZDR_YJDJ,
D_GS_BK_SSJZ,
/* D_GS_BK_SQLX, */
D_BZ_SF,
D_GS_XS_LY,
D_BZ_SSZT,
D_GS_XS_LX,
D_GS_XS_QTLX
} = proxy.$dict(
"D_GS_ZDQT_ZT",
"D_BZ_RCBKZT",
"D_GS_ZDR_RYJB",
"D_BZ_XB",
"D_BZ_MZ",
"D_BZ_XZQHDM",
"D_ZDRGK_GKZT",
"D_GS_ZDR_CZZT",
"D_GS_BQ_ZL",
"D_GS_BQ_LB",
"D_GS_BQ_LX",
"D_GS_ZDR_YJDJ",
"D_GS_BK_SSJZ",
/* "D_GS_BK_SQLX", */
"D_BZ_SF",
"D_GS_XS_LY",
"D_BZ_SSZT",
"D_GS_XS_LX",
"D_GS_XS_QTLX"
);
const obj = ref({});
const showzxs = ref(false);
const zxsDilof = ref();
@ -160,6 +249,20 @@ const searchConfiger = ref([
showType: "select",
options: D_GS_ZDR_RYJB
},
{
label: "所属警种",
prop: "zdrSsjz",
placeholder: "请选择所属警种",
showType: "select",
options: D_GS_BK_SSJZ
},
{
label: "涉及警种",
prop: "zdrSjjz",
placeholder: "请选择涉及警种",
showType: "select",
options: D_GS_BK_SSJZ
},
]);
const queryFrom = ref({});
const pageData = reactive({
@ -175,30 +278,51 @@ const pageData = reactive({
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 250,
tableColumn: [
{ label: "姓名", prop: "ryXm",width: 100 },
{ label: "性别", prop: "ryXb", showSolt: true, width: 80 },
{ label: "姓名", prop: "ryXm", width: 100 },
{ label: "性别", prop: "ryXb", slotName: "ryXb", width: 80 },
{ label: "身份证", prop: "rySfzh", width: 170 },
{ label: "民族", prop: "ryMz", showSolt: true, width: 80 },
{ label: "民族", prop: "ryMz", slotName: "ryMz", width: 80 },
{ label: "户籍派出所", prop: "hjdPcsmc" },
{ label: "标签", prop: "bqList", showSolt: true, showOverflowTooltip: true },
{ label: "管辖单位", prop: "gxSsbmmc" },
{ label: "管控状态", prop: "zdrBkZt", showOverflowTooltip: true,showSolt: true, width: 100 },
{ label: "审核状态", prop: "zdrZt", showSolt: true, width: 100 },
{ label: "入库时间", prop: "zdrRkkssj", },
{
label: "标签",
prop: "bqList",
slotName: "bqList",
showOverflowTooltip: true
},
{ label: "协管单位", prop: "gxSsbmmc" },
{
label: "管控状态",
prop: "zdrBkZt",
showOverflowTooltip: true,
slotName: "zdrBkZt",
width: 100
},
{ label: "审核状态", prop: "zdrZt", slotName: "zdrZt", width: 100 },
{ label: "入库时间", prop: "zdrRkkssj" },
{ label: "所属警种", prop: "zdrSsjz",slotName: "zdrSsjz", },
{ label: "涉及警种", prop: "zdrSjjz",slotName: "zdrSjjz", },
{
label: "操作",
prop: "controls",
slotName: "controls",
align: "center",
width: 350
}
]
});
const isShiQzDelet = ref(false)
const isShiQzDelet = ref(false);
onMounted(() => {
tabHeightFn();
const isShiQz = getItem('roleList').find(item => item.roleCode == 'JS_777777') != undefined
if (isShiQz) isShiQzDelet.value = true
const isShiQz =
getItem("roleList").find((item) => item.roleCode == "JS_777777") !=
undefined;
if (isShiQz) isShiQzDelet.value = true;
if (route.query.id) {
addEdit('x', {
addEdit("x", {
id: route.query.id
})
}else{
});
} else {
getList();
}
});
@ -224,14 +348,16 @@ const getList = () => {
pageData.tableConfiger.loading = true;
// 人员类型D_ZDRY_RYLX(01 重点 02 普通〉
// rylx: '01',
let data = {...pageData.pageConfiger, ...queryFrom.value,rylx: '01' };
qcckGet(data, "/mosty-gsxt/tbGsxtZdry/selectPage").then((res) => {
pageData.tableData = res.records || [];
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch(() => {
pageData.tableConfiger.loading = false;
});
let data = { ...pageData.pageConfiger, ...queryFrom.value, rylx: "01" };
qcckGet(data, "/mosty-gsxt/tbGsxtZdry/selectPage")
.then((res) => {
pageData.tableData = res.records || [];
pageData.total = res.total;
pageData.tableConfiger.loading = false;
})
.catch(() => {
pageData.tableConfiger.loading = false;
});
};
//送审
@ -241,18 +367,27 @@ const handleSend = (id) => {
proxy.$message({ type: "success", message: "送审成功" });
getList();
});
})
});
};
// 移除
const handleremove = (id) => {
proxy.$confirm("确定要移除此重点人员?", "警告", { type: "warning" }).then(() => {
qcckPost({ id, rylx: '02' }, "/mosty-gsxt/tbGsxtZdry/update").then(() => {
proxy
.$confirm("确定要移除此重点人员?", "警告", { type: "warning" })
.then(() => {
qcckPost({ id, rylx: "02" }, "/mosty-gsxt/tbGsxtZdry/update").then(() => {
proxy.$message({ type: "success", message: "移除成功" });
getList();
});
});
};
const handleMoveToFocus = (id) => {
proxy.$confirm("确定要移至关注库?", "警告", { type: "warning" }).then(() => {
qcckPost({ id, rylx: "03" }, "/mosty-gsxt/tbGsxtZdry/rylxyd").then(() => {
proxy.$message({ type: "success", message: "移除成功" });
getList();
});
})
}
});
};
const chooseData = (data) => {
ids.value = Array.isArray(data) ? data.map((item) => item.id) : [];
@ -260,14 +395,17 @@ const chooseData = (data) => {
};
// 选择申请数据数据
const handleApplication = () => {
if (ids.value.length === 0) return ElMessage.error("请先选择需要布控的重点人");
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addBksq").then(() => {
ElMessage.success("申请成功");
visible.value = false;
getList();
}).catch(() => {
ElMessage.error("布控申请失败");
});
if (ids.value.length === 0)
return ElMessage.error("请先选择需要布控的重点人");
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addBksq")
.then(() => {
ElMessage.success("申请成功");
visible.value = false;
getList();
})
.catch(() => {
ElMessage.error("布控申请失败");
});
};
const handleUserSelected = (val) => {
@ -277,33 +415,43 @@ const handleUserSelected = (val) => {
// 处理分配
const handlefp = () => {
if (ids.value.length === 0) return ElMessage.error("请先选择需要布控的重点人");
qcckPost({ ids: ids.value, uid: obj.value.fpid }, "/mosty-gsxt/tbGsxtZdry/addGkmj").then(() => {
ElMessage.success("分配成功");
visible.value = false;
visiblefp.value = false;
getList();
}).catch(() => {
ElMessage.error("分配失败");
});
if (ids.value.length === 0)
return ElMessage.error("请先选择需要布控的重点人");
qcckPost(
{ ids: ids.value, uid: obj.value.fpid },
"/mosty-gsxt/tbGsxtZdry/addGkmj"
)
.then(() => {
ElMessage.success("分配成功");
visible.value = false;
visiblefp.value = false;
getList();
})
.catch(() => {
ElMessage.error("分配失败");
});
};
// 移交管控
const handleMove = () => {
if (ids.value.length === 0) return ElMessage.error("请先选择需要移交管控的重点群体");
if (ids.value.length === 0)
return ElMessage.error("请先选择需要移交管控的重点群体");
proxy.$confirm("是否确定移交?", "警告", { type: "warning" }).then(() => {
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addSfyj").then(() => {
ElMessage.success("移交管控成功");
getList();
}).catch(() => {
ElMessage.error("移交管控失败");
});
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addSfyj")
.then(() => {
ElMessage.success("移交管控成功");
getList();
})
.catch(() => {
ElMessage.error("移交管控失败");
});
});
};
// 转线索
const handleZxs = () => {
if (ids.value.length === 0) return ElMessage.error("请先选择需要转线索的重点群体");
if (ids.value.length === 0)
return ElMessage.error("请先选择需要转线索的重点群体");
showzxs.value = true;
nextTick(() => {
zxsDilof.value.init(choosList.value);
@ -320,22 +468,38 @@ const deleteRow = (id) => {
});
};
//新增编辑
const addEdit = (type, row) => {
show.value = true;
nextTick(() => {
addFormDiloag.value.init(type, row);
})
});
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight =
window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};
};
// 标签颜色
const Bqys = (ys) => {
switch (ys) {
case "01":
return "#fd4343";
case "02":
return "#c26e09";
case "03":
return "#ffd208ff";
case "04":
return "#01abee";
default:
break;
}
};
</script>
<style lang="scss" scoped>

View File

@ -3,112 +3,258 @@
<div class="headClass">
<h3>人员信息</h3>
<!-- @click="gettbGsxtZdqtUpdate" -->
<el-button type="primary" v-if="showBut" :disabled="disabled" @click="submit">保存</el-button>
<el-button
type="primary"
v-if="showBut"
:disabled="disabled"
@click="submit"
>保存</el-button
>
</div>
<div>
<FormMessage :disabled="disabled" v-model="listQuery" :formList="formData" labelWidth="100px" ref="elform"
:rules="rules">
<FormMessage
:disabled="disabled"
v-model="listQuery"
:formList="formData"
labelWidth="130px"
ref="elform"
:rules="rules"
>
<template #ryzp>
<div style="width: 100%; padding-left: 50px">
<MOSTY.Upload :showBtn="false" :limit="1" v-model="listQuery.ryzp" />
<MOSTY.Upload
:showBtn="false"
:limit="1"
v-model="listQuery.ryzp"
/>
</div>
</template>
<template #ryLxdh>
<div class="phone-input-container">
<div class="inputGroup" v-for="(item, index) in listQuery.ryLxdh" :key="index">
<el-input v-model="listQuery.ryLxdh[index]" class="group" placeholder="请输入电话号码" />
<div class="flex align-center but" >
<el-button type="primary" :icon="Plus" circle @click="addPhone" title="添加电话号码"
v-if="listQuery.ryLxdh.length - 1 == index" />
<el-button type="success" :icon="Minus" circle @click="removePhone(index)" title="删除电话号码" />
</div>
</div>
<template #gkMjXm>
<div>
<el-input
v-model="listQuery.gkMjXm"
class="group"
placeholder="请输入管控民警姓名"
readonly
@click="chooseMarksVisible = true"
/>
</div>
</template>
<!-- <template #gkMjSfzh>
<div>
<el-input v-model="listQuery.gkMjSfzh" class="group" placeholder="请输入管控民警身份证号" readonly
@click="chooseMarksVisible = true" />
</div>
</template> -->
<!-- { label: "管控民警", prop: "gkMjXm", type: "slot" }, -->
<!-- { label: "管控民警身份证号", prop: "gkMjSfzh", type: "slot" }, -->
</FormMessage>
</div>
</div>
<!-- <ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" /> -->
<ChooseUser
v-model="chooseMarksVisible"
@choosedUsers="choosed"
:roleIds="roleIds"
/>
</template>
<script setup>
import * as rule from "@/utils/rules.js";
import { IdCard } from "@/utils/validate.js";
import * as MOSTY from "@/components/MyComponents/index";
import { Plus, Minus } from "@element-plus/icons-vue";
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
import { ref, reactive, onMounted, getCurrentInstance, watch } from "vue";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import { ref, reactive, onMounted, getCurrentInstance, watch, computed } from "vue";
import { tbGsxtZdryUpdate } from "@/api/zdr.js";
const { proxy } = getCurrentInstance();
const { D_BZ_XB, D_BZ_ZZMM, D_BZ_HYZK, D_BZ_MZ, D_BZ_XZQHDM, D_ZDRY_RYLX, D_BZ_RCBKZT, D_GS_ZDR_RYJB, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_ZDR_CZZT, D_BZ_WHCD, D_ZDRY_ZYLB } =
proxy.$dict('D_BZ_XB', 'D_BZ_ZZMM', 'D_BZ_HYZK', 'D_BZ_MZ', "D_ZDRY_RYLX", 'D_BZ_XZQHDM', 'D_BZ_RCBKZT', 'D_GS_ZDR_RYJB', 'D_GS_ZDR_YJDJ', 'D_GS_BK_SSJZ', 'D_GS_ZDR_CZZT', 'D_BZ_WHCD', 'D_ZDRY_ZYLB')
const {
D_BZ_XB,
D_BZ_ZZMM,
D_BZ_HYZK,
D_BZ_MZ,
D_BZ_XZQHDM,
D_ZDRY_RYLX,
D_BZ_RCBKZT,
D_GS_ZDR_RYJB,
D_GS_ZDR_YJDJ,
D_GS_BK_SSJZ,
D_GS_ZDR_CZZT,
D_BZ_WHCD,
D_ZDRY_ZYLB
} = proxy.$dict(
"D_BZ_XB",
"D_BZ_ZZMM",
"D_BZ_HYZK",
"D_BZ_MZ",
"D_ZDRY_RYLX",
"D_BZ_XZQHDM",
"D_BZ_RCBKZT",
"D_GS_ZDR_RYJB",
"D_GS_ZDR_YJDJ",
"D_GS_BK_SSJZ",
"D_GS_ZDR_CZZT",
"D_BZ_WHCD",
"D_ZDRY_ZYLB"
);
const props = defineProps({
dataList: {
type: Object,
default: () => { },
}, disabled: {
default: () => {}
},
disabled: {
type: Boolean,
default: false
},
showBut: {
type: Boolean,
default: false
},
})
}
});
const emit = defineEmits(["close"]);
const rules = reactive({
ryXm: [{ required: true, message: "请输入姓名", trigger: "blur" }],
...rule.identityCardRule({ validator: true }, 'rySfzh'), //身份证校验
...rule.phoneRule({ validator: true }, "ryLxdh"), // 是否必填 是否进行校验,
...rule.identityCardRule({ validator: true }, "rySfzh"), //身份证校验
...rule.phoneRule({ validator: true }, "gkMjLxfs"), // 是否必填 是否进行校验,
rySfzh: [{ required: true, message: "请输入身份证号", trigger: "blur" }],
ryLxdh: [{ required: true, message: "请输入联系电话", trigger: "blur" }],
ryXb: [{ required: true, message: "请选择性别", trigger: "change" }],
zyBm: [{ required: true, message: "请选择职业", trigger: "change" }],
ryMz: [{ required: true, message: "请选择民族", trigger: "change" }],
ryCsrq: [{ required: true, message: "请选择出生日期", trigger: "change" }],
ryJg: [{ required: true, message: "请选择籍贯", trigger: "change" }],
zdrRyjb: [{ required: true, message: "请选择人员级别", trigger: "change" }],
zdrYjdj: [{ required: true, message: "请选择预警等级", trigger: "change" }],
gxSsbmdm: [{ required: true, message: "请选择协管单位", trigger: "change" }],
zdrRkkssj: [
{ required: true, message: "请选择入库开始时间", trigger: "change" }
],
zdrRkjssj: [
{ required: true, message: "请选择入库结束时间", trigger: "change" }
],
gkMjLxfs: [{ required: true, message: "请输入民警联系方式", trigger: "blur" }]
// gkMjXm: [{ required: true, message: "请选择管控民警", trigger: "change" }],
// gkMjSfzh: [{ required: true, message: "请选择管控民警身份证号", trigger: "change" }],
// rylx: [{ required: true, message: "请选择人员类型", trigger: "change" }]
});
const listQuery = ref({ ryLxdh: [""] }); //表单
const listQuery = ref({}); //表单
const chooseMarksVisible = ref(false); // 控制标签选择弹窗显示
const roleIds = ref([]); // 已选择的标签ID
const formData = ref([
const formData = computed(() => [
{ label: "人员照片", prop: "ryzp", type: "slot", width: "100%" },
{ label: "姓名", prop: "ryXm", type: "input" },
{ label: "性别", prop: "ryXb", type: "select", options: D_BZ_XB },
{ label: "身份证号", prop: "rySfzh", type: "input" },
{ label: "籍贯", prop: "ryJg", type: "select", options: D_BZ_XZQHDM },
{ label: "曾用名", prop: "cym", type: "input" },
{ label: "文化程度", prop: "whcdBm", type: "select", options: D_BZ_WHCD },
{ label: "民族", prop: "ryMz", type: "select", options: D_BZ_MZ },
{ label: "政治面貌", prop: "zzmm", type: "select", options: D_BZ_ZZMM },
{ label: "职业", prop: "zyBm", type: "select", options: D_ZDRY_ZYLB },
{ label: "人员级别", prop: "zdrRyjb", type: "select", options: D_GS_ZDR_RYJB },
{ label: "预警等级", prop: "zdrYjdj", type: "select", options: D_GS_ZDR_YJDJ },
{ label: "出生日期", prop: "ryCsrq", type: "date" },
{ label: "户籍地区划", prop: "hjdQh", type: "select", options: D_BZ_XZQHDM },
{ label: "户籍地详址", prop: "hjdXz", type: "input" },
{ label: "户籍地派出所", prop: "hjdPcsdm",depMc:"hjdPcsmc" ,type: "department" },
{ label: "现住地区划", prop: "xzdQh", type: "select", options: D_BZ_XZQHDM },
{ label: "现住地详址", prop: "xzdXz", type: "input" },
{ label: "现住地派出所", prop: "xzdPcsdm",depMc:"xzdPcsmc" ,type: "department" },
{ label: "管单位", prop: "gxSsbmdm", depMc: 'gxSsbmmc', type: "department" },
{ label: "诉求单位", prop: "sqSsbmdm", depMc: 'sqSsbmmc', type: "department" },
{ label: "责任单位", prop: "zrSsbmdm", depMc: 'zrSsbmmc', type: "department" },
{ label: "所属警种", prop: "zdrSsjz", type: "select", options: D_GS_BK_SSJZ },
{ label: "涉及警种", prop: "zdrSjjz", type: "select", options: D_GS_BK_SSJZ, multiple: true },
{ label: "婚姻状态", prop: "hyzk", type: "select", options: D_BZ_HYZK },
// { label: "处置状态", prop: "zdrCzzt", type: "select", options: D_GS_ZDR_CZZT },
// { label: "布控状态", prop: "zdrBkZt", type: "select", options: D_BZ_RCBKZT },
{ label: "姓名", prop: "ryXm", type: "input", width: "30%" },
{ label: "身份证号", prop: "rySfzh", type: "input", width: "30%" },
{
label: "性别",
prop: "ryXb",
type: "select",
options: D_BZ_XB.value,
width: "30%"
},
{ label: "出生日期", prop: "ryCsrq", type: "date", width: "30%" },
{
label: "民族",
prop: "ryMz",
type: "select",
options: D_BZ_MZ.value,
width: "30%"
},
{
label: "管单位",
prop: "gxSsbmdm",
depMc: "gxSsbmmc",
type: "department",
width: "30%"
},
{
label: "预警等级",
prop: "zdrYjdj",
type: "select",
options: D_GS_ZDR_YJDJ.value,
width: "30%"
},
{ label: "管控民警", prop: "gkMjXm", type: "slot", width: "30%" },
{ label: "民警联系方式", prop: "gkMjLxfs", type: "input", width: "30%" },
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime", width: "30%" },
{ label: "入库结束时间", prop: "zdrRkjssj", type: "datetime", width: "30%" },
{ label: "重点人联系电话", prop: "ryLxdh", type: "input", width: "30%" },
{ label: "籍贯", prop: "ryJg", type: "input", width: "30%" },
{ label: "曾用名", prop: "cym", type: "input", width: "30%" },
{
label: "文化程度",
prop: "whcdBm",
type: "select",
options: D_BZ_WHCD.value,
width: "30%"
},
{
label: "政治面貌",
prop: "zzmm",
type: "select",
options: D_BZ_ZZMM.value,
width: "30%"
},
{ label: "职业", prop: "zyBm", type: "input", width: "30%" },
{
label: "人员级别",
prop: "zdrRyjb",
type: "select",
options: D_GS_ZDR_RYJB.value,
width: "30%"
},
{ label: "户籍地区划", prop: "hjdQh", type: "input", width: "30%" },
{ label: "户籍地详址", prop: "hjdXz", type: "input", width: "30%" },
{ label: "户籍地派出所", prop: "hjdPcsmc", type: "input", width: "30%" },
{ label: "现住地区划", prop: "xzdQh", type: "input", width: "30%" },
{ label: "现住地详址", prop: "xzdXz", type: "input", width: "30%" },
{
label: "现住地派出所",
prop: "xzdPcsdm",
depMc: "xzdPcsmc",
type: "department",
width: "30%"
},
// { label: "民警身份证", prop: "gkMjSfzh", type: "slot" },
{ label: "诉求单位", prop: "sqSsbmmc", type: "input", width: "30%" },
{ label: "责任单位", prop: "zrSsbmmc", type: "input", width: "30%" },
{
label: "所属警种",
prop: "zdrSsjz",
type: "select",
options: D_GS_BK_SSJZ.value,
width: "30%"
},
{
label: "涉及警种",
prop: "zdrSjjz",
type: "select",
options: D_GS_BK_SSJZ.value,
multiple: true,
width: "30%"
},
{
label: "婚姻状态",
prop: "hyzk",
type: "select",
options: D_BZ_HYZK.value,
width: "30%"
},
{
label: "处置状态",
prop: "zdrCzzt",
type: "select",
options: D_GS_ZDR_CZZT.value,
width: "30%"
},
{
label: "布控状态",
prop: "zdrBkZt",
type: "select",
options: D_BZ_RCBKZT.value,
width: "30%"
},
// { label: "人员类型", prop: "rylx", type: "select", options: D_ZDRY_RYLX },
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime" },
{ label: "入库结束时间", prop: "zdrRkjssj", type: "datetime" },
{ label: "Mac地址", prop: "macDz", type: "input" },
{ label: "联系电话", prop: "ryLxdh", type: "slot", width: "100%" },
{ label: "Mac地址", prop: "macDz", type: "input", width: "30%" },
// { label: "标签选择", prop: "tags", type: "slot", width: "100%" },
{ label: "管控原因", prop: "zdrLkyy", type: "textarea", width: "100%" },
{ label: "管控原因", prop: "zdrLkyy", type: "textarea", width: "100%" }
]);
const loading = ref(false);
const elform = ref();
@ -116,14 +262,14 @@ const disabled = ref(false);
// phoneList已重构为listQuery.value.ryLxdh
// 创建一个工具函数进行深拷贝
const deepClone = (obj) => {
if (obj === null || typeof obj !== 'object') {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
return obj.map((item) => deepClone(item));
}
const clonedObj = {};
for (const key in obj) {
@ -133,124 +279,123 @@ const deepClone = (obj) => {
}
return clonedObj;
};
// 监听props.dataList变化处理初始化数据
watch(() => props.dataList, (val) => {
if (val) {
// 使用深拷贝避免直接引用同一个对象
listQuery.value = deepClone(val);
// 处理照片数据
listQuery.value.ryzp = val.ryzp == null || val.ryzp == '' ? [] : [val.ryzp];
listQuery.value.zdrSjjz = val.zdrSjjz == null || val.zdrSjjz == '' ? [] : JSON.parse(val.zdrSjjz);
// 处理标签ID数据确保数据回显
if (val.tagIds && Array.isArray(val.tagIds) && val.tagIds.length > 0) {
roleIds.value = [...val.tagIds];
} else if (val.bqIds && Array.isArray(val.bqIds) && val.bqIds.length > 0) {
roleIds.value = [...val.bqIds];
} else {
roleIds.value = [];
// 监听身份证号变化,自动填充性别、出生日期和民族
watch(
() => listQuery.value.rySfzh,
(val) => {
if (val && val.length === 18) {
// 使用IdCard方法提取出生日期
listQuery.value.ryCsrq = IdCard(val, 1);
// 使用IdCard方法提取性别
const genderText = IdCard(val, 2);
listQuery.value.ryXb = D_BZ_XB.value.find(
(item) => item.zdmc === genderText
).dm;
}
}
}, { deep: true })
);
// 监听props.dataList变化处理初始化数据
watch(
() => props.dataList,
(val) => {
if (val) {
console.log(val);
// 使用深拷贝避免直接引用同一个对象
listQuery.value = deepClone(val);
// 处理照片数据
listQuery.value.ryzp =
val.ryzp == null || val.ryzp == "" ? [] : [val.ryzp];
listQuery.value.zdrSjjz =
val.zdrSjjz == null || val.zdrSjjz == "" ? [] : JSON.parse(val.zdrSjjz);
// 处理标签ID数据确保数据回显
if (val.tagIds && Array.isArray(val.tagIds) && val.tagIds.length > 0) {
roleIds.value = [...val.tagIds];
} else if (
val.bqIds &&
Array.isArray(val.bqIds) &&
val.bqIds.length > 0
) {
roleIds.value = [...val.bqIds];
} else {
roleIds.value = [];
}
}
},
{ deep: true }
);
// 提交
const submit = () => {
loading.value = true
gettbGsxtZdryUpdate()
loading.value = true;
gettbGsxtZdryUpdate();
};
//
const gettbGsxtZdryUpdate = () => {
const promes = {
...listQuery.value,
ryzp: listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : "",
ryLxdh: listQuery.value.ryLxdh,
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
}
ryzp:
listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : "",
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
};
elform.value.submit((data) => {
tbGsxtZdryUpdate(promes).then((res) => {
listQuery.value.ryzp = []
proxy.$message({
message: '更新成功',
type: 'success',
})
}).catch((err) => {
}).finally(() => {
loading.value = false
tbGsxtZdryUpdate(promes)
.then((res) => {
listQuery.value.ryzp = [];
proxy.$message({
message: "更新成功",
type: "success"
});
emit("close");
})
.catch((err) => {})
.finally(() => {
loading.value = false;
});
});
})
}
// 添加电话号码
const addPhone = () => {
// 确保新添加的电话号码与现有数据结构一致
// 创建深拷贝以避免响应式更新问题
const newPhoneList = [...listQuery.value.ryLxdh];
newPhoneList.push('');
// 用全新数组替换现有数组确保Vue正确检测到变化
listQuery.value.ryLxdh = newPhoneList;
}
// 删除电话号码
const removePhone = (index) => {
if (listQuery.value.ryLxdh.length > 1) {
listQuery.value.ryLxdh.splice(index, 1);
} else {
// 清空输入但保留输入框
listQuery.value.ryLxdh[0] = '';
proxy.$message.warning('至少保留一个联系电话');
}
}
};
const throwData = () => {
return new Promise((resolve, reject) => {
if (elform.value && elform.value.validate) {
elform.value.submit((data) => {
// 过滤掉空的电话号码
const validPhones = listQuery.value.ryLxdh.filter(phone => phone && phone.trim());
if (validPhones.length === 0) {
proxy.$message.warning('请至少输入一个有效的联系电话');
reject(new Error('请至少输入一个有效的联系电话'));
return;
}
resolve({
...listQuery.value,
ryzp: listQuery.value.ryzp && listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : '',
ryLxdh: validPhones,
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
ryzp:
listQuery.value.ryzp && listQuery.value.ryzp.length > 0
? listQuery.value.ryzp.toString()
: "",
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
});
})
});
} else {
elform.value.submit((data) => {
// 如果没有验证方法,直接返回数据
const validPhones = listQuery.value.ryLxdh.filter(phone => phone && phone.trim());
if (validPhones.length === 0) {
proxy.$message.warning('请至少输入一个有效的联系电话');
reject(new Error('请至少输入一个有效的联系电话'));
return;
}
resolve({
...listQuery.value,
ryzp: listQuery.value.ryzp && listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : '',
ryLxdh: validPhones,
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
ryzp:
listQuery.value.ryzp && listQuery.value.ryzp.length > 0
? listQuery.value.ryzp.toString()
: "",
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
});
})
});
}
});
};
const choosed = (val) => {
roleIds.value = [val[0].id];
listQuery.value.gkMjXm = val[0].userName;
listQuery.value.gkMjSfzh = val[0].idEntityCard;
listQuery.value.gkMjLxfs = val[0].mobile;
listQuery.value.gkMjJh = val[0].inDustRialId;
console.log(listQuery.value);
};
defineExpose({
throwData,
throwData
});
</script>
<style lang="scss" scoped>
@ -294,7 +439,7 @@ defineExpose({
}
.headClass::after {
content: '';
content: "";
position: absolute;
left: 0;
bottom: -2px;

View File

@ -2,10 +2,21 @@
<div>
<div class="headClass" style="">
<h3>人员标签</h3>
<el-button type="primary" :disabled="disabled" @click="chooseMarksVisible = true">选择</el-button>
<el-button
type="primary"
:disabled="disabled"
@click="chooseMarksVisible = true"
>选择</el-button
>
</div>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="pageData.keyCount"
:tableConfiger="pageData.tableConfiger"
:controlsWidth="pageData.controlsWidth"
>
<template #bqLx="{ row }">
<DictTag :tag="false" :value="row.bqLx" :options="D_GS_BQ_DJ" />
</template>
@ -18,143 +29,181 @@
</template>
</MyTable>
</div>
<ChooseMarks v-model="chooseMarksVisible" @choosed="addMarks" :roleIds="roleIds" />
<ChooseMarks
v-model="chooseMarksVisible"
@choosed="addMarks"
:roleIds="roleIds"
:bqLx="defaultBqLx"
/>
</template>
<script setup>
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted, onUnmounted } from "vue";
import {
ref,
reactive,
watch,
toRaw,
computed,
getCurrentInstance,
onMounted,
onUnmounted
} from "vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
import { tbGsxtZdryUpdate } from '@/api/zdr.js'
import { tbGsxtZdryUpdate } from "@/api/zdr.js";
import { ElMessage, ElMessageBox } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
const chooseMarksVisible = ref(false)
const chooseMarksVisible = ref(false);
const props = defineProps({
dataList: {
type: Object,
default: () => { },
}, disabled: {
default: () => {}
},
disabled: {
type: Boolean,
default: false
},
showBut: {
type: Boolean,
default: false
},
})
const listData = ref({})
watch(() => props.dataList, (val) => {
if (val) {
listData.value = val
pageData.tableData = val.bqList
roleIds.value = val.bqList.map(v => v.bqId)
console.log(roleIds.value);
}
}, { deep: true })
const roleIds = ref([])
});
const listData = ref({});
const roleIds = ref([]);
watch(
() => props.dataList,
(val) => {
if (val) {
listData.value = val;
pageData.tableData = val.bqList;
roleIds.value = val.bqList.map((v) => v.bqId);
console.log(roleIds.value);
}
},
{ deep: true }
);
// 表格数据
const pageData = reactive({
tableData: [],
tableColumn: [{
prop: 'bqMc',
label: '标签名称',
showOverflowTooltip: true
}, {
prop: 'bqDm',
label: '标签代码',
}, {
showSolt: true,
prop: 'bqLx',
label: '标签类型',
}, {
showSolt: true,
prop: 'bqLb',
label: '标签类别',
}],
tableHeight: '200px',
tableColumn: [
{
prop: "bqMc",
label: "标签名称",
showOverflowTooltip: true
},
{
prop: "bqDm",
label: "标签代码"
},
{
showSolt: true,
prop: "bqLx",
label: "标签类型"
},
{
showSolt: true,
prop: "bqLb",
label: "标签类别"
}
],
tableHeight: "200px",
keyCount: 0,
tableConfiger: {
border: true,
stripe: true,
showHeader: true,
showIndex: true,
indexLabel: '序号',
indexLabel: "序号",
indexWidth: 60,
align: 'center',
align: "center",
showOverflowTooltip: true,
haveControls: !props.disabled
},
controlsWidth: 200,
})
controlsWidth: 200
});
// 计算默认的标签类型:如果已选数据中有身份标签则默认显示身份标签,否则默认显示行为标签
const defaultBqLx = computed(() => {
if (roleIds.value && roleIds.value.length > 0) {
const selectedItem = pageData.tableData.find((item) => roleIds.value.includes(item.bqId));
if (selectedItem && selectedItem.bqLx) {
return selectedItem.bqLx;
}
}
return "02";
});
// 修改数据接口
const zdqtUpdate = (val) => {
const params = {
id: listData.value.id,
bqList: pageData.tableData,
rySfzh: listData.value.rySfzh,
}
tbGsxtZdryUpdate(params).then(res => {
rySfzh: listData.value.rySfzh
};
tbGsxtZdryUpdate(params).then((res) => {
proxy.$message({
message: val,
type: 'success'
})
})
}
type: "success"
});
});
};
// 新增标签
const addMarks = (val) => {
pageData.tableData = val.map(v => {
return { bqDm: v.bqDm, bqId: v.id, bqLb: v.bqLb, bqLx: v.bqLx, bqMc: v.bqMc }
pageData.tableData = val.map((v) => {
return {
bqDm: v.bqDm,
bqId: v.id,
bqLb: v.bqLb,
bqLx: v.bqLx,
bqMc: v.bqMc,
bqYs: v.bqYs
};
});
roleIds.value = val.map(v => v.id)
roleIds.value = val.map((v) => v.id);
if (!props.disabled && props.showBut) {
zdqtUpdate("标签添加成功")
zdqtUpdate("标签添加成功");
}
}
};
// 删除标签
const delDictItem = (val) => {
if (!props.disabled && props.showBut) {
ElMessageBox.confirm(
'是否删除标签',
'提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
pageData.tableData = pageData.tableData.filter(v => v.bqId != val)
roleIds.value = roleIds.value.filter(v => v != val)
zdqtUpdate("标签删除成功")
ElMessageBox.confirm("是否删除标签", "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning"
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
.then(() => {
pageData.tableData = pageData.tableData.filter((v) => v.bqId != val);
roleIds.value = roleIds.value.filter((v) => v != val);
zdqtUpdate("标签删除成功");
})
})
.catch(() => {
ElMessage({
type: "info",
message: "取消删除"
});
});
} else {
pageData.tableData = pageData.tableData.filter(v => v.bqId != val)
roleIds.value = roleIds.value.filter(v => v != val)
pageData.tableData = pageData.tableData.filter((v) => v.bqId != val);
roleIds.value = roleIds.value.filter((v) => v != val);
}
}
};
// 抛出数据并验证标签列表不为空
const throwData = () => {
return new Promise((resolve) => {
// 验证:确保标签列表不为空
if (!pageData.tableData || pageData.tableData.length === 0) {
throw new Error('请选择群体标签');
throw new Error("请选择群体标签");
}
resolve(pageData.tableData);
});
}
};
defineExpose({
throwData
})
});
</script>
<style lang="scss" scoped>
@ -196,7 +245,7 @@ defineExpose({
}
.headClass::after {
content: '';
content: "";
position: absolute;
left: 0;
bottom: -2px;

View File

@ -37,7 +37,7 @@
</template>
</PageTitle> -->
<!-- 表格 -->
<div class="tabBox heightBox">
<div class="margTop">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
@ -96,48 +96,6 @@
<!-- 操作 -->
<template #controls="{ row }">
<el-popover placement="left" :visible="row.visible" :width="400" trigger="manual">
<template #reference>
<el-link size="small" type="warning" v-if="row.zdrZt == '02'"
@click="row.visible = !row.visible, chooseRow.id = row.id">审核</el-link>
</template>
<el-form :model="chooseRow" ref="elRowForm" :inline="true" label-width="100px" :rules="rules">
<el-form-item label="是否通过" prop="sftg" class="mt10 mb10" style="width: 100%;">
<MOSTY.Select filterable v-model="chooseRow.sftg" :dictEnum="D_BZ_SF" width="100%" clearable
placeholder="请选择是否通过" />
</el-form-item>
<el-form-item label="不通过原因" prop="shBtgyy" v-if="chooseRow.sftg == 0" style="width: 100%;">
<MOSTY.Other style="width: 100%;" clearable v-model="chooseRow.shBtgyy" type="textarea"
placeholder="请输入不通过原因" />
</el-form-item>
</el-form>
<div class="flex just-center mt10">
<el-button @click.stop="cancelRow(row)">取消</el-button>
<el-button type="primary" @click.stop="handleSend(row)" v-loading="btnloading">确定</el-button>
</div>
</el-popover>
<el-popover placement="left" :visible="row.visible1" :width="400" trigger="manual">
<template #reference>
<el-link size="small" type="primary" v-if="row.zdrZt == '04'"
@click="row.visible1 = !row.visible1, chooseRow.id = row.id">审批</el-link>
</template>
<el-form :model="chooseRow" ref="elRowForm1" :inline="true" label-width="100px" :rules="rules">
<el-form-item label="是否通过" prop="sftg" class="mt10 mb10" style="width: 100%;">
<MOSTY.Select filterable v-model="chooseRow.sftg" :dictEnum="D_BZ_SF" width="100%" clearable
placeholder="请选择是否通过" />
</el-form-item>
<el-form-item label="不通过原因" prop="spBtgyy" v-if="chooseRow.sftg == 0" style="width: 100%;">
<MOSTY.Other style="width: 100%;" clearable v-model="chooseRow.spBtgyy" type="textarea"
placeholder="请输入不通过原因" />
</el-form-item>
</el-form>
<div class="flex just-center mt10">
<el-button @click.stop="cancelRowSp(row)">取消</el-button>
<el-button type="primary" @click.stop="handleSendSp(row)" v-loading="btnloading">确定</el-button>
</div>
</el-popover>
<el-link size="small" type="primary" @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
@ -147,19 +105,18 @@
}"></Pages>
</div>
<!-- 详情 -->
<AddForm ref="addFormDiloag" @updateDate="getList"
<AddForm ref="addFormDiloag" @updateDate="getList" :showButData="true"
:dic="{ D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_GS_ZDR_BK_ZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ }" />
<!-- 选择用户 -->
<ChooseUser v-model="chooseUserVisible" @choosedUsers="handleUserSelected" :roleIds="roleIds" />
<!-- 转线索 -->
<ZxsForm v-if="showzxs" ref="zxsDilof" @change="getList"
:dic="{ D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX }"></ZxsForm>
<Ypdolog v-model="showYpdolog" :dataList="ids"/>
<Ypdolog v-model="showYpdolog" :dataList="ids" />
</div>
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index";
import { ElMessage } from "element-plus";
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import ZxsForm from "../mpvPeo/components/zxsForm.vue";
@ -184,15 +141,6 @@ const ids = ref([]);
const choosList = ref([]);
const visible = ref(false);
const visiblefp = ref(false);
const chooseRow = ref({})
const btnloading = ref(false)
const elRowForm = ref()
const elRowForm1 = ref()
const rules = reactive({
sftg: [{ required: true, message: "请选择是否通过", trigger: "change" }],
shBtgyy: [{ required: true, message: "请输入不通过原因", trigger: "blur" }],
spBtgyy: [{ required: true, message: "请输入不通过原因", trigger: "blur" }]
});
const searchConfiger = ref([
{
@ -346,50 +294,7 @@ const handleZxs = () => {
};
const cancelRow = (row) => {
row.visible = false;
chooseRow.value = {};
btnloading.value = false;
elRowForm.value.resetFields()
};
// 审核
const handleSend = (val) => {
elRowForm.value.validate((valid) => {
if (!valid) return;
btnloading.value = true;
qcckPost(chooseRow.value, "/mosty-gsxt/tbGsxtZdry/updateSh").then(() => {
proxy.$message({ type: "success", message: "审核成功" });
cancelRow(val)
getList();
}).catch(() => {
btnloading.value = false;
});
})
}
// 审批
const cancelRowSp = (row) => {
row.visible1 = false;
chooseRow.value = {};
btnloading.value = false;
elRowForm1.value.resetFields()
}
// 审批
const handleSendSp = (val) => {
elRowForm1.value.validate((valid) => {
if (!valid) return;
btnloading.value = true;
qcckPost(chooseRow.value, "/mosty-gsxt/tbGsxtZdry/updateSp").then(() => {
proxy.$message({ type: "success", message: "审批成功" });
cancelRowSp(val);
getList();
}).catch(() => {
btnloading.value = false;
});
})
}
const showYpdolog=ref(false)
const showYpdolog = ref(false)
//新增编辑
const addEdit = (type, row) => {
@ -401,7 +306,7 @@ const addEdit = (type, row) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 200;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};

View File

@ -73,12 +73,16 @@ import Details from './details.vue'
import Information from "@/views/home/model/information.vue";
import SemdFqzl from '@/components/instructionHasBeen/sendFqzl.vue'
const { proxy } = getCurrentInstance();
const { D_BZ_RCSHZT, D_GS_RQFJ_LX, D_GS_RQFJ_FXDJ, D_BZ_SF, D_GS_RQFJ_FXLB } =
const { D_BZ_RCSHZT,
// D_GS_RQFJ_LX,
D_GS_RQFJ_FXDJ,
// D_BZ_SF,
D_GS_RQFJ_FXLB } =
proxy.$dict(
"D_BZ_RCSHZT",
"D_GS_RQFJ_LX",
// "D_GS_RQFJ_LX",
"D_GS_RQFJ_FXDJ",
"D_BZ_SF",
// "D_BZ_SF",
"D_GS_RQFJ_FXLB"
);

View File

@ -3,6 +3,7 @@
<div class="head_box">
<span class="title">线索{{ title }}</span>
<div>
<el-button type="primary" v-if="!disabled" :loading="loading" @click="submit">保存</el-button>
<el-button @click="close">关闭</el-button>
</div>
</div>
@ -19,6 +20,7 @@
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { qbcjAdd, qbcjUpdate, qbcjSelectByid } from "@/api/Intelligence.js";
import { qcckGet, qcckPost } from '@/api/qcckApi'
import pursueContent from "@/views/backOfficeSystem/HumanIntelligence/components/pursueContent.vue";
import { ref, defineExpose, onMounted, defineEmits, watch, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance()
@ -33,6 +35,12 @@ const props = defineProps({
const loading = ref(false)
const dialogForm = ref(false); //弹窗
const formData = ref();
const rules = ref({
qbmc: [{ required: true, message: "请输入情报标题", trigger: ["blur"] }],
zxssj: [{ required: true, message: "请选择转线索时间", trigger: ["blur"] }],
qbnr: [{ required: true, message: "请输入情报内容", trigger: ["blur"] }],
});
watch(() => dialogForm.value, (val) => {
@ -48,29 +56,45 @@ watch(() => dialogForm.value, (val) => {
}
}, { deep: true })
const listQuery = ref({}); //表单
const elform = ref();
onMounted(() => {
})
const addForm = ref()
const msgeDat = ref()
const title = ref("")
const showPj = ref(false)
const disabled = ref(false)
// 初始化数据
const init = (type, row) => {
console.log(row,"测试");
title.value = type == "add" ? "新增" : type == "info" ? "详情" : "编辑"
disabled.value = type == 'info' ? true : false
// disabled.value = type == 'info' ? true : false
dialogForm.value = true;
if (type == 'info' || type == 'edit') {
if (type != 'add') {
showPj.value = true
listQuery.value = row
if (type == 'info') {
disabled.value = true
} else {
disabled.value = false
}
} else {
disabled.value = false
}
};
// 新增修改
const submit = () => {
const promes = { ...listQuery.value }
const url = title.value == "新增" ? "/mosty-gsxt/xxcj/zxs/addEntity" : "/mosty-gsxt/xxcj/zxs/updateEntity"
qcckPost({...promes,qbly:'0'}, url).then(res => {
proxy.$message({
message: "操作成功",
type: "success",
});
emit("getList")
close()
})
};
const close = () => {
dialogForm.value = false;
listQuery.value = {};
};
defineExpose({ init });
@ -185,7 +209,8 @@ defineExpose({ init });
color: #f78989;
transform: scale(1.1);
}
::v-deep .el-textarea.is-disabled .el-textarea__inner{
::v-deep .el-textarea.is-disabled .el-textarea__inner {
color: #000;
}
</style>

View File

@ -2,7 +2,15 @@
<div>
<!-- 搜索 -->
<div ref="searchBox" class="mt10 mb10">
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount" />
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount">
<el-button type="primary" size="small" @click="getDataById('add', null)">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
<el-button type="danger" size="small" @click="handleRow()">批量删除</el-button>
</Search>
</div>
<!-- 表格 -->
<div class="tabBox heightBox">
@ -15,9 +23,14 @@
<template #cjlx="{ row }">
<DictTag :tag="false" :value="row.cjLx" :options="D_BZ_CJLX" />
</template>
<template #qbly="{ row }">
<DictTag :tag="false" :value="row.qbly" :options="D_GS_XS_LY" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="primary" @click="getDataById(row)">详情</el-link>
<el-link size="small" type="primary" @click="getDataById('info',row)">详情</el-link>
<el-link size="small" type="primary" @click="getDataById('edit',row)">编辑</el-link>
<el-link size="small" type="danger" @click="handleRow(row.id)">删除</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
@ -26,21 +39,21 @@
}"></Pages>
</div>
</div>
<AddForm ref="addForm" :dict="{ D_BZ_CJLX, D_GS_XS_LX }" />
<AddForm ref="addForm" :dict="{ D_BZ_CJLX, D_GS_XS_LX }" @getList="getList" />
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import { useRoute } from 'vue-router'
import { xxcjZxsSelectPage } from "@/api/xxcj.js";
import { qcckGet, qcckPost } from '@/api/qcckApi'
import { reactive, ref, onMounted, getCurrentInstance, watch } from "vue";
import AddForm from "./addForm.vue"
import { getItem } from '@//utils/storage.js'
const { proxy } = getCurrentInstance();
const { D_BZ_CJLX, D_GS_XS_LX } = proxy.$dict("D_BZ_CJLX", "D_GS_XS_LX"); //获取字典数据
const { D_BZ_CJLX, D_GS_XS_LX,D_GS_XS_LY } = proxy.$dict("D_BZ_CJLX", "D_GS_XS_LX","D_GS_XS_LY"); //获取字典数据
const detailDiloag = ref();
const searchBox = ref(); //搜索框
const ids = ref([])
@ -90,12 +103,12 @@ const pageData = reactive({
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 100,
controlsWidth: 180,
tableColumn: [
{ label: "情报标题", prop: "qbmc",width:250 },
{ label: "编号", prop: "xsBh",width:190 },
// { label: "情报类型", prop: "qblx", showSolt: true },
// { label: "情报来源", prop: "cjlx", showSolt: true },
{ label: "情报来源", prop: "qbly", showSolt: true },
{ label: "转线索时间", prop: "zxssj",width:190 },
{ label: "情报内容", prop: "qbnr",width:190 },
{ label: "所属部门", prop: "ssbm" },
@ -126,17 +139,36 @@ const getList = () => {
pageData.tableConfiger.loading = true;
let data = { ...pageData.pageConfiger, ...queryFrom.value };
delete data.times;
xxcjZxsSelectPage(data).then(res => {
pageData.tableData = res.records || [];
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch(() => { pageData.tableConfiger.loading = false; })
}
qcckGet(data, "/mosty-gsxt/xxcj/zxs/selectPage").then((res) => {
pageData.tableData = res.records || [];
pageData.total = res.total;
}).catch(() => {
}).finally(() => {
pageData.tableConfiger.loading = false;
})
// xxcjZxsSelectPage(data).then(res => {
// pageData.tableData = res.records || [];
// pageData.total = res.total;
// pageData.tableConfiger.loading = false;
// }).catch(() => { pageData.tableConfiger.loading = false; })
}
// 删除
const handleRow = (id) => {
const promes = {
ids: id ? [id] : ids.value
}
proxy.$confirm("确定要删除?", "警告", { type: "warning" }).then(() => {
qcckPost(promes, "/mosty-gsxt/xxcj/zxs/deletes").then(() => {
proxy.$message({ type: "success", message: "删除成功" });
getList();
});
})
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 200;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};
@ -147,10 +179,8 @@ const getRouter = () => {
routerMate.value = route.meta
}
const addForm = ref(null)
const getDataById = (row) => {
addForm.value.init('info', row);
console.log(row);
const getDataById = (type,row) => {
addForm.value.init(type, row);
}
</script>

View File

@ -9,23 +9,14 @@
</div>
<div class="form_cnt">
<FormMessage v-model="listQuery" :formList="formData" ref="elform" :rules="rules" :disabled="title == '详情'">
<template #bkyj>
<el-divider content-position="left"><span style="color: blue;">布控预警</span></el-divider>
<template #yjNum>
<el-divider content-position="left"><span style="color: blue;">预警</span></el-divider>
</template>
<template #clyj>
<el-divider content-position="left"><span style="color: blue;">车辆预警</span></el-divider>
<template #csfs>
<el-divider content-position="left"><span style="color: blue;">信息</span></el-divider>
</template>
<template #qlry>
<el-divider content-position="left"><span style="color: blue;">7类重点人员预警</span></el-divider>
</template>
<template #rxyj>
<el-divider content-position="left"><span style="color: blue;">人像预警</span></el-divider>
</template>
<template #zbyj>
<el-divider content-position="left"><span style="color: blue;">政保预警</span></el-divider>
</template>
<template #fs>
<el-divider content-position="left"><span style="color: blue;">考核分数</span></el-divider>
<template #ypNum>
<el-divider content-position="left"><span style="color: blue;">研判</span></el-divider>
</template>
</FormMessage>
</div>
@ -62,25 +53,21 @@ const formData = ref([
{ label: "考核开始日期", prop: "ksrq", type: "date" },
{ label: "考核结束日期", prop: "jsrq", type: "date" },
{ label: "考核描述", prop: "khzbms", type: "textarea", width: "100%" },
{ prop: "fs", type: "slot", width: "100%" },
{ label: "采集分数", prop: "cjfs", type: "number", min: 0, max: 100, step: 1 },
{ label: "研判分数", prop: "ypfs", type: "number", min: 0, max: 100, step: 1 },
{ prop: "bkyj", type: "slot", width: "100%" },
{ prop: "yjNum", type: "slot", width: "100%" },
{ label: "布控预警反馈率", prop: "bkyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "布控预警签收率", prop: "bkyjQsl", type: "number", min: 0, max: 100, step: 0.01 },
{ prop: "clyj", type: "slot", width: "100%" },
{ label: "车辆预警反馈率", prop: "clyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "车辆预警签收率", prop: "clyjQsl", type: "number", min: 0, max: 100, step: 0.01 },
{ prop: "qlry", type: "slot", width: "100%" },
{ label: "7类重点人员反馈率", prop: "qlryFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "7类重点人员签收率", prop: "qlryQsl", type: "number", min: 0, max: 100, step: 0.01 },
{ prop: "rxyj", type: "slot", width: "100%" },
{ label: "人像预警反馈率", prop: "rxyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "7类重点人员反馈率", prop: "qlryFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "人像预警签收率", prop: "rxyjQsl", type: "number", min: 0, max: 100, step: 0.01 },
{ prop: "zbyj", type: "slot", width: "100%" },
{ label: "政保预警反馈率", prop: "zbyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "人像预警反馈率", prop: "rxyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "政保预警签收率", prop: "zbyjQsl", type: "number", min: 0, max: 100, step: 0.01 },
{ label: "政保预警反馈率", prop: "zbyjFkl", type: "number", min: 0, max: 100, step: 0.01 },
{ prop: "csfs", type: "slot", width: "100%" },
{ label: "采集分数", prop: "cjfs", type: "number", min: 0, max: 100, step: 1 },
{ prop: "ypNum", type: "slot", width: "100%" },
{ label: "研判分数", prop: "ypfs", type: "number", min: 0, max: 100, step: 1 },
]);
const loading = ref(false);

View File

@ -2,20 +2,22 @@
<div>
<!-- 搜索 -->
<div ref="searchBox" class="mt10">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
<el-button size="small" type="primary" @click="addEdit('add', '')">
<Search :searchArr="searchConfiger" @submit="onSearch" >
<el-button size="small" type="primary" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</Search>
</div>
<!-- <PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
<template #left>
</template>
</PageTitle>
</PageTitle> -->
<!-- 表格 -->
<div class="tabBox">
<div class="margTop">
<!-- <MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"> -->
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
@ -157,7 +159,7 @@ const addEdit = (type, row) => {
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
window.onresize = function () {
tabHeightFn();
};

View File

@ -26,11 +26,13 @@
<div v-if="disabled">
<h3 class="tags-title">审核状态</h3>
<div style="display: flex;justify-content:space-between;width: 200%;">
<div style="display: flex;">
市审核状态<DictTag v-model:value="listQuery.sldshzt" :options="dict.D_BZ_SSSHZT" :tag="false" />
<div style="display: flex;">
市审核状态
<DictTag v-model:value="listQuery.sldshzt" :options="dict.D_BZ_SSSHZT" :tag="false" />
</div>
<div style="display: flex;">
县审核状态<DictTag v-model:value="listQuery.xldshzt" :options="dict.D_BZ_SSSHZT" :tag="false" />
<div style="display: flex;">
县审核状态
<DictTag v-model:value="listQuery.xldshzt" :options="dict.D_BZ_SSSHZT" :tag="false" />
</div>
</div>
</div>
@ -183,7 +185,7 @@ watch(() => dialogForm.value, (val) => {
{ label: "情报标题", prop: "qbmc", type: "input", width: '45%' },
{ label: "情报内容", prop: "qbnr", type: "textarea", width: '100%', rows: 100 },
{ label: "附件上传", prop: "fjdz", type: "upload", width: '100%', isImg: false },
{ label: "", prop: "jbxx", type: "slot", width: '100%',},
{ label: "", prop: "jbxx", type: "slot", width: '100%', },
{ label: "", prop: "shzt", type: "slot", width: '100%' },
]
@ -236,7 +238,6 @@ const init = (type, row) => {
// 根据id查询详情
const getDataById = (id) => {
xxcjSelectByid({ id }).then((res) => {
lcList.value = res.czlcList || []
listQuery.value = res;
listQuery.value.fjdz = res.fjdz ? res.fjdz?.split(",") : []
@ -305,9 +306,7 @@ const close = () => {
const lcList = ref([])
const getqbcjPldb = (id) => {
xxcjSelectCzlcList({ qbid: id }).then(res => {
console.log(res);
xxcjSelectCzlcList({ id }).then(res => {
lcList.value = res || []
})
.catch(() => {

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