Merge branch 'master-yly'
# Conflicts: # CLAUDE.md
This commit is contained in:
168
ruoyi-ui/CLAUDE.md
Normal file
168
ruoyi-ui/CLAUDE.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
**数字支行辅助管理系统** - 基于 RuoYi-Vue 框架的银行客户网格化管理平台。
|
||||
|
||||
这是一个全栈项目:
|
||||
- **前端**: `ruoyi-ui/` - Vue 2.6 + Element UI
|
||||
- **后端**: `../ibs/` - Java Spring Boot (若依框架)
|
||||
|
||||
## 常用命令
|
||||
|
||||
### 开发
|
||||
```bash
|
||||
# 安装依赖(建议使用国内镜像)
|
||||
npm install --registry=https://registry.npmmirror.com
|
||||
|
||||
# 启动开发服务器 (默认端口80)
|
||||
npm run dev
|
||||
|
||||
# Node.js 版本兼容性问题的启动方式
|
||||
npm run dev_t
|
||||
```
|
||||
|
||||
### 构建
|
||||
```bash
|
||||
# 构建生产环境
|
||||
npm run build:prod
|
||||
|
||||
# 构建测试环境
|
||||
npm run build:stage
|
||||
|
||||
# 构建预发布环境
|
||||
npm run build:pre
|
||||
```
|
||||
|
||||
### 代码质量
|
||||
```bash
|
||||
# ESLint 检查
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Mock 服务
|
||||
```bash
|
||||
# 启动 Mock 服务器
|
||||
npm run mock
|
||||
```
|
||||
|
||||
## 项目架构
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
ruoyi-ui/
|
||||
├── src/
|
||||
│ ├── api/ # API 接口层,按业务模块分组
|
||||
│ ├── assets/ # 静态资源(图片、样式、图标SVG)
|
||||
│ ├── components/ # 全局通用组件
|
||||
│ ├── directive/ # Vue 自定义指令
|
||||
│ ├── layout/ # 布局组件(侧边栏、头部等)
|
||||
│ ├── map/ # 地图相关工具/配置
|
||||
│ ├── plugins/ # 插件配置
|
||||
│ ├── router/ # 路由配置
|
||||
│ ├── store/ # Vuex 状态管理
|
||||
│ ├── utils/ # 工具函数
|
||||
│ ├── views/ # 页面组件
|
||||
│ ├── App.vue # 根组件
|
||||
│ ├── main.js # 入口文件
|
||||
│ └── permission.js # 路由权限控制
|
||||
├── public/
|
||||
│ ├── baidu/ # 百度地图静态资源
|
||||
│ └── index.html
|
||||
├── mock/ # Mock 数据
|
||||
├── .env.development # 开发环境配置
|
||||
├── .env.production # 生产环境配置
|
||||
└── .env.staging # 测试环境配置
|
||||
```
|
||||
|
||||
### 核心业务模块
|
||||
|
||||
| 目录 | 功能 |
|
||||
|------|------|
|
||||
| `views/grid/` | 网格管理(创建、列表、地图、走访、绩效) |
|
||||
| `views/customer/` | 客户管理(360视图、建档、客群、标签) |
|
||||
| `views/system/` | 系统管理(用户、角色、菜单、字典) |
|
||||
| `views/monitor/` | 系统监控(日志、在线用户、服务监控) |
|
||||
| `views/configure/` | 配置管理(级别配置、参数设置、模板) |
|
||||
| `views/approveCenter/` | 审批中心 |
|
||||
| `views/gridSearch/` | 网格搜索(管户、绩效、公海池) |
|
||||
|
||||
### API 层组织
|
||||
|
||||
API 请求按业务模块组织在 `src/api/` 目录:
|
||||
- 每个模块导出具体的请求函数
|
||||
- 使用 `src/utils/request.js` 中的 axios 实例
|
||||
- 默认添加 Bearer Token 认证
|
||||
- 统一错误处理(401/500/601等状态码)
|
||||
|
||||
### 状态管理 (Vuex)
|
||||
|
||||
Store 模块位于 `src/store/modules/`:
|
||||
- `app` - 应用状态(侧边栏、设备类型)
|
||||
- `user` - 用户信息
|
||||
- `permission` - 权限路由
|
||||
- `settings` - 系统设置
|
||||
- `dict` - 字典数据
|
||||
- `tagsView` - 标签页视图
|
||||
- `featuredAreas` - 特色区域
|
||||
- `rate` - 汇率相关
|
||||
|
||||
使用 `vuex-persistedstate` 将 settings 持久化到 localStorage。
|
||||
|
||||
### 路由系统
|
||||
|
||||
- 路由分为 `constantRoutes`(静态路由)和 `dynamicRoutes`(动态路由)
|
||||
- 动态路由基于用户权限(permissions)动态加载
|
||||
- 使用 `src/permission.js` 进行路由守卫和权限控制
|
||||
- 支持嵌套路由和路由元信息配置
|
||||
|
||||
### 百度地图集成
|
||||
|
||||
项目深度集成百度地图 API:
|
||||
- 静态资源位于 `public/baidu/`
|
||||
- 地图相关 API 在 `src/api/grid/` 下
|
||||
- 支持 WebGL 渲染、绘制管理器、热力图等
|
||||
|
||||
## 环境变量配置
|
||||
|
||||
| 变量 | 说明 |
|
||||
|------|------|
|
||||
| `VUE_APP_BASE_API` | 后端 API 基础路径 |
|
||||
| `VUE_APP_MOCK_API` | Mock API 路径 |
|
||||
| `VUE_APP_MOCK` | 是否启用 Mock |
|
||||
| `VUE_APP_STAGE_URL` | 测试环境地址 |
|
||||
| `VUE_APP_BAIDU_URL` | 百度地图服务地址 |
|
||||
| `VUE_APP_SHARP_URL` | SHARP 服务地址 |
|
||||
|
||||
## 代码规范
|
||||
|
||||
- ESLint 配置基于 `plugin:vue/recommended`
|
||||
- 使用单引号、2空格缩进
|
||||
- 组件名使用 PascalCase
|
||||
- pre-commit 钩子自动执行 lint-staged
|
||||
|
||||
## 全局组件
|
||||
|
||||
以下组件已全局注册,可直接使用:
|
||||
- `Pagination` - 分页组件
|
||||
- `RightToolbar` - 表格工具栏
|
||||
- `Editor` - 富文本编辑器
|
||||
- `FileUpload` - 文件上传
|
||||
- `ImageUpload` - 图片上传
|
||||
- `ImagePreview` - 图片预览
|
||||
- `DictTag` - 字典标签
|
||||
- `treeselect` - 树形选择器
|
||||
- `DownloadBtn` - 下载按钮
|
||||
|
||||
## 全局方法
|
||||
|
||||
通过 `Vue.prototype` 挂载的全局方法:
|
||||
- `getDicts()` - 获取字典数据
|
||||
- `getConfigKey()` - 获取配置项
|
||||
- `parseTime()` - 时间格式化
|
||||
- `resetForm()` - 重置表单
|
||||
- `download()` - 文件下载
|
||||
- `handleTree()` - 处理树形数据
|
||||
@@ -287,6 +287,15 @@ export function getFeaturegrid(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取网格列表(用于客群创建,简化查询)
|
||||
export function getSimpleGridList(data) {
|
||||
return request({
|
||||
url: `/draw/grid/simpleList`,
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除网格
|
||||
export function featureGridDelete(data) {
|
||||
return request({
|
||||
|
||||
137
ruoyi-ui/src/api/group/custGroup.js
Normal file
137
ruoyi-ui/src/api/group/custGroup.js
Normal file
@@ -0,0 +1,137 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询客群列表
|
||||
export function listCustGroup(query) {
|
||||
return request({
|
||||
url: '/group/cust/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取客群详情
|
||||
export function getCustGroup(id) {
|
||||
return request({
|
||||
url: '/group/cust/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 异步创建客群(网格导入)
|
||||
export function createCustGroupByGrid(data) {
|
||||
return request({
|
||||
url: '/group/cust/createByGrid',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 异步创建客群(模板导入)
|
||||
export function createCustGroupByTemplate(data) {
|
||||
return request({
|
||||
url: '/group/cust/createByTemplate',
|
||||
method: 'post',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
}
|
||||
|
||||
// 更新客群
|
||||
export function updateCustGroup(data) {
|
||||
return request({
|
||||
url: '/group/cust/update',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新客群(网格导入)
|
||||
export function updateCustGroupByGrid(data) {
|
||||
return request({
|
||||
url: '/group/cust/updateByGrid',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新客群(模板导入)
|
||||
export function updateCustGroupByTemplate(data) {
|
||||
return request({
|
||||
url: '/group/cust/updateByTemplate',
|
||||
method: 'post',
|
||||
data: data,
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
}
|
||||
|
||||
// 轮询客群创建状态
|
||||
export function getCreateStatus(id) {
|
||||
return request({
|
||||
url: '/group/cust/createStatus/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 客户信息模板下载
|
||||
export function downloadTemplate() {
|
||||
return request({
|
||||
url: '/group/cust/download',
|
||||
method: 'post',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除客群
|
||||
export function deleteCustGroup(idList) {
|
||||
return request({
|
||||
url: '/group/cust/delete',
|
||||
method: 'post',
|
||||
data: idList
|
||||
})
|
||||
}
|
||||
|
||||
// 手动移除客群客户
|
||||
export function removeMembers(groupId, memberIds) {
|
||||
return request({
|
||||
url: '/group/cust/removeMembers',
|
||||
method: 'post',
|
||||
params: { groupId: groupId },
|
||||
data: memberIds
|
||||
})
|
||||
}
|
||||
|
||||
// 检查客群名称是否存在
|
||||
export function checkGroupNameExist(groupName) {
|
||||
return request({
|
||||
url: '/group/cust/checkName',
|
||||
method: 'get',
|
||||
params: { groupName: groupName }
|
||||
})
|
||||
}
|
||||
|
||||
// 根据网格类型获取客户经理列表
|
||||
export function getManagerList(gridType) {
|
||||
return request({
|
||||
url: '/grid/cmpm/managerList',
|
||||
method: 'get',
|
||||
params: { gridType: gridType }
|
||||
})
|
||||
}
|
||||
|
||||
// 分页查询客群成员列表
|
||||
export function listCustGroupMembers(groupId, query) {
|
||||
return request({
|
||||
url: '/group/member/list/' + groupId,
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询地理网格列表(专用于客群创建)
|
||||
export function getRegionGridListForGroup(query) {
|
||||
return request({
|
||||
url: '/grid/region/groupList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -257,4 +257,12 @@ export function warningCardNum(query) {
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询所有预警类型
|
||||
export function getAlterTypes() {
|
||||
return request({
|
||||
url: '/work/record/alter/types',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -227,6 +227,17 @@ export const constantRoutes = [
|
||||
}]
|
||||
|
||||
},
|
||||
{
|
||||
path: '/group/custGroup/detail',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
children: [{
|
||||
path: '/group/custGroup/detail',
|
||||
name: 'CustGroupDetail',
|
||||
meta: { title: '客群详情', activeMenu: '/group/custGroup' },
|
||||
component: () => import('@/views/group/custGroup/detail')
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/checklist/customerlist',
|
||||
component: Layout,
|
||||
|
||||
@@ -11,6 +11,7 @@ const user = {
|
||||
permissions: [],
|
||||
nickName: '',
|
||||
userName: '',
|
||||
deptId: '',
|
||||
groupErr:{},
|
||||
},
|
||||
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
<div class="customer-wrap">
|
||||
<div>
|
||||
<el-radio-group class="header-radio" v-model="selectedTab" @change="handleTabChange">
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<template v-if="String(deptId).substring(0, 3) === '875'">
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
<div class="customerMain">
|
||||
<div :class="iscollapsed ? 'customerMain_left_sq' : 'customerMain_left_zk'">
|
||||
@@ -317,6 +324,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles', 'userName']),
|
||||
deptId() {
|
||||
return this.$store.state.user.deptId
|
||||
},
|
||||
filtereDate() {
|
||||
if (this.searchQuery) {
|
||||
return this.tableData.filter((item) => item.companyName.includes(this.searchQuery) || item.legalName.includes(this.searchQuery))
|
||||
@@ -776,6 +786,12 @@ export default {
|
||||
if (query.backUrl) {
|
||||
this.selectedTab = query.selectedTab
|
||||
this.queryParams.custPattern = query.selectedTab
|
||||
} else {
|
||||
// 默认选中第一个tab
|
||||
const deptId = this.$store.state.user.deptId
|
||||
const deptIdStr = deptId ? String(deptId) : ''
|
||||
this.selectedTab = deptIdStr.startsWith('875') ? '0' : '2'
|
||||
this.queryParams.custPattern = this.selectedTab
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
const commonCol = function (isCom, type) {
|
||||
return [
|
||||
// 当headId=875时需要隐藏的字段列表
|
||||
const HIDDEN_PROPS_FOR_875 = [
|
||||
'regionTopGridName', // 总行行政网格名称
|
||||
'regionSecGridName', // 支行行政网格名称
|
||||
'belongBranchName', // 行政网格归属支行
|
||||
'belongOutletName', // 行政网格归属网点
|
||||
'belongUserNameList', // 行政网格客户经理
|
||||
'drawGridName', // 自绘地图网格名称
|
||||
'drawBranchNames', // 自绘地图网格归属支行
|
||||
'drawOutletNames', // 自绘地图网格归属网点
|
||||
'drawUserNames', // 自绘地图网格客户经理
|
||||
'virtualGridName', // 自建名单网格名称
|
||||
'virtualBranchNames', // 自建名单网格归属支行
|
||||
'virtualOutletNames', // 自建名单网格归属网点
|
||||
'virtualUserNames', // 自建名单网格客户经理
|
||||
]
|
||||
|
||||
const commonCol = function (isCom, type, headId) {
|
||||
const allColumns = [
|
||||
{
|
||||
prop: 'regionTopGridName',
|
||||
label: '总行行政网格名称',
|
||||
@@ -101,9 +118,16 @@ const commonCol = function (isCom, type) {
|
||||
showOverflowTooltip: true,
|
||||
},
|
||||
]
|
||||
|
||||
// 当headId=875时,过滤掉指定的列
|
||||
if (String(headId).startsWith('875')) {
|
||||
return allColumns.filter(col => !HIDDEN_PROPS_FOR_875.includes(col.prop))
|
||||
}
|
||||
|
||||
return allColumns
|
||||
}
|
||||
|
||||
export const placeholderMap = (type) => ({
|
||||
export const placeholderMap = (type, headId) => ({
|
||||
'2': {
|
||||
placeholder: '搜索企业名称/法人名字',
|
||||
custPattern: '2',
|
||||
@@ -138,7 +162,7 @@ export const placeholderMap = (type) => ({
|
||||
type: 'myCustLevel',
|
||||
// desc: '建档输入/取新华社数据',
|
||||
},
|
||||
...commonCol('2', type),
|
||||
...commonCol('2', type, headId),
|
||||
{
|
||||
prop: 'lpName',
|
||||
label: '法人姓名',
|
||||
@@ -393,7 +417,7 @@ export const placeholderMap = (type) => ({
|
||||
type: 'myCustIdsn',
|
||||
// desc: '建档输入/取新华社数据',
|
||||
},
|
||||
...commonCol('1', type),
|
||||
...commonCol('1', type, headId),
|
||||
{
|
||||
prop: 'lpName',
|
||||
label: '经营者姓名',
|
||||
@@ -634,7 +658,7 @@ export const placeholderMap = (type) => ({
|
||||
type: 'myCustLevel',
|
||||
// desc: '取大信贷数据',
|
||||
},
|
||||
...commonCol('0', type),
|
||||
...commonCol('0', type, headId),
|
||||
{
|
||||
prop: 'custPhone',
|
||||
label: '联系方式',
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
<div class="customer-wrap">
|
||||
<div>
|
||||
<el-radio-group class="header-radio" v-model="selectedTab" @change="handleTabChange">
|
||||
<el-radio-button label="2" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button> // :disabled="isPrivate"
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<template v-if="String(deptId).substring(0, 3) === '875'">
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
<div class="customerMain">
|
||||
<div :class="iscollapsed ? 'customerMain_left_sq' : 'customerMain_left_zk'">
|
||||
@@ -283,8 +290,9 @@ export default {
|
||||
const type = this.roles.includes('headPublic') ? 'isPublic' :
|
||||
this.roles.includes('headPrivate') ? 'isPrivate' :
|
||||
this.roles.includes('headOps') ? 'isOps' : ""
|
||||
this.tableColoumns = placeholderMap(type)[val].tableColoumns
|
||||
this.placeholder = placeholderMap(type)[val].placeholder
|
||||
const headId = this.deptId
|
||||
this.tableColoumns = placeholderMap(type, headId)[val].tableColoumns
|
||||
this.placeholder = placeholderMap(type, headId)[val].placeholder
|
||||
this.queryParams.custPattern = val
|
||||
this.searchColoumns = this.getSearchColoumns()
|
||||
}
|
||||
@@ -310,6 +318,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
deptId() {
|
||||
return this.$store.state.user.deptId
|
||||
},
|
||||
filtereDate() {
|
||||
if (this.searchQuery) {
|
||||
return this.tableData.filter((item) => item.companyName.includes(this.searchQuery) || item.legalName.includes(this.searchQuery))
|
||||
@@ -777,6 +788,12 @@ export default {
|
||||
if (query.backUrl) {
|
||||
this.selectedTab = query.selectedTab
|
||||
this.queryParams.custPattern = query.selectedTab
|
||||
} else {
|
||||
// 默认选中第一个tab
|
||||
const deptId = this.$store.state.user.deptId
|
||||
const deptIdStr = deptId ? String(deptId) : ''
|
||||
this.selectedTab = deptIdStr.startsWith('875') ? '0' : '2'
|
||||
this.queryParams.custPattern = this.selectedTab
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
680
ruoyi-ui/src/views/group/custGroup/components/create-dialog.vue
Normal file
680
ruoyi-ui/src/views/group/custGroup/components/create-dialog.vue
Normal file
@@ -0,0 +1,680 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="isEdit ? '编辑客群' : '创建客群'"
|
||||
:visible.sync="visible"
|
||||
width="700px"
|
||||
:before-close="handleClose"
|
||||
append-to-body
|
||||
>
|
||||
<el-alert
|
||||
v-if="isEdit && isProcessing"
|
||||
title="客群正在处理中,请等待处理完成后再进行编辑"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
style="margin-bottom: 15px"
|
||||
/>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px" v-loading="submitting">
|
||||
<el-form-item label="客群名称" prop="groupName">
|
||||
<el-input v-model="form.groupName" placeholder="请输入客群名称" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客群模式" prop="groupMode">
|
||||
<el-radio-group v-model="form.groupMode" :disabled="isEdit && form.createStatus === '1'">
|
||||
<el-radio label="0">静态客群</el-radio>
|
||||
<el-radio label="1">动态客群</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tip">
|
||||
静态客群:创建后客户列表固定,除非手动更新
|
||||
<br />
|
||||
动态客群:系统定期根据原始条件自动刷新客户列表
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="有效期" prop="validTime">
|
||||
<el-date-picker
|
||||
v-model="form.validTime"
|
||||
type="datetime"
|
||||
placeholder="选择有效期截止时间"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="form-tip">留空表示永久有效</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :rows="2" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启共享">
|
||||
<el-switch v-model="shareEnabled" />
|
||||
</el-form-item>
|
||||
<el-form-item label="可见部门" v-if="shareEnabled">
|
||||
<el-select
|
||||
v-model="form.shareDeptIdList"
|
||||
multiple
|
||||
placeholder="请选择可见部门"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="dept in deptOptions"
|
||||
:key="dept.deptId"
|
||||
:label="dept.deptName"
|
||||
:value="dept.deptId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建方式" prop="createMode">
|
||||
<el-radio-group v-model="form.createMode" :disabled="isEdit">
|
||||
<el-radio label="1">模板导入</el-radio>
|
||||
<el-radio label="2">绩效网格</el-radio>
|
||||
<el-radio label="3">地理网格</el-radio>
|
||||
<el-radio label="4">绘制网格</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 模板导入 -->
|
||||
<template v-if="form.createMode === '1'">
|
||||
<el-form-item label="客户文件" prop="file">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
:on-change="handleFileChange"
|
||||
:auto-upload="false"
|
||||
:show-file-list="true"
|
||||
:limit="1"
|
||||
accept=".xlsx,.xls"
|
||||
>
|
||||
<el-button slot="trigger" size="small" icon="el-icon-upload">选择文件</el-button>
|
||||
<el-button size="small" type="text" @click.stop="downloadTemplate" style="margin-left: 15px">
|
||||
下载模板
|
||||
</el-button>
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
仅支持Excel文件,文件大小不超过10MB
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 绩效网格 -->
|
||||
<template v-if="form.createMode === '2'">
|
||||
<el-form-item label="业务类型" prop="cmpmBizType">
|
||||
<el-select v-model="gridForm.cmpmBizType" placeholder="请选择业务类型" style="width: 100%" @change="handleCmpmBizTypeChange">
|
||||
<el-option label="零售" value="retail" />
|
||||
<el-option label="对公" value="corporate" />
|
||||
<el-option label="对公账户" value="corporate_account" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户经理" prop="userNames">
|
||||
<el-select
|
||||
v-model="gridForm.userNames"
|
||||
multiple
|
||||
filterable
|
||||
placeholder="请选择客户经理"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="user in userOptions"
|
||||
:key="user.userName"
|
||||
:label="user.nickName"
|
||||
:value="user.userName"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 地理网格 -->
|
||||
<template v-if="form.createMode === '3'">
|
||||
<el-form-item label="网格级别">
|
||||
<el-radio-group v-model="regionQuery.gridLevel">
|
||||
<el-radio label="1">总行行政网格</el-radio>
|
||||
<el-radio label="2">支行行政网格</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="责任类型">
|
||||
<el-select v-model="regionQuery.gridDutyType" placeholder="请选择责任类型" style="width: 100%" clearable>
|
||||
<el-option label="责任网格" value="1" />
|
||||
<el-option label="竞争网格" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="网格名称">
|
||||
<el-input v-model="regionQuery.gridName" placeholder="请输入网格名称(可选)" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="loadRegionGridOptions" :loading="regionLoading">查询网格</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetRegionQuery">重置条件</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择网格">
|
||||
<el-select
|
||||
v-model="gridForm.regionGridIds"
|
||||
multiple
|
||||
filterable
|
||||
collapse-tags
|
||||
placeholder="请先查询网格,然后选择"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="grid in regionGridOptions"
|
||||
:key="grid.gridId"
|
||||
:label="grid.gridName"
|
||||
:value="grid.gridId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<!-- 绘制网格 -->
|
||||
<template v-if="form.createMode === '4'">
|
||||
<el-form-item label="绘制网格" prop="drawGridIds">
|
||||
<el-select
|
||||
v-model="gridForm.drawGridIds"
|
||||
multiple
|
||||
filterable
|
||||
placeholder="请选择绘制网格"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="grid in drawGridOptions"
|
||||
:key="grid.gridId"
|
||||
:label="grid.gridName"
|
||||
:value="grid.gridId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
<el-button type="primary" :loading="submitting" :disabled="isProcessing" @click="handleSubmit">
|
||||
{{ submitButtonText }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createCustGroupByGrid,
|
||||
createCustGroupByTemplate,
|
||||
updateCustGroupByGrid,
|
||||
updateCustGroupByTemplate,
|
||||
downloadTemplate,
|
||||
getManagerList,
|
||||
getRegionGridListForGroup
|
||||
} from '@/api/group/custGroup'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { listUser } from '@/api/system/user'
|
||||
import { listDept } from '@/api/system/dept'
|
||||
import { getSimpleGridList } from '@/api/grid/list/gridlist'
|
||||
|
||||
export default {
|
||||
name: 'CreateDialog',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
groupData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 提交中状态
|
||||
submitting: false,
|
||||
// 上传地址
|
||||
uploadUrl: process.env.VUE_APP_BASE_API + '/group/cust/createByTemplate',
|
||||
uploadHeaders: { Authorization: 'Bearer ' + getToken() },
|
||||
// 处理中提示
|
||||
processTipVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 是否正在处理中(创建或更新)
|
||||
isProcessing() {
|
||||
return this.form.createStatus === '0'
|
||||
},
|
||||
// 提交按钮文本
|
||||
submitButtonText() {
|
||||
if (this.submitting) return '提交中...'
|
||||
if (this.isEdit && this.isProcessing) return '客群处理中,请稍后...'
|
||||
return '确 定'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 提交中状态
|
||||
submitting: false,
|
||||
// 上传地址
|
||||
uploadUrl: process.env.VUE_APP_BASE_API + '/group/cust/createByTemplate',
|
||||
uploadHeaders: { Authorization: 'Bearer ' + getToken() },
|
||||
// 处理中提示
|
||||
processTipVisible: false,
|
||||
// 表单数据
|
||||
form: {
|
||||
id: null,
|
||||
groupName: null,
|
||||
groupMode: '0',
|
||||
createMode: '1',
|
||||
groupStatus: '0',
|
||||
shareEnabled: 0,
|
||||
shareDeptIdList: [],
|
||||
remark: null,
|
||||
validTime: null
|
||||
},
|
||||
// 共享开关
|
||||
shareEnabled: false,
|
||||
// 网格表单数据
|
||||
gridForm: {
|
||||
gridType: '0',
|
||||
cmpmBizType: null,
|
||||
userNames: [],
|
||||
regionGridIds: [],
|
||||
drawGridIds: []
|
||||
},
|
||||
// 上传文件
|
||||
uploadFile: null,
|
||||
// 表单验证规则
|
||||
rules: {
|
||||
groupName: [
|
||||
{ required: true, message: '请输入客群名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
groupMode: [{ required: true, message: '请选择客群模式', trigger: 'change' }],
|
||||
createMode: [{ required: true, message: '请选择创建方式', trigger: 'change' }]
|
||||
},
|
||||
// 部门选项
|
||||
deptOptions: [],
|
||||
// 用户选项
|
||||
userOptions: [],
|
||||
// 地理网格选项
|
||||
regionGridOptions: [],
|
||||
// 地理网格查询条件
|
||||
regionQuery: {
|
||||
gridLevel: '1',
|
||||
gridDutyType: null,
|
||||
gridName: null
|
||||
},
|
||||
// 地理网格加载状态
|
||||
regionLoading: false,
|
||||
// 绘制网格选项
|
||||
drawGridOptions: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
groupData: {
|
||||
handler(val) {
|
||||
if (val && Object.keys(val).length > 0) {
|
||||
this.form = { ...val }
|
||||
this.shareEnabled = val.shareEnabled === 1
|
||||
// 解析 shareDeptIds 字符串为 shareDeptIdList 数组
|
||||
if (val.shareDeptIds) {
|
||||
this.form.shareDeptIdList = val.shareDeptIds.split(',').filter(id => id)
|
||||
} else {
|
||||
this.form.shareDeptIdList = []
|
||||
}
|
||||
|
||||
// 反显网格数据(需要在 form.createMode watch 之后执行)
|
||||
this.$nextTick(() => {
|
||||
this.restoreGridData(val)
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
'form.createMode'(val) {
|
||||
// 重置网格表单
|
||||
this.gridForm = {
|
||||
gridType: val === '2' ? '0' : val === '3' ? '1' : '2',
|
||||
regionGridIds: [],
|
||||
drawGridIds: []
|
||||
}
|
||||
// 切换到地理网格模式时,重置查询条件
|
||||
if (val === '3') {
|
||||
this.resetRegionQuery()
|
||||
}
|
||||
// 切换到绘制网格模式时,加载绘制网格列表
|
||||
if (val === '4') {
|
||||
this.loadDrawGridOptions()
|
||||
}
|
||||
},
|
||||
'gridForm.cmpmBizType'(val) {
|
||||
// 当业务类型改变时,清空已选择的客户经理
|
||||
if (val) {
|
||||
this.gridForm.userNames = []
|
||||
this.loadManagerOptions()
|
||||
}
|
||||
},
|
||||
'form.createStatus'(val) {
|
||||
// 监听创建状态变化,显示提示
|
||||
if (this.isEdit && val === '0') {
|
||||
this.processTipVisible = true
|
||||
} else if (this.processTipVisible) {
|
||||
this.processTipVisible = false
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadDeptOptions()
|
||||
},
|
||||
methods: {
|
||||
/** 初始化 */
|
||||
init() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
// 编辑模式下,恢复网格数据
|
||||
if (this.isEdit && this.groupData && Object.keys(this.groupData).length > 0) {
|
||||
this.restoreGridData(this.groupData)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 反显网格数据 */
|
||||
restoreGridData(data) {
|
||||
if (!this.isEdit) return
|
||||
|
||||
const createMode = String(data.createMode)
|
||||
// 根据创建方式反显网格数据
|
||||
if (createMode === '2' && data.gridType === '0') {
|
||||
// 绩效网格
|
||||
this.gridForm.gridType = '0'
|
||||
this.gridForm.cmpmBizType = data.cmpmBizType
|
||||
if (data.gridUserNames) {
|
||||
this.gridForm.userNames = data.gridUserNames.split(',').filter(n => n)
|
||||
// 加载客户经理选项
|
||||
this.loadManagerOptions()
|
||||
}
|
||||
} else if (createMode === '3' && data.gridType === '1') {
|
||||
// 地理网格 - 需要查询所有网格以便正确反显
|
||||
this.gridForm.gridType = '1'
|
||||
// 设置默认查询条件(获取所有网格)
|
||||
this.regionQuery = {
|
||||
gridLevel: '1',
|
||||
gridDutyType: null,
|
||||
gridName: null
|
||||
}
|
||||
if (data.regionGridIds) {
|
||||
this.gridForm.regionGridIds = data.regionGridIds.split(',').map(id => parseInt(id)).filter(id => id)
|
||||
// 加载地理网格选项(无查询条件,获取全部)
|
||||
this.loadRegionGridOptions()
|
||||
}
|
||||
} else if (createMode === '4' && data.gridType === '2') {
|
||||
// 绘制网格
|
||||
this.gridForm.gridType = '2'
|
||||
if (data.drawGridIds) {
|
||||
this.gridForm.drawGridIds = data.drawGridIds.split(',').map(id => parseInt(id)).filter(id => id)
|
||||
// 加载绘制网格选项
|
||||
this.loadDrawGridOptions()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** 加载部门选项 */
|
||||
loadDeptOptions() {
|
||||
listDept().then(response => {
|
||||
this.deptOptions = response.data || []
|
||||
}).catch(() => {
|
||||
this.deptOptions = []
|
||||
})
|
||||
},
|
||||
|
||||
/** 加载用户选项 */
|
||||
loadUserOptions() {
|
||||
listUser().then(response => {
|
||||
this.userOptions = response.rows || []
|
||||
}).catch(() => {
|
||||
this.userOptions = []
|
||||
})
|
||||
},
|
||||
|
||||
/** 根据业务类型加载客户经理选项 */
|
||||
loadManagerOptions() {
|
||||
if (!this.gridForm.cmpmBizType) {
|
||||
this.userOptions = []
|
||||
return
|
||||
}
|
||||
getManagerList(this.gridForm.cmpmBizType).then(response => {
|
||||
this.userOptions = response.data || []
|
||||
}).catch(() => {
|
||||
this.userOptions = []
|
||||
})
|
||||
},
|
||||
|
||||
/** 业务类型改变处理 */
|
||||
handleCmpmBizTypeChange(val) {
|
||||
// 清空已选择的客户经理
|
||||
this.gridForm.userNames = []
|
||||
},
|
||||
|
||||
/** 加载地理网格选项 */
|
||||
loadRegionGridOptions() {
|
||||
this.regionLoading = true
|
||||
const params = {
|
||||
gridLevel: this.regionQuery.gridLevel
|
||||
}
|
||||
if (this.regionQuery.gridDutyType) {
|
||||
params.gridDutyType = this.regionQuery.gridDutyType
|
||||
}
|
||||
if (this.regionQuery.gridName) {
|
||||
params.gridName = this.regionQuery.gridName
|
||||
}
|
||||
|
||||
getRegionGridListForGroup(params).then(response => {
|
||||
this.regionGridOptions = response.data || []
|
||||
}).catch(() => {
|
||||
this.regionGridOptions = []
|
||||
}).finally(() => {
|
||||
this.regionLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 重置地理网格查询条件 */
|
||||
resetRegionQuery() {
|
||||
this.regionQuery = {
|
||||
gridLevel: '1',
|
||||
gridDutyType: null,
|
||||
gridName: null
|
||||
}
|
||||
this.gridForm.regionGridIds = []
|
||||
},
|
||||
|
||||
/** 加载绘制网格选项 */
|
||||
loadDrawGridOptions() {
|
||||
getSimpleGridList().then(response => {
|
||||
this.drawGridOptions = response.data || []
|
||||
}).catch(() => {
|
||||
this.drawGridOptions = []
|
||||
})
|
||||
},
|
||||
|
||||
/** 文件改变 */
|
||||
handleFileChange(file) {
|
||||
this.uploadFile = file.raw
|
||||
},
|
||||
|
||||
/** 上传成功 */
|
||||
handleUploadSuccess(response) {
|
||||
this.$modal.msgSuccess('创建成功')
|
||||
this.submitting = false
|
||||
this.$emit('submit', { id: response.data })
|
||||
this.handleClose()
|
||||
},
|
||||
|
||||
/** 上传失败 */
|
||||
handleUploadError() {
|
||||
this.$modal.msgError('创建失败')
|
||||
this.submitting = false
|
||||
},
|
||||
|
||||
/** 下载模板 */
|
||||
downloadTemplate() {
|
||||
downloadTemplate().then(response => {
|
||||
const url = window.URL.createObjectURL(new Blob([response]))
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', '客户信息模板.xlsx')
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
},
|
||||
|
||||
/** 提交表单 */
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
// 处理共享设置
|
||||
this.form.shareEnabled = this.shareEnabled ? 1 : 0
|
||||
// 转换 shareDeptIdList 数组为 shareDeptIds 逗号分隔字符串
|
||||
this.form.shareDeptIds = this.form.shareDeptIdList.join(',')
|
||||
|
||||
// 根据创建方式处理提交数据
|
||||
if (this.form.createMode === '1') {
|
||||
this.handleTemplateSubmit()
|
||||
} else {
|
||||
this.handleGridSubmit()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 模板导入提交 */
|
||||
handleTemplateSubmit() {
|
||||
if (!this.uploadFile && !this.isEdit) {
|
||||
this.$modal.msgWarning('请选择要上传的文件')
|
||||
return
|
||||
}
|
||||
|
||||
this.submitting = true
|
||||
|
||||
// 构建表单数据
|
||||
const formData = new FormData()
|
||||
formData.append('dto', JSON.stringify(this.form))
|
||||
if (this.uploadFile) {
|
||||
formData.append('file', this.uploadFile)
|
||||
}
|
||||
|
||||
if (this.isEdit) {
|
||||
// 编辑模式:重新导入模板文件
|
||||
updateCustGroupByTemplate(formData).then(response => {
|
||||
this.$modal.msgSuccess('客群更新中,请稍后刷新查看')
|
||||
this.submitting = false
|
||||
this.$emit('submit', { id: this.form.id })
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
} else {
|
||||
// 新增模式
|
||||
createCustGroupByTemplate(formData).then(response => {
|
||||
this.$modal.msgSuccess('客群创建中,请稍后刷新查看')
|
||||
this.submitting = false
|
||||
this.$emit('submit', { id: response.data })
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/** 网格导入提交 */
|
||||
handleGridSubmit() {
|
||||
this.submitting = true
|
||||
|
||||
// 构建提交数据
|
||||
const submitData = {
|
||||
custGroup: { ...this.form },
|
||||
gridType: this.form.createMode === '2' ? '0' : this.form.createMode === '3' ? '1' : '2',
|
||||
cmpmBizType: this.gridForm.cmpmBizType,
|
||||
userNames: this.gridForm.userNames,
|
||||
regionGridIds: this.gridForm.regionGridIds,
|
||||
drawGridIds: this.gridForm.drawGridIds
|
||||
}
|
||||
|
||||
if (this.isEdit) {
|
||||
// 编辑模式:重新导入网格
|
||||
updateCustGroupByGrid(submitData).then(response => {
|
||||
// 使用后端返回的消息
|
||||
const msg = response.msg || '客群更新成功'
|
||||
if (msg.includes('更新中')) {
|
||||
this.$modal.msgSuccess('客群更新中,请稍后刷新查看')
|
||||
} else {
|
||||
this.$modal.msgSuccess(msg)
|
||||
}
|
||||
this.submitting = false
|
||||
this.$emit('submit', { id: this.form.id })
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
} else {
|
||||
// 新增模式
|
||||
createCustGroupByGrid(submitData).then(response => {
|
||||
this.$modal.msgSuccess('客群创建中,请稍后刷新查看')
|
||||
this.submitting = false
|
||||
this.$emit('submit', { id: response.data })
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/** 关闭弹窗 */
|
||||
handleClose() {
|
||||
this.$emit('update:visible', false)
|
||||
this.resetForm()
|
||||
},
|
||||
|
||||
/** 重置表单 */
|
||||
resetForm() {
|
||||
this.form = {
|
||||
id: null,
|
||||
groupName: null,
|
||||
groupMode: '0',
|
||||
createMode: '1',
|
||||
groupStatus: '0',
|
||||
shareEnabled: 0,
|
||||
shareDeptIdList: [],
|
||||
remark: null,
|
||||
validTime: null
|
||||
}
|
||||
this.shareEnabled = false
|
||||
this.gridForm = {
|
||||
gridType: '0',
|
||||
cmpmBizType: null,
|
||||
userNames: [],
|
||||
regionGridIds: [],
|
||||
drawGridIds: []
|
||||
}
|
||||
this.uploadFile = null
|
||||
if (this.$refs.upload) {
|
||||
this.$refs.upload.clearFiles()
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
line-height: 1.5;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
187
ruoyi-ui/src/views/group/custGroup/detail.vue
Normal file
187
ruoyi-ui/src/views/group/custGroup/detail.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="customer-wrap detail-wrap">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<el-button icon="el-icon-arrow-left" size="small" @click="goBack">返回</el-button>
|
||||
<span class="page-title">客群客户列表</span>
|
||||
</div>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-area">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="80px">
|
||||
<el-form-item label="客户类型" prop="custType">
|
||||
<el-select v-model="queryParams.custType" placeholder="请选择" clearable style="width: 150px">
|
||||
<el-option label="个人" value="0" />
|
||||
<el-option label="商户" value="1" />
|
||||
<el-option label="企业" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户姓名" prop="custName">
|
||||
<el-input
|
||||
v-model="queryParams.custName"
|
||||
placeholder="请输入客户姓名"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<div class="main_table">
|
||||
<el-table v-loading="loading" :data="memberList">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" :index="indexMethod" />
|
||||
<el-table-column label="客户类型" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.custType === '0'" size="small">个人</el-tag>
|
||||
<el-tag v-else-if="scope.row.custType === '1'" size="small" type="warning">商户</el-tag>
|
||||
<el-tag v-else-if="scope.row.custType === '2'" size="small" type="success">企业</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户号" prop="custId" width="150" />
|
||||
<el-table-column label="客户姓名" prop="custName" width="120" />
|
||||
<el-table-column label="身份证号" prop="custIdc" show-overflow-tooltip />
|
||||
<el-table-column label="统信码" prop="socialCreditCode" show-overflow-tooltip />
|
||||
<el-table-column label="添加时间" prop="createTime" width="180" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCustGroupMembers } from '@/api/group/custGroup'
|
||||
|
||||
export default {
|
||||
name: 'CustGroupDetail',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
groupId: null,
|
||||
memberList: [],
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
custType: null,
|
||||
custName: null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.groupId = this.$route.query.groupId
|
||||
if (this.groupId) {
|
||||
this.getList()
|
||||
} else {
|
||||
this.$modal.msgError('缺少客群ID参数')
|
||||
this.goBack()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route.query.groupId'(newGroupId) {
|
||||
if (newGroupId && newGroupId !== this.groupId) {
|
||||
this.groupId = newGroupId
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询客户列表 */
|
||||
getList(param) {
|
||||
if (param) {
|
||||
this.queryParams.pageNum = param.page
|
||||
this.queryParams.pageSize = param.limit
|
||||
}
|
||||
this.loading = true
|
||||
listCustGroupMembers(this.groupId, this.queryParams).then(response => {
|
||||
this.memberList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 搜索 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
/** 重置 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
|
||||
/** 返回 */
|
||||
goBack() {
|
||||
this.$router.push({ path: '/group/custGroup' })
|
||||
},
|
||||
|
||||
/** 序号计算方法 */
|
||||
indexMethod(index) {
|
||||
return (this.queryParams.pageNum - 1) * this.queryParams.pageSize + index + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.customer-wrap {
|
||||
background-color: #ffffff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 8px 0 #00000017;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 24px 30px;
|
||||
|
||||
&.detail-wrap {
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.page-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #222222;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-area {
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.el-form {
|
||||
margin-bottom: -8px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main_table {
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
288
ruoyi-ui/src/views/group/custGroup/index.vue
Normal file
288
ruoyi-ui/src/views/group/custGroup/index.vue
Normal file
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<div class="customer-wrap">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-area" v-show="showSearch">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="80px">
|
||||
<el-form-item label="客群名称" prop="groupName">
|
||||
<el-input
|
||||
v-model="queryParams.groupName"
|
||||
placeholder="请输入客群名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="客群模式" prop="groupMode">
|
||||
<el-select v-model="queryParams.groupMode" placeholder="请选择" clearable style="width: 150px">
|
||||
<el-option label="静态" value="0" />
|
||||
<el-option label="动态" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建方式" prop="createMode">
|
||||
<el-select v-model="queryParams.createMode" placeholder="请选择" clearable style="width: 150px">
|
||||
<el-option label="模板导入" value="1" />
|
||||
<el-option label="绩效网格" value="2" />
|
||||
<el-option label="地理网格" value="3" />
|
||||
<el-option label="绘制网格" value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="客群状态" prop="groupStatus">
|
||||
<el-select v-model="queryParams.groupStatus" placeholder="请选择" clearable style="width: 150px">
|
||||
<el-option label="正常" value="0" />
|
||||
<el-option label="已禁用" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 操作栏 -->
|
||||
<section class="operate-cnt">
|
||||
<div class="operate-left">
|
||||
<el-button type="primary" icon="el-icon-plus" size="small" @click="handleAdd">新增</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" size="small" :disabled="multiple" @click="handleDelete">删除</el-button>
|
||||
</div>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</section>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<div class="main_table">
|
||||
<el-table v-loading="loading" :data="groupList" @selection-change="handleSelectionChange" style="width: 100%" max-height="625">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="客群名称" prop="groupName" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column label="客群模式" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.groupMode === '0'" type="info" size="small">静态</el-tag>
|
||||
<el-tag v-else-if="scope.row.groupMode === '1'" type="success" size="small">动态</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建方式" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.createMode === '1'">模板导入</span>
|
||||
<span v-else-if="scope.row.createMode === '2'">绩效网格</span>
|
||||
<span v-else-if="scope.row.createMode === '3'">地理网格</span>
|
||||
<span v-else-if="scope.row.createMode === '4'">绘制网格</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户数量" align="center" prop="custCount" width="100" />
|
||||
<el-table-column label="客群状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.groupStatus === '0'" type="success" size="small">正常</el-tag>
|
||||
<el-tag v-else-if="scope.row.groupStatus === '1'" type="danger" size="small">已禁用</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建者" prop="nickName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" prop="createTime" width="180" />
|
||||
<el-table-column label="操作" align="center" width="180" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)">查看</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 创建/编辑客群弹窗 -->
|
||||
<create-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:group-data="form"
|
||||
:is-edit="isEdit"
|
||||
@submit="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCustGroup, getCustGroup, deleteCustGroup } from '@/api/group/custGroup'
|
||||
import CreateDialog from './components/create-dialog'
|
||||
|
||||
export default {
|
||||
name: 'CustGroup',
|
||||
components: { CreateDialog },
|
||||
data() {
|
||||
return {
|
||||
// 加载状态
|
||||
loading: false,
|
||||
// 显示搜索
|
||||
showSearch: true,
|
||||
// 选中ID数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 客群列表
|
||||
groupList: [],
|
||||
// 弹窗显示
|
||||
dialogVisible: false,
|
||||
// 是否编辑
|
||||
isEdit: false,
|
||||
// 表单数据
|
||||
form: {},
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
groupName: null,
|
||||
groupMode: null,
|
||||
createMode: null,
|
||||
groupStatus: null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
/** 查询客群列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listCustGroup(this.queryParams).then(response => {
|
||||
this.groupList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
|
||||
/** 多选框选中数据 */
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.isEdit = false
|
||||
this.dialogVisible = true
|
||||
},
|
||||
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id || this.ids[0]
|
||||
getCustGroup(id).then(response => {
|
||||
this.form = response.data
|
||||
this.isEdit = true
|
||||
this.dialogVisible = true
|
||||
})
|
||||
},
|
||||
|
||||
/** 查看按钮操作 */
|
||||
handleView(row) {
|
||||
this.$router.push({
|
||||
path: '/group/custGroup/detail',
|
||||
query: { groupId: row.id }
|
||||
})
|
||||
},
|
||||
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id ? [row.id] : this.ids
|
||||
this.$modal.confirm('是否确认删除选中的客群?').then(() => {
|
||||
return deleteCustGroup(ids)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/** 提交表单 */
|
||||
handleSubmit() {
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
},
|
||||
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
groupName: null,
|
||||
groupMode: '0',
|
||||
createMode: null,
|
||||
groupStatus: '0',
|
||||
shareEnabled: 0,
|
||||
shareDeptIdList: [],
|
||||
remark: null,
|
||||
validTime: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.customer-wrap {
|
||||
background-color: #ffffff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 8px 0 #00000017;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 24px 30px;
|
||||
|
||||
.search-area {
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.el-form {
|
||||
margin-bottom: -8px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.operate-cnt {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 24px 0 16px 0;
|
||||
|
||||
.operate-left {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.main_table {
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -20,6 +20,7 @@
|
||||
<span style="font-size: 14px;">较上月变动</span>
|
||||
<span v-if="String(item.inc).includes('-')" style=" font-size: 14px;color: #00B453">{{ changeData(item.inc)
|
||||
}}<i class="el-icon-caret-bottom"></i></span>
|
||||
<span v-else-if="item.inc == 0 || item.inc === '0'" style=" font-size: 14px;color: #409EFF">{{ changeData(item.inc) }}</span>
|
||||
<span v-else style=" font-size: 14px;color: #EF3F35">{{ changeData(item.inc) }}<i
|
||||
class="el-icon-caret-top"></i></span>
|
||||
</div>
|
||||
@@ -43,6 +44,11 @@
|
||||
@click="goToCustManager(item.itemNm, 'fall')">
|
||||
{{ item.curAmt }}<i class="el-icon-caret-bottom"></i>
|
||||
</span>
|
||||
<span v-else-if="item.curAmt == 0 || item.curAmt === '0'"
|
||||
style="font-size: 14px; color: #409EFF; cursor: pointer;"
|
||||
@click="goToCustManager(item.itemNm, 'rise')">
|
||||
{{ item.curAmt }}
|
||||
</span>
|
||||
<span v-else
|
||||
style="font-size: 14px; color: #EF3F35; cursor: pointer;"
|
||||
@click="goToCustManager(item.itemNm, 'rise')">
|
||||
@@ -60,7 +66,7 @@
|
||||
<el-radio-button label="4">预警任务</el-radio-button>
|
||||
<el-radio-button label="5">二次走访提醒</el-radio-button>
|
||||
<el-radio-button label="6">走访资源提醒</el-radio-button>
|
||||
<el-radio-button label="7">营销任务</el-radio-button>
|
||||
<el-radio-button label="7" v-if="!shouldHideFor875">营销任务</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<el-table v-if="selectedTab==='3'" key="3" :data="tableData" :loading="loading" style="width: 100%;margin-top: 20px;">
|
||||
@@ -152,7 +158,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table v-if="selectedTab==='7'" key="7" :data="tableData" :loading="loading" style="width: 100%;margin-top: 20px;">
|
||||
<el-table v-if="selectedTab==='7' && !shouldHideFor875" key="7" :data="tableData" :loading="loading" style="width: 100%;margin-top: 20px;">
|
||||
<el-table-column label="营销任务" width="200" prop="marketTaskName" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="客户姓名" prop="custName" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="客户号" width="200" prop="custId" min-width="140" show-overflow-tooltip />
|
||||
@@ -194,9 +200,9 @@
|
||||
<el-table-column label="结束时间" width="200" prop="endTime" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<el-pagination @size-change="handleAgentSizeChange" @current-change="handleAgentCurrentChange"
|
||||
class="warnPagination" :page-sizes="[5, 10, 20, 30]" :page-size="agentPageSize"
|
||||
layout="->,total,sizes,prev,pager,next" :total="agentTotal" :current-page="agentPageNum"></el-pagination>
|
||||
<el-pagination @current-change="handleAgentCurrentChange"
|
||||
class="warnPagination" :page-size="5"
|
||||
layout="->,total,prev,pager,next" :total="agentTotal" :current-page="agentPageNum"></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-vr">
|
||||
@@ -210,7 +216,7 @@
|
||||
</span>
|
||||
</p>
|
||||
<ul class="operate-cnt">
|
||||
<li v-for="(it, ind) in optArr" :key="ind" class="setLi" @mouseenter="onMouseOver(ind, true)"
|
||||
<li v-for="(it, ind) in filteredOptArr" :key="ind" class="setLi" @mouseenter="onMouseOver(ind, true)"
|
||||
@mouseleave="onMouseOver(ind, false)">
|
||||
<div class="noSetting" v-if="it.setShow">
|
||||
<svg-icon :icon-class="getCurrentImg(ind)" :class="isSetting ? 'svg-icon-imgSetting' : 'svg-icon-img'"
|
||||
@@ -230,7 +236,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="page-vr-middle page-common-wrap no-padding-cnt page-vr-top" id="yjxxMain">
|
||||
<div class="page-vr-middle page-common-wrap no-padding-cnt page-vr-top" id="yjxxMain" v-if="!shouldHideFor875">
|
||||
<p class="page-title page-btm">预警信息</p>
|
||||
<ul class="common-ul">
|
||||
<li v-for="(it, ind) in warnArr" :key="ind" style="cursor: pointer;" @click="handleWarn(it)" class="yjxxLi">
|
||||
@@ -857,6 +863,27 @@ export default {
|
||||
},
|
||||
showposition() {
|
||||
return this.userName.slice(0, 3) === '875'
|
||||
},
|
||||
// headId为875时隐藏预警信息和营销任务
|
||||
shouldHideFor875() {
|
||||
return this.userName && (this.userName + '').substring(0, 3) === '875'
|
||||
},
|
||||
// headId为875时,便捷操作只显示快速入门
|
||||
filteredOptArr() {
|
||||
// 当deptId以875开头时,只保留快速入门
|
||||
if (this.deptId && String(this.deptId).startsWith('875')) {
|
||||
return this.optArr.filter(item => item.name === '快速入门')
|
||||
}
|
||||
return this.optArr
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedTab(newVal, oldVal) {
|
||||
// 切换tab时重置分页为第1页
|
||||
if (newVal !== oldVal) {
|
||||
this.pageNum = 1
|
||||
this.agentPageNum = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -1135,8 +1162,7 @@ export default {
|
||||
this.getData()
|
||||
},
|
||||
handleAgentCurrentChange(val) {
|
||||
// this.agentPageNum = val
|
||||
// this.initBranchList()
|
||||
this.agentPageNum = val
|
||||
this.pageNum = val
|
||||
this.getData()
|
||||
},
|
||||
@@ -1565,6 +1591,8 @@ p {
|
||||
.page-vr {
|
||||
width: 24%;
|
||||
margin-left: 1%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
@@ -1602,7 +1630,11 @@ p {
|
||||
}
|
||||
|
||||
.page-vr-middle {
|
||||
margin: 22px 0;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.page-vr-top {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.page-vl-top {
|
||||
@@ -1873,7 +1905,7 @@ p {
|
||||
.page-vr-btm {
|
||||
height: 350px;
|
||||
overflow-y: scroll;
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
::v-deep .el-badge__content {
|
||||
@@ -1943,8 +1975,10 @@ p {
|
||||
}
|
||||
|
||||
.url-box {
|
||||
max-height: 210px;
|
||||
flex: 1;
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.yjxxLi {
|
||||
|
||||
@@ -6,24 +6,46 @@
|
||||
v-model="selectedTab"
|
||||
@input="handleChange"
|
||||
>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button
|
||||
>
|
||||
<template v-if="String(deptId).substring(0, 3) === '875'">
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button
|
||||
>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button
|
||||
>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
<div class="searchForm">
|
||||
<el-form
|
||||
@@ -403,6 +425,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["roles", "userName"]),
|
||||
deptId() {
|
||||
return this.$store.state.user.deptId
|
||||
},
|
||||
//总行
|
||||
isHeadAdmin() {
|
||||
return this.roles.includes("headAdmin");
|
||||
@@ -441,12 +466,17 @@ export default {
|
||||
if (selectedTab) {
|
||||
this.selectedTab = selectedTab;
|
||||
} else {
|
||||
// 默认选中第一个tab
|
||||
const deptId = this.$store.state.user.deptId
|
||||
const deptIdStr = deptId ? String(deptId) : ''
|
||||
const defaultTab = deptIdStr.startsWith('875') ? '0' : '2'
|
||||
|
||||
if (this.isPublic) {
|
||||
this.selectedTab = '2'
|
||||
} else if (this.isPrivate) {
|
||||
this.selectedTab = '0'
|
||||
this.selectedTab = defaultTab
|
||||
} else {
|
||||
this.selectedTab = '2'
|
||||
this.selectedTab = defaultTab
|
||||
}
|
||||
}
|
||||
this.initVisitingTaskList();
|
||||
|
||||
@@ -64,9 +64,16 @@
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-radio-group class="header-radio" v-model="selectedTab" @input="handleChange">
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<template v-if="String(deptId).substring(0, 3) === '875'">
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-radio-button label="2" :disabled="isPrivate" :class="{ 'btn-disabled': isPrivate }">企业</el-radio-button>
|
||||
<el-radio-button label="0" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">个人</el-radio-button>
|
||||
<el-radio-button label="1" :disabled="isPublic" :class="{ 'btn-disabled': isPublic }">商户</el-radio-button>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
<!-- <div class="taskTop">
|
||||
<div class="taskTop_left">
|
||||
@@ -292,6 +299,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
deptId() {
|
||||
return this.$store.state.user.deptId
|
||||
},
|
||||
//总行
|
||||
isHeadAdmin() {
|
||||
return this.roles.includes('headAdmin')
|
||||
@@ -334,12 +344,17 @@ export default {
|
||||
delete this.$route.query[key];
|
||||
}
|
||||
} else {
|
||||
// 默认选中第一个tab
|
||||
const deptId = this.$store.state.user.deptId
|
||||
const deptIdStr = deptId ? String(deptId) : ''
|
||||
const defaultTab = deptIdStr.startsWith('875') ? '0' : '2'
|
||||
|
||||
if (this.isPublic) {
|
||||
this.selectedTab = '2'
|
||||
} else if (this.isPrivate) {
|
||||
this.selectedTab = '0'
|
||||
this.selectedTab = defaultTab
|
||||
} else {
|
||||
this.selectedTab = '2'
|
||||
this.selectedTab = defaultTab
|
||||
}
|
||||
}
|
||||
if (this.isBranchAdmin) {
|
||||
|
||||
@@ -6,21 +6,40 @@
|
||||
class="header-radio"
|
||||
@input="handleChange"
|
||||
>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button>
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button>
|
||||
<template v-if="String(deptId).substring(0, 3) === '875'">
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-radio-button
|
||||
label="2"
|
||||
:disabled="isPrivate"
|
||||
:class="{ 'btn-disabled': isPrivate }"
|
||||
>企业</el-radio-button>
|
||||
<el-radio-button
|
||||
label="0"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>个人</el-radio-button>
|
||||
<el-radio-button
|
||||
label="1"
|
||||
:disabled="isPublic"
|
||||
:class="{ 'btn-disabled': isPublic }"
|
||||
>商户</el-radio-button>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
<div class="taskTop">
|
||||
<div class="taskTop_left">
|
||||
@@ -1180,6 +1199,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
deptId() {
|
||||
return this.$store.state.user.deptId
|
||||
},
|
||||
// 总行
|
||||
isHeadAdmin() {
|
||||
return this.roles.includes('headAdmin')
|
||||
@@ -1215,17 +1237,22 @@ export default {
|
||||
created() {
|
||||
// getGroupInfoByGroupId({})
|
||||
this.isUserType()
|
||||
// 根据deptId动态设置默认tab:默认选中第一个tab
|
||||
const deptId = this.$store.state.user.deptId
|
||||
const deptIdStr = deptId ? String(deptId) : ''
|
||||
const defaultTab = deptIdStr.startsWith('875') ? '0' : '2'
|
||||
|
||||
if (this.isPublic) {
|
||||
this.selectedTab = '2'
|
||||
this.custTypeList = [{ label: '企业', value: '2' }]
|
||||
} else if (this.isPrivate) {
|
||||
this.selectedTab = '0'
|
||||
this.selectedTab = defaultTab
|
||||
this.custTypeList = [
|
||||
{ label: '个人', value: '0' },
|
||||
{ label: '商户', value: '1' }
|
||||
]
|
||||
} else {
|
||||
this.selectedTab = '2'
|
||||
this.selectedTab = defaultTab
|
||||
this.custTypeList = [
|
||||
{ label: '个人', value: '0' },
|
||||
{ label: '商户', value: '1' },
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
<template>
|
||||
<div class="app-container" style="padding: 0px !important;">
|
||||
<el-date-picker
|
||||
v-model="reportTime"
|
||||
placeholder="请选择日期"
|
||||
@change="initCardList"
|
||||
class="time-picker"
|
||||
/>
|
||||
<el-row :gutter="24" style="padding: 0 30px;margin-left: -15px;">
|
||||
<el-row :gutter="24" style="padding: 0 30px;">
|
||||
<el-col :span="6">
|
||||
<el-card class="box-card">
|
||||
<div class="my-span-checklist-title">
|
||||
总预警推送次数
|
||||
<el-card class="stat-card stat-card-blue">
|
||||
<div class="stat-icon">
|
||||
<i class="el-icon-bell"></i>
|
||||
</div>
|
||||
<div class="my-span-checklist-main">
|
||||
<span>{{ cardInfo.alterCount }}</span>
|
||||
<div class="stat-content">
|
||||
<div class="stat-title">总预警推送次数</div>
|
||||
<div class="stat-value">{{ cardInfo.alterCount }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="box-card1">
|
||||
<div class="my-span-checklist-title">
|
||||
反馈完成率
|
||||
<el-card class="stat-card stat-card-blue2">
|
||||
<div class="stat-icon">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
</div>
|
||||
<div class="my-span-checklist-main">
|
||||
<span>{{ cardInfo.completeRate + '%' }}</span>
|
||||
<div class="stat-content">
|
||||
<div class="stat-title">反馈完成率</div>
|
||||
<div class="stat-value">{{ cardInfo.completeRate + '%' }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -35,6 +31,14 @@
|
||||
:inline="true"
|
||||
style="margin-top:20px;"
|
||||
>
|
||||
<el-form-item label="日期">
|
||||
<el-date-picker
|
||||
v-model="reportTime"
|
||||
placeholder="请选择日期"
|
||||
@change="initCardList"
|
||||
style="width:100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="searchArray.status" placeholder="请选择状态" style="width: 100%" clearable>
|
||||
<el-option
|
||||
@@ -46,20 +50,26 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="预警类型" prop="alterType">
|
||||
<el-input
|
||||
<el-select
|
||||
v-model="searchArray.alterType"
|
||||
placeholder="请输入预警类型"
|
||||
placeholder="请选择预警类型"
|
||||
clearable
|
||||
style="width:100%"
|
||||
>
|
||||
</el-input>
|
||||
<el-option
|
||||
v-for="item in alterTypeOptions"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="searchFn">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetFn">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="loading" :data="tableData" :height="dyHeight" :key="tableKey">
|
||||
<el-table v-loading="loading" :data="tableData">
|
||||
<template>
|
||||
<el-table-column label="序号" prop="xh" width="80">
|
||||
<template slot-scope="scope">
|
||||
@@ -91,17 +101,15 @@
|
||||
</el-table-column> -->
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="pagination_end">
|
||||
<el-pagination
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:current-page="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
@current-change="currentChangeFn"
|
||||
:total="total"
|
||||
@size-change="sizeChangeFn"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<el-pagination
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:page-size="pageSize"
|
||||
layout="->,total,prev,pager,next,sizes"
|
||||
:total="total"
|
||||
:current-page="pageNum"
|
||||
@current-change="currentChangeFn"
|
||||
@size-change="sizeChangeFn"
|
||||
></el-pagination>
|
||||
|
||||
<el-dialog
|
||||
:title="dialogTitle"
|
||||
@@ -199,7 +207,8 @@
|
||||
import {
|
||||
warningworkRecordList,
|
||||
warningworkRecordSubmit,
|
||||
warningCardNum
|
||||
warningCardNum,
|
||||
getAlterTypes
|
||||
} from "@/api/system/home";
|
||||
import _ from "lodash";
|
||||
import dayjs from "dayjs";
|
||||
@@ -243,6 +252,8 @@ export default {
|
||||
}
|
||||
],
|
||||
|
||||
alterTypeOptions: [],
|
||||
|
||||
searchArray: {
|
||||
status: "",
|
||||
alterType: ""
|
||||
@@ -252,8 +263,6 @@ export default {
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
dyHeight: {},
|
||||
tableKey: false,
|
||||
dialogTitle: '',
|
||||
dialogForm: {
|
||||
custName: '',
|
||||
@@ -277,12 +286,9 @@ export default {
|
||||
};
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("resize", () => {
|
||||
this.dyHeight = Number(window.innerHeight) - 330;
|
||||
});
|
||||
this.dyHeight = Number(window.innerHeight) - 330;
|
||||
this.resetFn();
|
||||
this.initCardList()
|
||||
this.initCardList();
|
||||
this.getAlterTypeList();
|
||||
},
|
||||
filters: {
|
||||
formatFilter(v, type, list) {
|
||||
@@ -293,6 +299,13 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAlterTypeList() {
|
||||
getAlterTypes().then(res => {
|
||||
if (res.code === 200) {
|
||||
this.alterTypeOptions = res.data || [];
|
||||
}
|
||||
});
|
||||
},
|
||||
initCardList() {
|
||||
warningCardNum({ reportTime: this.reportTime ? dayjs(this.reportTime).format('YYYY-MM-DD') + ' 23:59:59' : '' }).then(res => {
|
||||
this.cardInfo = res
|
||||
@@ -326,7 +339,6 @@ export default {
|
||||
} else {
|
||||
this.$message.error(response.msg || "操作失败");
|
||||
}
|
||||
this.tableKey = !this.tableKey;
|
||||
});
|
||||
},
|
||||
currentChangeFn(val) {
|
||||
@@ -369,45 +381,79 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pagination_end {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.time-picker {
|
||||
margin: 20px 0 0 0px;
|
||||
}
|
||||
|
||||
.box-card {
|
||||
// 统计卡片样式
|
||||
.stat-card {
|
||||
height: 100px;
|
||||
border-radius: 8px;
|
||||
margin-top: 25px;
|
||||
margin-left: -30px;
|
||||
border: 3px solid #a8c2f5;
|
||||
}
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
.box-card1 {
|
||||
height: 100px;
|
||||
border-radius: 8px;
|
||||
margin-top: 25px;
|
||||
border: 3px solid #a8c2f5;
|
||||
}
|
||||
// 左侧装饰条
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.my-span-checklist-title {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.stat-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.my-span-checklist-main {
|
||||
line-height: 40px;
|
||||
font-size: 30px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
i {
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.stat-title {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// 蓝色渐变卡片1(左上深→右下浅)
|
||||
&.stat-card-blue {
|
||||
background: linear-gradient(135deg, #1e7ee6 0%, #a0cfff 100%);
|
||||
}
|
||||
|
||||
// 蓝色渐变卡片2(左上浅→右下深)
|
||||
&.stat-card-blue2 {
|
||||
background: linear-gradient(135deg, #a0cfff 0%, #1e7ee6 100%);
|
||||
}
|
||||
}
|
||||
.header-radio {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user