Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9720ee005a |
@ -1,4 +1,4 @@
|
|||||||
# 管理系统 (Font ERP)
|
# 丰链管理系统 (Font ERP)
|
||||||
|
|
||||||
基于 Vue 3 + Vite 构建的现代化企业资源管理系统
|
基于 Vue 3 + Vite 构建的现代化企业资源管理系统
|
||||||
|
|
||||||
|
|||||||
2
env/.env.prod
vendored
2
env/.env.prod
vendored
@ -1,6 +1,6 @@
|
|||||||
mode = prod
|
mode = prod
|
||||||
VITE_APP_MODE = 'prod'
|
VITE_APP_MODE = 'prod'
|
||||||
VITE_API_URL = https://erpapi.cydculture.com/
|
VITE_API_URL = https://erpapi.fontree.cn/
|
||||||
VITE_FIEE_API_URL = 'https://erpapi.fiee.com/'
|
VITE_FIEE_API_URL = 'https://erpapi.fiee.com/'
|
||||||
VITE_FIEE_API_URL_FILE = 'https://saas.fiee.com/'
|
VITE_FIEE_API_URL_FILE = 'https://saas.fiee.com/'
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta
|
<meta
|
||||||
http-equiv="keywords"
|
http-equiv="keywords"
|
||||||
content="管理系统"
|
content="丰链管理系统"
|
||||||
/>
|
/>
|
||||||
<link rel="stylesheet" href="/static/loading.css" />
|
<link rel="stylesheet" href="/static/loading.css" />
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.1 KiB |
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
.first-loading-wrp .content {
|
.first-loading-wrp .content {
|
||||||
box-sizing: content-box!important;
|
box-sizing: content-box!important;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -14,7 +14,7 @@
|
|||||||
width: 100px!important;
|
width: 100px!important;
|
||||||
height: 100px!important;
|
height: 100px!important;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--theme-primary, #2730D0);
|
background:black;
|
||||||
padding: 5px!important;
|
padding: 5px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,24 @@
|
|||||||
$theme-primary: #2730D0;
|
// 动态主题色配置
|
||||||
$theme-darker: rgba(39, 48, 208, 0.5);
|
// 这些SCSS变量现在会从CSS变量中获取值,支持动态主题切换
|
||||||
$theme-dark: #DFD7F2;
|
|
||||||
$basic-white: #FFFFFF;
|
|
||||||
$basic-black: #000000;
|
|
||||||
|
|
||||||
$text-disabled: #C3C3C3;
|
$theme-primary: var(--theme-primary, #BA4A8F);
|
||||||
$text-basic: #939393;
|
$theme-darker: var(--theme-darker, #C1B2E5);
|
||||||
$text-theme: #2730D0;
|
$theme-dark: var(--theme-dark, #DFD7F2);
|
||||||
|
$theme-success: var(--theme-success, #18a058);
|
||||||
|
$theme-warning: var(--theme-warning, #f0a020);
|
||||||
|
$theme-error: var(--theme-error, #d03050);
|
||||||
|
$theme-info: var(--theme-info, #2080f0);
|
||||||
|
|
||||||
$border-theme: #C1B2E5;
|
$basic-white: var(--basic-white, #FFFFFF);
|
||||||
|
$basic-black: var(--basic-black, #000000);
|
||||||
|
|
||||||
$input-bg: #777777;
|
$text-disabled: var(--text-disabled, #C3C3C3);
|
||||||
|
$text-basic: var(--text-basic, #939393);
|
||||||
|
$text-theme: var(--text-theme, #BA4A8F);
|
||||||
|
|
||||||
$btn-primary: linear-gradient(to left, #2730D0, #212462);
|
$border-theme: var(--border-theme, #C1B2E5);
|
||||||
$btn-basic: #EEEAF7;
|
|
||||||
|
$input-bg: var(--input-bg, #777777);
|
||||||
|
|
||||||
|
$btn-primary: var(--btn-primary, #BA4A8F);
|
||||||
|
$btn-basic: var(--btn-basic, #EEEAF7);
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
@import "color.scss";
|
@import "color.scss";
|
||||||
|
|
||||||
// 定义CSS自定义属性(CSS变量)
|
// 定义CSS自定义属性(CSS变量)
|
||||||
|
// 注意:这些默认值会被JavaScript动态覆盖
|
||||||
:root {
|
:root {
|
||||||
--theme-primary: #{$theme-primary};
|
--theme-primary: #{$theme-primary};
|
||||||
--theme-darker: #{$theme-darker};
|
--theme-darker: #{$theme-darker};
|
||||||
--theme-dark: #{$theme-dark};
|
--theme-dark: #{$theme-dark};
|
||||||
|
--theme-success: #18a058;
|
||||||
|
--theme-warning: #f0a020;
|
||||||
|
--theme-error: #d03050;
|
||||||
|
--theme-info: #2080f0;
|
||||||
--basic-white: #{$basic-white};
|
--basic-white: #{$basic-white};
|
||||||
--basic-black: #{$basic-black};
|
--basic-black: #{$basic-black};
|
||||||
--text-theme: #{$text-theme};
|
--text-theme: #{$text-theme};
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 980 KiB |
92
src/components/ThemeSwitch.vue
Normal file
92
src/components/ThemeSwitch.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="theme-switch">
|
||||||
|
<n-select
|
||||||
|
v-model:value="selectedTheme"
|
||||||
|
:options="themeOptions"
|
||||||
|
@update:value="handleThemeChange"
|
||||||
|
placeholder="选择主题"
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
|
<template #option="{ node, option }">
|
||||||
|
<div class="theme-option">
|
||||||
|
<div
|
||||||
|
class="theme-color-preview"
|
||||||
|
:style="{ backgroundColor: option.color }"
|
||||||
|
></div>
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</n-select>
|
||||||
|
|
||||||
|
<!-- 当前主题信息 -->
|
||||||
|
<div v-if="currentTheme" class="current-theme-info">
|
||||||
|
<small>当前主题: {{ currentTheme.config.name }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
import { NSelect } from 'naive-ui';
|
||||||
|
import { switchTheme, getCurrentTheme, getAllThemes, onThemeChange } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const selectedTheme = ref('');
|
||||||
|
const currentTheme = ref(null);
|
||||||
|
|
||||||
|
// 主题选项
|
||||||
|
const themeOptions = computed(() => {
|
||||||
|
const themes = getAllThemes();
|
||||||
|
return Object.entries(themes).map(([key, config]) => ({
|
||||||
|
label: config.name,
|
||||||
|
value: key,
|
||||||
|
color: config.primary
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理主题切换
|
||||||
|
const handleThemeChange = async (themeKey) => {
|
||||||
|
if (themeKey) {
|
||||||
|
await switchTheme(themeKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化当前主题
|
||||||
|
currentTheme.value = getCurrentTheme();
|
||||||
|
selectedTheme.value = currentTheme.value?.key || 'default';
|
||||||
|
|
||||||
|
// 监听主题变化事件
|
||||||
|
onThemeChange((themeInfo) => {
|
||||||
|
currentTheme.value = getCurrentTheme();
|
||||||
|
selectedTheme.value = themeInfo.key;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.theme-switch {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-color-preview {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-theme-info {
|
||||||
|
color: var(--theme-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<div class="wrap2"
|
<div class="wrap2"
|
||||||
v-if="!state.isCollapse">
|
v-if="!state.isCollapse">
|
||||||
常熟常艺达文化艺术交流有限公司
|
苏州虞航咨询股份有限公司
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<n-modal v-model:show="showModal"
|
<n-modal v-model:show="showModal"
|
||||||
|
|||||||
@ -465,12 +465,12 @@ watch(
|
|||||||
// console.log(1111111111111, currentRoute)
|
// console.log(1111111111111, currentRoute)
|
||||||
// })
|
// })
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// getALLApprovalNum();
|
getALLApprovalNum();
|
||||||
// getOAALLApprovalNum();
|
getOAALLApprovalNum();
|
||||||
ishasToChangePWD();
|
ishasToChangePWD();
|
||||||
// recruitRedDot();
|
recruitRedDot();
|
||||||
// getBellNum();
|
getBellNum();
|
||||||
// getexPayApproveNum();
|
getexPayApproveNum();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1518,7 +1518,7 @@ const numWidth = computed(() => {
|
|||||||
|
|
||||||
.x-upload-download-button:hover {
|
.x-upload-download-button:hover {
|
||||||
background-color: #e6fffb;
|
background-color: #e6fffb;
|
||||||
color: #13c2c2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.x-upload-delete-button:hover {
|
.x-upload-delete-button:hover {
|
||||||
|
|||||||
@ -3,6 +3,6 @@ export const settingConfig= {
|
|||||||
sideTheme: 'light',
|
sideTheme: 'light',
|
||||||
sideWidth: 210,
|
sideWidth: 210,
|
||||||
layoutMode: 'ltr',
|
layoutMode: 'ltr',
|
||||||
themeColor: '#2730D0'
|
themeColor: '#BA4A8F'
|
||||||
}
|
}
|
||||||
export const projectName = import.meta.env.MODE==='main'?'管理系统':'管理系统'
|
export const projectName = import.meta.env.MODE==='main'?'管理系统':'管理系统'
|
||||||
|
|||||||
177
src/config/theme/README.md
Normal file
177
src/config/theme/README.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# 主题系统使用文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
这个主题系统可以根据网站URL自动切换主题色,支持多环境和多品牌的主题配置。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 🎨 基于URL自动切换主题
|
||||||
|
- 🔄 支持运行时动态切换主题
|
||||||
|
- 🎯 同时更新CSS变量和UI框架主题
|
||||||
|
- 📱 支持多环境配置(开发、测试、生产)
|
||||||
|
- 🛠️ 提供完整的工具函数和组件
|
||||||
|
|
||||||
|
## 配置文件
|
||||||
|
|
||||||
|
### 主题配置 (`src/config/theme/index.js`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const themeConfigs = {
|
||||||
|
default: {
|
||||||
|
name: '体制外主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
// ... 其他颜色
|
||||||
|
},
|
||||||
|
main: {
|
||||||
|
name: '体制内主题',
|
||||||
|
primary: '#1890FF',
|
||||||
|
// ... 其他颜色
|
||||||
|
}
|
||||||
|
// ... 更多主题
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### URL映射规则
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
'main': ['main.fontree.com', 'fontree-main.com'],
|
||||||
|
'default': ['fontree.com', 'www.fontree.com'],
|
||||||
|
'test': ['test.fontree.com', 'staging'],
|
||||||
|
'dev': ['localhost', '127.0.0.1']
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 自动主题切换
|
||||||
|
|
||||||
|
系统会在应用启动时自动检测URL并应用相应主题,无需手动配置。
|
||||||
|
|
||||||
|
### 2. 手动切换主题
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { switchTheme } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 切换到指定主题
|
||||||
|
switchTheme('main'); // 切换到体制内主题
|
||||||
|
switchTheme('test'); // 切换到测试主题
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 在Vue组件中使用
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p>当前主题: {{ currentTheme?.config.name }}</p>
|
||||||
|
<button @click="switchTheme('main')">切换到体制内主题</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useTheme } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
const { currentTheme, switchTheme } = useTheme();
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 使用主题切换组件
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<ThemeSwitch />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import ThemeSwitch from '@/components/ThemeSwitch.vue';
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 在CSS中使用主题变量
|
||||||
|
|
||||||
|
```css
|
||||||
|
.my-component {
|
||||||
|
background-color: var(--theme-primary);
|
||||||
|
color: var(--theme-success);
|
||||||
|
border: 1px solid var(--theme-darker);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 监听主题变化
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { onThemeChange } from '@/utils/theme.js';
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
const unsubscribe = onThemeChange((themeInfo) => {
|
||||||
|
console.log('主题已切换:', themeInfo.key, themeInfo.config);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 取消监听
|
||||||
|
unsubscribe();
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSS变量列表
|
||||||
|
|
||||||
|
系统会自动设置以下CSS变量:
|
||||||
|
|
||||||
|
- `--theme-primary`: 主题主色
|
||||||
|
- `--theme-darker`: 主题深色
|
||||||
|
- `--theme-dark`: 主题更深色
|
||||||
|
- `--theme-success`: 成功色
|
||||||
|
- `--theme-warning`: 警告色
|
||||||
|
- `--theme-error`: 错误色
|
||||||
|
- `--theme-info`: 信息色
|
||||||
|
|
||||||
|
## 添加新主题
|
||||||
|
|
||||||
|
1. 在 `themeConfigs` 中添加新主题配置
|
||||||
|
2. 在 `urlThemeMapping` 中添加URL匹配规则
|
||||||
|
3. 重启应用即可生效
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 添加新主题
|
||||||
|
export const themeConfigs = {
|
||||||
|
// ... 现有主题
|
||||||
|
custom: {
|
||||||
|
name: '自定义主题',
|
||||||
|
primary: '#FF6B35',
|
||||||
|
darker: '#FF8C69',
|
||||||
|
// ... 其他颜色
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加URL映射
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
// ... 现有映射
|
||||||
|
'custom': ['custom.fontree.com', 'my-custom-domain.com']
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 调试和测试
|
||||||
|
|
||||||
|
在浏览器控制台中可以看到主题切换的日志信息:
|
||||||
|
|
||||||
|
```
|
||||||
|
当前URL: http://localhost:3000
|
||||||
|
当前hostname: localhost
|
||||||
|
匹配到主题: dev (开发环境主题)
|
||||||
|
CSS变量已更新: {primary: "#13C2C2", ...}
|
||||||
|
主题系统初始化完成: {...}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 主题系统会在应用启动时自动初始化
|
||||||
|
2. URL匹配是模糊匹配,会检查hostname和完整URL
|
||||||
|
3. 如果没有匹配到任何规则,会使用默认主题
|
||||||
|
4. 主题切换会同时更新CSS变量和UI框架配置
|
||||||
|
5. 所有主题变化都会触发 `themeChanged` 事件
|
||||||
|
|
||||||
|
## 扩展功能
|
||||||
|
|
||||||
|
- 可以添加主题持久化存储
|
||||||
|
- 可以添加主题预览功能
|
||||||
|
- 可以集成用户偏好设置
|
||||||
|
- 可以添加主题动画过渡效果
|
||||||
98
src/config/theme/colors.js
Normal file
98
src/config/theme/colors.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* 动态颜色配置
|
||||||
|
* 统一管理所有颜色变量,支持主题切换
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { themeConfigs } from './index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前主题的颜色配置
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {Object} 颜色配置对象
|
||||||
|
*/
|
||||||
|
export function getThemeColors(themeKey = 'default') {
|
||||||
|
const theme = themeConfigs[themeKey] || themeConfigs.default;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// 主题色系
|
||||||
|
'theme-primary': theme.primary,
|
||||||
|
'theme-darker': theme.darker,
|
||||||
|
'theme-dark': theme.dark,
|
||||||
|
'theme-success': theme.success,
|
||||||
|
'theme-warning': theme.warning,
|
||||||
|
'theme-error': theme.error,
|
||||||
|
'theme-info': theme.info,
|
||||||
|
|
||||||
|
// 基础色系
|
||||||
|
'basic-white': '#FFFFFF',
|
||||||
|
'basic-black': '#000000',
|
||||||
|
|
||||||
|
// 文本色系
|
||||||
|
'text-disabled': '#C3C3C3',
|
||||||
|
'text-basic': '#939393',
|
||||||
|
'text-theme': theme.primary,
|
||||||
|
|
||||||
|
// 边框色系
|
||||||
|
'border-theme': theme.darker,
|
||||||
|
|
||||||
|
// 输入框色系
|
||||||
|
'input-bg': '#777777',
|
||||||
|
|
||||||
|
// 按钮色系
|
||||||
|
'btn-primary': theme.primary,
|
||||||
|
'btn-basic': '#EEEAF7'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成CSS变量字符串
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {string} CSS变量定义字符串
|
||||||
|
*/
|
||||||
|
export function generateCSSVariables(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
|
||||||
|
let cssVars = ':root {\n';
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
cssVars += ` --${key}: ${value};\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
cssVars += '}\n';
|
||||||
|
|
||||||
|
return cssVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SCSS变量字符串
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
* @returns {string} SCSS变量定义字符串
|
||||||
|
*/
|
||||||
|
export function generateSCSSVariables(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
|
||||||
|
let scssVars = '// 动态生成的SCSS变量 - 请勿手动修改\n';
|
||||||
|
scssVars += `// 当前主题: ${themeConfigs[themeKey]?.name || '默认主题'}\n\n`;
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
const scssKey = key.replace(/-/g, '-'); // 保持连字符格式
|
||||||
|
scssVars += `$${scssKey}: ${value};\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return scssVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用颜色到DOM
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
*/
|
||||||
|
export function applyColorsToDOM(themeKey = 'default') {
|
||||||
|
const colors = getThemeColors(themeKey);
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
Object.entries(colors).forEach(([key, value]) => {
|
||||||
|
root.style.setProperty(`--${key}`, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('颜色已应用到DOM:', colors);
|
||||||
|
}
|
||||||
225
src/config/theme/index.js
Normal file
225
src/config/theme/index.js
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/**
|
||||||
|
* 基于URL的主题配置系统
|
||||||
|
* 根据网站URL自动切换主题色
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 主题配置映射表
|
||||||
|
export const themeConfigs = {
|
||||||
|
// 默认主题(体制外)
|
||||||
|
default: {
|
||||||
|
name: '体制外主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
darker: '#C1B2E5',
|
||||||
|
dark: '#DFD7F2',
|
||||||
|
success: '#18a058',
|
||||||
|
warning: '#f0a020',
|
||||||
|
error: '#d03050',
|
||||||
|
info: '#2080f0'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 体制内主题
|
||||||
|
main: {
|
||||||
|
name: '体制内主题',
|
||||||
|
primary: '#1890FF',
|
||||||
|
darker: '#40A9FF',
|
||||||
|
dark: '#91D5FF',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#faad14',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#1890ff'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 测试环境主题
|
||||||
|
test: {
|
||||||
|
name: '测试环境主题',
|
||||||
|
primary: '#722ED1',
|
||||||
|
darker: '#B37FEB',
|
||||||
|
dark: '#D3ADF7',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#fa8c16',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#722ed1'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开发环境主题
|
||||||
|
dev: {
|
||||||
|
name: '开发环境主题',
|
||||||
|
primary: '#BA4A8F',
|
||||||
|
darker: '#BA4A8F',
|
||||||
|
dark: '#BA4A8F',
|
||||||
|
success: '#52c41a',
|
||||||
|
warning: '#faad14',
|
||||||
|
error: '#f5222d',
|
||||||
|
info: '#BA4A8F '
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// URL匹配规则
|
||||||
|
export const urlThemeMapping = {
|
||||||
|
// 生产环境 - 体制内
|
||||||
|
'main': ['main.fontree.com', 'fontree-main.com', 'main-fontree'],
|
||||||
|
|
||||||
|
// 生产环境 - 体制外(默认)
|
||||||
|
'default': ['fontree.com', 'www.fontree.com', 'app.fontree.com'],
|
||||||
|
|
||||||
|
// 测试环境
|
||||||
|
'test': ['127.0.0.1', 'fontree-test.com', 'test-fontree', 'staging'],
|
||||||
|
|
||||||
|
// 开发环境
|
||||||
|
'dev': ['localhost', '127.2.0.1', 'dev.fontree.com', 'fontree-dev.com', 'dev-fontree']
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据当前URL获取主题配置
|
||||||
|
* @returns {Object} 主题配置对象
|
||||||
|
*/
|
||||||
|
export function getThemeByUrl() {
|
||||||
|
const hostname = window.location.hostname;
|
||||||
|
const href = window.location.href;
|
||||||
|
|
||||||
|
console.log('当前URL:', href);
|
||||||
|
console.log('当前hostname:', hostname);
|
||||||
|
|
||||||
|
// 遍历URL映射规则
|
||||||
|
for (const [themeKey, patterns] of Object.entries(urlThemeMapping)) {
|
||||||
|
for (const pattern of patterns) {
|
||||||
|
if (hostname.includes(pattern) || href.includes(pattern)) {
|
||||||
|
console.log(`匹配到主题: ${themeKey} (${themeConfigs[themeKey].name})`);
|
||||||
|
return {
|
||||||
|
key: themeKey,
|
||||||
|
config: themeConfigs[themeKey]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认返回体制外主题
|
||||||
|
console.log('使用默认主题');
|
||||||
|
return {
|
||||||
|
key: 'default',
|
||||||
|
config: themeConfigs.default
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用主题到CSS变量
|
||||||
|
* @param {Object} themeConfig 主题配置
|
||||||
|
*/
|
||||||
|
export async function applyThemeToCSS(themeConfig) {
|
||||||
|
// 使用新的颜色配置系统
|
||||||
|
const { applyColorsToDOM } = await import('./colors.js');
|
||||||
|
|
||||||
|
// 根据主题配置找到对应的主题键名
|
||||||
|
const themeKey = Object.keys(themeConfigs).find(key =>
|
||||||
|
themeConfigs[key].primary === themeConfig.primary
|
||||||
|
) || 'default';
|
||||||
|
|
||||||
|
// 应用所有颜色到DOM
|
||||||
|
applyColorsToDOM(themeKey);
|
||||||
|
|
||||||
|
console.log('CSS变量已更新:', themeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成Naive UI主题配置
|
||||||
|
* @param {Object} themeConfig 主题配置
|
||||||
|
* @returns {Object} Naive UI主题覆盖配置
|
||||||
|
*/
|
||||||
|
export function generateNaiveUITheme(themeConfig) {
|
||||||
|
return {
|
||||||
|
common: {
|
||||||
|
primaryColor: themeConfig.primary,
|
||||||
|
primaryColorHover: themeConfig.darker,
|
||||||
|
primaryColorPressed: themeConfig.primary,
|
||||||
|
primaryColorSuppl: themeConfig.primary,
|
||||||
|
successColor: themeConfig.success,
|
||||||
|
warningColor: themeConfig.warning,
|
||||||
|
errorColor: themeConfig.error,
|
||||||
|
infoColor: themeConfig.info
|
||||||
|
},
|
||||||
|
Button: {
|
||||||
|
// Primary按钮的颜色配置
|
||||||
|
colorPrimary: themeConfig.primary,
|
||||||
|
colorHoverPrimary: themeConfig.darker,
|
||||||
|
colorPressedPrimary: themeConfig.primary,
|
||||||
|
colorFocusPrimary: themeConfig.primary,
|
||||||
|
|
||||||
|
// Tertiary按钮的颜色配置
|
||||||
|
textColor: themeConfig.primary,
|
||||||
|
textColorHover: themeConfig.darker,
|
||||||
|
textColorPressed: themeConfig.primary,
|
||||||
|
textColorFocus: themeConfig.primary,
|
||||||
|
textColorDisabled: '#c0c4cc',
|
||||||
|
|
||||||
|
// 边框颜色
|
||||||
|
borderPrimary: themeConfig.primary,
|
||||||
|
borderHoverPrimary: themeConfig.darker,
|
||||||
|
borderPressedPrimary: themeConfig.primary,
|
||||||
|
borderFocusPrimary: themeConfig.primary,
|
||||||
|
|
||||||
|
// 波纹效果颜色
|
||||||
|
rippleColorPrimary: `${themeConfig.primary}1a`
|
||||||
|
},
|
||||||
|
DataTable: {
|
||||||
|
thColor: themeConfig.primary,
|
||||||
|
thColorHover: themeConfig.darker,
|
||||||
|
thTextColor: '#fff',
|
||||||
|
itemColorActive: themeConfig.primary,
|
||||||
|
sorterIconColor: '#fff'
|
||||||
|
},
|
||||||
|
Input: {
|
||||||
|
borderHover: themeConfig.primary,
|
||||||
|
borderFocus: themeConfig.primary,
|
||||||
|
boxShadowFocus: `0 0 0 2px ${themeConfig.primary}1a`
|
||||||
|
},
|
||||||
|
Select: {
|
||||||
|
peers: {
|
||||||
|
InternalSelection: {
|
||||||
|
borderHover: themeConfig.primary,
|
||||||
|
borderFocus: themeConfig.primary,
|
||||||
|
boxShadowFocus: `0 0 0 2px ${themeConfig.primary}1a`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 添加更多组件的主题配置
|
||||||
|
Checkbox: {
|
||||||
|
colorChecked: themeConfig.primary,
|
||||||
|
colorCheckedHover: themeConfig.darker,
|
||||||
|
colorCheckedPressed: themeConfig.primary
|
||||||
|
},
|
||||||
|
Radio: {
|
||||||
|
colorActive: themeConfig.primary,
|
||||||
|
colorActiveHover: themeConfig.darker
|
||||||
|
},
|
||||||
|
Switch: {
|
||||||
|
railColorActive: themeConfig.primary,
|
||||||
|
railColorActiveHover: themeConfig.darker
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化主题系统
|
||||||
|
*/
|
||||||
|
export async function initThemeSystem() {
|
||||||
|
const { key, config } = getThemeByUrl();
|
||||||
|
|
||||||
|
// 应用CSS变量
|
||||||
|
await applyThemeToCSS(config);
|
||||||
|
|
||||||
|
// 存储当前主题信息到全局
|
||||||
|
window.__CURRENT_THEME__ = {
|
||||||
|
key,
|
||||||
|
config,
|
||||||
|
naiveUITheme: generateNaiveUITheme(config)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 触发自定义事件,通知其他组件主题已更新
|
||||||
|
window.dispatchEvent(new CustomEvent('themeChanged', {
|
||||||
|
detail: { key, config }
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('主题系统初始化完成:', window.__CURRENT_THEME__);
|
||||||
|
|
||||||
|
return window.__CURRENT_THEME__;
|
||||||
|
}
|
||||||
46
src/main.js
46
src/main.js
@ -2,17 +2,39 @@ import router from "@/router/index.js";
|
|||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import { registerPlugins } from "./plugins/index.js";
|
import { registerPlugins } from "./plugins/index.js";
|
||||||
import { settingConfig } from "@/config/settings/index.js";
|
import { initThemeSystem } from "@/config/theme/index.js";
|
||||||
window.process = {
|
import store from "@/store/index.js";
|
||||||
env: {
|
|
||||||
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 动态设置CSS变量值
|
// 异步初始化应用
|
||||||
document.documentElement.style.setProperty('--theme-primary', settingConfig.themeColor);
|
async function initApp() {
|
||||||
|
window.process = {
|
||||||
|
env: {
|
||||||
|
VUE_APP_API_URL: import.meta.env.VITE_API_URL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const app = createApp(App);
|
// 初始化主题系统(必须在创建应用之前)
|
||||||
// 注册插件
|
const currentTheme = await initThemeSystem();
|
||||||
registerPlugins(app);
|
|
||||||
app.mount("#app");
|
// 更新store中的主题配置
|
||||||
|
store.updateTheme(currentTheme.naiveUITheme);
|
||||||
|
|
||||||
|
// 监听主题变化事件
|
||||||
|
window.addEventListener('themeChanged', (event) => {
|
||||||
|
const { key, config } = event.detail;
|
||||||
|
console.log('主题已切换:', key, config);
|
||||||
|
|
||||||
|
// 更新store中的主题
|
||||||
|
if (window.__CURRENT_THEME__) {
|
||||||
|
store.updateTheme(window.__CURRENT_THEME__.naiveUITheme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
// 注册插件
|
||||||
|
registerPlugins(app);
|
||||||
|
app.mount("#app");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动应用
|
||||||
|
initApp().catch(console.error);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
/* 模块-----路由 */
|
/* 画家宝模块-----路由 */
|
||||||
const artistRoute = [
|
const artistRoute = [
|
||||||
{
|
{
|
||||||
path: "/paintersideblack",
|
path: "/paintersideblack",
|
||||||
name: "paintersideBlack",
|
name: "paintersideBlack",
|
||||||
meta: {
|
meta: {
|
||||||
title: "黑名单",
|
title: "画家宝黑名单",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/blacklist/index"),
|
component: () => import("../views/atrist-app/blacklist/index"),
|
||||||
},
|
},
|
||||||
@ -12,7 +12,7 @@ const artistRoute = [
|
|||||||
path: "/paintersideartist",
|
path: "/paintersideartist",
|
||||||
name: "painterSideArtist",
|
name: "painterSideArtist",
|
||||||
meta: {
|
meta: {
|
||||||
title: "大师画家",
|
title: "画家宝大师画家",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersideartist/index"),
|
component: () => import("../views/atrist-app/paintersideartist/index"),
|
||||||
},
|
},
|
||||||
@ -20,7 +20,7 @@ const artistRoute = [
|
|||||||
path: "/paintersideartistnocert",
|
path: "/paintersideartistnocert",
|
||||||
name: "painterSideArtistnoCert",
|
name: "painterSideArtistnoCert",
|
||||||
meta: {
|
meta: {
|
||||||
title: "普通画家",
|
title: "画家宝普通画家",
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import("../views/atrist-app/paintersideartistnocert/index"),
|
import("../views/atrist-app/paintersideartistnocert/index"),
|
||||||
@ -29,7 +29,7 @@ const artistRoute = [
|
|||||||
path: "/paintersideartwork",
|
path: "/paintersideartwork",
|
||||||
name: "painterSideArtwork",
|
name: "painterSideArtwork",
|
||||||
meta: {
|
meta: {
|
||||||
title: "基本画作",
|
title: "画家宝基本画作",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersideartwork/index"),
|
component: () => import("../views/atrist-app/paintersideartwork/index"),
|
||||||
},
|
},
|
||||||
@ -37,7 +37,7 @@ const artistRoute = [
|
|||||||
path: "/paintersideextraartwork",
|
path: "/paintersideextraartwork",
|
||||||
name: "painterSideExtraArtwork",
|
name: "painterSideExtraArtwork",
|
||||||
meta: {
|
meta: {
|
||||||
title: "补充画作",
|
title: "画家宝补充画作",
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import("../views/atrist-app/paintersideextraartwork/index"),
|
import("../views/atrist-app/paintersideextraartwork/index"),
|
||||||
@ -70,7 +70,7 @@ const artistRoute = [
|
|||||||
path: "/paintersidecontract",
|
path: "/paintersidecontract",
|
||||||
name: "painterSideContract",
|
name: "painterSideContract",
|
||||||
meta: {
|
meta: {
|
||||||
title: "合同",
|
title: "画家宝合同",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersidecontract/index"),
|
component: () => import("../views/atrist-app/paintersidecontract/index"),
|
||||||
},
|
},
|
||||||
@ -78,7 +78,7 @@ const artistRoute = [
|
|||||||
path: "/paintersideconartwork",
|
path: "/paintersideconartwork",
|
||||||
name: "painterSideConArtwork",
|
name: "painterSideConArtwork",
|
||||||
meta: {
|
meta: {
|
||||||
title: "合同画作",
|
title: "画家宝合同画作",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersideconartwork/index"),
|
component: () => import("../views/atrist-app/paintersideconartwork/index"),
|
||||||
},
|
},
|
||||||
@ -86,7 +86,7 @@ const artistRoute = [
|
|||||||
path: "/paintersidereceipt",
|
path: "/paintersidereceipt",
|
||||||
name: "painterSideReceipt",
|
name: "painterSideReceipt",
|
||||||
meta: {
|
meta: {
|
||||||
title: "物权对账",
|
title: "画家宝物权对账",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersidereceipt/index"),
|
component: () => import("../views/atrist-app/paintersidereceipt/index"),
|
||||||
},
|
},
|
||||||
@ -94,7 +94,7 @@ const artistRoute = [
|
|||||||
path: "/paintersidereceiptcopy",
|
path: "/paintersidereceiptcopy",
|
||||||
name: "painterSideReceiptCopy",
|
name: "painterSideReceiptCopy",
|
||||||
meta: {
|
meta: {
|
||||||
title: "版权对账",
|
title: "画家宝版权对账",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/paintersidereceiptcopy/index"),
|
component: () => import("../views/atrist-app/paintersidereceiptcopy/index"),
|
||||||
},
|
},
|
||||||
@ -102,7 +102,7 @@ const artistRoute = [
|
|||||||
path: "/inviteindex",
|
path: "/inviteindex",
|
||||||
name: "inviteIndex",
|
name: "inviteIndex",
|
||||||
meta: {
|
meta: {
|
||||||
title: "邀请关系",
|
title: "画家宝邀请关系",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/inviteindex/index"),
|
component: () => import("../views/atrist-app/inviteindex/index"),
|
||||||
},
|
},
|
||||||
@ -110,7 +110,7 @@ const artistRoute = [
|
|||||||
path: "/inviteperindex",
|
path: "/inviteperindex",
|
||||||
name: "inviteperIndex",
|
name: "inviteperIndex",
|
||||||
meta: {
|
meta: {
|
||||||
title: "邀请人",
|
title: "画家宝邀请人",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/inviteperindex/index"),
|
component: () => import("../views/atrist-app/inviteperindex/index"),
|
||||||
},
|
},
|
||||||
@ -158,7 +158,7 @@ const artistRoute = [
|
|||||||
path: "/customerservice",
|
path: "/customerservice",
|
||||||
name: "customerService",
|
name: "customerService",
|
||||||
meta: {
|
meta: {
|
||||||
title: "客服",
|
title: "画家宝客服",
|
||||||
},
|
},
|
||||||
component: () => import("../views/atrist-app/customerservice/index"),
|
component: () => import("../views/atrist-app/customerservice/index"),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,8 +19,22 @@ const commonRoute = [
|
|||||||
},
|
},
|
||||||
component: () => import("../views/workbench/index"),
|
component: () => import("../views/workbench/index"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/szhWorkBentch",
|
||||||
|
name: "SzhWorkBentch",
|
||||||
|
meta: {
|
||||||
|
title: "数字化工作台",
|
||||||
|
},
|
||||||
|
component: () => import("../views/workbench/components/quickIndex"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/jzWorkBentch",
|
||||||
|
name: "JzWorkBentch",
|
||||||
|
meta: {
|
||||||
|
title: "鉴证科工作台",
|
||||||
|
},
|
||||||
|
component: () => import("../views/workbench/components/quickIndex"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/masterBench",
|
path: "/masterBench",
|
||||||
name: "MasterBench",
|
name: "MasterBench",
|
||||||
@ -72,72 +86,7 @@ const commonRoute = [
|
|||||||
},
|
},
|
||||||
component: () => import("@/views/artworkreturn/index.vue"),
|
component: () => import("@/views/artworkreturn/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/posimanage/create",
|
|
||||||
name: "PosiManageCre",
|
|
||||||
meta: {
|
|
||||||
title: "岗位管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/posimanage/create"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/orgmanage",
|
|
||||||
name: "OrgManage",
|
|
||||||
meta: {
|
|
||||||
title: "组织管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/orgmanage/index"),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: "/posimanage",
|
|
||||||
name: "PosiManage",
|
|
||||||
meta: {
|
|
||||||
title: "岗位管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/posimanage/index"),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: "/posirecordlog",
|
|
||||||
name: "PosiRecordLog",
|
|
||||||
meta: {
|
|
||||||
title: "岗位操作记录",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/posirecordlog/index"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/peomanage",
|
|
||||||
name: "PeoManage",
|
|
||||||
meta: {
|
|
||||||
title: "人员管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/peomanage/index"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/peomanage/personnelManage",
|
|
||||||
name: "personnelManage",
|
|
||||||
meta: {
|
|
||||||
title: "人员管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/peomanage/personnelManage"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/peomanage/create",
|
|
||||||
name: "PeoManageCre",
|
|
||||||
meta: {
|
|
||||||
title: "人员管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/peomanage/create"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/peomanage/editPeo",
|
|
||||||
name: "PeoManageEdi",
|
|
||||||
meta: {
|
|
||||||
title: "人员管理",
|
|
||||||
},
|
|
||||||
component: () => import("../views/manage/peomanage/editPeo"),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default commonRoute;
|
export default commonRoute;
|
||||||
|
|||||||
@ -1,7 +1,22 @@
|
|||||||
/* 工作台模块-----路由 */
|
/* 工作台模块-----路由 */
|
||||||
|
|
||||||
const workbenchRoute = [
|
const workbenchRoute = [
|
||||||
|
{
|
||||||
|
path: "/szhWorkBentch",
|
||||||
|
name: "SzhWorkBentch",
|
||||||
|
meta: {
|
||||||
|
title: "数字化工作台",
|
||||||
|
},
|
||||||
|
component: () => import("../views/workbench/components/quickIndex"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/jzWorkBentch",
|
||||||
|
name: "JzWorkBentch",
|
||||||
|
meta: {
|
||||||
|
title: "鉴证科工作台",
|
||||||
|
},
|
||||||
|
component: () => import("../views/workbench/components/quickIndex"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/masterBench",
|
path: "/masterBench",
|
||||||
name: "MasterBench",
|
name: "MasterBench",
|
||||||
|
|||||||
@ -1,10 +1,21 @@
|
|||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import VisitedViewAction from "./modules/visited-view";
|
import VisitedViewAction from "./modules/visited-view";
|
||||||
import { settingConfig } from "@/config/settings/index.js";
|
import { settingConfig } from "@/config/settings/index.js";
|
||||||
|
import { generateNaiveUITheme } from "@/config/theme/index.js";
|
||||||
|
|
||||||
|
// 获取初始主题色(如果主题系统还未初始化,使用默认值)
|
||||||
|
const getInitialTheme = () => {
|
||||||
|
if (window.__CURRENT_THEME__) {
|
||||||
|
return generateNaiveUITheme(window.__CURRENT_THEME__.config);
|
||||||
|
}
|
||||||
|
return null; // 将在main.js中初始化后更新
|
||||||
|
};
|
||||||
|
|
||||||
const primaryColor = settingConfig.themeColor;
|
const primaryColor = settingConfig.themeColor;
|
||||||
const originState = {
|
const originState = {
|
||||||
isCollapse: false,
|
isCollapse: false,
|
||||||
themeOverrides: {
|
themeOverrides: getInitialTheme() || {
|
||||||
|
// 默认主题配置(作为后备)
|
||||||
DataTable: {
|
DataTable: {
|
||||||
sorterIconColor:'#fff',
|
sorterIconColor:'#fff',
|
||||||
thColorHover: primaryColor,
|
thColorHover: primaryColor,
|
||||||
@ -48,6 +59,13 @@ const store = {
|
|||||||
changeDevice(device) {
|
changeDevice(device) {
|
||||||
this.state.device = device;
|
this.state.device = device;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新主题
|
||||||
|
updateTheme(themeOverrides) {
|
||||||
|
this.state.themeOverrides = themeOverrides;
|
||||||
|
console.log('Store主题已更新:', themeOverrides);
|
||||||
|
},
|
||||||
|
|
||||||
...VisitedViewAction
|
...VisitedViewAction
|
||||||
};
|
};
|
||||||
export default store;
|
export default store;
|
||||||
|
|||||||
136
src/utils/theme.js
Normal file
136
src/utils/theme.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* 主题工具函数
|
||||||
|
* 提供主题切换和管理的实用工具
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { applyThemeToCSS, generateNaiveUITheme, themeConfigs } from "@/config/theme/index.js";
|
||||||
|
import store from "@/store/index.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动切换主题
|
||||||
|
* @param {string} themeKey 主题键名
|
||||||
|
*/
|
||||||
|
export async function switchTheme(themeKey) {
|
||||||
|
if (!themeConfigs[themeKey]) {
|
||||||
|
console.error('主题不存在:', themeKey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = themeConfigs[themeKey];
|
||||||
|
|
||||||
|
// 应用CSS变量
|
||||||
|
await applyThemeToCSS(config);
|
||||||
|
|
||||||
|
// 生成并应用UI框架主题
|
||||||
|
const naiveUITheme = generateNaiveUITheme(config);
|
||||||
|
store.updateTheme(naiveUITheme);
|
||||||
|
|
||||||
|
// 更新全局主题信息
|
||||||
|
window.__CURRENT_THEME__ = {
|
||||||
|
key: themeKey,
|
||||||
|
config,
|
||||||
|
naiveUITheme
|
||||||
|
};
|
||||||
|
|
||||||
|
// 强制刷新页面样式(确保所有组件都能应用新主题)
|
||||||
|
document.documentElement.style.display = 'none';
|
||||||
|
setTimeout(() => {
|
||||||
|
document.documentElement.style.display = '';
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// 触发主题变化事件
|
||||||
|
window.dispatchEvent(new CustomEvent('themeChanged', {
|
||||||
|
detail: { key: themeKey, config }
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('手动切换主题成功:', themeKey, config);
|
||||||
|
console.log('应用的Naive UI主题:', naiveUITheme);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前主题信息
|
||||||
|
* @returns {Object} 当前主题信息
|
||||||
|
*/
|
||||||
|
export function getCurrentTheme() {
|
||||||
|
return window.__CURRENT_THEME__ || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有可用主题
|
||||||
|
* @returns {Object} 所有主题配置
|
||||||
|
*/
|
||||||
|
export function getAllThemes() {
|
||||||
|
return themeConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据颜色值获取对比色(用于文本颜色)
|
||||||
|
* @param {string} hexColor 十六进制颜色值
|
||||||
|
* @returns {string} 对比色(黑色或白色)
|
||||||
|
*/
|
||||||
|
export function getContrastColor(hexColor) {
|
||||||
|
// 移除#号
|
||||||
|
const hex = hexColor.replace('#', '');
|
||||||
|
|
||||||
|
// 转换为RGB
|
||||||
|
const r = parseInt(hex.substr(0, 2), 16);
|
||||||
|
const g = parseInt(hex.substr(2, 2), 16);
|
||||||
|
const b = parseInt(hex.substr(4, 2), 16);
|
||||||
|
|
||||||
|
// 计算亮度
|
||||||
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
|
|
||||||
|
// 返回对比色
|
||||||
|
return brightness > 128 ? '#000000' : '#ffffff';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成主题色的变体(浅色、深色等)
|
||||||
|
* @param {string} baseColor 基础颜色
|
||||||
|
* @returns {Object} 颜色变体
|
||||||
|
*/
|
||||||
|
export function generateColorVariants(baseColor) {
|
||||||
|
// 这里可以实现颜色变体生成算法
|
||||||
|
// 简单示例:
|
||||||
|
return {
|
||||||
|
base: baseColor,
|
||||||
|
light: baseColor + '40', // 添加透明度
|
||||||
|
lighter: baseColor + '20',
|
||||||
|
dark: baseColor,
|
||||||
|
darker: baseColor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听主题变化
|
||||||
|
* @param {Function} callback 回调函数
|
||||||
|
* @returns {Function} 取消监听的函数
|
||||||
|
*/
|
||||||
|
export function onThemeChange(callback) {
|
||||||
|
const handler = (event) => {
|
||||||
|
callback(event.detail);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('themeChanged', handler);
|
||||||
|
|
||||||
|
// 返回取消监听的函数
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('themeChanged', handler);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建主题切换的Vue组合式函数
|
||||||
|
* @returns {Object} 主题相关的响应式数据和方法
|
||||||
|
*/
|
||||||
|
export function useTheme() {
|
||||||
|
const currentTheme = getCurrentTheme();
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentTheme,
|
||||||
|
switchTheme,
|
||||||
|
getAllThemes,
|
||||||
|
onThemeChange
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -26,7 +26,7 @@
|
|||||||
></n-button
|
></n-button
|
||||||
>
|
>
|
||||||
<n-button v-else text :loading="state.btnLoading" @click="handleEdit"
|
<n-button v-else text :loading="state.btnLoading" @click="handleEdit"
|
||||||
><text class="font-bold theme-color" style=" font-size: 16px"
|
><text class="font-bold" style="color: #46299d; font-size: 16px"
|
||||||
>修改</text
|
>修改</text
|
||||||
></n-button
|
></n-button
|
||||||
>
|
>
|
||||||
|
|||||||
@ -76,8 +76,8 @@
|
|||||||
<div class="col-12 row justify-center">
|
<div class="col-12 row justify-center">
|
||||||
<n-button
|
<n-button
|
||||||
tertiary
|
tertiary
|
||||||
class="fl-mr-md theme-color"
|
class="fl-mr-md"
|
||||||
style="width: 161px;"
|
style="width: 161px; background: #c7c7c9; color: #ffffff"
|
||||||
@click="state.dialogAddOne = false"
|
@click="state.dialogAddOne = false"
|
||||||
>取消</n-button
|
>取消</n-button
|
||||||
>
|
>
|
||||||
|
|||||||
@ -21,12 +21,12 @@
|
|||||||
text
|
text
|
||||||
:loading="state.btnLoading"
|
:loading="state.btnLoading"
|
||||||
@click="handleConfirm"
|
@click="handleConfirm"
|
||||||
><text class="font-bold theme-color" style="font-size: 16px"
|
><text class="font-bold" style="color: #46299d; font-size: 16px"
|
||||||
>确认</text
|
>确认</text
|
||||||
></n-button
|
></n-button
|
||||||
>
|
>
|
||||||
<n-button v-else text :loading="state.btnLoading" @click="handleEdit"
|
<n-button v-else text :loading="state.btnLoading" @click="handleEdit"
|
||||||
><text class="font-bold theme-color" style="font-size: 16px"
|
><text class="font-bold" style="color: #46299d; font-size: 16px"
|
||||||
>修改</text
|
>修改</text
|
||||||
></n-button
|
></n-button
|
||||||
>
|
>
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
"
|
"
|
||||||
|
tertiary
|
||||||
class="fl-mb-md"
|
class="fl-mb-md"
|
||||||
:loading="state.btnLoading"
|
:loading="state.btnLoading"
|
||||||
@click="handleInitiate"
|
@click="handleInitiate"
|
||||||
@ -72,8 +72,8 @@
|
|||||||
<div class="col-12 row justify-center">
|
<div class="col-12 row justify-center">
|
||||||
<n-button
|
<n-button
|
||||||
tertiary
|
tertiary
|
||||||
class="fl-mr-md theme-color"
|
class="fl-mr-md"
|
||||||
:style="`width: 161px;`"
|
:style="`width: 161px; background: ${themeDarker}; color: #ffffff`"
|
||||||
@click="state.dialogAddOne = false"
|
@click="state.dialogAddOne = false"
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
@ -163,7 +163,7 @@
|
|||||||
<n-button
|
<n-button
|
||||||
tertiary
|
tertiary
|
||||||
class="fl-mr-md"
|
class="fl-mr-md"
|
||||||
:style="`width: 161px;`"
|
:style="`width: 161px; background: ${themeDarker}; color: #ffffff`"
|
||||||
@click="handleDialogInitiateCancel"
|
@click="handleDialogInitiateCancel"
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
@ -230,7 +230,8 @@
|
|||||||
<div class="col-2 row">单号</div>
|
<div class="col-2 row">单号</div>
|
||||||
<div class="col-3 row">{{ idx }}</div>
|
<div class="col-3 row">{{ idx }}</div>
|
||||||
<div
|
<div
|
||||||
class="col-4 row items-center cursor theme-color"
|
class="col-4 row items-center cursor"
|
||||||
|
style="color: #46299d"
|
||||||
@click="handleDialogIntakeArtworkShow(item)"
|
@click="handleDialogIntakeArtworkShow(item)"
|
||||||
>
|
>
|
||||||
查看已关联的 {{ item.artworkData.length }} 幅画作
|
查看已关联的 {{ item.artworkData.length }} 幅画作
|
||||||
@ -484,8 +485,8 @@
|
|||||||
<div class="col-12 row justify-center fl-mt-md">
|
<div class="col-12 row justify-center fl-mt-md">
|
||||||
<n-button
|
<n-button
|
||||||
tertiary
|
tertiary
|
||||||
class="fl-mr-md theme-color"
|
class="fl-mr-md"
|
||||||
:style="`width: 161px;`"
|
:style="`width: 161px; background: ${themeDarker}; color: #fff`"
|
||||||
@click="handleDialogAuditRemark"
|
@click="handleDialogAuditRemark"
|
||||||
>
|
>
|
||||||
不通过
|
不通过
|
||||||
@ -546,12 +547,12 @@
|
|||||||
<div
|
<div
|
||||||
@click="handleAddMailAddress"
|
@click="handleAddMailAddress"
|
||||||
class="col-2 row justify-center border-1 border-solid border-primary cursor-pointer"
|
class="col-2 row justify-center border-1 border-solid border-primary cursor-pointer"
|
||||||
:style="`
|
style="
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: ${themeColor};`"
|
color: #46299d;
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<span>新增地址</span>
|
<span>新增地址</span>
|
||||||
</div>
|
</div>
|
||||||
@ -569,9 +570,8 @@
|
|||||||
</n-button>
|
</n-button>
|
||||||
|
|
||||||
<n-button
|
<n-button
|
||||||
|
tertiary
|
||||||
style="width: 161px; color: #fff"
|
style="width: 161px; background: #46299d; color: #fff"
|
||||||
type="primary"
|
|
||||||
:loading="state.saveAddressEditBtnLoading"
|
:loading="state.saveAddressEditBtnLoading"
|
||||||
@click="saveEditReceiveAddress"
|
@click="saveEditReceiveAddress"
|
||||||
:disabled="!state.canUseSaveAddressBtn"
|
:disabled="!state.canUseSaveAddressBtn"
|
||||||
@ -614,8 +614,8 @@
|
|||||||
/>
|
/>
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
<div class="col-12 row justify-center fl-mt-md">
|
||||||
<n-button
|
<n-button
|
||||||
type="primary"
|
tertiary
|
||||||
style="width: 161px; color: #fff"
|
style="width: 161px; background: #46299d; color: #fff"
|
||||||
@click="handleDialogAuditRemarkConfirm"
|
@click="handleDialogAuditRemarkConfirm"
|
||||||
:loading="state.btnLoading"
|
:loading="state.btnLoading"
|
||||||
>
|
>
|
||||||
@ -708,7 +708,7 @@ const cascaderRefs = ref([]);
|
|||||||
|
|
||||||
// 计算属性:获取主题色
|
// 计算属性:获取主题色
|
||||||
const themeColor = computed(() => settingConfig.themeColor);
|
const themeColor = computed(() => settingConfig.themeColor);
|
||||||
|
const themeDarker = '#C1B2E5'; // 对应 $theme-darker
|
||||||
const basicWhite = '#FFFFFF'; // 对应 $basic-white
|
const basicWhite = '#FFFFFF'; // 对应 $basic-white
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@ -990,7 +990,7 @@ const state = reactive({
|
|||||||
"span",
|
"span",
|
||||||
{
|
{
|
||||||
style: {
|
style: {
|
||||||
color: themeColor.value,
|
color: "#46299D",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
padding: "10px 15px",
|
padding: "10px 15px",
|
||||||
},
|
},
|
||||||
@ -1132,7 +1132,7 @@ const state = reactive({
|
|||||||
"span",
|
"span",
|
||||||
{
|
{
|
||||||
style: {
|
style: {
|
||||||
color: themeColor.value,
|
color: "#46299D",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
padding: "10px 15px",
|
padding: "10px 15px",
|
||||||
},
|
},
|
||||||
@ -1292,7 +1292,7 @@ const state = reactive({
|
|||||||
{
|
{
|
||||||
width: 120,
|
width: 120,
|
||||||
type: "select",
|
type: "select",
|
||||||
label: "审核状态",
|
label: "画家宝审核状态",
|
||||||
field: "baseAuditStatus",
|
field: "baseAuditStatus",
|
||||||
config: {
|
config: {
|
||||||
options: [
|
options: [
|
||||||
@ -2384,7 +2384,7 @@ const getProvinceCityAreaOptions = async () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 13px 35px;
|
padding: 13px 35px;
|
||||||
background-color: $theme-darker;
|
background-color: rgb(238, 233, 248);
|
||||||
margin: 0 16px;
|
margin: 0 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
.receive-artwork-address-info {
|
.receive-artwork-address-info {
|
||||||
@ -2412,7 +2412,7 @@ const getProvinceCityAreaOptions = async () => {
|
|||||||
}
|
}
|
||||||
.edit-receive-address-btn {
|
.edit-receive-address-btn {
|
||||||
span {
|
span {
|
||||||
color: $theme-primary;
|
color: #409eff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,13 +16,12 @@
|
|||||||
text
|
text
|
||||||
style="
|
style="
|
||||||
width: 161px;
|
width: 161px;
|
||||||
|
color: #764cf6;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(50% + 40px);
|
left: calc(50% + 40px);
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
"
|
"
|
||||||
type="primary"
|
|
||||||
class="fl-ml-md"
|
class="fl-ml-md"
|
||||||
:loading="state.btnLoading"
|
:loading="state.btnLoading"
|
||||||
@click="handleGeneratedRandomly"
|
@click="handleGeneratedRandomly"
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
class="fl-py-sm font-bold"
|
class="fl-py-sm font-bold"
|
||||||
style="border-bottom: 4px solid #764cf6"
|
style="border-bottom: 4px solid #764cf6"
|
||||||
>
|
>
|
||||||
客服
|
画家宝客服
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
@ -585,7 +585,7 @@ const state = reactive({
|
|||||||
},
|
},
|
||||||
], //画家搜索框配置
|
], //画家搜索框配置
|
||||||
artistSearchBtnLoading: false, //按钮加载中状态
|
artistSearchBtnLoading: false, //按钮加载中状态
|
||||||
artistList: [], //的画家列表
|
artistList: [], //画家宝的画家列表
|
||||||
pagination: {
|
pagination: {
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<div class="content-login">
|
<div class="content-login">
|
||||||
<div class="wrap1">
|
<div class="wrap1">
|
||||||
<div class="wrap1_1">系统登录</div>
|
<div class="wrap1_1">系统登陆</div>
|
||||||
<!-- <div class="wrap1_2">{{ state.title }}!</div> -->
|
<!-- <div class="wrap1_2">{{ state.title }}!</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="wrap2">
|
<div class="wrap2">
|
||||||
@ -163,7 +163,7 @@ const state = reactive({
|
|||||||
title:
|
title:
|
||||||
import.meta.env.VITE_APP_MODE === "main"
|
import.meta.env.VITE_APP_MODE === "main"
|
||||||
? "体制外管理系统"
|
? "体制外管理系统"
|
||||||
: "管理系统",
|
: "丰链管理系统",
|
||||||
});
|
});
|
||||||
|
|
||||||
const formValue = ref({
|
const formValue = ref({
|
||||||
|
|||||||
@ -1,430 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row"
|
|
||||||
style="padding: 35px">
|
|
||||||
<div class="col-3 fl-pa-md"
|
|
||||||
style="
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: rgba(188, 188, 188, 0.18) 0px 3px 6px 1px;
|
|
||||||
">
|
|
||||||
<div class="row font-16"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5">
|
|
||||||
<div class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6">
|
|
||||||
组织架构
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row"
|
|
||||||
style="height: 76vh; overflow: auto">
|
|
||||||
<fl-tree :data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
:config="{
|
|
||||||
actions: ['edit', 'add', 'subtraction'],
|
|
||||||
addShow: '[%=level%]!==4',
|
|
||||||
}"
|
|
||||||
@triggerTreeAction="handleTreeAction"
|
|
||||||
@triggerTreeClick="handleTreeClick"></fl-tree>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-9 row fl-px-md">
|
|
||||||
<div style="background: #fff"
|
|
||||||
class="fl-pa-md">
|
|
||||||
<div class="col-12 row font-16"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5">
|
|
||||||
<div class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6">
|
|
||||||
{{ state.treeSelectData.title || "平台开发管理项目组" }}所有人员
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row fl-mt-sm">
|
|
||||||
<fln-table :config="state.tableConfig"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
:fatherData="state.treeSelectData">
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<n-modal v-model:show="state.dialogAddTree"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card">
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
添加组织
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div class="fl-my-lg font-20">
|
|
||||||
<n-input v-model:value="state.dialogAddTreeData"
|
|
||||||
placeholder="请输入组织名称" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #764cf6; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogAddTreeSave">保存</n-button>
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
|
||||||
@click="state.dialogAddTree = false">返回</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
<n-modal v-model:show="state.dialogSubtractionTree"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card">
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
删除组织
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div class="font-20"
|
|
||||||
style="margin: 115px 0">
|
|
||||||
是否确认删除该组织及其子组织(如有)?
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #764cf6; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogSubtractionTreeSave">确定</n-button>
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
|
||||||
@click="state.dialogSubtractionTree = false">返回</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 岗位
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
} from "vue";
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const state = reactive({
|
|
||||||
dialogData: {},
|
|
||||||
dialogAddTree: false,
|
|
||||||
dialogAddTreeData: "",
|
|
||||||
dialogSubtractionTree: false,
|
|
||||||
treeSelectData: {},
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
requestbysf: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "user/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "请输入姓名",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "手机号",
|
|
||||||
field: "telNum",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "请输入手机号",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "岗位",
|
|
||||||
field: "positionName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "请输入岗位",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "请输入员工工号",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
title: "手机号",
|
|
||||||
field: "telNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "岗位",
|
|
||||||
align: 'left',
|
|
||||||
field: "nowPositions",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
tagField: "name",
|
|
||||||
tagBgColorField: "color",
|
|
||||||
showLength: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
let treeSelectData = Local.get("orgmanage_treeSelectData");
|
|
||||||
if (treeSelectData) {
|
|
||||||
state.treeSelectData = treeSelectData;
|
|
||||||
state.clickKey = treeSelectData.key;
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
});
|
|
||||||
onMounted(() => { });
|
|
||||||
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/my";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.clickKey === data[0].key &&
|
|
||||||
!state.expandedKeys.includes(data[0].key)
|
|
||||||
) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
state.expandedKeys.push(state.clickKey);
|
|
||||||
}
|
|
||||||
if (data.length === 1 && !state.expandedKeys.includes(data[0].key)) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreatePosi = () => {
|
|
||||||
console.log("handleCreatePosi");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTreeAction = ({ type, val }) => {
|
|
||||||
state.dialogData = val;
|
|
||||||
if (type === "add") {
|
|
||||||
state.clickKey = val.key;
|
|
||||||
state.treeSelectData = val;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
state.dialogAddTreeData = "";
|
|
||||||
state.dialogAddTree = true;
|
|
||||||
}
|
|
||||||
if (type === "subtraction") {
|
|
||||||
state.dialogSubtractionTree = true;
|
|
||||||
}
|
|
||||||
if (type === "save") {
|
|
||||||
let url = "/department/v2/update";
|
|
||||||
let params = {
|
|
||||||
name: val.title,
|
|
||||||
ID: val.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
getTreeData();
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (type === "cancel") {
|
|
||||||
getTreeData();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
Local.set("orgmanage_treeSelectData", tree);
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
// const handleTreeDefaultClick = () => {
|
|
||||||
// state.treeSelectData = state.treeData[0];
|
|
||||||
// state.clickKey = state.treeData[0].key;
|
|
||||||
// Local.remove("orgmanage_treeSelectData");
|
|
||||||
// state.tableConfig.refreshCount++;
|
|
||||||
// };
|
|
||||||
const handleCloseModal = () => {
|
|
||||||
// emits("triggerCloseModal");
|
|
||||||
};
|
|
||||||
// 树 新增
|
|
||||||
const handleDialogAddTreeSave = () => {
|
|
||||||
let url = "/department/v2/create";
|
|
||||||
let params = {
|
|
||||||
name: state.dialogAddTreeData,
|
|
||||||
pid: state.dialogData.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
if (Array.isArray(res.data.levelPathList)) {
|
|
||||||
state.expandedKeys = [];
|
|
||||||
res.data.levelPathList.forEach((treeid) => {
|
|
||||||
if (!state.expandedKeys.includes(treeid)) {
|
|
||||||
state.expandedKeys.push(treeid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
// 树 减
|
|
||||||
const handleDialogSubtractionTreeSave = () => {
|
|
||||||
let url = "/department/v2/remove";
|
|
||||||
let params = {
|
|
||||||
ID: state.dialogData.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
getTreeData();
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,893 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row" style="padding: 35px; margin-bottom: 80px">
|
|
||||||
<div
|
|
||||||
class="col-12 row"
|
|
||||||
style="
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 17px 20px;
|
|
||||||
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row font-20"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'create'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
新增
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'edit'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
修改
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'view'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.nickName"
|
|
||||||
:config="{
|
|
||||||
label: '姓名:',
|
|
||||||
field: 'nickName',
|
|
||||||
placeholder: '请输入姓名',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValBlur="handleValBlur"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.telNum"
|
|
||||||
:config="{
|
|
||||||
label: '手机号:',
|
|
||||||
field: 'telNum',
|
|
||||||
placeholder: '请输入手机号',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.mailAccount"
|
|
||||||
:config="{
|
|
||||||
label: '邮箱:',
|
|
||||||
field: 'mailAccount',
|
|
||||||
placeholder: '自动生成',
|
|
||||||
}"
|
|
||||||
:disable="true"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="date"
|
|
||||||
:val="state.formData.enterDate"
|
|
||||||
:config="{
|
|
||||||
label: '入职时间:',
|
|
||||||
field: 'enterDate',
|
|
||||||
placeholder: '请输入入职时间',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="select"
|
|
||||||
:val="state.formData.status"
|
|
||||||
:config="{
|
|
||||||
placeholder: '请输入状态',
|
|
||||||
label: '状态:',
|
|
||||||
field: 'status',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: '有效',
|
|
||||||
value: 'notactive',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '无效',
|
|
||||||
value: 'left',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.jobNum"
|
|
||||||
:config="{
|
|
||||||
label: '员工工号:',
|
|
||||||
field: 'jobNum',
|
|
||||||
placeholder: '请输入员工工号',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="upload"
|
|
||||||
title="图片上传"
|
|
||||||
:config="{
|
|
||||||
limit4096: true,
|
|
||||||
label: '员工近照:',
|
|
||||||
field: 'recentImg',
|
|
||||||
placeholder: '请输入员工近照',
|
|
||||||
style: 'width:80px',
|
|
||||||
}"
|
|
||||||
:val="state.formData.recentImg"
|
|
||||||
:otherParams="{
|
|
||||||
source: 'artwork',
|
|
||||||
mask: '',
|
|
||||||
type: 'image',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row col-3">
|
|
||||||
<div class="col-12 row items-center">
|
|
||||||
<fln-form-item
|
|
||||||
type="upload"
|
|
||||||
title="图片上传"
|
|
||||||
:config="{
|
|
||||||
limit4096: true,
|
|
||||||
label: '员工头像:',
|
|
||||||
field: 'avatar',
|
|
||||||
placeholder: '请输入员工近照',
|
|
||||||
style: 'width:80px',
|
|
||||||
}"
|
|
||||||
:val="state.formData.avatar"
|
|
||||||
:otherParams="{
|
|
||||||
source: 'artwork',
|
|
||||||
mask: '',
|
|
||||||
type: 'image',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
>
|
|
||||||
<template #uploadRight v-if="!calcPageDisable()">
|
|
||||||
<div class="row" style="width: calc(100% - 84px)">
|
|
||||||
<img
|
|
||||||
v-for="(item, index) in state.defaultImgList"
|
|
||||||
:src="item + '?x-oss-process=image/resize,w_158,h_158'"
|
|
||||||
:key="index"
|
|
||||||
class="img-avatar"
|
|
||||||
:class="
|
|
||||||
state.defaultImgSelect == index ? 'border-active' : ''
|
|
||||||
"
|
|
||||||
@click="handleSetImg(item, index)"
|
|
||||||
/>
|
|
||||||
</div> </template
|
|
||||||
></fln-form-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="col-12 row fl-mt-md"
|
|
||||||
style="
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 17px 20px;
|
|
||||||
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
Array.isArray(state.depPositions) &&
|
|
||||||
state.depPositions.filter((item) => item.positions?.length > 0)
|
|
||||||
.length > 0
|
|
||||||
"
|
|
||||||
class="col-12 row"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 fl-mt-md row items-center fl-pb-xs"
|
|
||||||
style="min-height: 40px"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-between items-center fl-px-md"
|
|
||||||
style="
|
|
||||||
min-height: 40px;
|
|
||||||
background: #46299dff;
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="color-white">设置所属部门及岗位</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style="border: 1px solid #c3c3c3; border-radius: 0 0 3px 3px"
|
|
||||||
class="col-12 row fl-pb-xs"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row"
|
|
||||||
style="padding: 11px 0; background: #dfd7f2"
|
|
||||||
>
|
|
||||||
<div class="col-3 text-center">所属部门</div>
|
|
||||||
<div class="col-6 text-left">所属岗位</div>
|
|
||||||
</div>
|
|
||||||
<template v-for="(row, rowIdx) in state.depPositions">
|
|
||||||
<div
|
|
||||||
class="col-12 row fl-py-sm"
|
|
||||||
v-if="row.positions?.length > 0"
|
|
||||||
:style="
|
|
||||||
rowIdx !== state.depPositions.length - 1
|
|
||||||
? 'border-bottom:1px solid #c3c3c3'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
:key="rowIdx"
|
|
||||||
>
|
|
||||||
<div class="col-3 row items-center justify-center">
|
|
||||||
{{ row.name }}
|
|
||||||
</div>
|
|
||||||
<div class="col-6 row items-center">
|
|
||||||
<div
|
|
||||||
v-for="(tag, idx) in row.positions"
|
|
||||||
:key="idx"
|
|
||||||
class="fl-mr-sm fl-px-sm fl-py-xs row items-center fl-mb-xs"
|
|
||||||
style="border: solid 1px #ded7f1; border-radius: 3px"
|
|
||||||
:style="{
|
|
||||||
borderColor: tag.color,
|
|
||||||
color: tag.color || '#fff',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<n-popover :show-arrow="true">
|
|
||||||
<template #trigger>
|
|
||||||
{{ tag.name }}
|
|
||||||
</template>
|
|
||||||
{{ tag.name }}
|
|
||||||
</n-popover>
|
|
||||||
|
|
||||||
<close-circle-outlined
|
|
||||||
v-if="!calcPageDisable()"
|
|
||||||
class="fl-ml-md"
|
|
||||||
@click="handleClearPage(rowIdx, tag)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div
|
|
||||||
class="col-3 row fl-px-md"
|
|
||||||
style="overflow: auto; box-shadow: 0 3px 6px 1px #bcbcbc2e"
|
|
||||||
>
|
|
||||||
<fln-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fln-tree>
|
|
||||||
</div>
|
|
||||||
<div class="col-9 row fl-pl-md" style="align-content: flex-start">
|
|
||||||
<fln-table
|
|
||||||
class="artwork-table"
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:defaultSelectedRows="state.tableDefaultPositions"
|
|
||||||
:clearSelectRowKey="state.tableClearKey"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:fatherParams="state.tableSearchData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerRowSelect="handleTableRowSelect"
|
|
||||||
@triggerRowSelectAll="handleTableCheckAll"
|
|
||||||
>
|
|
||||||
<template #table-header>
|
|
||||||
<span style="color: #fd0000" class="fl-mx-sm">*</span>
|
|
||||||
请至少勾选一个岗位</template
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="width-100 row fl-pt-md fl-pb-lg"
|
|
||||||
style="position: fixed; bottom: 0px; background: #f0f0f5"
|
|
||||||
>
|
|
||||||
<div class="col-10 row justify-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
class="fl-mr-md"
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #ffffffff"
|
|
||||||
@click="handleBack"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="state.pageType === 'edit'"
|
|
||||||
style="width: 161px; height: 34px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleSave"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="state.pageType === 'create'"
|
|
||||||
style="width: 161px; height: 34px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleCreate"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
import flnTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
|
|
||||||
import { CloseCircleOutlined } from "@ant-design/icons-vue";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onActivated,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
watch,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const state = reactive({
|
|
||||||
tableClearKey: null,
|
|
||||||
treeSelectData: {},
|
|
||||||
tableDefaultPositions: [],
|
|
||||||
depPositions: [],
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
formData: {
|
|
||||||
nickName: null,
|
|
||||||
telNum: null,
|
|
||||||
status: "notactive",
|
|
||||||
positionName: null,
|
|
||||||
jobNum: null,
|
|
||||||
mailAccount: null,
|
|
||||||
enterDate: null,
|
|
||||||
recentImg: null,
|
|
||||||
avatar: null,
|
|
||||||
},
|
|
||||||
tableSearchData: {},
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
hasSelection: true,
|
|
||||||
requestbysf: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/position/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "岗位ID",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
align: "left",
|
|
||||||
title: "岗位名",
|
|
||||||
field: "name",
|
|
||||||
type: "sfBgColor",
|
|
||||||
bgConfig: {
|
|
||||||
bgColorField: "color",
|
|
||||||
color: "#fff",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
align: "left",
|
|
||||||
width: 120,
|
|
||||||
title: "岗位描述",
|
|
||||||
field: "remark",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
align: "left",
|
|
||||||
title: "页面权限",
|
|
||||||
field: "menuAuths",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#fff",
|
|
||||||
borderRadius: "14px",
|
|
||||||
style: "border-radius: 14px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
defaultImgList: [
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/image/avart/0/d5f416d5-0b95-4b2c-82c4-6218d4017d17.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/image/avart/0/012a339a-53d2-43f7-ae47-84d444d5ca6f.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/file/avart/11/48ae18e2-37a4-4eab-bd03-5fe1099892c3.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/file/avart/11/0a53fd8a-951e-4a8e-8d71-0198dad5e7ae.jpg",
|
|
||||||
],
|
|
||||||
defaultImgSelect: null,
|
|
||||||
btnLoading: false,
|
|
||||||
pageType: "create",
|
|
||||||
});
|
|
||||||
watch(
|
|
||||||
() => state.clickKey,
|
|
||||||
(newVal, oldVal) => {
|
|
||||||
state.tableDefaultPositions =
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length > 0
|
|
||||||
? state.depPositions.filter((item) => item.ID === state.clickKey)[0]
|
|
||||||
.positions
|
|
||||||
: [];
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getTreeData();
|
|
||||||
if (route.query.type) {
|
|
||||||
state.pageType = route.query.type;
|
|
||||||
}
|
|
||||||
if (route.query.type === "view") {
|
|
||||||
state.tableConfig.hasSelection = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onActivated(() => {
|
|
||||||
getTreeData();
|
|
||||||
if (route.query.type) {
|
|
||||||
state.pageType = route.query.type;
|
|
||||||
}
|
|
||||||
if (route.query.type === "view") {
|
|
||||||
state.tableConfig.hasSelection = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
const getPageData = () => {
|
|
||||||
if (route.query.ID) {
|
|
||||||
let url = "/user/v2/detail";
|
|
||||||
let params = {
|
|
||||||
ID: Number(route.query.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.formData = {
|
|
||||||
nickName: res.data.nickName,
|
|
||||||
telNum: res.data.telNum,
|
|
||||||
status: res.data.status,
|
|
||||||
positionName: res.data.positionName,
|
|
||||||
jobNum: res.data.jobNum,
|
|
||||||
mailAccount: res.data.mailAccount,
|
|
||||||
enterDate: res.data.enterDate,
|
|
||||||
recentImg: res.data.recentImg,
|
|
||||||
avatar: res.data.avatar,
|
|
||||||
};
|
|
||||||
state.depPositions = res.data.depPositions || [];
|
|
||||||
state.tableDefaultPositions =
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey)
|
|
||||||
.length > 0
|
|
||||||
? state.depPositions.filter(
|
|
||||||
(item) => item.ID === state.clickKey
|
|
||||||
)[0].positions
|
|
||||||
: [];
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
item.isLeader = item.isLeader || false;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取数据失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/all";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
if (!state.expandedKeys.includes(data[0].key)) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
if (route.query.ID) {
|
|
||||||
getPageData();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleValChange = ({ val, config }) => {
|
|
||||||
state.formData[config.field] = val;
|
|
||||||
};
|
|
||||||
const handleValBlur = ({ val, config }) => {
|
|
||||||
if (config.field === "nickName" && state.formData.nickName) {
|
|
||||||
let url = "/user/mail/account";
|
|
||||||
let params = {
|
|
||||||
nickName: val,
|
|
||||||
ID: route.query.ID ? Number(route.query.ID) : null,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.formData.mailAccount = res.data.mailAccount;
|
|
||||||
} else {
|
|
||||||
processError("生成邮箱错误:" + res.msg);
|
|
||||||
state.formData.mailAccount = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
() => {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
|
||||||
state.tableSearchData = JSON.parse(JSON.stringify(state.formData));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTableRowSelect = ({ record, selected, selectedRows }) => {
|
|
||||||
if (
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length === 0
|
|
||||||
) {
|
|
||||||
state.depPositions.push({
|
|
||||||
isLeader: false,
|
|
||||||
ID: state.clickKey,
|
|
||||||
name: state.treeSelectData.title,
|
|
||||||
positions: selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
if (item.ID === state.clickKey) {
|
|
||||||
if (selected) {
|
|
||||||
// 当前部门有其他子岗位时不直接覆盖
|
|
||||||
item.positions = item.positions.filter(
|
|
||||||
(depItem) => depItem.ID !== record.ID
|
|
||||||
);
|
|
||||||
item.positions = item.positions.concat([
|
|
||||||
{
|
|
||||||
ID: record.ID,
|
|
||||||
name: record.name,
|
|
||||||
color: record.color,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
item.positions = item.positions.filter(
|
|
||||||
(depItem) => depItem.ID !== record.ID
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
};
|
|
||||||
const handleTableCheckAll = ({ selectedRowKeys, selectedRows }) => {
|
|
||||||
if (
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length === 0
|
|
||||||
) {
|
|
||||||
state.depPositions.push({
|
|
||||||
isLeader: false,
|
|
||||||
ID: state.clickKey,
|
|
||||||
name: state.treeSelectData.title,
|
|
||||||
positions: selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
if (item.ID === state.clickKey) {
|
|
||||||
item.positions = selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
};
|
|
||||||
const handleDialogSave = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
const calcPageDisable = () => {
|
|
||||||
return state.pageType === "view";
|
|
||||||
};
|
|
||||||
const handleSetImg = (item, index) => {
|
|
||||||
state.formData.avatar = "";
|
|
||||||
nextTick(() => {
|
|
||||||
state.formData.avatar = item;
|
|
||||||
state.defaultImgSelect = index;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const handleCreate = () => {
|
|
||||||
if (
|
|
||||||
state.formData.jobNum === null ||
|
|
||||||
state.formData.jobNum === "" ||
|
|
||||||
state.formData.jobNum === undefined
|
|
||||||
) {
|
|
||||||
processError("请输入员工工号");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
let url = "/user/v2/create";
|
|
||||||
let params = {
|
|
||||||
depPositions: state.depPositions,
|
|
||||||
};
|
|
||||||
Object.assign(params, state.formData);
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
router.go(-1);
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleSave = () => {
|
|
||||||
if (
|
|
||||||
state.formData.jobNum === null ||
|
|
||||||
state.formData.jobNum === "" ||
|
|
||||||
state.formData.jobNum === undefined
|
|
||||||
) {
|
|
||||||
processError("请输入员工工号");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
let url = "/user/v2/update";
|
|
||||||
let params = {
|
|
||||||
ID: Number(route.query.ID),
|
|
||||||
depPositions: state.depPositions,
|
|
||||||
};
|
|
||||||
Object.assign(params, state.formData);
|
|
||||||
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
getPageData();
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleLink = (path) => {
|
|
||||||
router.push(path);
|
|
||||||
};
|
|
||||||
const handleBack = () => {
|
|
||||||
router.go(-1);
|
|
||||||
};
|
|
||||||
const calcDepPositions = () => {
|
|
||||||
for (let key in state.depPositions) {
|
|
||||||
let data = state.depPositions[key];
|
|
||||||
if (!data || JSON.stringify(data) === "[]") {
|
|
||||||
delete state.depPositions[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleClearPage = (idx, clearItem) => {
|
|
||||||
state.depPositions[idx].positions.forEach((item, index) => {
|
|
||||||
if (item.name === clearItem.name) {
|
|
||||||
state.depPositions[idx].positions.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.depPositions[idx].positions.length === 0) {
|
|
||||||
state.depPositions.splice(idx, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
state.tableClearKey = clearItem.ID;
|
|
||||||
};
|
|
||||||
const calcSfBgColorWidth = (val) => {
|
|
||||||
if (val) {
|
|
||||||
return val.length * 15 + "px !important";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.avatar-uploader > .ant-upload) {
|
|
||||||
background: #fafafcff;
|
|
||||||
}
|
|
||||||
:deep(.ant-image) {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-image-img) {
|
|
||||||
object-fit: cover !important;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-image-mask) {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-upload) {
|
|
||||||
color: #c1b2e5;
|
|
||||||
}
|
|
||||||
:deep(.ant-select) {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
:deep(.ant-select-selector .ant-select-selection-placeholder) {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.img-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin: 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.border-active {
|
|
||||||
border: 2px solid #764cf6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,893 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row" style="padding: 35px; margin-bottom: 80px">
|
|
||||||
<div
|
|
||||||
class="col-12 row"
|
|
||||||
style="
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 17px 20px;
|
|
||||||
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row font-20"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'create'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
新增
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'edit'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
修改
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.pageType === 'view'"
|
|
||||||
class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6"
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.nickName"
|
|
||||||
:config="{
|
|
||||||
label: '姓名:',
|
|
||||||
field: 'nickName',
|
|
||||||
placeholder: '请输入姓名',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValBlur="handleValBlur"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.telNum"
|
|
||||||
:config="{
|
|
||||||
label: '手机号:',
|
|
||||||
field: 'telNum',
|
|
||||||
placeholder: '请输入手机号',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.mailAccount"
|
|
||||||
:config="{
|
|
||||||
label: '邮箱:',
|
|
||||||
field: 'mailAccount',
|
|
||||||
placeholder: '自动生成',
|
|
||||||
}"
|
|
||||||
:disable="true"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="date"
|
|
||||||
:val="state.formData.enterDate"
|
|
||||||
:config="{
|
|
||||||
label: '入职时间:',
|
|
||||||
field: 'enterDate',
|
|
||||||
format: 'YYYY-MM-dd',
|
|
||||||
placeholder: '请输入入职时间',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="select"
|
|
||||||
:val="state.formData.status"
|
|
||||||
:config="{
|
|
||||||
placeholder: '请输入状态',
|
|
||||||
label: '状态:',
|
|
||||||
field: 'status',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: '有效',
|
|
||||||
value: 'notactive',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '无效',
|
|
||||||
value: 'left',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row items-center col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="text"
|
|
||||||
:val="state.formData.jobNum"
|
|
||||||
:config="{
|
|
||||||
label: '员工工号:',
|
|
||||||
field: 'jobNum',
|
|
||||||
placeholder: '请输入员工工号',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="search-item fl-mt-md row col-3">
|
|
||||||
<fln-form-item
|
|
||||||
type="upload"
|
|
||||||
title="图片上传"
|
|
||||||
:config="{
|
|
||||||
limit4096: true,
|
|
||||||
label: '员工近照:',
|
|
||||||
field: 'recentImg',
|
|
||||||
placeholder: '请输入员工近照',
|
|
||||||
style: 'width:80px',
|
|
||||||
}"
|
|
||||||
:val="state.formData.recentImg"
|
|
||||||
:otherParams="{
|
|
||||||
source: 'artwork',
|
|
||||||
mask: '',
|
|
||||||
type: 'image',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mt-md row col-3">
|
|
||||||
<div class="col-12 row items-center">
|
|
||||||
<fln-form-item
|
|
||||||
type="upload"
|
|
||||||
title="图片上传"
|
|
||||||
:config="{
|
|
||||||
limit4096: true,
|
|
||||||
label: '员工头像:',
|
|
||||||
field: 'avatar',
|
|
||||||
placeholder: '请输入员工近照',
|
|
||||||
style: 'width:80px',
|
|
||||||
}"
|
|
||||||
:val="state.formData.avatar"
|
|
||||||
:otherParams="{
|
|
||||||
source: 'artwork',
|
|
||||||
mask: '',
|
|
||||||
type: 'image',
|
|
||||||
}"
|
|
||||||
:disable="calcPageDisable()"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
>
|
|
||||||
<template #uploadRight v-if="!calcPageDisable()">
|
|
||||||
<div class="row" style="width: calc(100% - 84px)">
|
|
||||||
<img
|
|
||||||
v-for="(item, index) in state.defaultImgList"
|
|
||||||
:src="item + '?x-oss-process=image/resize,w_158,h_158'"
|
|
||||||
:key="index"
|
|
||||||
class="img-avatar"
|
|
||||||
:class="
|
|
||||||
state.defaultImgSelect == index ? 'border-active' : ''
|
|
||||||
"
|
|
||||||
@click="handleSetImg(item, index)"
|
|
||||||
/>
|
|
||||||
</div> </template
|
|
||||||
></fln-form-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="col-12 row fl-mt-md"
|
|
||||||
style="
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 17px 20px;
|
|
||||||
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
Array.isArray(state.depPositions) &&
|
|
||||||
state.depPositions.filter((item) => item.positions?.length > 0)
|
|
||||||
.length > 0
|
|
||||||
"
|
|
||||||
class="col-12 row"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 fl-mt-md row items-center fl-pb-xs"
|
|
||||||
style="min-height: 40px"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-between items-center fl-px-md"
|
|
||||||
style="
|
|
||||||
min-height: 40px;
|
|
||||||
background: #46299dff;
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="color-white">设置所属部门及岗位</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style="border: 1px solid #c3c3c3; border-radius: 0 0 3px 3px"
|
|
||||||
class="col-12 row fl-pb-xs"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row"
|
|
||||||
style="padding: 11px 0; background: #dfd7f2"
|
|
||||||
>
|
|
||||||
<div class="col-3 text-center">所属部门</div>
|
|
||||||
<div class="col-6 text-left">所属岗位</div>
|
|
||||||
</div>
|
|
||||||
<template v-for="(row, rowIdx) in state.depPositions">
|
|
||||||
<div
|
|
||||||
class="col-12 row fl-py-sm"
|
|
||||||
v-if="row.positions?.length > 0"
|
|
||||||
:style="
|
|
||||||
rowIdx !== state.depPositions.length - 1
|
|
||||||
? 'border-bottom:1px solid #c3c3c3'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
:key="rowIdx"
|
|
||||||
>
|
|
||||||
<div class="col-3 row items-center justify-center">
|
|
||||||
{{ row.name }}
|
|
||||||
</div>
|
|
||||||
<div class="col-6 row items-center">
|
|
||||||
<div
|
|
||||||
v-for="(tag, idx) in row.positions"
|
|
||||||
:key="idx"
|
|
||||||
class="fl-mr-sm fl-px-sm fl-py-xs row items-center fl-mb-xs"
|
|
||||||
style="border: solid 1px #ded7f1; border-radius: 3px"
|
|
||||||
:style="{
|
|
||||||
borderColor: tag.color,
|
|
||||||
color: tag.color || '#fff',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<n-popover :show-arrow="true">
|
|
||||||
<template #trigger>
|
|
||||||
{{ tag.name }}
|
|
||||||
</template>
|
|
||||||
{{ tag.name }}
|
|
||||||
</n-popover>
|
|
||||||
|
|
||||||
<close-circle-outlined
|
|
||||||
v-if="!calcPageDisable()"
|
|
||||||
class="fl-ml-md"
|
|
||||||
@click="handleClearPage(rowIdx, tag)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div
|
|
||||||
class="col-3 row fl-px-md"
|
|
||||||
style="overflow: auto; box-shadow: 0 3px 6px 1px #bcbcbc2e"
|
|
||||||
>
|
|
||||||
<fln-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fln-tree>
|
|
||||||
</div>
|
|
||||||
<div class="col-9 row fl-pl-md" style="align-content: flex-start">
|
|
||||||
<fln-table
|
|
||||||
class="artwork-table"
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:defaultSelectedRows="state.tableDefaultPositions"
|
|
||||||
:clearSelectRowKey="state.tableClearKey"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:fatherParams="state.tableSearchData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerRowSelect="handleTableRowSelect"
|
|
||||||
@triggerRowSelectAll="handleTableCheckAll"
|
|
||||||
>
|
|
||||||
<template #table-header>
|
|
||||||
<span style="color: #fd0000" class="fl-mx-sm">*</span>
|
|
||||||
请至少勾选一个岗位</template
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="width-100 row fl-pt-md fl-pb-lg"
|
|
||||||
style="position: fixed; bottom: 0px; background: #f0f0f5"
|
|
||||||
>
|
|
||||||
<div class="col-10 row justify-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
class="fl-mr-md"
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #ffffffff"
|
|
||||||
@click="handleBack"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="state.pageType === 'edit'"
|
|
||||||
style="width: 161px; height: 34px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleSave"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="state.pageType === 'create'"
|
|
||||||
style="width: 161px; height: 34px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleCreate"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
import flnTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
|
|
||||||
import { CloseCircleOutlined } from "@ant-design/icons-vue";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onActivated,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
watch,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const state = reactive({
|
|
||||||
tableClearKey: null,
|
|
||||||
treeSelectData: {},
|
|
||||||
tableDefaultPositions: [],
|
|
||||||
depPositions: [],
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
formData: {
|
|
||||||
nickName: null,
|
|
||||||
telNum: null,
|
|
||||||
status: "notactive",
|
|
||||||
positionName: null,
|
|
||||||
jobNum: null,
|
|
||||||
mailAccount: null,
|
|
||||||
enterDate: null,
|
|
||||||
recentImg: null,
|
|
||||||
avatar: null,
|
|
||||||
},
|
|
||||||
tableSearchData: {},
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
hasSelection: true,
|
|
||||||
requestbysf: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/position/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "岗位ID",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
align: "left",
|
|
||||||
title: "岗位名",
|
|
||||||
field: "name",
|
|
||||||
type: "sfBgColor",
|
|
||||||
bgConfig: {
|
|
||||||
bgColorField: "color",
|
|
||||||
color: "#fff",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
align: "left",
|
|
||||||
width: 120,
|
|
||||||
title: "岗位描述",
|
|
||||||
field: "remark",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
align: "left",
|
|
||||||
title: "页面权限",
|
|
||||||
field: "menuAuths",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#fff",
|
|
||||||
borderRadius: "14px",
|
|
||||||
style: "border-radius: 14px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
defaultImgList: [
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/image/avart/0/d5f416d5-0b95-4b2c-82c4-6218d4017d17.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/image/avart/0/012a339a-53d2-43f7-ae47-84d444d5ca6f.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/file/avart/11/48ae18e2-37a4-4eab-bd03-5fe1099892c3.jpg",
|
|
||||||
"https://cdns.fontree.cn/fonchain-main/prod/runtime/file/avart/11/0a53fd8a-951e-4a8e-8d71-0198dad5e7ae.jpg",
|
|
||||||
],
|
|
||||||
defaultImgSelect: null,
|
|
||||||
btnLoading: false,
|
|
||||||
pageType: "create",
|
|
||||||
});
|
|
||||||
watch(
|
|
||||||
() => state.clickKey,
|
|
||||||
(newVal, oldVal) => {
|
|
||||||
state.tableDefaultPositions =
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length > 0
|
|
||||||
? state.depPositions.filter((item) => item.ID === state.clickKey)[0]
|
|
||||||
.positions
|
|
||||||
: [];
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getTreeData();
|
|
||||||
if (route.query.type) {
|
|
||||||
state.pageType = route.query.type;
|
|
||||||
}
|
|
||||||
if (route.query.type === "view") {
|
|
||||||
state.tableConfig.hasSelection = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onActivated(() => {
|
|
||||||
getTreeData();
|
|
||||||
if (route.query.type) {
|
|
||||||
state.pageType = route.query.type;
|
|
||||||
}
|
|
||||||
if (route.query.type === "view") {
|
|
||||||
state.tableConfig.hasSelection = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
const getPageData = () => {
|
|
||||||
if (route.query.ID) {
|
|
||||||
let url = "/user/v2/boss/staff/detail";
|
|
||||||
let params = {
|
|
||||||
ID: Number(route.query.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.formData = {
|
|
||||||
nickName: res.data.nickName,
|
|
||||||
telNum: res.data.telNum,
|
|
||||||
status: res.data.status,
|
|
||||||
positionName: res.data.positionName,
|
|
||||||
jobNum: res.data.jobNum,
|
|
||||||
mailAccount: res.data.mailAccount,
|
|
||||||
enterDate: res.data.enterDate,
|
|
||||||
recentImg: res.data.recentImg,
|
|
||||||
avatar: res.data.avatar,
|
|
||||||
};
|
|
||||||
state.depPositions = res.data.depPositions || [];
|
|
||||||
state.tableDefaultPositions =
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey)
|
|
||||||
.length > 0
|
|
||||||
? state.depPositions.filter(
|
|
||||||
(item) => item.ID === state.clickKey
|
|
||||||
)[0].positions
|
|
||||||
: [];
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
item.isLeader = item.isLeader || false;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取数据失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const getTreeData = () => {
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.viewMyTree(params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
if (!state.expandedKeys.includes(data[0].key)) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
if (route.query.ID) {
|
|
||||||
getPageData();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleValChange = ({ val, config }) => {
|
|
||||||
state.formData[config.field] = val;
|
|
||||||
};
|
|
||||||
const handleValBlur = ({ val, config }) => {
|
|
||||||
if (config.field === "nickName" && state.formData.nickName) {
|
|
||||||
let url = "/user/mail/account";
|
|
||||||
let params = {
|
|
||||||
nickName: val,
|
|
||||||
ID: route.query.ID ? Number(route.query.ID) : null,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.formData.mailAccount = res.data.mailAccount;
|
|
||||||
} else {
|
|
||||||
processError("生成邮箱错误:" + res.msg);
|
|
||||||
state.formData.mailAccount = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
() => {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
|
||||||
state.tableSearchData = JSON.parse(JSON.stringify(state.formData));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTableRowSelect = ({ record, selected, selectedRows }) => {
|
|
||||||
if (
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length === 0
|
|
||||||
) {
|
|
||||||
state.depPositions.push({
|
|
||||||
isLeader: false,
|
|
||||||
ID: state.clickKey,
|
|
||||||
name: state.treeSelectData.title,
|
|
||||||
positions: selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
if (item.ID === state.clickKey) {
|
|
||||||
if (selected) {
|
|
||||||
// 当前部门有其他子岗位时不直接覆盖
|
|
||||||
item.positions = item.positions.filter(
|
|
||||||
(depItem) => depItem.ID !== record.ID
|
|
||||||
);
|
|
||||||
item.positions = item.positions.concat([
|
|
||||||
{
|
|
||||||
ID: record.ID,
|
|
||||||
name: record.name,
|
|
||||||
color: record.color,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
item.positions = item.positions.filter(
|
|
||||||
(depItem) => depItem.ID !== record.ID
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
};
|
|
||||||
const handleTableCheckAll = ({ selectedRowKeys, selectedRows }) => {
|
|
||||||
if (
|
|
||||||
state.depPositions.filter((item) => item.ID === state.clickKey).length === 0
|
|
||||||
) {
|
|
||||||
state.depPositions.push({
|
|
||||||
isLeader: false,
|
|
||||||
ID: state.clickKey,
|
|
||||||
name: state.treeSelectData.title,
|
|
||||||
positions: selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
state.depPositions.forEach((item) => {
|
|
||||||
if (item.ID === state.clickKey) {
|
|
||||||
item.positions = selectedRows.map((item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
name: item.name,
|
|
||||||
color: item.color,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
};
|
|
||||||
const handleDialogSave = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
const calcPageDisable = () => {
|
|
||||||
return state.pageType === "view";
|
|
||||||
};
|
|
||||||
const handleSetImg = (item, index) => {
|
|
||||||
state.formData.avatar = "";
|
|
||||||
nextTick(() => {
|
|
||||||
state.formData.avatar = item;
|
|
||||||
state.defaultImgSelect = index;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const handleCreate = () => {
|
|
||||||
if (
|
|
||||||
state.formData.jobNum === null ||
|
|
||||||
state.formData.jobNum === "" ||
|
|
||||||
state.formData.jobNum === undefined
|
|
||||||
) {
|
|
||||||
processError("请输入员工工号");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
let url = "/user/v2/create";
|
|
||||||
let params = {
|
|
||||||
depPositions: state.depPositions,
|
|
||||||
};
|
|
||||||
Object.assign(params, state.formData);
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
router.go(-1);
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleSave = () => {
|
|
||||||
if (
|
|
||||||
state.formData.jobNum === null ||
|
|
||||||
state.formData.jobNum === "" ||
|
|
||||||
state.formData.jobNum === undefined
|
|
||||||
) {
|
|
||||||
processError("请输入员工工号");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
state.depPositions = state.depPositions.filter((item) => {
|
|
||||||
return item.positions && item.positions.length > 0;
|
|
||||||
});
|
|
||||||
let url = "/user/v2/boss/staff/update";
|
|
||||||
let params = {
|
|
||||||
ID: Number(route.query.ID),
|
|
||||||
depPositions: state.depPositions,
|
|
||||||
};
|
|
||||||
Object.assign(params, state.formData);
|
|
||||||
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
getPageData();
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleLink = (path) => {
|
|
||||||
router.push(path);
|
|
||||||
};
|
|
||||||
const handleBack = () => {
|
|
||||||
router.go(-1);
|
|
||||||
};
|
|
||||||
const calcDepPositions = () => {
|
|
||||||
for (let key in state.depPositions) {
|
|
||||||
let data = state.depPositions[key];
|
|
||||||
if (!data || JSON.stringify(data) === "[]") {
|
|
||||||
delete state.depPositions[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleClearPage = (idx, clearItem) => {
|
|
||||||
state.depPositions[idx].positions.forEach((item, index) => {
|
|
||||||
if (item.name === clearItem.name) {
|
|
||||||
state.depPositions[idx].positions.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.depPositions[idx].positions.length === 0) {
|
|
||||||
state.depPositions.splice(idx, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
state.tableClearKey = clearItem.ID;
|
|
||||||
};
|
|
||||||
const calcSfBgColorWidth = (val) => {
|
|
||||||
if (val) {
|
|
||||||
return val.length * 15 + "px !important";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.avatar-uploader > .ant-upload) {
|
|
||||||
background: #fafafcff;
|
|
||||||
}
|
|
||||||
:deep(.ant-image) {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-image-img) {
|
|
||||||
object-fit: cover !important;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-image-mask) {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
:deep(.ant-upload) {
|
|
||||||
color: #c1b2e5;
|
|
||||||
}
|
|
||||||
:deep(.ant-select) {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
:deep(.ant-select-selector .ant-select-selection-placeholder) {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.img-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin: 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.border-active {
|
|
||||||
border: 2px solid #764cf6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,578 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row" style="padding: 35px">
|
|
||||||
<div
|
|
||||||
class="col-3 fl-pa-md"
|
|
||||||
style="
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: rgba(188, 188, 188, 0.18) 0px 3px 6px 1px;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="row font-16"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5"
|
|
||||||
>
|
|
||||||
<div class="fl-py-sm" style="border-bottom: 4px solid #764cf6">
|
|
||||||
组织架构
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" style="height: 76vh; overflow: auto">
|
|
||||||
<fl-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fl-tree>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-9 row fl-px-md" style="align-items: flex-start">
|
|
||||||
<fln-table
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerRowActions="handleRowActions"
|
|
||||||
@triggerTableBatchActions="handleTableBatchActions"
|
|
||||||
>
|
|
||||||
<template #search-header>
|
|
||||||
<div
|
|
||||||
class="col-12 row font-18"
|
|
||||||
style="
|
|
||||||
color: #764cf6;
|
|
||||||
border-bottom: 1px solid #c1b2e5;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="fl-py-sm" style="border-bottom: 4px solid #764cf6">
|
|
||||||
{{ state.treeSelectData.title || "平台开发管理项目组" }}所有人员
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<n-button @click="goToPeoManage" v-permission="'per-system-btn'">
|
|
||||||
系统所有人员
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
import { NButton, NPopover } from "naive-ui";
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request, $hadRule } =
|
|
||||||
currentInstance.appContext.config.globalProperties;
|
|
||||||
const state = reactive({
|
|
||||||
permission: false,
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
btnLoading: false,
|
|
||||||
treeSelectData: {},
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
hasSelection: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
|
|
||||||
url: "user/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "fatherDepartmentId",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "手机号",
|
|
||||||
field: "telNum",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
label: "状态",
|
|
||||||
field: "status",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "有效",
|
|
||||||
value: "notactive",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "无效",
|
|
||||||
value: "left",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "部门",
|
|
||||||
field: "departmentName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "岗位",
|
|
||||||
field: "positionName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "邮箱",
|
|
||||||
field: "mailAccount",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "rangdate",
|
|
||||||
label: "入职时间",
|
|
||||||
class: "col-4",
|
|
||||||
field: ["startEnterDate", "endEnterDate"],
|
|
||||||
placeholder: ["开始时间", "结束时间"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
title: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
title: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
title: "手机",
|
|
||||||
field: "telNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "归属部门",
|
|
||||||
align: "left",
|
|
||||||
field: "depPositions",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
tagField: "name",
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#E0E0E6FF",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: $hadRule("posi-edit-btn")
|
|
||||||
? "岗位(可点击岗位修改权限)"
|
|
||||||
: "岗位",
|
|
||||||
align: "left",
|
|
||||||
field: "positions",
|
|
||||||
render(row, index) {
|
|
||||||
const positions = row.positions;
|
|
||||||
if (!positions || positions.length === 0) {
|
|
||||||
return h("span", "No positions available");
|
|
||||||
}
|
|
||||||
// 渲染前3个标签
|
|
||||||
const visibleTags = positions.slice(0, 3).map((position) =>
|
|
||||||
h(
|
|
||||||
NButton,
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
marginRight: "2px",
|
|
||||||
borderWidth: "1px",
|
|
||||||
borderStyle: "solid",
|
|
||||||
color: position.color,
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
if ($hadRule("posi-edit-btn")) {
|
|
||||||
router.push(
|
|
||||||
`/posimanage/create?ID=${position.ID}&&type=edit`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ default: () => position.name }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 如果标签数量超过3个,渲染省略号按钮
|
|
||||||
if (positions.length > 3) {
|
|
||||||
const hiddenTags = positions.slice(3);
|
|
||||||
visibleTags.push(
|
|
||||||
h(
|
|
||||||
NPopover,
|
|
||||||
{
|
|
||||||
trigger: "hover",
|
|
||||||
placement: "bottom",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
trigger: () =>
|
|
||||||
h(
|
|
||||||
"span",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
marginLeft: "10px",
|
|
||||||
borderWidth: "1px",
|
|
||||||
borderStyle: "solid",
|
|
||||||
color: "#000",
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
padding: "10px 15px",
|
|
||||||
borderRadius: "5px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"..."
|
|
||||||
),
|
|
||||||
default: () =>
|
|
||||||
h(
|
|
||||||
"div",
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
padding: "10px",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
borderRadius: "5px",
|
|
||||||
boxShadow: "0 2px 12px rgba(0, 0, 0, 0.1)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hiddenTags.map((position) =>
|
|
||||||
h(
|
|
||||||
NButton,
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
marginRight: "2px",
|
|
||||||
borderWidth: "1px",
|
|
||||||
borderStyle: "solid",
|
|
||||||
color: position.color,
|
|
||||||
},
|
|
||||||
onClick: () => {
|
|
||||||
if ($hadRule("posi-edit-btn")) {
|
|
||||||
router.push(
|
|
||||||
`/posimanage/create?ID=${position.ID}&&type=edit`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ default: () => position.name }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return visibleTags;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
width: 260,
|
|
||||||
title: "邮箱",
|
|
||||||
field: "mailAccount",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
type: "avatar",
|
|
||||||
title: "员工头像",
|
|
||||||
field: "avatar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
type: "avatar",
|
|
||||||
title: "员工近照",
|
|
||||||
field: "recentImg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
title: "状态",
|
|
||||||
field: "status",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "有效",
|
|
||||||
value: "notactive",
|
|
||||||
class: "color-primary",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "无效",
|
|
||||||
value: "left",
|
|
||||||
class: "color-draft",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
title: "入职时间",
|
|
||||||
field: "enterDate",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 200,
|
|
||||||
title: "最近一次更新时间",
|
|
||||||
field: "updatedAt",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
fixed: "right",
|
|
||||||
title: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 200,
|
|
||||||
fixed: "right",
|
|
||||||
title: "操作",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "act_view",
|
|
||||||
type: "label",
|
|
||||||
label: "查看",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "act_edit",
|
|
||||||
type: "label",
|
|
||||||
label: "修改",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tableBatchActions: [
|
|
||||||
{
|
|
||||||
notLimitSelect: true,
|
|
||||||
actionType: "peo-create",
|
|
||||||
type: "primary",
|
|
||||||
label: "新增人员",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "peo-pass-set",
|
|
||||||
style: "background:#F7EFFFFF;color:#8352B4FF",
|
|
||||||
type: "primary",
|
|
||||||
label: "重置密码",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getTreeData();
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
|
|
||||||
const handleRowActions = ({ btnConfig, rowData }) => {
|
|
||||||
state.dialogData = rowData;
|
|
||||||
Local.set("orgmanage_treeSelectData", state.treeSelectData);
|
|
||||||
if (btnConfig.actionType === "act_edit") {
|
|
||||||
router.push(`/peomanage/editPeo?ID=${rowData.ID}&&type=edit`);
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_view") {
|
|
||||||
router.push(`/peomanage/editPeo?ID=${rowData.ID}&&type=view`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTableBatchActions = ({ selectedRows, btnConfig, fatherData }) => {
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
if (btnConfig.actionType === "peo-create") {
|
|
||||||
handleCreatePeo();
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "peo-pass-set") {
|
|
||||||
handleResetPass();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreatePeo = () => {
|
|
||||||
router.push("/peomanage/editPeo");
|
|
||||||
};
|
|
||||||
|
|
||||||
const goToPeoManage = () => {
|
|
||||||
router.push("/peomanage/personnelManage");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleResetPass = () => {
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/user/v2/reset/pwd";
|
|
||||||
let params = {
|
|
||||||
IDs: state.selectedRows.map((item) => item.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.selectedRows = [];
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//只有自己的树
|
|
||||||
const getTreeData = () => {
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.viewMyTree(params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
|
|
||||||
// 获取最近点击的部门
|
|
||||||
let localSelect = Local.get("orgmanage_treeSelectData");
|
|
||||||
if (localSelect && JSON.stringify(localSelect) !== "{}") {
|
|
||||||
state.treeSelectData = localSelect;
|
|
||||||
state.expandedKeys = localSelect.pathIds;
|
|
||||||
state.clickKey = localSelect.key;
|
|
||||||
} else {
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.clickKey === data[0].key &&
|
|
||||||
!state.expandedKeys.includes(data[0].key)
|
|
||||||
) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
state.expandedKeys.push(state.clickKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
Local.set("orgmanage_treeSelectData", state.treeSelectData);
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select) {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
:deep(.ant-select-selector .ant-select-selection-placeholder) {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,483 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row"
|
|
||||||
style="padding: 35px">
|
|
||||||
<div class="col-12 row">
|
|
||||||
<fln-table :config="state.tableConfig"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerRowActions="handleRowActions"
|
|
||||||
@triggerTableBatchActions="handleTableBatchActions">
|
|
||||||
<template #search-header>
|
|
||||||
<div class="col-12 row font-18"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5; display: flex; justify-content: space-between; align-items: center;">
|
|
||||||
<div class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6">
|
|
||||||
系统所有人员
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<n-button @click="goToIndex">
|
|
||||||
返回部门人员
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<n-modal v-model:show="state.dialogDel"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card">
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
删除
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div v-if="state.dialogData.type === 'one'"
|
|
||||||
class="font-20"
|
|
||||||
style="color: #1f2225ff; margin: 80px 0">
|
|
||||||
确定删除该人员吗? 删除后将不可恢复!
|
|
||||||
</div>
|
|
||||||
<div v-if="state.dialogData.type === 'batch'"
|
|
||||||
class="font-20"
|
|
||||||
style="color: #1f2225ff; margin: 80px 0">
|
|
||||||
确定删除选中的人员吗? 删除后将不可恢复!
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogBack">返回</n-button>
|
|
||||||
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleDialogSave">确定</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import { NButton } from "naive-ui";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const state = reactive({
|
|
||||||
dialogDel: false,
|
|
||||||
dialogData: {},
|
|
||||||
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
hasSelection: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "user/v2/list",
|
|
||||||
params: [],
|
|
||||||
},
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "手机号",
|
|
||||||
field: "telNum",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
label: "状态",
|
|
||||||
field: "status",
|
|
||||||
placeholder: "",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "有效",
|
|
||||||
value: "notactive",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "无效",
|
|
||||||
value: "left",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "部门",
|
|
||||||
field: "departmentName",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "岗位",
|
|
||||||
field: "positionName",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "邮箱",
|
|
||||||
field: "mailAccount",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "rangdate",
|
|
||||||
label: "入职时间",
|
|
||||||
field: ["startEnterDate", "endEnterDate"],
|
|
||||||
placeholder: ["开始时间", "结束时间"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
title: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
title: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
title: "手机",
|
|
||||||
field: "telNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "归属部门",
|
|
||||||
align: 'left',
|
|
||||||
field: "depPositions",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
tagField: "name",
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#E0E0E6FF",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "岗位",
|
|
||||||
align: 'left',
|
|
||||||
field: "positions",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
tagField: "name",
|
|
||||||
tagBgColorField: "color",
|
|
||||||
showLength: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 260,
|
|
||||||
title: "邮箱",
|
|
||||||
field: "mailAccount",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
type: "avatar",
|
|
||||||
title: "员工头像",
|
|
||||||
field: "avatar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 100,
|
|
||||||
type: "avatar",
|
|
||||||
title: "员工近照",
|
|
||||||
field: "recentImg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
title: "状态",
|
|
||||||
field: "status",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "有效",
|
|
||||||
value: "notactive",
|
|
||||||
class: "color-primary",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "无效",
|
|
||||||
value: "left",
|
|
||||||
class: "color-draft",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
title: "入职时间",
|
|
||||||
field: "enterDate",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 160,
|
|
||||||
title: "最近一次更新时间",
|
|
||||||
field: "updatedAt",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
fixed: "right",
|
|
||||||
title: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 200,
|
|
||||||
fixed: "right",
|
|
||||||
title: "操作",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "act_view",
|
|
||||||
type: "label",
|
|
||||||
label: "查看",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "act_edit",
|
|
||||||
type: "label",
|
|
||||||
label: "修改",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "act_del",
|
|
||||||
type: "label",
|
|
||||||
label: "删除",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tableBatchActions: [
|
|
||||||
{
|
|
||||||
notLimitSelect: true,
|
|
||||||
actionType: "peo-create",
|
|
||||||
type: "primary",
|
|
||||||
label: "新建人员",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "peo-pass-set",
|
|
||||||
style: "background:#F7EFFFFF;color:#8352B4FF",
|
|
||||||
type: "primary",
|
|
||||||
label: "重置密码",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onBeforeMount(() => { });
|
|
||||||
onMounted(() => { });
|
|
||||||
|
|
||||||
const handleRowActions = ({ btnConfig, rowData }) => {
|
|
||||||
state.dialogData = rowData;
|
|
||||||
if (btnConfig.actionType === "act_del") {
|
|
||||||
if (rowData.status !== "left") {
|
|
||||||
processError("该人员在职,不可删除");
|
|
||||||
return
|
|
||||||
}
|
|
||||||
state.dialogData.type = "one";
|
|
||||||
state.dialogDel = true;
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_edit") {
|
|
||||||
router.push(`/peomanage/create?ID=${rowData.ID}&&type=edit`);
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_view") {
|
|
||||||
router.push(`/peomanage/create?ID=${rowData.ID}&&type=view`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTableBatchActions = ({ selectedRows, btnConfig, fatherData }) => {
|
|
||||||
state.selectedRows = selectedRows
|
|
||||||
|
|
||||||
if (btnConfig.actionType === "peo-create") {
|
|
||||||
handleCreatePeo();
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "peo-pass-set") {
|
|
||||||
handleResetPass();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const goToIndex = () => {
|
|
||||||
router.push("/peomanage");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreatePeo = () => {
|
|
||||||
router.push("/peomanage/create");
|
|
||||||
};
|
|
||||||
const handleResetPass = () => {
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/user/v2/reset/pwd";
|
|
||||||
let params = {
|
|
||||||
IDs: state.selectedRows.map((item) => item.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.selectedRows = [];
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteBatch = () => {
|
|
||||||
state.dialogData.type = "batch";
|
|
||||||
state.dialogDel = true;
|
|
||||||
};
|
|
||||||
const handleDeleteBatchSave = () => {
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/user/v2/batch/remove";
|
|
||||||
let params = {
|
|
||||||
IDs: state.selectedRows.map((item) => item.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.selectedRows = [];
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
state.dialogDel = false;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
state.dialogDel = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
state.dialogDel = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleDialogSave = () => {
|
|
||||||
if (state.dialogData.type === "batch") {
|
|
||||||
handleDeleteBatchSave();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/user/v2/remove";
|
|
||||||
let params = {
|
|
||||||
ID: state.dialogData.ID,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
state.dialogDel = false;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
state.dialogDel = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select) {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
:deep(.ant-select-selector .ant-select-selection-placeholder) {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@ -1,311 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-modal v-model:show="state.dialogModal" :mask-closable="false">
|
|
||||||
<n-card
|
|
||||||
style="width: 80vw"
|
|
||||||
:bordered="false"
|
|
||||||
size="huge"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
批量加入审批发起人
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #header-extra>
|
|
||||||
<n-button @click="triggerCalcApproval" text style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
<div class="row justify-center fl-pa-md" style="color: #333639">
|
|
||||||
<div class="row col-12 fl-mt-lg">
|
|
||||||
<div class="col-12">请选择审批类型</div>
|
|
||||||
<div class="col-12 fl-mt-md overflow-auto" style="height: 60vh">
|
|
||||||
<fln-table
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerSelectCheck="handleTableSelectCheck"
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="triggerCalcApproval"
|
|
||||||
>上一步</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #46299dff; color: #fff"
|
|
||||||
:disabled="state.selectedRows.length === 0"
|
|
||||||
@click="triggerCalcApproval('submit')"
|
|
||||||
>确定</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
// 岗位新建中 选模版时的添加审批
|
|
||||||
import {
|
|
||||||
UpOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
DragOutlined,
|
|
||||||
} from "@ant-design/icons-vue";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
import flAboutApproval from "./aboutApproval.vue";
|
|
||||||
import draggable from "vuedraggable";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
import { ChevronDownOutline, ChevronUpOutline } from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
const emit = defineEmits(["triggerCalcApproval"]);
|
|
||||||
const state = reactive({
|
|
||||||
btnLoading: false,
|
|
||||||
dialogModal: true,
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "GroupList",
|
|
||||||
url: "/approval/v2/only-group",
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "审批类型分组",
|
|
||||||
field: "Title",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "",
|
|
||||||
field: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "",
|
|
||||||
field: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "",
|
|
||||||
field: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "",
|
|
||||||
field: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "",
|
|
||||||
field: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
expandConfig: {
|
|
||||||
defaultSelectedRows: [],
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "TypeList",
|
|
||||||
url: "/approval/v2/type/all",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "domain",
|
|
||||||
field: "Domain",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "groupId",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
type: "selection",
|
|
||||||
width: 50,
|
|
||||||
disabled(row) {
|
|
||||||
return row.Auths[0].UserID !== 0 || row.Auths[0].IsAll !== 0;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "流程名称",
|
|
||||||
field: "Title",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "发起人",
|
|
||||||
dataIndex: "Auths",
|
|
||||||
key: "Auths",
|
|
||||||
render(row) {
|
|
||||||
return h(
|
|
||||||
"div",
|
|
||||||
{
|
|
||||||
style:
|
|
||||||
"word-break:break-all;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;",
|
|
||||||
title: `${getAuths(row?.Auths)}`,
|
|
||||||
},
|
|
||||||
`${getAuths(row?.Auths)}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "审批节点",
|
|
||||||
key: "ApprovalUsers",
|
|
||||||
dataIndex: "ApprovalUsers",
|
|
||||||
render(row) {
|
|
||||||
return h("div", {}, `${getApprovalUsers(row?.ApprovalUsers)}`);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "抄送",
|
|
||||||
dataIndex: "CopyUsers",
|
|
||||||
key: "CopyUsers",
|
|
||||||
render(row) {
|
|
||||||
return h(
|
|
||||||
"div",
|
|
||||||
{},
|
|
||||||
`${
|
|
||||||
Array.isArray(row.CopyUsers)
|
|
||||||
? row.CopyUsers.map((item) =>
|
|
||||||
item.ID !== 0
|
|
||||||
? item.Name
|
|
||||||
: `${item.DepartmentName}-${item.PositionName}`
|
|
||||||
).join(",")
|
|
||||||
: "-"
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "备注",
|
|
||||||
dataIndex: "Remark",
|
|
||||||
key: "Remark",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selectedRows: [],
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.dialogModal = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
const getAuths = (auths) => {
|
|
||||||
if (auths) {
|
|
||||||
if (auths && auths.length === 1 && auths[0].IsAll === 1) {
|
|
||||||
return "全公司人员";
|
|
||||||
} else {
|
|
||||||
return auths
|
|
||||||
.filter((item) => item.IsAll === 0)
|
|
||||||
.map((item) =>
|
|
||||||
item.Name ? item.Name : item.DepartmentName + item.PositionName
|
|
||||||
)
|
|
||||||
.filter(Boolean)
|
|
||||||
.join("—");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const getApprovalUsers = (userList) => {
|
|
||||||
let user = "";
|
|
||||||
if (userList) {
|
|
||||||
user = userList
|
|
||||||
.filter((item) => item.DepartmentUID !== "undefined")
|
|
||||||
.map((item) => {
|
|
||||||
return {
|
|
||||||
flow:
|
|
||||||
item.IsDirect === 1 && item.IsDesignate === 1
|
|
||||||
? `直属第${item.Level}级`
|
|
||||||
: item.IsDirect === 1
|
|
||||||
? `直属${item.Level}级`
|
|
||||||
: item.Name
|
|
||||||
? item.Name
|
|
||||||
: item.DepartmentName + item.PositionName,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.map((item) => item.flow)
|
|
||||||
.join("—");
|
|
||||||
} else {
|
|
||||||
user = "";
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
};
|
|
||||||
const triggerCalcApproval = (type) => {
|
|
||||||
if (type === "submit") {
|
|
||||||
emit("triggerCalcApproval", state.selectedRows);
|
|
||||||
} else {
|
|
||||||
emit("triggerCalcApproval", []);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTableSelectCheck = (data) => {
|
|
||||||
if (data && Array.isArray(data.selectedRow)) {
|
|
||||||
data.selectedRow = data.selectedRow.filter((item) => {
|
|
||||||
if (item) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "check" || data.action === "checkAll") {
|
|
||||||
state.selectedRows = state.selectedRows.concat(data.selectedRow);
|
|
||||||
state.selectedRows = state.selectedRows.filter((item, index, arr) => {
|
|
||||||
return (
|
|
||||||
arr.findIndex((obj) => JSON.stringify(obj) === JSON.stringify(item)) ===
|
|
||||||
index
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheck") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return item.ID !== data.selectedRow.ID;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheckAll") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return (
|
|
||||||
data.selectedRow.findIndex((obj) => {
|
|
||||||
return obj.ID === item.ID;
|
|
||||||
}) === -1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
state.tableConfig.expandConfig.defaultSelectedRows = state.selectedRows;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
:deep(
|
|
||||||
.fln-table
|
|
||||||
.n-data-table-table
|
|
||||||
.n-checkbox.n-checkbox--disabled
|
|
||||||
.n-checkbox-box
|
|
||||||
) {
|
|
||||||
background-color: #d5d5d5 !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,156 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="fl-tree width-100 fl-mt-md">
|
|
||||||
<div class="row justify-end">
|
|
||||||
<div style="margin-right: 220px">是否为销售部门</div>
|
|
||||||
</div>
|
|
||||||
<n-tree
|
|
||||||
v-if="state.treeLoading"
|
|
||||||
block-line
|
|
||||||
:default-expanded-keys="state.expandedKeys"
|
|
||||||
:default-selected-keys="state.clickKey"
|
|
||||||
label-field="name"
|
|
||||||
key-field="key"
|
|
||||||
:expand-on-click="true"
|
|
||||||
:render-label="renderLabel"
|
|
||||||
:data="state.treeData"
|
|
||||||
@update:selected-keys="handleSelectTree"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
defineEmits,
|
|
||||||
watch,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
|
|
||||||
import treeLabel from "./treelabel.vue";
|
|
||||||
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
let props = defineProps({
|
|
||||||
data: Object,
|
|
||||||
refreshCount: Number,
|
|
||||||
config: Object,
|
|
||||||
expandedKeys: Array,
|
|
||||||
clickKey: [String, Number],
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
expandedKeys: [],
|
|
||||||
editTitle: "",
|
|
||||||
treeData: [],
|
|
||||||
clickKey: [],
|
|
||||||
treeLoading: true,
|
|
||||||
selectOptions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.refreshCount,
|
|
||||||
() => {
|
|
||||||
state.clickKey = [props.clickKey];
|
|
||||||
state.treeLoading = false;
|
|
||||||
nextTick(() => {
|
|
||||||
state.treeData = props.data;
|
|
||||||
calcDefaultConfig(state.treeData, 1);
|
|
||||||
state.treeLoading = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.expandedKeys,
|
|
||||||
() => {
|
|
||||||
state.clickKey = [props.clickKey];
|
|
||||||
state.expandedKeys = props.expandedKeys;
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.clickKey = [props.clickKey];
|
|
||||||
state.treeData = props.data;
|
|
||||||
calcDefaultConfig(state.treeData, 1);
|
|
||||||
state.expandedKeys = state.treeData.map((item) => item.key);
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getSelectOptions();
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits([
|
|
||||||
"triggerTreeAction",
|
|
||||||
"triggerTreeClick",
|
|
||||||
"triggerTreeDefaultClick",
|
|
||||||
]);
|
|
||||||
const handleSelectTree = (keys, option, meta) => {
|
|
||||||
if (keys.length === 1) {
|
|
||||||
emit("triggerTreeClick", { selectedKey: keys[0], tree: option[0] });
|
|
||||||
} else {
|
|
||||||
emit("triggerTreeDefaultClick");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const renderLabel = (option, checked) => {
|
|
||||||
return h(
|
|
||||||
treeLabel,
|
|
||||||
{
|
|
||||||
dataRef: option,
|
|
||||||
checked: checked,
|
|
||||||
config: props.config,
|
|
||||||
clickKey: props.clickKey,
|
|
||||||
options: state.selectOptions,
|
|
||||||
onTriggerTreeAction: handleTreeAction,
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const calcDefaultConfig = (data, level) => {
|
|
||||||
for (let item of data) {
|
|
||||||
if (!item.key) {
|
|
||||||
item.key = item.title + "_" + level;
|
|
||||||
}
|
|
||||||
item.edit = false;
|
|
||||||
if (item.children) {
|
|
||||||
calcDefaultConfig(item.children, level + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const override = ({ option }) => {
|
|
||||||
if (option.children) {
|
|
||||||
return "toggleExpand";
|
|
||||||
}
|
|
||||||
return "default";
|
|
||||||
};
|
|
||||||
const handleTreeAction = ({ type, val }) => {
|
|
||||||
emit("triggerTreeAction", { type, val });
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSelectOptions = () => {
|
|
||||||
let url = "department/head/list";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
let resData = res.data.list || [];
|
|
||||||
state.selectOptions = resData.filter((item) => item.alias);
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
@ -1,240 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row items-center">
|
|
||||||
<div v-if="state.treeData.edit">
|
|
||||||
<n-input v-model:value="state.editTitle" style="width: 120px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<n-popover trigger="hover" v-else>
|
|
||||||
<template #trigger>
|
|
||||||
<div style="width: 120px" class="fl-px-sm sf-text-ellipsis">
|
|
||||||
{{ state.treeData.title }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div>{{ state.treeData.title }}</div>
|
|
||||||
</n-popover>
|
|
||||||
<div class="row" style="width: calc(100% - 120px)">
|
|
||||||
<div class="col-4 row items-center">
|
|
||||||
<n-icon
|
|
||||||
:component="CreateOutline"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
size="20"
|
|
||||||
v-if="config?.actions.includes('edit') && !state.treeData.edit"
|
|
||||||
@click.stop="handleTreeEdit(state.treeData)"
|
|
||||||
/>
|
|
||||||
<n-icon
|
|
||||||
:component="Remove"
|
|
||||||
size="20"
|
|
||||||
v-if="
|
|
||||||
config?.actions.includes('subtraction') &&
|
|
||||||
!state.treeData.edit &&
|
|
||||||
visibleFormItem(config.subtractionShow, state.treeData)
|
|
||||||
"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
@click.stop="handleTreeSubtraction(state.treeData)"
|
|
||||||
/>
|
|
||||||
<n-icon
|
|
||||||
:component="Add"
|
|
||||||
size="20"
|
|
||||||
v-if="
|
|
||||||
config?.actions.includes('add') &&
|
|
||||||
!state.treeData.edit &&
|
|
||||||
visibleFormItem(config.addShow, state.treeData)
|
|
||||||
"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
@click.stop="handleTreeAdd(state.treeData)"
|
|
||||||
/>
|
|
||||||
<drag-outlined
|
|
||||||
v-if="
|
|
||||||
config?.actions.includes('move') &&
|
|
||||||
!state.treeData.edit &&
|
|
||||||
visibleFormItem(config.moveShow, state.treeData)
|
|
||||||
"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
@click.stop="handleTreeMove(state.treeData)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- <n-icon :component="MoveOutline"
|
|
||||||
size="20"
|
|
||||||
v-if="config?.actions.includes('move')&&!state.treeData.edit&&visibleFormItem(config.moveShow, state.treeData)"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
@click.stop="handleTreeMove(state.treeData)" /> -->
|
|
||||||
|
|
||||||
<n-icon
|
|
||||||
:component="Checkmark"
|
|
||||||
size="20"
|
|
||||||
v-if="state.treeData.edit"
|
|
||||||
class="fl-ml-sm"
|
|
||||||
@click.stop="handleTreeSave(state.treeData)"
|
|
||||||
/>
|
|
||||||
<n-icon
|
|
||||||
:component="Close"
|
|
||||||
size="20"
|
|
||||||
v-if="state.treeData.edit"
|
|
||||||
class="fl-ml-md"
|
|
||||||
@click.stop="handleTreeNotSave(state.treeData)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="col-8 row items-center justify-end" @click.stop>
|
|
||||||
<div>
|
|
||||||
<n-radio-group
|
|
||||||
v-model:value="state.radioVal"
|
|
||||||
@update:value="handleRadioChange"
|
|
||||||
>
|
|
||||||
<n-space>
|
|
||||||
<n-radio :value="true"> 是 </n-radio>
|
|
||||||
<n-radio :value="false"> 否 </n-radio>
|
|
||||||
</n-space>
|
|
||||||
</n-radio-group>
|
|
||||||
</div>
|
|
||||||
<div class="fl-ml-md" style="width: 200px" @click="handleSelectClick">
|
|
||||||
<n-select
|
|
||||||
v-model:value="state.selectVal"
|
|
||||||
size="small"
|
|
||||||
filterable
|
|
||||||
clearable
|
|
||||||
placeholder="请选择对应部门"
|
|
||||||
label-field="alias"
|
|
||||||
value-field="storeId"
|
|
||||||
:options="options"
|
|
||||||
@update:value="handleSelectChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { onBeforeMount, onMounted, watch, getCurrentInstance } from "vue";
|
|
||||||
import { visibleFormItem } from "@/utils/helper/form";
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
import {
|
|
||||||
UpOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
DragOutlined,
|
|
||||||
} from "@ant-design/icons-vue";
|
|
||||||
import {
|
|
||||||
Add,
|
|
||||||
Checkmark,
|
|
||||||
Close,
|
|
||||||
CreateOutline,
|
|
||||||
Remove,
|
|
||||||
MoveOutline,
|
|
||||||
} from "@vicons/ionicons5";
|
|
||||||
let props = defineProps({
|
|
||||||
dataRef: Object,
|
|
||||||
checked: Boolean,
|
|
||||||
config: Object,
|
|
||||||
clickKey: [String, Number],
|
|
||||||
options: Array,
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
expandedKeys: [],
|
|
||||||
editTitle: "",
|
|
||||||
treeData: [],
|
|
||||||
radioVal: null,
|
|
||||||
selectVal: null,
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.treeData = props.dataRef.option;
|
|
||||||
state.radioVal = state.treeData.sync;
|
|
||||||
if (state.treeData.syncId) {
|
|
||||||
state.selectVal = state.treeData.syncId * 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
watch(
|
|
||||||
() => props.dataRef.option,
|
|
||||||
(val) => {
|
|
||||||
state.treeData = props.dataRef.option;
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
const emit = defineEmits(["triggerTreeAction", "triggerTreeClick"]);
|
|
||||||
|
|
||||||
// const myComponentRef = ref(null);
|
|
||||||
const handleTreeEdit = () => {
|
|
||||||
state.editTitle = state.treeData.title;
|
|
||||||
state.treeData.edit = true;
|
|
||||||
// myComponentRef.value.$forceUpdate();
|
|
||||||
};
|
|
||||||
const handleTreeAdd = () => {
|
|
||||||
emit("triggerTreeAction", { type: "add", val: state.treeData });
|
|
||||||
};
|
|
||||||
const handleTreeMove = () => {
|
|
||||||
emit("triggerTreeAction", { type: "move", val: state.treeData });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTreeSubtraction = () => {
|
|
||||||
emit("triggerTreeAction", { type: "subtraction", val: state.treeData });
|
|
||||||
};
|
|
||||||
const handleTreeSave = () => {
|
|
||||||
state.treeData.title = state.editTitle;
|
|
||||||
emit("triggerTreeAction", { type: "save", val: state.treeData });
|
|
||||||
};
|
|
||||||
const handleTreeNotSave = () => {
|
|
||||||
state.editTitle = "";
|
|
||||||
emit("triggerTreeAction", { type: "cancel", val: state.treeData });
|
|
||||||
};
|
|
||||||
const handleRadioChange = (val) => {
|
|
||||||
let url = "department/v2/update";
|
|
||||||
let params = {
|
|
||||||
ID: state.treeData.key,
|
|
||||||
name: state.treeData.title,
|
|
||||||
sync: val,
|
|
||||||
syncID: state.treeData.syncId,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.treeData.sync = val;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleSelectChange = (val) => {
|
|
||||||
let syncID = "";
|
|
||||||
if (val === null || val === undefined || val === "") {
|
|
||||||
syncID = "";
|
|
||||||
} else {
|
|
||||||
syncID = val + "";
|
|
||||||
}
|
|
||||||
let url = "department/v2/update";
|
|
||||||
let params = {
|
|
||||||
ID: state.treeData.key,
|
|
||||||
name: state.treeData.title,
|
|
||||||
sync: state.treeData.sync,
|
|
||||||
syncID: syncID,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.treeData.syncId = syncID;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleSelectClick = () => {
|
|
||||||
console.log(props.options);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,942 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-modal v-model:show="state.dialogModal" :mask-closable="false">
|
|
||||||
<n-card
|
|
||||||
style="width: 1050px"
|
|
||||||
:bordered="false"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
新增岗位
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #header-extra>
|
|
||||||
<n-button @click="handleDialogBack" text style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pb-md" style="color: #333639">
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div class="search-item fl-mb-sm row items-center">
|
|
||||||
<div>*岗位名</div>
|
|
||||||
<fln-form-item
|
|
||||||
style="width: 180px; margin-left: 45px"
|
|
||||||
type="text"
|
|
||||||
:config="{
|
|
||||||
placeholder: '请输入岗位名',
|
|
||||||
field: 'name',
|
|
||||||
}"
|
|
||||||
:val="state.formData.name"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mb-sm row items-center">
|
|
||||||
<div style="margin-left: 16px">岗位描述</div>
|
|
||||||
<fln-form-item
|
|
||||||
style="width: 180px; margin-left: 38px"
|
|
||||||
type="text"
|
|
||||||
:config="{
|
|
||||||
placeholder: '请输入岗位描述',
|
|
||||||
field: 'remark',
|
|
||||||
}"
|
|
||||||
:val="state.formData.remark"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mb-sm row items-center">
|
|
||||||
<div style="margin-left: 16px">标签颜色</div>
|
|
||||||
<fln-form-item
|
|
||||||
style="width: 122px; margin-left: 38px"
|
|
||||||
type="colorpicker"
|
|
||||||
:val="state.formData.color"
|
|
||||||
:config="{
|
|
||||||
field: 'color',
|
|
||||||
}"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-item fl-mb-sm row items-center">
|
|
||||||
<fln-form-item
|
|
||||||
style="margin-left: 38px"
|
|
||||||
type="checkbox"
|
|
||||||
:val="state.formData.isOwner"
|
|
||||||
:config="{
|
|
||||||
field: 'isOwner',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: '设为部门负责人',
|
|
||||||
value: 'true',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row col-12 fl-mt-sm">
|
|
||||||
<div class="col-12 row justify-between fl-mt-md fl-mb-sm">
|
|
||||||
<div>请选择以下模板进行新增岗位:</div>
|
|
||||||
<div>
|
|
||||||
可将该岗位模板加入到审批中,<span
|
|
||||||
class="cursor"
|
|
||||||
style="color: #6c00ff"
|
|
||||||
@click="state.dialogApproval = true"
|
|
||||||
>去试试</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<fl-about-approval
|
|
||||||
:show="state.dialogApproval"
|
|
||||||
@triggerCalcApproval="handleApproval"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div
|
|
||||||
v-for="(temp, tempidx) in state.tempList"
|
|
||||||
:key="tempidx"
|
|
||||||
class="fl-py-xs text-center cursor fl-mr-sm fl-mb-sm row justify-center items-center"
|
|
||||||
:style="[
|
|
||||||
state.selectTemplate === temp.name
|
|
||||||
? { border: '1px solid #46299d' }
|
|
||||||
: {},
|
|
||||||
]"
|
|
||||||
style="
|
|
||||||
border-radius: 3px;
|
|
||||||
min-width: 176px;
|
|
||||||
background: #f7efff;
|
|
||||||
color: #8352b4;
|
|
||||||
"
|
|
||||||
@click="handleTempClick(temp)"
|
|
||||||
>
|
|
||||||
{{ temp.name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="fl-my-lg row col-12">
|
|
||||||
<div class="col-2 font-14 fl-mb-md">已选模版:</div>
|
|
||||||
<div class="col-10 row items-center fl-mb-md">
|
|
||||||
<div
|
|
||||||
class="fl-py-xs text-center row justify-center items-center"
|
|
||||||
style="
|
|
||||||
border-radius: 3px;
|
|
||||||
min-width: 193px;
|
|
||||||
background: #f7f7f7ff;
|
|
||||||
border: solid 1px #e0e0e5ff;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ state.selectTemplate }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-2 font-14">
|
|
||||||
*所选页面
|
|
||||||
<span style="color: #1f2225ff">{{
|
|
||||||
state.selectedRows.length
|
|
||||||
}}</span>
|
|
||||||
个:
|
|
||||||
</div>
|
|
||||||
<n-spin
|
|
||||||
class="fl-ml-md"
|
|
||||||
v-if="state.dataLoading"
|
|
||||||
v-show="state.dataLoading"
|
|
||||||
description="获取中..."
|
|
||||||
style="color: #1f2225ff"
|
|
||||||
/>
|
|
||||||
<div v-else class="col-10 row">
|
|
||||||
<div
|
|
||||||
v-for="(select, idx) in state.selectedRows"
|
|
||||||
:key="idx"
|
|
||||||
class="fl-py-xs text-center fl-mr-sm fl-mb-sm row justify-center items-center"
|
|
||||||
style="
|
|
||||||
border-radius: 3px;
|
|
||||||
min-width: 193px;
|
|
||||||
background: #f7f7f7ff;
|
|
||||||
border: solid 1px #e0e0e5ff;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<n-tooltip trigger="hover">
|
|
||||||
<template #trigger>
|
|
||||||
{{ select.name }}
|
|
||||||
</template>
|
|
||||||
{{ select.name }}
|
|
||||||
</n-tooltip>
|
|
||||||
<close-circle-outlined
|
|
||||||
class="fl-ml-md"
|
|
||||||
@click="handleClearPage(select)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="row items-center fl-mr-sm fl-mb-sm">
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #e0e0e5;
|
|
||||||
width: 27px;
|
|
||||||
height: 27px;
|
|
||||||
"
|
|
||||||
class="row items-center justify-center fl-mr-sm cursor"
|
|
||||||
@click="handleEditSelectTemp"
|
|
||||||
>
|
|
||||||
<n-icon>
|
|
||||||
<ChevronUpOutline v-if="state.showTempRuleListData" />
|
|
||||||
<ChevronDownOutline v-else />
|
|
||||||
</n-icon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span style="color: rgba(0, 0, 0, 0.3)">点击展开可进行编辑</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.showTempRuleListData"
|
|
||||||
style="max-height: 40vh"
|
|
||||||
class="overflow-auto col-12 row"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="(row, rowIdx) in state.listData"
|
|
||||||
:key="rowIdx"
|
|
||||||
class="col-12 fl-mb-md row items-center fl-pb-xs"
|
|
||||||
style="min-height: 40px"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-between items-center fl-px-md"
|
|
||||||
style="min-height: 40px; background: #46299dff"
|
|
||||||
:style="{ borderRadius: row.showChild ? '3px 3px 0 0' : '3px' }"
|
|
||||||
>
|
|
||||||
<div class="color-white">
|
|
||||||
<n-checkbox
|
|
||||||
v-model:checked="row.selected"
|
|
||||||
@update:checked="(e) => handlePageSelectChange(e)"
|
|
||||||
>
|
|
||||||
</n-checkbox>
|
|
||||||
{{ row.name }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="!row.showChild"
|
|
||||||
style="background: #ffffffff; color: #46299dff"
|
|
||||||
icon-placement="right"
|
|
||||||
round
|
|
||||||
secondary
|
|
||||||
strong
|
|
||||||
size="small"
|
|
||||||
@click="row.showChild = true"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<ChevronDownOutline />
|
|
||||||
</n-icon>
|
|
||||||
</template>
|
|
||||||
展开
|
|
||||||
</n-button>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="row.showChild"
|
|
||||||
style="background: #ffffffff; color: #46299dff"
|
|
||||||
icon-placement="right"
|
|
||||||
round
|
|
||||||
secondary
|
|
||||||
strong
|
|
||||||
size="small"
|
|
||||||
@click="row.showChild = false"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<ChevronUpOutline />
|
|
||||||
</n-icon>
|
|
||||||
</template>
|
|
||||||
收起
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="row.showChild"
|
|
||||||
style="border: 1px solid #1f2225ff; border-radius: 0 0 3px 3px"
|
|
||||||
class="col-12 row"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12 row"
|
|
||||||
style="padding: 11px 0; background: #dfd7f2"
|
|
||||||
>
|
|
||||||
<div class="col-3 text-center">按钮权限</div>
|
|
||||||
<div class="col-3 text-center">列表权限</div>
|
|
||||||
<div class="col-3 text-center">数据范围权限</div>
|
|
||||||
<div class="col-3 text-center">列表字段权限</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row">
|
|
||||||
<div class="col-3 fl-py-md">
|
|
||||||
<div class="" style="margin-left: 30%">
|
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
Array.isArray(row.buttonList) &&
|
|
||||||
row.buttonList.length > 1
|
|
||||||
"
|
|
||||||
class="row"
|
|
||||||
>
|
|
||||||
<n-checkbox
|
|
||||||
v-model:checked="row.btnSelectedAll"
|
|
||||||
:indeterminate="row.btnIndeterminate"
|
|
||||||
@update:checked="
|
|
||||||
(e) => handleBtnSelectAllChange(e, rowIdx)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
全选
|
|
||||||
</n-checkbox>
|
|
||||||
</div>
|
|
||||||
<n-checkbox-group
|
|
||||||
v-model:value="row.btnSelected"
|
|
||||||
@update:value="(e) => handleBtnSelectChange(e, rowIdx)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-12"
|
|
||||||
v-for="(btn, btnIdx) in row.buttonList"
|
|
||||||
:key="btnIdx"
|
|
||||||
>
|
|
||||||
<n-checkbox :value="btn.ID">
|
|
||||||
{{ btn.name }}
|
|
||||||
</n-checkbox>
|
|
||||||
</div>
|
|
||||||
</n-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-9 row">
|
|
||||||
<div
|
|
||||||
v-for="(list, listIdx) in row.interfaceList"
|
|
||||||
:key="listIdx"
|
|
||||||
class="col-12 row"
|
|
||||||
:style="{
|
|
||||||
'border-left':
|
|
||||||
row.interfaceList.length > 1 ? '1px solid #C1B2E5' : '',
|
|
||||||
'border-bottom':
|
|
||||||
listIdx !== row.interfaceList.length - 1
|
|
||||||
? '1px solid #C1B2E5'
|
|
||||||
: '',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="col-4 row fl-pa-md justify-center">
|
|
||||||
<n-checkbox
|
|
||||||
v-model:checked="list.selected"
|
|
||||||
@update:checked="
|
|
||||||
(e) => handleListSelectChange(e, rowIdx, listIdx)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ list.name }}
|
|
||||||
</n-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-4 row fl-pa-md justify-center">
|
|
||||||
<n-radio-group v-model:value="list.limitSelected">
|
|
||||||
<n-radio
|
|
||||||
:style="radioStyle"
|
|
||||||
v-for="(limit, limitIdx) in list.limit"
|
|
||||||
:key="limitIdx"
|
|
||||||
:value="limit.value"
|
|
||||||
>
|
|
||||||
<div class="relative">
|
|
||||||
{{ limit.label }}
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
v-if="
|
|
||||||
list.limitSelected === 5 && limit.value === 5
|
|
||||||
"
|
|
||||||
size="small"
|
|
||||||
style="
|
|
||||||
position: absolute;
|
|
||||||
right: -120px;
|
|
||||||
width: 70px;
|
|
||||||
background: #ffffff;
|
|
||||||
color: #6d5c9c;
|
|
||||||
border: 1px solid #8a67ef;
|
|
||||||
"
|
|
||||||
@click.stop="
|
|
||||||
handleChangeSelfLimitData(rowIdx, listIdx, list)
|
|
||||||
"
|
|
||||||
>设置</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</n-radio>
|
|
||||||
</n-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-4 row fl-pa-md justify-center">
|
|
||||||
<n-checkbox-group
|
|
||||||
v-if="Array.isArray(list.positionRuleFields)"
|
|
||||||
v-model:value="list.fieldsSelected"
|
|
||||||
>
|
|
||||||
<div class="col-12">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
class="fl-ml-md"
|
|
||||||
size="small"
|
|
||||||
style="
|
|
||||||
width: 70px;
|
|
||||||
background: #ffffff;
|
|
||||||
color: #6d5c9c;
|
|
||||||
border: 1px solid #8a67ef;
|
|
||||||
"
|
|
||||||
@click="handleEditField(rowIdx, listIdx)"
|
|
||||||
>设置</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
class="fl-ml-md"
|
|
||||||
size="small"
|
|
||||||
style="
|
|
||||||
width: 70px;
|
|
||||||
background: #ffffff;
|
|
||||||
color: #6d5c9c;
|
|
||||||
border: 1px solid #8a67ef;
|
|
||||||
"
|
|
||||||
@click="handleEditFieldSort(rowIdx, listIdx)"
|
|
||||||
>排序</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="col-12"
|
|
||||||
v-for="(field, fieldIdx) in list.positionRuleFields"
|
|
||||||
:key="fieldIdx"
|
|
||||||
>
|
|
||||||
<n-checkbox :value="field.ID">
|
|
||||||
{{ field.fieldCnName }}
|
|
||||||
</n-checkbox>
|
|
||||||
</div>
|
|
||||||
</n-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogBack"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #46299dff; color: #fff"
|
|
||||||
:loading="state.btnLoading"
|
|
||||||
@click="handleDialogSubmit"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
|
|
||||||
<fl-limit-data
|
|
||||||
v-if="state.dialogSelfLimtiData"
|
|
||||||
:fatherData="state.dataDepartmentIds"
|
|
||||||
@triggerLimitData="handleLimitData"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
// 岗位新建方式选择 弹窗
|
|
||||||
import {
|
|
||||||
UpOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
DragOutlined,
|
|
||||||
} from "@ant-design/icons-vue";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
import flAboutApproval from "./aboutApproval.vue";
|
|
||||||
import draggable from "vuedraggable";
|
|
||||||
import flLimitData from "./limitData.vue";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
import { ChevronDownOutline, ChevronUpOutline } from "@vicons/ionicons5";
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
|
|
||||||
const emits = defineEmits(["triggerClose"]);
|
|
||||||
const radioStyle = reactive({
|
|
||||||
display: "flex",
|
|
||||||
height: "30px",
|
|
||||||
lineHeight: "30px",
|
|
||||||
});
|
|
||||||
let props = defineProps({
|
|
||||||
fatherData: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
selectedRows: [],
|
|
||||||
dialogField: false,
|
|
||||||
dialogData: {
|
|
||||||
fieldList: [],
|
|
||||||
},
|
|
||||||
listData: [],
|
|
||||||
formData: {
|
|
||||||
name: "",
|
|
||||||
remark: "",
|
|
||||||
color: "#1F2225",
|
|
||||||
isOwner: [],
|
|
||||||
},
|
|
||||||
btnLoading: false,
|
|
||||||
pageType: "create",
|
|
||||||
enabled: true,
|
|
||||||
dialogFieldSort: false,
|
|
||||||
dataLoading: false,
|
|
||||||
dialogModal: true,
|
|
||||||
tempList: [],
|
|
||||||
selectTemplate: "",
|
|
||||||
showTempRuleListData: false,
|
|
||||||
dialogApproval: false,
|
|
||||||
dialogSelfLimtiData: false,
|
|
||||||
dialogLimitData: {},
|
|
||||||
dataDepartmentIds: [],
|
|
||||||
approvalData: [],
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
console.log("onBeforeMount");
|
|
||||||
state.dialogModal = true;
|
|
||||||
getTempData();
|
|
||||||
if (route.query.type) {
|
|
||||||
state.pageType = route.query.type;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
const getTempData = () => {
|
|
||||||
let url = "/position/v2/model/list";
|
|
||||||
$request.HTTP.components.postDataByParams(url, {}).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.tempList = res.data || [];
|
|
||||||
state.selectTemplate = state.tempList[0].name || "无数据";
|
|
||||||
if (state.tempList.length > 0) {
|
|
||||||
getRulesData(state.tempList[0]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取数据失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const getRulesData = (temp) => {
|
|
||||||
let url = "/position/v2/model/detail";
|
|
||||||
$request.HTTP.components.postDataByParams(url, { uuid: temp.uuid }).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
let data = res.data.positionTreeRule;
|
|
||||||
data.map((item) => {
|
|
||||||
item.selected = false;
|
|
||||||
item.showChild = false;
|
|
||||||
|
|
||||||
item.btnSelected = [];
|
|
||||||
item.btnSelectedAll = false;
|
|
||||||
item.btnIndeterminate = false;
|
|
||||||
if (Array.isArray(item.interfaceList)) {
|
|
||||||
item.interfaceList.map((listItem) => {
|
|
||||||
listItem.selected = false;
|
|
||||||
listItem.limit = [
|
|
||||||
{
|
|
||||||
label: "仅自己",
|
|
||||||
value: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "自己及下属",
|
|
||||||
value: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "本部门",
|
|
||||||
value: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "所有",
|
|
||||||
value: 4,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
listItem.limitSelected = 4;
|
|
||||||
listItem.positionRuleFields = listItem.positionRuleFields || [];
|
|
||||||
listItem.fieldsSelected = listItem.positionRuleFields.map(
|
|
||||||
(item) => item.ID
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
state.listData = data;
|
|
||||||
setRulesDataDefaultVal(data, state.listData);
|
|
||||||
state.selectedRows = state.listData.filter((item) => item.selected);
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取数据失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取数据失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleValChange = ({ val, config }) => {
|
|
||||||
state.formData[config.field] = val;
|
|
||||||
};
|
|
||||||
const handleDialogSubmit = () => {
|
|
||||||
if (state.formData.name === "") {
|
|
||||||
processError("请填写岗位名称");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let url = "/position/v2/create";
|
|
||||||
let params = {
|
|
||||||
name: state.formData.name,
|
|
||||||
remark: state.formData.remark,
|
|
||||||
color: state.formData.color,
|
|
||||||
positionTreeRule: [],
|
|
||||||
departmentID: Number(props.fatherData.key),
|
|
||||||
isLeader: state.formData.isOwner.length > 0,
|
|
||||||
};
|
|
||||||
let data = state.listData;
|
|
||||||
data
|
|
||||||
.filter((item) => item.selected)
|
|
||||||
.map((item) => {
|
|
||||||
let obj = {
|
|
||||||
ID: item.ID,
|
|
||||||
buttonList: Array.isArray(item.buttonList)
|
|
||||||
? item.buttonList.filter((btnItem) =>
|
|
||||||
item.btnSelected.includes(btnItem.ID)
|
|
||||||
)
|
|
||||||
: [],
|
|
||||||
interfaceList: Array.isArray(item.interfaceList)
|
|
||||||
? item.interfaceList
|
|
||||||
.filter((listItem) => listItem.selected)
|
|
||||||
.map((listItem) => {
|
|
||||||
return {
|
|
||||||
ID: listItem.ID,
|
|
||||||
dataRange: listItem.limitSelected,
|
|
||||||
positionRuleFields: Array.isArray(listItem.positionRuleFields)
|
|
||||||
? listItem.positionRuleFields.filter((fieldItem) =>
|
|
||||||
listItem.fieldsSelected.includes(fieldItem.ID)
|
|
||||||
)
|
|
||||||
: [],
|
|
||||||
};
|
|
||||||
})
|
|
||||||
: [],
|
|
||||||
};
|
|
||||||
params.positionTreeRule.push(obj);
|
|
||||||
});
|
|
||||||
state.btnLoading = true;
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
// 岗位绑定审批发起人
|
|
||||||
if (state.approvalData.length > 0) {
|
|
||||||
let url = "/approval/v2/create-auth";
|
|
||||||
let params = {
|
|
||||||
typeId: state.approvalData.map((item) => item.ID),
|
|
||||||
departmentUID: res.data.DepartmentID.toString(),
|
|
||||||
departmentName: res.data.DepartmentName,
|
|
||||||
positionUID: res.data.ID.toString(),
|
|
||||||
positionName: res.data.Name,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
emits("triggerClose");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
emits("triggerClose");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleBack = () => {
|
|
||||||
router.go(-1);
|
|
||||||
};
|
|
||||||
const handleEditField = (rowIdx, listIdx) => {
|
|
||||||
state.dialogData.clickData = state.listData[rowIdx];
|
|
||||||
state.dialogData.ID = state.listData[rowIdx].interfaceList[listIdx].ID;
|
|
||||||
state.dialogData.rowIdx = rowIdx;
|
|
||||||
state.dialogData.listIdx = listIdx;
|
|
||||||
state.dialogData.fieldList = JSON.parse(
|
|
||||||
JSON.stringify(
|
|
||||||
state.listData[rowIdx].interfaceList[listIdx].positionRuleFields.map(
|
|
||||||
(item) => {
|
|
||||||
return {
|
|
||||||
ID: item.ID,
|
|
||||||
field: item.fieldKey,
|
|
||||||
fieldCnName: item.fieldCnName,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
state.dialogField = true;
|
|
||||||
};
|
|
||||||
const handleBtnSelectAllChange = (checked, idx) => {
|
|
||||||
if (checked) {
|
|
||||||
state.listData[idx].btnSelected = state.listData[idx].buttonList.map(
|
|
||||||
(item) => item.ID
|
|
||||||
);
|
|
||||||
state.listData[idx].btnIndeterminate = false;
|
|
||||||
} else {
|
|
||||||
state.listData[idx].btnSelected = [];
|
|
||||||
state.listData[idx].btnIndeterminate = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleBtnSelectChange = (e, idx) => {
|
|
||||||
if (e.length === 0) {
|
|
||||||
state.listData[idx].btnSelectedAll = false;
|
|
||||||
state.listData[idx].btnIndeterminate = false;
|
|
||||||
} else if (e.length === state.listData[idx].buttonList.length) {
|
|
||||||
state.listData[idx].btnSelectedAll = true;
|
|
||||||
state.listData[idx].btnIndeterminate = false;
|
|
||||||
} else {
|
|
||||||
state.listData[idx].btnSelectedAll = false;
|
|
||||||
state.listData[idx].btnIndeterminate = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleListSelectChange = (e, rowIdx, listIdx) => {
|
|
||||||
state.listData[rowIdx].listSelected = state.listData[
|
|
||||||
rowIdx
|
|
||||||
].interfaceList.filter((item) => item.selected);
|
|
||||||
};
|
|
||||||
const handlePageSelectChange = (e) => {
|
|
||||||
state.selectedRows = state.listData.filter((item) => item.selected);
|
|
||||||
};
|
|
||||||
const handleClearPage = (select) => {
|
|
||||||
state.listData.forEach((item) => {
|
|
||||||
if (item.name === select.name) {
|
|
||||||
item.selected = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
state.selectedRows = state.listData.filter((item) => item.selected);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelDialogFieldList = (delIdx) => {
|
|
||||||
state.dialogData.fieldList.splice(delIdx, 1);
|
|
||||||
};
|
|
||||||
const handleCreDialogFieldList = () => {
|
|
||||||
state.dialogData.fieldList.push({
|
|
||||||
field: "",
|
|
||||||
fieldCnName: "",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogField = false;
|
|
||||||
emits("triggerClose");
|
|
||||||
};
|
|
||||||
const handleLink = (path) => {
|
|
||||||
router.push(path);
|
|
||||||
};
|
|
||||||
|
|
||||||
const setRulesDataDefaultVal = (pageData, listData) => {
|
|
||||||
pageData.map((pageDataItem) => {
|
|
||||||
listData.map((listItem) => {
|
|
||||||
if (pageDataItem.ID === listItem.ID) {
|
|
||||||
listItem.selected = true;
|
|
||||||
listItem.showChild = false;
|
|
||||||
|
|
||||||
listItem.btnSelected = Array.isArray(pageDataItem.buttonList)
|
|
||||||
? pageDataItem.buttonList.map((btnItem) => btnItem.ID)
|
|
||||||
: [];
|
|
||||||
if (
|
|
||||||
Array.isArray(listItem.interfaceList) &&
|
|
||||||
Array.isArray(pageDataItem.interfaceList)
|
|
||||||
) {
|
|
||||||
listItem.interfaceList.map((interfaceItem) => {
|
|
||||||
pageDataItem.interfaceList.map((pageDataInterfaceItem) => {
|
|
||||||
if (interfaceItem.ID === pageDataInterfaceItem.ID) {
|
|
||||||
interfaceItem.selected = true;
|
|
||||||
interfaceItem.limitSelected = pageDataInterfaceItem.dataRange;
|
|
||||||
pageDataInterfaceItem.positionRuleFields =
|
|
||||||
pageDataInterfaceItem.positionRuleFields || [];
|
|
||||||
interfaceItem.fieldsSelected =
|
|
||||||
pageDataInterfaceItem.positionRuleFields.map(
|
|
||||||
(fieldItem) => fieldItem.ID
|
|
||||||
);
|
|
||||||
interfaceItem.positionRuleFields.map((fieldItem) => {
|
|
||||||
pageDataInterfaceItem.positionRuleFields.map(
|
|
||||||
(pageDataFieldItem) => {
|
|
||||||
if (fieldItem.ID === pageDataFieldItem.ID) {
|
|
||||||
fieldItem.index = pageDataFieldItem.index || 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditFieldSort = (rowIdx, listIdx) => {
|
|
||||||
state.dialogData.clickData = state.listData[rowIdx];
|
|
||||||
state.dialogData.ID = state.listData[rowIdx].interfaceList[listIdx].ID;
|
|
||||||
state.dialogData.rowIdx = rowIdx;
|
|
||||||
state.dialogData.listIdx = listIdx;
|
|
||||||
let fieldsSelected =
|
|
||||||
state.listData[rowIdx].interfaceList[listIdx].fieldsSelected;
|
|
||||||
let fieldList = [];
|
|
||||||
state.listData[rowIdx].interfaceList[listIdx].positionRuleFields.map(
|
|
||||||
(item) => {
|
|
||||||
if (fieldsSelected.includes(item.ID)) {
|
|
||||||
fieldList.push({
|
|
||||||
ID: item.ID,
|
|
||||||
field: item.fieldKey,
|
|
||||||
fieldCnName: item.fieldCnName,
|
|
||||||
index: item.index || 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
fieldList.sort((a, b) => {
|
|
||||||
return a.index - b.index;
|
|
||||||
});
|
|
||||||
state.dialogData.fieldList = fieldList;
|
|
||||||
state.dialogFieldSort = true;
|
|
||||||
};
|
|
||||||
const handleDialogSortSave = () => {
|
|
||||||
let rowIdx = state.dialogData.rowIdx;
|
|
||||||
let listIdx = state.dialogData.listIdx;
|
|
||||||
|
|
||||||
state.dialogData.fieldList.forEach((item, idx) => {
|
|
||||||
item.index = idx + 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
state.listData[rowIdx].interfaceList[listIdx].positionRuleFields.map(
|
|
||||||
(item) => {
|
|
||||||
state.dialogData.fieldList.map((fieldItem) => {
|
|
||||||
if (item.ID === fieldItem.ID) {
|
|
||||||
item.index = fieldItem.index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
state.dialogFieldSort = false;
|
|
||||||
};
|
|
||||||
const handleDialogSortBack = () => {
|
|
||||||
state.dialogFieldSort = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTempClick = (temp) => {
|
|
||||||
state.selectTemplate = temp.name;
|
|
||||||
getRulesData(temp);
|
|
||||||
};
|
|
||||||
const handleEditSelectTemp = () => {
|
|
||||||
state.showTempRuleListData = !state.showTempRuleListData;
|
|
||||||
};
|
|
||||||
const handleApproval = (approvalData) => {
|
|
||||||
state.approvalData = approvalData;
|
|
||||||
state.dialogApproval = false;
|
|
||||||
};
|
|
||||||
const handleChangeSelfLimitData = (rowIdx, listIdx, list) => {
|
|
||||||
state.dialogLimitData = {
|
|
||||||
rowIdx,
|
|
||||||
listIdx,
|
|
||||||
};
|
|
||||||
state.dataDepartmentIds = list.dataDepartmentIds;
|
|
||||||
state.dialogSelfLimtiData = true;
|
|
||||||
};
|
|
||||||
const handleLimitData = (data) => {
|
|
||||||
let rowIdx = state.dialogLimitData.rowIdx;
|
|
||||||
let listIdx = state.dialogLimitData.listIdx;
|
|
||||||
state.listData[rowIdx].interfaceList[listIdx].dataDepartmentIds = data;
|
|
||||||
state.dialogSelfLimtiData = false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.n-card-header {
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,628 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div ref="posimanageeditAuth"></div>
|
|
||||||
<n-modal v-model:show="state.showModal" :mask-closable="false">
|
|
||||||
<n-card
|
|
||||||
style="width: 80vw"
|
|
||||||
:bordered="false"
|
|
||||||
class="create-contianer"
|
|
||||||
size="huge"
|
|
||||||
width="1200px"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div class="title-visible">{{ props.title }}</div>
|
|
||||||
</template>
|
|
||||||
<template #header-extra>
|
|
||||||
<img
|
|
||||||
src="@/assets/image/icon/close-tabs.png"
|
|
||||||
class="close-icon"
|
|
||||||
@click="handleClose"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="center-content">
|
|
||||||
<div class="left-box">
|
|
||||||
<div class="title">基础设置</div>
|
|
||||||
<div class="content" ref="modalSelect">
|
|
||||||
<a-form
|
|
||||||
ref="formRef"
|
|
||||||
name="custom-validation"
|
|
||||||
:model="formState"
|
|
||||||
:rules="rules"
|
|
||||||
v-bind="layout"
|
|
||||||
:hideRequiredMark="true"
|
|
||||||
>
|
|
||||||
<a-form-item label="权限类型" name="type">
|
|
||||||
<a-radio-group
|
|
||||||
v-model:value="formState.type"
|
|
||||||
@change="changeType"
|
|
||||||
name="radioGroup"
|
|
||||||
>
|
|
||||||
<a-radio :value="'menu'">菜单权限</a-radio>
|
|
||||||
<a-radio :value="'button'">按钮权限</a-radio>
|
|
||||||
<a-radio :value="'interface'">列表字段权限</a-radio>
|
|
||||||
</a-radio-group>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="菜单管理"
|
|
||||||
name="menuType"
|
|
||||||
v-if="formState.type == 'menu'"
|
|
||||||
>
|
|
||||||
<a-radio-group
|
|
||||||
v-model:value="formState.menuType"
|
|
||||||
name="radioGroup"
|
|
||||||
>
|
|
||||||
<a-radio :value="'1'">父级菜单</a-radio>
|
|
||||||
<a-radio :value="'2'">子级菜单</a-radio>
|
|
||||||
</a-radio-group>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="上级菜单"
|
|
||||||
name="pid"
|
|
||||||
v-if="formState.menuType == '2'"
|
|
||||||
>
|
|
||||||
<n-select
|
|
||||||
v-model:value="formState.pid"
|
|
||||||
:options="state.menuList"
|
|
||||||
label-field="Title"
|
|
||||||
value-field="ID"
|
|
||||||
filterable
|
|
||||||
/>
|
|
||||||
<!-- <a-select ref="select"
|
|
||||||
v-model:value="formState.pid"
|
|
||||||
style="width: 200px">
|
|
||||||
<a-select-option v-for="(item,index) in state.menuList"
|
|
||||||
:key="index"
|
|
||||||
:value="item.ID">{{item.Title}}</a-select-option>
|
|
||||||
</a-select> -->
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="权限名称" name="title">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formState.title"
|
|
||||||
autocomplete="off"
|
|
||||||
maxLength="12"
|
|
||||||
placeholder="最长输入12个字符"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="上级权限"
|
|
||||||
name="pid"
|
|
||||||
v-if="formState.type !== 'menu'"
|
|
||||||
>
|
|
||||||
<n-tree-select
|
|
||||||
filterable
|
|
||||||
v-model:value="formState.pid"
|
|
||||||
:options="state.menuTreeList"
|
|
||||||
@update:value="handleUpdatemenuTreeValue"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="路由/按钮名/接口名" name="url">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formState.url"
|
|
||||||
autocomplete="off"
|
|
||||||
:placeholder="
|
|
||||||
formState.type == 'menu' ? '不做路由跳转可为空' : ''
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="图标"
|
|
||||||
name="icon"
|
|
||||||
v-if="formState.type == 'menu' && formState.menuType == '1'"
|
|
||||||
>
|
|
||||||
<Upload
|
|
||||||
:maxCount="1"
|
|
||||||
v-model:uploadVal="formState.icon"
|
|
||||||
:zIndex="9000"
|
|
||||||
class="upload"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="选中图标"
|
|
||||||
name="grayIcon"
|
|
||||||
v-if="formState.type == 'menu' && formState.menuType == '1'"
|
|
||||||
>
|
|
||||||
<Upload
|
|
||||||
:maxCount="1"
|
|
||||||
v-model:uploadVal="formState.grayIcon"
|
|
||||||
:zIndex="9000"
|
|
||||||
class="upload"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
label="排序"
|
|
||||||
name="weigh"
|
|
||||||
v-if="formState.type == 'menu'"
|
|
||||||
>
|
|
||||||
<n-input-number
|
|
||||||
:show-button="false"
|
|
||||||
v-model:value="formState.weigh"
|
|
||||||
autocomplete="off"
|
|
||||||
placeholder="1-100,越大排序越靠前"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
<div v-show="formState.type == 'interface'" class="row">
|
|
||||||
<div class="col-4 text-right">
|
|
||||||
列表字段<span style="margin: 0 8px 0 2px">:</span>
|
|
||||||
</div>
|
|
||||||
<div class="col-8">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in formState.ruleFields"
|
|
||||||
:key="index"
|
|
||||||
style="margin-bottom: 10px"
|
|
||||||
>
|
|
||||||
<div class="flex">
|
|
||||||
<n-input
|
|
||||||
v-model:value="item.fieldCnName"
|
|
||||||
autocomplete="off"
|
|
||||||
placeholder="列表字段中文名称"
|
|
||||||
style="margin-bottom: 10px; width: 200px"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="cancel-btn"
|
|
||||||
@click="cancelRule(index)"
|
|
||||||
v-if="formState.ruleFields.length > 1"
|
|
||||||
>移除</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<n-input
|
|
||||||
type="textarea"
|
|
||||||
v-model:value="item.fieldKey"
|
|
||||||
placeholder="列表字段对应value值"
|
|
||||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4 row"></div>
|
|
||||||
<div class="col-8 row">
|
|
||||||
<a-button @click="addInput" style="width: 120px">
|
|
||||||
<PlusOutlined />
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<div class="row justify-end">
|
|
||||||
<div class="footer-content" v-if="state.isEdit">
|
|
||||||
<!-- <a-popconfirm title="是否确认删除该权限,删除后不可恢复?"
|
|
||||||
cancel-text="取消"
|
|
||||||
ok-text="确定"
|
|
||||||
@confirm="handleDel"
|
|
||||||
@cancel="departmentCel">
|
|
||||||
<a-button class="basic-btn">删除该权限</a-button>
|
|
||||||
</a-popconfirm> -->
|
|
||||||
<a-button
|
|
||||||
class="primary-btn"
|
|
||||||
:loading="state.btnLoading"
|
|
||||||
@click="handleUpdate"
|
|
||||||
>完成修改</a-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="footer-content" v-else>
|
|
||||||
<a-button class="basic-btn" @click="resetForm">清空</a-button>
|
|
||||||
<a-button
|
|
||||||
class="primary-btn"
|
|
||||||
:loading="state.btnLoading"
|
|
||||||
@click="handleCreate"
|
|
||||||
>完成设置</a-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 权限新建弹窗 旧代码
|
|
||||||
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons-vue";
|
|
||||||
import {
|
|
||||||
defineProps,
|
|
||||||
defineEmits,
|
|
||||||
watch,
|
|
||||||
reactive,
|
|
||||||
ref,
|
|
||||||
unref,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
} from "vue";
|
|
||||||
import Upload from "@/components/upload.vue";
|
|
||||||
import { Form, message } from "ant-design-vue";
|
|
||||||
import { processSuccess, processError } from "@/utils/helper/message";
|
|
||||||
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
|
|
||||||
const emits = defineEmits(["submit", "triggerClose"]);
|
|
||||||
let props = defineProps({
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
require: true,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
btnLoading: false,
|
|
||||||
menuList: [],
|
|
||||||
menuTreeList: [],
|
|
||||||
isEdit: false,
|
|
||||||
showModal: true,
|
|
||||||
});
|
|
||||||
onMounted(() => {
|
|
||||||
state.showModal = true;
|
|
||||||
getMenu();
|
|
||||||
getMenuTree();
|
|
||||||
if (props.data?.id) {
|
|
||||||
state.isEdit = true;
|
|
||||||
getDetail();
|
|
||||||
} else {
|
|
||||||
state.isEdit = false;
|
|
||||||
formState.dataOpen = true;
|
|
||||||
formState.method = "*";
|
|
||||||
formState.type = "";
|
|
||||||
formState.icon = "";
|
|
||||||
formState.pid = null;
|
|
||||||
formState.title = "";
|
|
||||||
formState.menuType = "";
|
|
||||||
formState.url = "";
|
|
||||||
formState.weigh = "";
|
|
||||||
formState.ruleFields = [{ fieldKey: "", fieldCnName: "" }];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
emits("triggerClose");
|
|
||||||
resetForm();
|
|
||||||
state.isEdit = false;
|
|
||||||
};
|
|
||||||
const layout = {
|
|
||||||
labelCol: { span: 8 },
|
|
||||||
wrapperCol: { span: 16 },
|
|
||||||
};
|
|
||||||
const formRef = ref();
|
|
||||||
const formState = reactive({
|
|
||||||
grayIcon: "",
|
|
||||||
dataOpen: true,
|
|
||||||
method: "*",
|
|
||||||
type: "", // 'menu'菜单,'button'按钮组件,'interface'列表字段权限
|
|
||||||
icon: "",
|
|
||||||
pid: null,
|
|
||||||
title: "",
|
|
||||||
menuType: "",
|
|
||||||
url: "",
|
|
||||||
weigh: "",
|
|
||||||
ruleFields: [{ fieldKey: "", fieldCnName: "" }],
|
|
||||||
});
|
|
||||||
const filedJsonV = async (_rule, value) => {
|
|
||||||
// 验空
|
|
||||||
if (
|
|
||||||
formState.type === "interface" &&
|
|
||||||
formState.ruleFields.some((val) => val.fieldKey == "" || val.fieldKey == "")
|
|
||||||
) {
|
|
||||||
return Promise.reject("请补充完整");
|
|
||||||
} else {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const urlV = async (_rule, value) => {
|
|
||||||
// 验空
|
|
||||||
if (formState.type === "menu" && formState.menuType === "1") {
|
|
||||||
return Promise.resolve();
|
|
||||||
} else {
|
|
||||||
if (value == "") {
|
|
||||||
return Promise.reject("请输入路由/唯一标识");
|
|
||||||
} else {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const rules = {
|
|
||||||
type: [{ required: true, message: "请选择权限类型", trigger: "change" }],
|
|
||||||
icon: [{ required: true, message: "请上传Icon", trigger: "change" }],
|
|
||||||
grayIcon: [{ required: true, message: "请上传选中Icon", trigger: "change" }],
|
|
||||||
menuType: [{ required: true, message: "请选择菜单等级", trigger: "change" }],
|
|
||||||
pid: [
|
|
||||||
{ required: true, message: "请选择上级权限/上级菜单", trigger: "change" },
|
|
||||||
],
|
|
||||||
title: [{ required: true, message: "请输入权限名称", trigger: "change" }],
|
|
||||||
url: [{ required: true, validator: urlV, trigger: "change" }], // message: '请输入路由/唯一标识',
|
|
||||||
weigh: [{ required: true, message: "请输入排序", trigger: "change" }],
|
|
||||||
ruleFields: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
validator: filedJsonV,
|
|
||||||
trigger: ["blur, change"],
|
|
||||||
type: "array",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const resetForm = () => {
|
|
||||||
formRef.value.resetFields();
|
|
||||||
};
|
|
||||||
const addInput = () => {
|
|
||||||
formState.ruleFields.push({ fieldKey: "", fieldCnName: "" });
|
|
||||||
};
|
|
||||||
const cancelRule = (index) => {
|
|
||||||
formState.ruleFields.splice(index, 1);
|
|
||||||
};
|
|
||||||
const changeType = () => {
|
|
||||||
formState.dataOpen = true;
|
|
||||||
formState.method = "*";
|
|
||||||
// formState.type = ''
|
|
||||||
formState.icon = "";
|
|
||||||
formState.pid = null;
|
|
||||||
formState.title = "";
|
|
||||||
formState.url = "";
|
|
||||||
formState.weigh = "";
|
|
||||||
formState.menuType = "";
|
|
||||||
formState.ruleFields = [{ fieldKey: "", fieldCnName: "" }];
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreate = () => {
|
|
||||||
formRef.value
|
|
||||||
.validate()
|
|
||||||
.then(() => {
|
|
||||||
formState.pid = formState.pid ? Number(formState.pid) : 0;
|
|
||||||
formState.weigh = formState.weigh ? Number(formState.weigh) : 1;
|
|
||||||
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/rule/create";
|
|
||||||
let params = formState;
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
processSuccess("添加成功");
|
|
||||||
handleClose();
|
|
||||||
emits("triggerClose");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((error) => {});
|
|
||||||
};
|
|
||||||
const handleDel = () => {
|
|
||||||
$request.HTTP.permission
|
|
||||||
.ruleRemove({ ID: formState.ID })
|
|
||||||
.then((res) => {
|
|
||||||
if (res.status == 0) {
|
|
||||||
message.success({
|
|
||||||
content: "删除成功",
|
|
||||||
duration: 2,
|
|
||||||
onClose() {
|
|
||||||
handleClose();
|
|
||||||
emits("triggerClose");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.error(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
message.error(e.response?.data?.msg || "操作失败,请稍后再试");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const departmentCel = () => {};
|
|
||||||
const handleUpdate = () => {
|
|
||||||
formRef.value
|
|
||||||
.validate()
|
|
||||||
.then(() => {
|
|
||||||
formState.pid = formState.pid ? Number(formState.pid) : 0;
|
|
||||||
formState.weigh = formState.weigh ? Number(formState.weigh) : 1;
|
|
||||||
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/rule/v2/update";
|
|
||||||
let params = formState;
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
message.success({
|
|
||||||
content: "修改成功",
|
|
||||||
duration: 2,
|
|
||||||
onClose() {
|
|
||||||
handleClose();
|
|
||||||
emits("triggerClose");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMenu = () => {
|
|
||||||
$request.HTTP.permission
|
|
||||||
.menuFList()
|
|
||||||
.then((res) => {
|
|
||||||
if (res.status == 0) {
|
|
||||||
state.menuList = res.data.data;
|
|
||||||
} else {
|
|
||||||
message.error(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
message.error(e.response?.data?.msg || "操作失败,请稍后再试");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMenuTree = () => {
|
|
||||||
$request.HTTP.permission
|
|
||||||
.menuSList()
|
|
||||||
.then((res) => {
|
|
||||||
if (res.status == 0) {
|
|
||||||
state.menuTreeList = res.data.data.map((item) => {
|
|
||||||
let obj = {
|
|
||||||
label: item.Title,
|
|
||||||
key: item.ID,
|
|
||||||
children: [],
|
|
||||||
};
|
|
||||||
if (item.Son) {
|
|
||||||
obj.children = item.Son.map((i) => {
|
|
||||||
return {
|
|
||||||
key: i.ID,
|
|
||||||
label: i.Title,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.error(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
message.error(e.response?.data?.msg || "操作失败,请稍后再试");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const handleUpdatemenuTreeValue = (val) => {
|
|
||||||
formState.pid = val;
|
|
||||||
};
|
|
||||||
const getDetail = () => {
|
|
||||||
let url = "/rule/v2/detail";
|
|
||||||
let params = {
|
|
||||||
ID: props.data.id,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
formState.ID = res.data.ID;
|
|
||||||
formState.type = res.data.type;
|
|
||||||
formState.title = res.data.title;
|
|
||||||
formState.url = res.data.url;
|
|
||||||
if (res.data.type == "button") {
|
|
||||||
formState.pid = res.data.pid;
|
|
||||||
}
|
|
||||||
if (res.data.type == "menu") {
|
|
||||||
formState.icon = res.data.icon;
|
|
||||||
formState.grayIcon = res.data.grayIcon;
|
|
||||||
formState.weigh = res.data.weigh;
|
|
||||||
formState.pid = res.data.pid;
|
|
||||||
formState.menuType = res.data.menuType;
|
|
||||||
}
|
|
||||||
if (res.data.type == "interface") {
|
|
||||||
formState.pid = res.data.pid;
|
|
||||||
formState.ruleFields = res.data.ruleFields;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.title-visible {
|
|
||||||
text-align: center;
|
|
||||||
color: $theme-primary;
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
:deep(.ant-modal-body) {
|
|
||||||
padding: 0 24px;
|
|
||||||
}
|
|
||||||
.create-contianer {
|
|
||||||
.ant-input {
|
|
||||||
color: #6d5c9c;
|
|
||||||
}
|
|
||||||
.center-content {
|
|
||||||
height: 65vh;
|
|
||||||
display: flex;
|
|
||||||
.title {
|
|
||||||
width: fit-content;
|
|
||||||
padding-left: 10px;
|
|
||||||
border-left: 4px solid $theme-primary;
|
|
||||||
color: $text-theme;
|
|
||||||
margin: 19px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-box {
|
|
||||||
width: 55%;
|
|
||||||
padding-right: 30px;
|
|
||||||
.content {
|
|
||||||
height: 54vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
color: $text-theme;
|
|
||||||
}
|
|
||||||
:deep(.ant-form-item-label > label) {
|
|
||||||
color: $text-theme;
|
|
||||||
}
|
|
||||||
.ant-form-item input[type="text"],
|
|
||||||
input,
|
|
||||||
textarea {
|
|
||||||
background: #e3dfea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-select :deep(.ant-select-selector) {
|
|
||||||
background: #e3dfea;
|
|
||||||
}
|
|
||||||
.control-item {
|
|
||||||
:deep(.ant-form-item-control) {
|
|
||||||
margin-left: 0px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.cancel-btn {
|
|
||||||
color: #999999;
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
color: $text-theme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.upload {
|
|
||||||
:deep(.ant-image) {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
:deep(.ant-image-img) {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.footer-content {
|
|
||||||
margin: 10px 0;
|
|
||||||
button {
|
|
||||||
width: 130px;
|
|
||||||
height: 30px;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 30px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 10px;
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,674 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row" style="padding: 35px">
|
|
||||||
<div
|
|
||||||
class="col-3 fl-pa-md"
|
|
||||||
style="
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: rgba(188, 188, 188, 0.18) 0px 3px 6px 1px;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="row font-16"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5"
|
|
||||||
>
|
|
||||||
<div class="fl-py-sm" style="border-bottom: 4px solid #764cf6">
|
|
||||||
组织架构
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" style="height: 76vh; overflow: auto">
|
|
||||||
<fl-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fl-tree>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-9 fl-px-md">
|
|
||||||
<div style="background: #fff" class="fl-pa-md">
|
|
||||||
<div
|
|
||||||
class="col-12 row font-18"
|
|
||||||
style="
|
|
||||||
color: #764cf6;
|
|
||||||
border-bottom: 1px solid #c1b2e5;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="fl-py-sm" style="border-bottom: 4px solid #764cf6">
|
|
||||||
岗位管理
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<n-button @click="goToOrgManage" v-permission="'org-manage-btn'">
|
|
||||||
组织管理
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row fl-mt-sm">
|
|
||||||
<fln-table
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
@triggerRowActions="handleRowActions"
|
|
||||||
@triggerTableBatchActions="handleTableBatchActions"
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #39109c; color: #fff"
|
|
||||||
@click="handlePermissMgm"
|
|
||||||
>权限列表</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<n-modal
|
|
||||||
v-model:show="state.dialogDel"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
删除
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div
|
|
||||||
v-if="state.dialogData.type === 'one'"
|
|
||||||
class="font-20"
|
|
||||||
style="color: #6d5c9c; margin: 80px 0"
|
|
||||||
>
|
|
||||||
确定删除该岗位吗?
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="state.dialogData.type === 'batch'"
|
|
||||||
class="font-20"
|
|
||||||
style="color: #6d5c9c; margin: 80px 0"
|
|
||||||
>
|
|
||||||
确定删除选中的岗位吗?
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogBack"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleDialogSave"
|
|
||||||
>确定</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
|
|
||||||
<fl-posi-permiss-mgm
|
|
||||||
v-if="state.dialogPermissMgm"
|
|
||||||
@triggerClose="state.dialogPermissMgm = false"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<orgManage
|
|
||||||
:orgVisible="state.org.orgVisible"
|
|
||||||
:title="'组织管理'"
|
|
||||||
@orgHandleOk="orgHandleOk"
|
|
||||||
></orgManage>
|
|
||||||
|
|
||||||
<fl-posi-dialog-create
|
|
||||||
v-if="state.dialogPosiCreate"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
@triggerClose="handleDialogCreateClose"
|
|
||||||
></fl-posi-dialog-create>
|
|
||||||
|
|
||||||
<n-modal
|
|
||||||
v-model:show="state.dialogLinkerNum"
|
|
||||||
style="width: 800px"
|
|
||||||
:mask-closable="true"
|
|
||||||
preset="card"
|
|
||||||
>
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<fln-table
|
|
||||||
:config="state.linkerNumConfig"
|
|
||||||
:fatherData="state.dialogData"
|
|
||||||
:refreshCount="state.linkerNumConfig.refreshCount"
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="state.dialogLinkerNum = false"
|
|
||||||
>关闭</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 岗位
|
|
||||||
import flPosiPermissMgm from "./permissionDialog.vue";
|
|
||||||
import { NButton } from "naive-ui";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
h,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
import login from "@/api/login";
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
import flPosiDialogCreate from "./dialogCreate.vue";
|
|
||||||
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
import orgManage from "./orgManage.vue";
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const title = ref("");
|
|
||||||
const state = reactive({
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
treeSelectData: {},
|
|
||||||
dialogPermissMgm: false,
|
|
||||||
dialogDel: false,
|
|
||||||
dialogData: {},
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
title: "",
|
|
||||||
org: {
|
|
||||||
orgVisible: false,
|
|
||||||
},
|
|
||||||
dialogLinkerNum: false,
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
hasSelection: true,
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/position/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "岗位ID",
|
|
||||||
field: "ID",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "岗位名",
|
|
||||||
field: "name",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "页面权限",
|
|
||||||
field: "menuAuth",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "rangdate",
|
|
||||||
label: "最近一次更新时间",
|
|
||||||
field: ["updateStartAt", "updateEndAt"],
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: ["开始", "结束"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "岗位ID",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
title: "岗位名",
|
|
||||||
field: "name",
|
|
||||||
type: "sfBgColor",
|
|
||||||
bgConfig: {
|
|
||||||
bgColorField: "color",
|
|
||||||
color: "#fff",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// width: 120,
|
|
||||||
// type: "select",
|
|
||||||
// title: "部门负责人",
|
|
||||||
// field: "",
|
|
||||||
// config: {
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// label: "是",
|
|
||||||
// value: 1,
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
type: "tooltip",
|
|
||||||
title: "岗位描述",
|
|
||||||
field: "remark",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "页面权限",
|
|
||||||
field: "menuAuths",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#fff",
|
|
||||||
borderRadius: "14px",
|
|
||||||
style: "border-radius: 14px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
sorter: true,
|
|
||||||
title: "被关联人数",
|
|
||||||
field: "linkerNum",
|
|
||||||
render(row) {
|
|
||||||
return h(
|
|
||||||
"div",
|
|
||||||
{
|
|
||||||
style: "color: #409eff; cursor: pointer",
|
|
||||||
onClick: () => {
|
|
||||||
handleLinkerNum(row);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
row.linkerNum
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
title: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 160,
|
|
||||||
title: "最近一次更新时间",
|
|
||||||
field: "updatedAt",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 200,
|
|
||||||
title: "操作",
|
|
||||||
fixed: "right",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "act_view",
|
|
||||||
type: "label",
|
|
||||||
label: "查看",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
permission: "r_manage_posimanage_btn_edit",
|
|
||||||
actionType: "act_edit",
|
|
||||||
type: "label",
|
|
||||||
label: "修改",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
permission: "r_manage_posimanage_btn_delete",
|
|
||||||
actionType: "act_del",
|
|
||||||
type: "label",
|
|
||||||
label: "删除",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tableBatchActions: [
|
|
||||||
{
|
|
||||||
permission: "r_manage_posimanage_btn_create",
|
|
||||||
notLimitSelect: true,
|
|
||||||
style: "background:#F7EFFFFF;color:#8352B4FF",
|
|
||||||
actionType: "posi-direct-create",
|
|
||||||
type: "primary",
|
|
||||||
label: "新建岗位",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
permission: "r_manage_posimanage_btn_create",
|
|
||||||
notLimitSelect: true,
|
|
||||||
style: "background:#F7EFFFFF;color:#8352B4FF",
|
|
||||||
actionType: "posi-create",
|
|
||||||
type: "primary",
|
|
||||||
label: "模版新建岗位",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
linkerNumConfig: {
|
|
||||||
tableScrollWitdh: 300,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/user/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "positionId",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "员工工号",
|
|
||||||
field: "jobNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "姓名",
|
|
||||||
field: "nickName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "手机",
|
|
||||||
field: "telNum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
title: "状态",
|
|
||||||
field: "status",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "有效",
|
|
||||||
value: "notactive",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "无效",
|
|
||||||
value: "left",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
dialogPosiCreate: false,
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getTreeData();
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/filter";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
// 获取最近点击的部门
|
|
||||||
let localSelect = Local.get("posimanage_treeSelectData");
|
|
||||||
if (localSelect && JSON.stringify(localSelect) !== "{}") {
|
|
||||||
state.treeSelectData = localSelect;
|
|
||||||
state.expandedKeys = localSelect.pathIds;
|
|
||||||
state.clickKey = localSelect.key;
|
|
||||||
} else {
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.clickKey === data[0].key &&
|
|
||||||
!state.expandedKeys.includes(data[0].key)
|
|
||||||
) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
state.expandedKeys.push(state.clickKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
Local.set("posimanage_treeSelectData", state.treeSelectData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRowActions = ({ btnConfig, rowData }) => {
|
|
||||||
state.dialogData = rowData;
|
|
||||||
Local.set("posimanage_treeSelectData", state.treeSelectData);
|
|
||||||
if (btnConfig.actionType === "act_del") {
|
|
||||||
state.dialogData.type = "one";
|
|
||||||
state.dialogDel = true;
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_edit") {
|
|
||||||
router.push(
|
|
||||||
`/posimanage/create?departmentID=${state.clickKey}&&ID=${rowData.ID}&&type=edit`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_view") {
|
|
||||||
router.push(
|
|
||||||
`/posimanage/create?departmentID=${state.clickKey}&&ID=${rowData.ID}&&type=view`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTableBatchActions = ({ selectedRows, btnConfig, fatherData }) => {
|
|
||||||
state.selectedRows = selectedRows;
|
|
||||||
if (btnConfig.actionType === "posi-create") {
|
|
||||||
Local.set("posimanage_treeSelectData", state.treeSelectData);
|
|
||||||
state.dialogPosiCreate = true;
|
|
||||||
// router.push(
|
|
||||||
// `/posimanage/create?departmentID=${state.clickKey}&&type=create`
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "posi-delete-bat") {
|
|
||||||
handleDeleteBatch();
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "posi-direct-create") {
|
|
||||||
router.push(
|
|
||||||
`/posimanage/create?departmentID=${
|
|
||||||
Local.get("posimanage_treeSelectData").key
|
|
||||||
}&&type=create`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteBatch = () => {
|
|
||||||
state.dialogData.type = "batch";
|
|
||||||
state.dialogDel = true;
|
|
||||||
};
|
|
||||||
const handleDeleteBatchSave = () => {
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/position/v2/batch/remove";
|
|
||||||
let params = {
|
|
||||||
IDs: state.selectedRows.map((item) => item.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.selectedRows = [];
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
state.dialogDel = false;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 单个删除
|
|
||||||
const handleDialogSave = () => {
|
|
||||||
if (state.dialogData.type === "batch") {
|
|
||||||
handleDeleteBatchSave();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/position/v2/batch/remove";
|
|
||||||
let params = {
|
|
||||||
IDs: [state.dialogData.ID],
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
state.dialogDel = false;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.btnLoading = false;
|
|
||||||
state.dialogDel = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogDel = false;
|
|
||||||
};
|
|
||||||
const handlePermissMgm = () => {
|
|
||||||
state.dialogPermissMgm = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 组织管理
|
|
||||||
const goToOrgManage = () => {
|
|
||||||
state.org = { orgVisible: true };
|
|
||||||
};
|
|
||||||
const orgHandleOk = () => {
|
|
||||||
state.org.orgVisible = false;
|
|
||||||
getTreeData();
|
|
||||||
};
|
|
||||||
const handleDialogCreateClose = () => {
|
|
||||||
state.dialogPosiCreate = false;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
const handleLinkerNum = (row) => {
|
|
||||||
console.log(row);
|
|
||||||
state.dialogData = row;
|
|
||||||
state.dialogLinkerNum = true;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-modal v-model:show="state.dialogModal"
|
|
||||||
:mask-closable="false">
|
|
||||||
<n-card style="width: 600px"
|
|
||||||
:bordered="false"
|
|
||||||
size="huge"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true">
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225">
|
|
||||||
自定义数据范围权限
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #header-extra>
|
|
||||||
<n-button @click="handleLimitData"
|
|
||||||
text
|
|
||||||
style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
<div class="row justify-center fl-pa-md"
|
|
||||||
style="color: #333639">
|
|
||||||
<div class="col-12 text-center font-14"
|
|
||||||
style="color: #333639">
|
|
||||||
被勾选的部门相关权限可被查看
|
|
||||||
</div>
|
|
||||||
<n-tree block-line
|
|
||||||
checkable
|
|
||||||
:selectable="false"
|
|
||||||
:data="state.treeData"
|
|
||||||
:default-checked-keys="props.fatherData"
|
|
||||||
@update:checked-keys="updateCheckedKeys" />
|
|
||||||
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleLimitData">返回</n-button>
|
|
||||||
|
|
||||||
<n-button tertiary
|
|
||||||
style="width: 161px; background: #46299dff; color: #fff"
|
|
||||||
@click="handleLimitData('submit')">保存</n-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 权限 自定义数据范围
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
let props = defineProps({
|
|
||||||
fatherData: {
|
|
||||||
type: Array,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
treeData: [],
|
|
||||||
dialogModal: true,
|
|
||||||
selectedKeys: []
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.dialogModal = true;
|
|
||||||
getTreeData()
|
|
||||||
if (props.fatherData) {
|
|
||||||
state.selectedKeys = props.fatherData;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/my";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const emits = defineEmits(["triggerLimitData"]);
|
|
||||||
const handleLimitData = (type) => {
|
|
||||||
if (type === 'submit') {
|
|
||||||
emits("triggerLimitData", state.selectedKeys);
|
|
||||||
} else {
|
|
||||||
emits("triggerLimitData", []);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateCheckedKeys = (keys) => {
|
|
||||||
state.selectedKeys = keys;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@ -1,576 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="org-dialog">
|
|
||||||
<n-modal
|
|
||||||
class="org-dialog"
|
|
||||||
v-model:show="props.orgVisible"
|
|
||||||
:z-index="1999"
|
|
||||||
:mask-closable="true"
|
|
||||||
style="min-width: 1000px; max-width: 1200px"
|
|
||||||
:to="app"
|
|
||||||
>
|
|
||||||
<n-card
|
|
||||||
:bordered="false"
|
|
||||||
:title="props.title"
|
|
||||||
size="huge"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header-extra>
|
|
||||||
<div class="close-box">
|
|
||||||
<n-button @click="closeFn" text style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="item-box">
|
|
||||||
<fl-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
:config="{
|
|
||||||
actions: ['edit', 'add', 'subtraction', 'move'],
|
|
||||||
moveShow: '[%=level%]>0',
|
|
||||||
subtractionShow: '[%=level%]>0',
|
|
||||||
}"
|
|
||||||
@triggerTreeAction="handleTreeAction"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fl-tree>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<div
|
|
||||||
style="text-align: center; padding-left: 20px; padding-right: 10px"
|
|
||||||
>
|
|
||||||
<n-button class="button-box" @click="closeFn"> 返回 </n-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
<n-modal
|
|
||||||
v-model:show="state.dialogAddTree"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
添加组织
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div class="fl-my-lg font-20">
|
|
||||||
<n-input
|
|
||||||
v-model:value="state.dialogAddTreeData"
|
|
||||||
placeholder="请输入组织名称"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #764cf6; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogAddTreeSave"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
|
||||||
@click="state.dialogAddTree = false"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
<n-modal
|
|
||||||
v-model:show="state.dialogSubtractionTree"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
删除组织
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div class="font-20" style="margin: 115px 0">
|
|
||||||
是否确认删除该组织及其子组织(如有)?
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #764cf6; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogSubtractionTreeSave"
|
|
||||||
>确定</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
|
||||||
@click="state.dialogSubtractionTree = false"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
<n-modal
|
|
||||||
v-model:show="state.dialogMoveTree"
|
|
||||||
style="width: 600px"
|
|
||||||
:mask-closable="false"
|
|
||||||
preset="card"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
移动
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-pa-md">
|
|
||||||
<div class="fl-my-lg font-20">
|
|
||||||
<div class="font-16 fl-mb-md">请选择部门节点</div>
|
|
||||||
<fln-form-item
|
|
||||||
type="select"
|
|
||||||
:val="null"
|
|
||||||
:fatherData="state.dialogData"
|
|
||||||
:config="{
|
|
||||||
placeholder: '选择归属组织',
|
|
||||||
config: {
|
|
||||||
optionConfig: {
|
|
||||||
resDataField: 'list',
|
|
||||||
url: '/department/v2/base/all/list',
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: 'notDepartmentIds',
|
|
||||||
field: 'key',
|
|
||||||
type: 'Array',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
labelField: 'name',
|
|
||||||
valueField: 'ID',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
:clearable="true"
|
|
||||||
@triggerValChange="handleValChange"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="font-14 fl-mt-sm" style="color: #ef0000">
|
|
||||||
确认后,所选部门及其所有子部门将统一归属于新选定的上级部门之下,且保持原有子部门层级关系不变。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #eeeaf7; color: #774ff6"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="state.dialogMoveTree = false"
|
|
||||||
>取消</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #764cf6; color: #fff"
|
|
||||||
@click="handleDialogMoveTreeSave"
|
|
||||||
>确定</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 组织管理
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flTree from "./components/flnindex.vue";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
defineProps,
|
|
||||||
defineEmits,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
} from "vue";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
import {
|
|
||||||
processError,
|
|
||||||
processSuccess,
|
|
||||||
processWarning,
|
|
||||||
} from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const app = document.getElementById("app");
|
|
||||||
const state = reactive({
|
|
||||||
dialogData: {},
|
|
||||||
dialogMoveTree: false,
|
|
||||||
dialogMoveTreeData: null,
|
|
||||||
departmentOptions: [],
|
|
||||||
dialogAddTree: false,
|
|
||||||
dialogAddTreeData: "",
|
|
||||||
dialogSubtractionTree: false,
|
|
||||||
treeSelectData: {},
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
requestbysf: true,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "user/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const props = defineProps({
|
|
||||||
orgVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
require: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
let treeSelectData = Local.get("orgmanage_treeSelectData");
|
|
||||||
if (treeSelectData) {
|
|
||||||
state.treeSelectData = treeSelectData;
|
|
||||||
state.clickKey = treeSelectData.key;
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/my";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
state.clickKey === data[0].key &&
|
|
||||||
!state.expandedKeys.includes(data[0].key)
|
|
||||||
) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
state.expandedKeys.push(state.clickKey);
|
|
||||||
}
|
|
||||||
if (data.length === 1 && !state.expandedKeys.includes(data[0].key)) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreatePosi = () => {};
|
|
||||||
const handleValChange = ({ val, config, selectOpt }) => {
|
|
||||||
state.dialogMoveTreeData = selectOpt;
|
|
||||||
};
|
|
||||||
const handleTreeAction = ({ type, val }) => {
|
|
||||||
state.dialogData = val;
|
|
||||||
if (type === "add") {
|
|
||||||
state.clickKey = val.key;
|
|
||||||
state.treeSelectData = val;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
state.dialogAddTreeData = "";
|
|
||||||
state.dialogAddTree = true;
|
|
||||||
}
|
|
||||||
if (type === "move") {
|
|
||||||
state.clickKey = val.key;
|
|
||||||
state.treeSelectData = val;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
state.dialogMoveTreeData = {};
|
|
||||||
state.dialogMoveTree = true;
|
|
||||||
}
|
|
||||||
if (type === "subtraction") {
|
|
||||||
state.dialogSubtractionTree = true;
|
|
||||||
}
|
|
||||||
if (type === "save") {
|
|
||||||
let url = "/department/v2/update";
|
|
||||||
let params = {
|
|
||||||
name: val.title,
|
|
||||||
ID: val.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
getTreeData();
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (type === "cancel") {
|
|
||||||
getTreeData();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
Local.set("orgmanage_treeSelectData", tree);
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
// const handleTreeDefaultClick = () => {
|
|
||||||
// state.treeSelectData = state.treeData[0];
|
|
||||||
// state.clickKey = state.treeData[0].key;
|
|
||||||
// Local.remove("orgmanage_treeSelectData");
|
|
||||||
// state.tableConfig.refreshCount++;
|
|
||||||
// };
|
|
||||||
const handleCloseModal = () => {
|
|
||||||
// emits("triggerCloseModal");
|
|
||||||
};
|
|
||||||
const handleDialogMoveTreeSave = () => {
|
|
||||||
let url = "/department/v2/update";
|
|
||||||
let params = {
|
|
||||||
ID: state.dialogData.key,
|
|
||||||
name: state.dialogData.label,
|
|
||||||
pid: state.dialogMoveTreeData.value,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
if (Array.isArray(res.data.levelPathList)) {
|
|
||||||
state.expandedKeys = [];
|
|
||||||
res.data.levelPathList.forEach((treeid) => {
|
|
||||||
if (!state.expandedKeys.includes(treeid)) {
|
|
||||||
state.expandedKeys.push(treeid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
state.dialogMoveTree = false;
|
|
||||||
if (
|
|
||||||
(state.dialogMoveTreeData.level || 0) +
|
|
||||||
1(state.dialogData.sonMaxDepth || 0) +
|
|
||||||
1 >
|
|
||||||
8
|
|
||||||
) {
|
|
||||||
processWarning("组织数已超过8级,建议不要再增加高度");
|
|
||||||
} else {
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
// 树 新增
|
|
||||||
const handleDialogAddTreeSave = () => {
|
|
||||||
let url = "/department/v2/create";
|
|
||||||
let params = {
|
|
||||||
name: state.dialogAddTreeData,
|
|
||||||
pid: state.dialogData.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
if (Array.isArray(res.data.levelPathList)) {
|
|
||||||
state.expandedKeys = [];
|
|
||||||
res.data.levelPathList.forEach((treeid) => {
|
|
||||||
if (!state.expandedKeys.includes(treeid)) {
|
|
||||||
state.expandedKeys.push(treeid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
if (state.dialogData.level > 7) {
|
|
||||||
processWarning("组织数已超过8级,建议不要再增加高度");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogAddTree = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
// 树 减
|
|
||||||
const handleDialogSubtractionTreeSave = () => {
|
|
||||||
let url = "/department/v2/remove";
|
|
||||||
let params = {
|
|
||||||
ID: state.dialogData.key,
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0) {
|
|
||||||
getTreeData();
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.dialogSubtractionTree = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const emit = defineEmits(["update:orgVisible", "orgHandleOk"]);
|
|
||||||
const closeFn = () => {
|
|
||||||
emit("orgHandleOk");
|
|
||||||
};
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.orgVisible,
|
|
||||||
(val) => {
|
|
||||||
let treeSelectData = Local.get("orgmanage_treeSelectData");
|
|
||||||
if (treeSelectData) {
|
|
||||||
state.treeSelectData = treeSelectData;
|
|
||||||
state.clickKey = treeSelectData.key;
|
|
||||||
}
|
|
||||||
getTreeData();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.org-dialog {
|
|
||||||
text-align: center;
|
|
||||||
.naive-modal-body {
|
|
||||||
height: 750px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.item-box {
|
|
||||||
height: 50vh;
|
|
||||||
overflow: auto;
|
|
||||||
text-align: center;
|
|
||||||
padding-left: 100px;
|
|
||||||
padding-right: 100px;
|
|
||||||
}
|
|
||||||
.button-box {
|
|
||||||
width: 150px;
|
|
||||||
background-color: rgba(199, 199, 201, 1);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-item {
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
|
||||||
background: #fff;
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
:deep(.ant-input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ant-picker) {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: #fff !important;
|
|
||||||
color: #c3c3c3;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
:deep(.ant-picker-input > input) {
|
|
||||||
color: #000;
|
|
||||||
&::placeholder {
|
|
||||||
color: #c3c3c3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,311 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-modal v-model:show="state.dialogModal" :mask-closable="false">
|
|
||||||
<n-card
|
|
||||||
style="width: 80vw"
|
|
||||||
:bordered="false"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div class="col-12 row justify-center relative">
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
权限列表
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #header-extra>
|
|
||||||
<n-button @click="handleDialogBack" text style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="row justify-center fl-px-md fl-pb-md">
|
|
||||||
<div class="col-12 overflow-auto" style="height: 60vh">
|
|
||||||
<fln-table
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
:defaultSelectedRows="state.selectedRows"
|
|
||||||
@triggerRowActions="handleRowActions"
|
|
||||||
@triggerSelectCheck="handleTableSelectCheck"
|
|
||||||
>
|
|
||||||
<template #table-header-box>
|
|
||||||
<div class="col-12 row fl-mb-sm justify-between">
|
|
||||||
<div class="row items-center">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #eff3ff; color: #6b69a3"
|
|
||||||
class="fl-mr-md"
|
|
||||||
:disabled="state.selectedRows.length === 0"
|
|
||||||
@click="handleQuickSelectPosi"
|
|
||||||
>快速添加到岗位</n-button
|
|
||||||
>
|
|
||||||
<div v-if="state.selectedRows.length > 0">
|
|
||||||
已选 {{ state.selectedRows.length }} 个
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #9c9ad3; color: #ffffff"
|
|
||||||
@click="handleCreatePermiss"
|
|
||||||
>新增权限</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogBack"
|
|
||||||
>返回</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
<Auth
|
|
||||||
v-if="state.showModal"
|
|
||||||
:title="state.modalAuth.title"
|
|
||||||
:data="state.modalAuth.data"
|
|
||||||
@triggerClose="handleCloseEditAuth"
|
|
||||||
/>
|
|
||||||
<fl-permission-bind-posi
|
|
||||||
v-if="state.diallogPosi"
|
|
||||||
:fatherData="state.selectedRows"
|
|
||||||
@triggerClose="handleQuickSelectPosiClose"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
// 权限列表 管理
|
|
||||||
import {
|
|
||||||
UpOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
DragOutlined,
|
|
||||||
} from "@ant-design/icons-vue";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import flnFormItem from "@/components/flnlayout/form/flnformItem.vue";
|
|
||||||
import flAboutApproval from "./aboutApproval.vue";
|
|
||||||
import flPermissionBindPosi from "./permissionbindposi.vue";
|
|
||||||
import draggable from "vuedraggable";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
import { ChevronDownOutline, ChevronUpOutline } from "@vicons/ionicons5";
|
|
||||||
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import Auth from "./editAuth.vue";
|
|
||||||
const emits = defineEmits(["triggerClose"]);
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
selectedRows: [],
|
|
||||||
btnLoading: false,
|
|
||||||
dialogModal: true,
|
|
||||||
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
hasSelection: true,
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/rule/list",
|
|
||||||
},
|
|
||||||
searchStyle: "padding-top:0px !important;",
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
label: "权限类型",
|
|
||||||
field: "Type",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: "menu",
|
|
||||||
label: "菜单权限",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "button",
|
|
||||||
label: "按钮权限",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "interface",
|
|
||||||
label: "接口权限",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "权限名称",
|
|
||||||
field: "Title",
|
|
||||||
class: "col-4",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "权限编号",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
title: "权限名",
|
|
||||||
field: "Title",
|
|
||||||
maxWidth: "100%",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
title: "权限类型",
|
|
||||||
field: "Type",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: "menu",
|
|
||||||
label: "菜单权限",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "button",
|
|
||||||
label: "按钮权限",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "interface",
|
|
||||||
label: "接口权限",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 200,
|
|
||||||
title: "操作",
|
|
||||||
fixed: "right",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "act_edit",
|
|
||||||
type: "label",
|
|
||||||
label: "修改",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
actionType: "act_del",
|
|
||||||
type: "label",
|
|
||||||
label: "删除",
|
|
||||||
shape: "round",
|
|
||||||
class: "fl-mx-xs fl-mt-xs",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
showModal: false,
|
|
||||||
modalAuth: { title: "新增权限", data: null },
|
|
||||||
diallogPosi: false,
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.dialogModal = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {});
|
|
||||||
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
state.dialogField = false;
|
|
||||||
emits("triggerClose");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRowActions = ({ btnConfig, rowData }) => {
|
|
||||||
if (btnConfig.actionType === "act_edit") {
|
|
||||||
state.modalAuth = { title: "修改与删除-权限", data: { id: rowData.ID } };
|
|
||||||
state.showModal = true;
|
|
||||||
}
|
|
||||||
if (btnConfig.actionType === "act_del") {
|
|
||||||
$request.HTTP.permission
|
|
||||||
.ruleRemove({ ID: rowData.ID })
|
|
||||||
.then((res) => {
|
|
||||||
if (res.status == 0) {
|
|
||||||
processSuccess("删除成功");
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
} else {
|
|
||||||
processError(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
processError(e.response?.data?.msg || "操作失败");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTableSelectCheck = (data) => {
|
|
||||||
if (data && Array.isArray(data.selectedRow)) {
|
|
||||||
data.selectedRow = data.selectedRow.filter((item) => {
|
|
||||||
if (item) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "check" || data.action === "checkAll") {
|
|
||||||
state.selectedRows = state.selectedRows.concat(data.selectedRow);
|
|
||||||
state.selectedRows = state.selectedRows.filter((item, index, arr) => {
|
|
||||||
return (
|
|
||||||
arr.findIndex((obj) => JSON.stringify(obj) === JSON.stringify(item)) ===
|
|
||||||
index
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheck") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return item.ID !== data.selectedRow.ID;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheckAll") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return (
|
|
||||||
data.selectedRow.findIndex((obj) => {
|
|
||||||
return obj.ID === item.ID;
|
|
||||||
}) === -1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleCreatePermiss = () => {
|
|
||||||
state.modalAuth = { title: "新增权限", data: null };
|
|
||||||
state.showModal = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQuickSelectPosi = () => {
|
|
||||||
state.diallogPosi = true;
|
|
||||||
};
|
|
||||||
const handleQuickSelectPosiClose = () => {
|
|
||||||
state.selectedRows = [];
|
|
||||||
state.diallogPosi = false;
|
|
||||||
};
|
|
||||||
const handleCloseEditAuth = (val) => {
|
|
||||||
state.showModal = false;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
@ -1,308 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-modal v-model:show="state.dialogModal" :mask-closable="false">
|
|
||||||
<n-card
|
|
||||||
style="width: 80vw"
|
|
||||||
:bordered="false"
|
|
||||||
size="huge"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<div
|
|
||||||
class="col-12 row justify-center relative"
|
|
||||||
style="border-bottom: 1px solid #dfd7f2"
|
|
||||||
>
|
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #1f2225ff">
|
|
||||||
选择需要所选权限的岗位
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #header-extra>
|
|
||||||
<n-button @click="handleDialogBack" text style="font-size: 24px">
|
|
||||||
<n-icon>
|
|
||||||
<close-icon />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="row justify-center fl-pa-md overflow-auto"
|
|
||||||
style="max-height: 60vh"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col-3 fl-pa-md row"
|
|
||||||
style="
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: rgba(188, 188, 188, 0.18) 0px 3px 6px 1px;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<fl-tree
|
|
||||||
:data="state.treeData"
|
|
||||||
:expandedKeys="state.expandedKeys"
|
|
||||||
:refreshCount="state.treeRefreshCount"
|
|
||||||
:clickKey="state.clickKey"
|
|
||||||
@triggerTreeClick="handleTreeClick"
|
|
||||||
></fl-tree>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-9 fl-px-md">
|
|
||||||
<fln-table
|
|
||||||
:config="state.tableConfig"
|
|
||||||
:fatherData="state.treeSelectData"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount"
|
|
||||||
:defaultSelectedRows="state.selectedRows"
|
|
||||||
@triggerRowActions="handleRowActions"
|
|
||||||
@triggerSelectCheck="handleTableSelectCheck"
|
|
||||||
>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 row justify-center fl-mt-md">
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #c7c7c9ff; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogBack"
|
|
||||||
>上一步</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
tertiary
|
|
||||||
style="width: 161px; background: #46299d; color: #fff"
|
|
||||||
class="fl-mr-md"
|
|
||||||
@click="handleDialogSave"
|
|
||||||
>保存</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 岗位
|
|
||||||
import { NButton } from "naive-ui";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
nextTick,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
import login from "@/api/login";
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
import flTree from "@/components/flnlayout/tree/flnindex.vue";
|
|
||||||
import { Close as CloseIcon } from "@vicons/ionicons5";
|
|
||||||
import { Local } from "@/utils/storage.js";
|
|
||||||
const router = useRouter();
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const emits = defineEmits(["triggerClose"]);
|
|
||||||
let props = defineProps({
|
|
||||||
fatherData: {
|
|
||||||
type: Array,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const state = reactive({
|
|
||||||
clickKey: "",
|
|
||||||
treeRefreshCount: 0,
|
|
||||||
expandedKeys: [],
|
|
||||||
treeData: [],
|
|
||||||
treeSelectData: {},
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
hasSelection: true,
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "data",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/position/v2/list",
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
label: "departmentID",
|
|
||||||
field: "key",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: "岗位ID",
|
|
||||||
field: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
title: "岗位名",
|
|
||||||
field: "name",
|
|
||||||
type: "sfBgColor",
|
|
||||||
bgConfig: {
|
|
||||||
bgColorField: "color",
|
|
||||||
color: "#fff",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 120,
|
|
||||||
type: "tooltip",
|
|
||||||
title: "岗位描述",
|
|
||||||
field: "remark",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 360,
|
|
||||||
title: "页面权限",
|
|
||||||
field: "menuAuths",
|
|
||||||
type: "tags",
|
|
||||||
tagConfig: {
|
|
||||||
showLength: 3,
|
|
||||||
bgColor: "#fff",
|
|
||||||
borderRadius: "14px",
|
|
||||||
style: "border-radius: 14px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: 140,
|
|
||||||
sorter: true,
|
|
||||||
title: "被关联人数",
|
|
||||||
field: "linkerNum",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
dialogModal: true,
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
state.dialogModal = true;
|
|
||||||
getTreeData();
|
|
||||||
});
|
|
||||||
onMounted(() => {});
|
|
||||||
const getTreeData = () => {
|
|
||||||
let url = "/department/v2/tree/my";
|
|
||||||
let params = {};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
if (res.status === 0 && Array.isArray(res.data.nodes)) {
|
|
||||||
let data = res.data.nodes;
|
|
||||||
calcTreeData(data);
|
|
||||||
state.treeData = data;
|
|
||||||
if (JSON.stringify(state.treeSelectData) === "{}") {
|
|
||||||
state.treeSelectData = data[0];
|
|
||||||
state.clickKey = data[0].key;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.clickKey === data[0].key &&
|
|
||||||
!state.expandedKeys.includes(data[0].key)
|
|
||||||
) {
|
|
||||||
state.expandedKeys.push(data[0].key);
|
|
||||||
}
|
|
||||||
if (!state.expandedKeys.includes(state.clickKey)) {
|
|
||||||
state.expandedKeys.push(state.clickKey);
|
|
||||||
}
|
|
||||||
state.treeRefreshCount++;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "获取失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("获取失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const calcTreeData = (data) => {
|
|
||||||
for (let item of data) {
|
|
||||||
item.key = item.ID;
|
|
||||||
item.label = item.name;
|
|
||||||
item.title = item.name;
|
|
||||||
if (item.sons) {
|
|
||||||
item.children = item.sons;
|
|
||||||
calcTreeData(item.children);
|
|
||||||
}
|
|
||||||
delete item.ID;
|
|
||||||
delete item.name;
|
|
||||||
delete item.sons;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleTreeClick = ({ selectedKey, tree }) => {
|
|
||||||
state.clickKey = tree.key;
|
|
||||||
state.treeSelectData = tree;
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRowActions = ({ btnConfig, rowData }) => {
|
|
||||||
Local.set("posimanage_treeSelectData", state.treeSelectData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDialogSave = () => {
|
|
||||||
if (state.selectedRows.length > 50) {
|
|
||||||
return processError("最多选择50个岗位!");
|
|
||||||
}
|
|
||||||
state.btnLoading = true;
|
|
||||||
let url = "/position/v2/batch/bind/auth";
|
|
||||||
let params = {
|
|
||||||
ids: state.selectedRows.map((item) => item.ID),
|
|
||||||
ruleIds: props.fatherData.map((item) => item.ID),
|
|
||||||
};
|
|
||||||
$request.HTTP.components.postDataByParams(url, params).then(
|
|
||||||
(res) => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
if (res.status === 0) {
|
|
||||||
state.tableConfig.refreshCount++;
|
|
||||||
processSuccess("操作成功!");
|
|
||||||
emits("triggerClose");
|
|
||||||
} else {
|
|
||||||
processError(res.msg || "操作失败!");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
processError("操作失败!");
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
state.btnLoading = false;
|
|
||||||
processError("操作失败!");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleDialogBack = () => {
|
|
||||||
emits("triggerClose");
|
|
||||||
};
|
|
||||||
const handleTableSelectCheck = (data) => {
|
|
||||||
if (data && Array.isArray(data.selectedRow)) {
|
|
||||||
data.selectedRow = data.selectedRow.filter((item) => {
|
|
||||||
if (item) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "check" || data.action === "checkAll") {
|
|
||||||
state.selectedRows = state.selectedRows.concat(data.selectedRow);
|
|
||||||
state.selectedRows = state.selectedRows.filter((item, index, arr) => {
|
|
||||||
return (
|
|
||||||
arr.findIndex((obj) => JSON.stringify(obj) === JSON.stringify(item)) ===
|
|
||||||
index
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheck") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return item.ID !== data.selectedRow.ID;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.action === "uncheckAll") {
|
|
||||||
state.selectedRows = state.selectedRows.filter((item) => {
|
|
||||||
return (
|
|
||||||
data.selectedRow.findIndex((obj) => {
|
|
||||||
return obj.ID === item.ID;
|
|
||||||
}) === -1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
@ -1,149 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="row"
|
|
||||||
style="padding: 35px">
|
|
||||||
<div class="col-12 row">
|
|
||||||
<fln-table :config="state.tableConfig"
|
|
||||||
:refreshCount="state.tableConfig.refreshCount">
|
|
||||||
<template #search-header>
|
|
||||||
<div class="col-12 row font-18"
|
|
||||||
style="color: #764cf6; border-bottom: 1px solid #c1b2e5;">
|
|
||||||
<div class="fl-py-sm"
|
|
||||||
style="border-bottom: 4px solid #764cf6;">
|
|
||||||
岗位操作记录
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</fln-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 岗位
|
|
||||||
import { NButton } from "naive-ui";
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
reactive,
|
|
||||||
onBeforeMount,
|
|
||||||
onMounted,
|
|
||||||
getCurrentInstance,
|
|
||||||
computed,
|
|
||||||
} from "vue";
|
|
||||||
import { processError, processSuccess } from "@/utils/helper/message";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
import flnTable from "@/components/flnlayout/table/flntable.vue";
|
|
||||||
|
|
||||||
const currentInstance = getCurrentInstance();
|
|
||||||
const { $request } = currentInstance.appContext.config.globalProperties;
|
|
||||||
const title = ref("");
|
|
||||||
const state = reactive({
|
|
||||||
btnLoading: false,
|
|
||||||
selectedRows: [],
|
|
||||||
tableConfig: {
|
|
||||||
tableScrollWitdh: 600,
|
|
||||||
rowKey: "ID",
|
|
||||||
refreshCount: 0,
|
|
||||||
listUrl: {
|
|
||||||
resDataField: "list",
|
|
||||||
pageField: "page",
|
|
||||||
pageSizeField: "pageSize",
|
|
||||||
url: "/position/v2/log/list",
|
|
||||||
},
|
|
||||||
searchConfig: [
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
label: "操作类型",
|
|
||||||
field: "operateType",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "新增",
|
|
||||||
value: "add",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "修改",
|
|
||||||
value: "edit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
value: "del",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "查看",
|
|
||||||
value: "detail",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
label: "操作人账号",
|
|
||||||
field: "OperatorTel",
|
|
||||||
placeholder: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "rangdate",
|
|
||||||
label: "操作时间",
|
|
||||||
field: ["StartCreatedAt", "EndCreatedAt"],
|
|
||||||
placeholder: ["开始", "结束"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
type: 'select',
|
|
||||||
title: "操作类型",
|
|
||||||
field: "operateType",
|
|
||||||
config: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "新增",
|
|
||||||
value: "add",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "修改",
|
|
||||||
value: "edit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
value: "del",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "查看",
|
|
||||||
value: "detail",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
title: "操作详情",
|
|
||||||
field: "info",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "tooltip",
|
|
||||||
title: "操作人",
|
|
||||||
field: "operatorName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作人账号",
|
|
||||||
field: "OperatorTel",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作时间",
|
|
||||||
field: "createdAt",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onBeforeMount(() => {
|
|
||||||
});
|
|
||||||
onMounted(() => { });
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
</style>
|
|
||||||
@ -389,16 +389,16 @@ const updateImg = () => {
|
|||||||
duration: 2,
|
duration: 2,
|
||||||
});
|
});
|
||||||
//修改头像成功后,同步更新聊天系统的头像
|
//修改头像成功后,同步更新聊天系统的头像
|
||||||
// const updateChatAvatarRes = await updateChatAvatar({
|
const updateChatAvatarRes = await updateChatAvatar({
|
||||||
// erpUserId: state.info.ID, //erp用户id
|
erpUserId: state.info.ID, //erp用户id
|
||||||
// avatar: state.avatar, //头像url
|
avatar: state.avatar, //头像url
|
||||||
// type: "" //送空,那就只更新聊天系统这边的头像,送erp,就erp的头像也更新
|
type: "" //送空,那就只更新聊天系统这边的头像,送erp,就erp的头像也更新
|
||||||
// })
|
})
|
||||||
// if(updateChatAvatarRes.status === 0){
|
if(updateChatAvatarRes.status === 0){
|
||||||
// message.success("更新聊天系统头像成功")
|
message.success("更新聊天系统头像成功")
|
||||||
// } else {
|
} else {
|
||||||
// message.error(updateChatAvatarRes.msg)
|
message.error(updateChatAvatarRes.msg)
|
||||||
// }
|
}
|
||||||
state.avatar = "";
|
state.avatar = "";
|
||||||
} else {
|
} else {
|
||||||
message.error(res.msg);
|
message.error(res.msg);
|
||||||
@ -654,7 +654,7 @@ const getCertList = async () => {
|
|||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
getUser();
|
getUser();
|
||||||
// getCertList();
|
getCertList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -267,7 +267,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 row align-center fl-mt-sm">
|
<div class="col-12 row align-center fl-mt-sm">
|
||||||
<div class="form-label-80">画作名称</div>
|
<div class="form-label-80">画家宝画作名称</div>
|
||||||
|
|
||||||
<div style="width: 200px">
|
<div style="width: 200px">
|
||||||
<a-input :disabled="true"
|
<a-input :disabled="true"
|
||||||
|
|||||||
1817
src/views/workbench/components/oaWorkbench.vue
Normal file
1817
src/views/workbench/components/oaWorkbench.vue
Normal file
File diff suppressed because it is too large
Load Diff
880
src/views/workbench/components/quickIndex.vue
Normal file
880
src/views/workbench/components/quickIndex.vue
Normal file
@ -0,0 +1,880 @@
|
|||||||
|
<template>
|
||||||
|
<div class="index-container height-100 artwork-table" id="index-container">
|
||||||
|
<fl-table
|
||||||
|
:key="state.keyNum"
|
||||||
|
:config="state.tableConfig"
|
||||||
|
:refreshCount="state.tableConfig.refreshCount"
|
||||||
|
class="artwork-table"
|
||||||
|
@triggerRowActions="handleRowActions"
|
||||||
|
@triggerTableData="handleTableData"
|
||||||
|
>
|
||||||
|
<template #top-right>
|
||||||
|
<a-select
|
||||||
|
v-if="state.dep == 2 && checked"
|
||||||
|
v-model:value="ChainState"
|
||||||
|
style="width: 150px; margin-right: 20px"
|
||||||
|
placeholder="上链状态"
|
||||||
|
:options="state.linkOptions"
|
||||||
|
@change="handleLinkChange"
|
||||||
|
></a-select>
|
||||||
|
<a-switch
|
||||||
|
class="switch"
|
||||||
|
v-model:checked="checked"
|
||||||
|
@change="changeList"
|
||||||
|
/><span style="color: #764cf6; margin-right: 20px">{{
|
||||||
|
checked ? "已完成" : "未完成"
|
||||||
|
}}</span>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
shape="round"
|
||||||
|
class="fl-mr-sm"
|
||||||
|
style="width: 182px"
|
||||||
|
@click="handleExportArtwork"
|
||||||
|
:loading="state.btnLoading"
|
||||||
|
>导出画作数据</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
shape="round"
|
||||||
|
class="fl-mr-sm"
|
||||||
|
style="width: 182px"
|
||||||
|
@click="handleBatchUpload"
|
||||||
|
:loading="state.btnLoading"
|
||||||
|
>批量上传</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
shape="round"
|
||||||
|
style="width: 182px"
|
||||||
|
@click="handleCreate"
|
||||||
|
:loading="state.btnLoading"
|
||||||
|
>添加</a-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template v-slot:Signpic="Signpic">
|
||||||
|
<div class="drag-img">
|
||||||
|
<commonUpload
|
||||||
|
:type="'drag'"
|
||||||
|
:otherParams="state.otherParams"
|
||||||
|
:val="Signpic.text.Signpic"
|
||||||
|
:height="100"
|
||||||
|
:config="{
|
||||||
|
popover: true,
|
||||||
|
}"
|
||||||
|
@triggerUpload="(e) => handleUpload(Signpic.text, e, 'Signpic')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:DigiArtImg="DigiArtImg">
|
||||||
|
<div class="drag-img">
|
||||||
|
<commonUpload
|
||||||
|
:type="'drag'"
|
||||||
|
:otherParams="state.otherParams"
|
||||||
|
:val="DigiArtImg.text.DigiArtImg"
|
||||||
|
:height="100"
|
||||||
|
:config="{
|
||||||
|
popover: true,
|
||||||
|
}"
|
||||||
|
@triggerLayoutUpload="
|
||||||
|
(e) => handleLayoutUpload(e, 'DigiArtImg', DigiArtImg.text)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:Sealpic="Sealpic">
|
||||||
|
<div class="drag-img">
|
||||||
|
<commonUpload
|
||||||
|
:type="'drag'"
|
||||||
|
:otherParams="state.otherParams"
|
||||||
|
:val="Sealpic.text.Sealpic"
|
||||||
|
:height="100"
|
||||||
|
:config="{
|
||||||
|
popover: true,
|
||||||
|
}"
|
||||||
|
@triggerUpload="(e) => handleUpload(Sealpic.text, e, 'Sealpic')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #pagination-left>
|
||||||
|
<div class="count">
|
||||||
|
<!-- <span v-show="!checked" style="margin-right: 20px"
|
||||||
|
>未完成数:{{ state.inCount }}</span
|
||||||
|
>
|
||||||
|
<span v-show="checked">已完完成数:{{ state.doneCount }}</span> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</fl-table>
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
v-if="state.batchUploadModalVisible"
|
||||||
|
v-model:visible="state.batchUploadModalVisible"
|
||||||
|
:bodyStyle="{ height: '80vh' }"
|
||||||
|
class="fl-sf-modal"
|
||||||
|
width="60vw"
|
||||||
|
:closable="false"
|
||||||
|
:maskClosable="false"
|
||||||
|
:keyboard="false"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<fl-artwork-batch-upload @triggerCloseModal="handleBatchUploadClose" />
|
||||||
|
</a-modal>
|
||||||
|
<a-modal
|
||||||
|
v-if="state.artworkModalVisible"
|
||||||
|
v-model:visible="state.artworkModalVisible"
|
||||||
|
width="90vw"
|
||||||
|
class="fl-modal-artwork"
|
||||||
|
:bodyStyle="{ height: '85vh' }"
|
||||||
|
:closable="false"
|
||||||
|
:maskClosable="false"
|
||||||
|
:keyboard="false"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<fl-artwork-modal
|
||||||
|
:pageType="state.pageType"
|
||||||
|
:fatherData="state.rowData"
|
||||||
|
@triggerCloseModal="handleCloseModal"
|
||||||
|
></fl-artwork-modal>
|
||||||
|
</a-modal>
|
||||||
|
<fl-artwork-export-modal
|
||||||
|
v-if="state.exportDialogVisible"
|
||||||
|
:openCount="state.openCount"
|
||||||
|
:extraListParams="{ label: 'SaleStatusMul', value: [4, 5] }"
|
||||||
|
@triggerCloseModal="handleCloseExport"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { SearchOutlined } from "@ant-design/icons-vue";
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
onBeforeMount,
|
||||||
|
onMounted,
|
||||||
|
getCurrentInstance,
|
||||||
|
nextTick,
|
||||||
|
watch,
|
||||||
|
} from "vue";
|
||||||
|
import flTable from "@/components/layout/table/commonTable.vue";
|
||||||
|
import flArtworkModal from "./artworkmodal.vue";
|
||||||
|
import flArtworkBatchUpload from "../../artwork/components/batchupload.vue";
|
||||||
|
import flArtworkExportModal from "../../artwork/artworkexportmodal.vue";
|
||||||
|
import commonUpload from "@/components/layout/upload/commonUpload.vue";
|
||||||
|
import {
|
||||||
|
processError,
|
||||||
|
processSuccess,
|
||||||
|
processWarning,
|
||||||
|
} from "@/utils/helper/message";
|
||||||
|
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||||
|
import { downImg } from "@/utils/helper/fileDownload";
|
||||||
|
const currentInstance = getCurrentInstance();
|
||||||
|
const { $request } = currentInstance.appContext.config.globalProperties;
|
||||||
|
const checked = ref(false);
|
||||||
|
const isTab = ref(true);
|
||||||
|
const ChainState = ref(0);
|
||||||
|
const Source = ref(null);
|
||||||
|
console.log(useRoute());
|
||||||
|
const state = reactive({
|
||||||
|
otherParams: {
|
||||||
|
type: "image",
|
||||||
|
source: "artwork",
|
||||||
|
},
|
||||||
|
linkTypeMap: ["", "泰丰艺术区块链", "澄信链", "超级链"],
|
||||||
|
linkOptions: [
|
||||||
|
{
|
||||||
|
label: "所有",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "未上链",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "已部分上链",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "已完成上链",
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
action: import.meta.env.VITE_API_URL + "upload/img",
|
||||||
|
fileList: [
|
||||||
|
{
|
||||||
|
url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ChainState: 0,
|
||||||
|
doneCount: 0,
|
||||||
|
inCount: 0,
|
||||||
|
dep: useRoute().name === "JzWorkBentch" ? 2 : 1,
|
||||||
|
openCount: 0,
|
||||||
|
exportDialogVisible: false,
|
||||||
|
btnLoading: false,
|
||||||
|
pageType: "create",
|
||||||
|
rowData: {},
|
||||||
|
artworkModalVisible: false,
|
||||||
|
batchUploadModalVisible: false,
|
||||||
|
keyNum: 0,
|
||||||
|
tableConfig: {
|
||||||
|
slotRight: true,
|
||||||
|
refreshCount: 0,
|
||||||
|
hasActionLoading: false,
|
||||||
|
listUrl: {
|
||||||
|
url: "artwork/my-aw-list",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
label: "IsOver",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ChainState",
|
||||||
|
value: ChainState,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Source",
|
||||||
|
value: Source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
slotRight: true,
|
||||||
|
defaultSearch: {
|
||||||
|
fields: ["Keyword"],
|
||||||
|
placeholder: "在此处输入编号/姓名/推荐人/平尺",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: "作者姓名",
|
||||||
|
field: "artistShowCount",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "画作名称",
|
||||||
|
field: "ArtworkName",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "长度",
|
||||||
|
field: "Length",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "宽度",
|
||||||
|
field: "Width",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "平尺数",
|
||||||
|
field: "Ruler",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "商城编号",
|
||||||
|
field: "Tfnum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "image",
|
||||||
|
title: "小图",
|
||||||
|
field: "HdPic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 140,
|
||||||
|
align: "center",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "wutong",
|
||||||
|
hasLoading: true,
|
||||||
|
label: "泰丰艺术区块链上链",
|
||||||
|
type: "label",
|
||||||
|
permission: "wutong",
|
||||||
|
show: "[%=WtState%]===1",
|
||||||
|
actionLoadingField: "wutong",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "super",
|
||||||
|
label: "超级链上链",
|
||||||
|
hasLoading: true,
|
||||||
|
type: "label",
|
||||||
|
permission: "chaoji",
|
||||||
|
show: "[%=BaiduState%]===1",
|
||||||
|
actionLoadingField: "super",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "chengxin",
|
||||||
|
label: "澄信链上链",
|
||||||
|
hasLoading: true,
|
||||||
|
type: "label",
|
||||||
|
permission: "chengxin",
|
||||||
|
show: "[%=Changchainstate%]===1",
|
||||||
|
actionLoadingField: "chengxin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "createBook",
|
||||||
|
label: "下载证书",
|
||||||
|
permission: "quick-work-download",
|
||||||
|
type: "label",
|
||||||
|
show: "[%=WtState%]===2&&[%=Changchainstate%]===2&&[%=BaiduState%]===2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "modal_view",
|
||||||
|
label: "详情",
|
||||||
|
type: "label",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// actionType: "delete",
|
||||||
|
// label: "删除",
|
||||||
|
// type: "label",
|
||||||
|
// tooltip: true,
|
||||||
|
// class: "color-danger",
|
||||||
|
// actionUrl: {
|
||||||
|
// url: "artwork/del",
|
||||||
|
// params: [
|
||||||
|
// {
|
||||||
|
// label: "ArtworkUuid",
|
||||||
|
// field: "ArtworkUuid",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "人工",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "update",
|
||||||
|
label: "完成",
|
||||||
|
type: "primary",
|
||||||
|
shape: "round",
|
||||||
|
actionUrl: {
|
||||||
|
url: "artwork/edit-aw-status",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
type: "Array",
|
||||||
|
label: "ArtworkIds",
|
||||||
|
field: "Id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ActionType",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 监听路由参数中的dep变化,如果变化则重新请求列表
|
||||||
|
onBeforeRouteUpdate((to, from, next) => {
|
||||||
|
console.log(to.query);
|
||||||
|
handleRenderTable(to.query.dep);
|
||||||
|
Source.value = to.query.dep == 1 ? 2 : 1;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
onBeforeMount(() => {
|
||||||
|
handleRenderTable();
|
||||||
|
Source.value = state.dep == 1 ? 2 : 1;
|
||||||
|
});
|
||||||
|
onMounted(() => {});
|
||||||
|
// 上链状态更改
|
||||||
|
const handleLinkChange = (val) => {
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
};
|
||||||
|
// 上传
|
||||||
|
const handleBatchUpload = () => {
|
||||||
|
state.batchUploadModalVisible = true;
|
||||||
|
};
|
||||||
|
// 根据权限重新渲染表格
|
||||||
|
const handleRenderTable = (val) => {
|
||||||
|
// 获取query中的dep参数
|
||||||
|
let dep = val || state.dep;
|
||||||
|
console.log(dep);
|
||||||
|
|
||||||
|
if (dep == 1) {
|
||||||
|
state.tableConfig.columns = [
|
||||||
|
{
|
||||||
|
title: "作者姓名",
|
||||||
|
field: "artistShowCount",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "画作名称",
|
||||||
|
field: "ArtworkName",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "画作编号",
|
||||||
|
field: "Tfnum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "image",
|
||||||
|
title: "画家提供图",
|
||||||
|
field: "HdPic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "slot",
|
||||||
|
slotName: "DigiArtImg",
|
||||||
|
title: "数字化图",
|
||||||
|
field: "DigiArtImg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "slot",
|
||||||
|
slotName: "Signpic",
|
||||||
|
title: "落款图",
|
||||||
|
field: "Signpic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "人名章图",
|
||||||
|
field: "Sealpic",
|
||||||
|
type: "slot",
|
||||||
|
slotName: "Sealpic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "预计时间",
|
||||||
|
field: "ScheduleTime",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 140,
|
||||||
|
align: "center",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "modal_view",
|
||||||
|
label: "详情",
|
||||||
|
type: "label",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "人工",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "update",
|
||||||
|
label: "完成",
|
||||||
|
type: "primary",
|
||||||
|
shape: "round",
|
||||||
|
actionUrl: {
|
||||||
|
url: "artwork/edit-aw-status",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
type: "Array",
|
||||||
|
label: "ArtworkIds",
|
||||||
|
field: "Id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ActionType",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else if (dep == 2) {
|
||||||
|
state.tableConfig.columns = [
|
||||||
|
{
|
||||||
|
title: "作者姓名",
|
||||||
|
field: "artistShowCount",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "画作名称",
|
||||||
|
field: "ArtworkName",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "长度",
|
||||||
|
field: "Length",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "宽度",
|
||||||
|
field: "Width",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "平尺数",
|
||||||
|
field: "Ruler",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "画作编号",
|
||||||
|
field: "Tfnum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "image",
|
||||||
|
title: "小图",
|
||||||
|
field: "HdPic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "已上传点位数",
|
||||||
|
field: "BitMapNum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "60",
|
||||||
|
field: "BmSixtyNum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "200",
|
||||||
|
field: "BmTwoHundredNum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "600",
|
||||||
|
field: "BmSixHundredNum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "2000",
|
||||||
|
field: "BmTwoThousandNum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "预计时间",
|
||||||
|
field: "ScheduleTime",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 140,
|
||||||
|
align: "center",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "wutong",
|
||||||
|
hasLoading: true,
|
||||||
|
label: "泰丰艺术区块链上链",
|
||||||
|
type: "label",
|
||||||
|
permission: "wutong",
|
||||||
|
show: "[%=WtState%]===1",
|
||||||
|
actionLoadingField: "wutong",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "iswutong",
|
||||||
|
label: "泰丰艺术区块链上链中",
|
||||||
|
type: "label",
|
||||||
|
permission: "wutong",
|
||||||
|
show: "[%=WtState%]===3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "super",
|
||||||
|
label: "超级链上链",
|
||||||
|
hasLoading: true,
|
||||||
|
type: "label",
|
||||||
|
permission: "chaoji",
|
||||||
|
show: "[%=BaiduState%]===1",
|
||||||
|
actionLoadingField: "super",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "issuper",
|
||||||
|
label: "超级链上链中",
|
||||||
|
type: "label",
|
||||||
|
permission: "chaoji",
|
||||||
|
show: "[%=BaiduState%]===3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "chengxin",
|
||||||
|
label: "澄信链上链",
|
||||||
|
hasLoading: true,
|
||||||
|
type: "label",
|
||||||
|
permission: "chengxin",
|
||||||
|
show: "[%=Changchainstate%]===1",
|
||||||
|
actionLoadingField: "chengxin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "ischengxin",
|
||||||
|
label: "澄信链上链中",
|
||||||
|
type: "label",
|
||||||
|
permission: "chengxin",
|
||||||
|
show: "[%=Changchainstate%]===3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "createBook",
|
||||||
|
label: "下载证书",
|
||||||
|
permission: "quick-work-download",
|
||||||
|
type: "label",
|
||||||
|
show: "State===2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: "modal_view",
|
||||||
|
label: "详情",
|
||||||
|
type: "label",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "人工",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "update",
|
||||||
|
label: "完成",
|
||||||
|
type: "primary",
|
||||||
|
shape: "round",
|
||||||
|
actionUrl: {
|
||||||
|
url: "artwork/edit-aw-status",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
type: "Array",
|
||||||
|
label: "ArtworkIds",
|
||||||
|
field: "Id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ActionType",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
state.keyNum++;
|
||||||
|
};
|
||||||
|
// 切换状态
|
||||||
|
const changeList = (val) => {
|
||||||
|
if (val) {
|
||||||
|
state.tableConfig.listUrl.params = [
|
||||||
|
{
|
||||||
|
label: "IsOver",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Source",
|
||||||
|
value: Source,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
state.tableConfig.columns.pop();
|
||||||
|
} else {
|
||||||
|
state.tableConfig.listUrl.params = [
|
||||||
|
{
|
||||||
|
label: "IsOver",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Source",
|
||||||
|
value: Source,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
state.tableConfig.columns.push({
|
||||||
|
title: "人工",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "update",
|
||||||
|
label: "完成",
|
||||||
|
type: "primary",
|
||||||
|
shape: "round",
|
||||||
|
actionUrl: {
|
||||||
|
url: "artwork/edit-aw-status",
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
type: "Array",
|
||||||
|
label: "ArtworkIds",
|
||||||
|
field: "Id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "ActionType",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
state.keyNum++;
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
};
|
||||||
|
const handleCreate = () => {
|
||||||
|
state.pageType = "create";
|
||||||
|
state.rowData = {};
|
||||||
|
state.artworkModalVisible = true;
|
||||||
|
};
|
||||||
|
const handleExportArtwork = () => {
|
||||||
|
state.exportDialogVisible = true;
|
||||||
|
state.openCount++;
|
||||||
|
};
|
||||||
|
const handleCloseExport = () => {
|
||||||
|
state.exportDialogVisible = false;
|
||||||
|
};
|
||||||
|
const handleLayoutUpload = ({ val, file }, field, rowData) => {
|
||||||
|
// 更新画作
|
||||||
|
let Rate = "";
|
||||||
|
if (file) {
|
||||||
|
let max = Math.max(file.width, file.height);
|
||||||
|
let min = Math.min(file.width, file.height);
|
||||||
|
Rate = (Math.floor((max / min) * 100) / 100).toFixed(2);
|
||||||
|
}
|
||||||
|
let url = "artwork/update-info-with-kv";
|
||||||
|
let params = {
|
||||||
|
ArtworkUuid: rowData.ArtworkUuid,
|
||||||
|
Column: field,
|
||||||
|
Value: val.ori_url || "",
|
||||||
|
Rate,
|
||||||
|
};
|
||||||
|
$request.HTTP.components.postDataByParams(url, params).then(
|
||||||
|
(res) => {
|
||||||
|
if (res.status === 0) {
|
||||||
|
processSuccess("操作成功");
|
||||||
|
} else {
|
||||||
|
processError(res.msg || "操作失败!");
|
||||||
|
}
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
processError(err.response.data.msg || "操作失败!");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const handleUpload = (v1, v2, Column) => {
|
||||||
|
// 更新画作
|
||||||
|
console.log(v1, v2, Column);
|
||||||
|
let params = { ArtworkUuid: v1.ArtworkUuid, Column: Column, Value: v2 };
|
||||||
|
$request.HTTP.artwork.artworkUpdate(params).then(
|
||||||
|
(res) => {
|
||||||
|
if (res.status === 0) {
|
||||||
|
processSuccess("操作成功");
|
||||||
|
} else {
|
||||||
|
processError(res.msg || "失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
processError(err || "失败");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
};
|
||||||
|
const handleTableData = (data, resData) => {
|
||||||
|
console.log(resData);
|
||||||
|
state.doneCount = resData.doneCount;
|
||||||
|
state.inCount = resData.inCount;
|
||||||
|
};
|
||||||
|
const handleContract = () => {};
|
||||||
|
const handleRowActions = (btnConfig, rowData) => {
|
||||||
|
if (btnConfig.actionType === "modal_view") {
|
||||||
|
state.pageType = "view";
|
||||||
|
state.rowData = rowData;
|
||||||
|
state.artworkModalVisible = true;
|
||||||
|
}
|
||||||
|
if (btnConfig.actionType === "wutong") {
|
||||||
|
goLink(rowData.ArtworkUuid, 1, btnConfig, rowData);
|
||||||
|
} else if (btnConfig.actionType === "super") {
|
||||||
|
goLink(rowData.ArtworkUuid, 3, btnConfig, rowData);
|
||||||
|
} else if (btnConfig.actionType === "chengxin") {
|
||||||
|
goLink(rowData.ArtworkUuid, 2, btnConfig, rowData);
|
||||||
|
} else if (btnConfig.actionType === "createBook") {
|
||||||
|
createBook(rowData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 上链接口
|
||||||
|
const goLink = async (uuid, type, btnConfig, rowData) => {
|
||||||
|
rowData[btnConfig.actionLoadingField] = true;
|
||||||
|
let params = { ArtworkUuid: uuid, Type: type };
|
||||||
|
await $request.HTTP.common.goLink(params).then(
|
||||||
|
(res) => {
|
||||||
|
if (res.status === 0) {
|
||||||
|
processSuccess(
|
||||||
|
"画作" +
|
||||||
|
res.data.Data.Tfnum +
|
||||||
|
state.linkTypeMap[res.data.Data.ChainType] +
|
||||||
|
"上链成功"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
processError(res.msg || "失败");
|
||||||
|
}
|
||||||
|
delete rowData[btnConfig.actionLoadingField];
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
processError(err || "失败");
|
||||||
|
delete rowData[btnConfig.actionLoadingField];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成证书
|
||||||
|
const createBook = (rowData) => {
|
||||||
|
let params = { ArtworkUuid: rowData.ArtworkUuid };
|
||||||
|
$request.HTTP.common.createBook(params).then(
|
||||||
|
async (res) => {
|
||||||
|
if (res.status === 0) {
|
||||||
|
processSuccess("操作成功");
|
||||||
|
await downImg(
|
||||||
|
res.data.CertTmUrl,
|
||||||
|
rowData.ArtistName + "-" + rowData.ArtworkName + "-证书"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
processError(res.msg || "失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
processError(err || "失败");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// state.keyNum++;
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
};
|
||||||
|
const handleCloseModal = (needRefresh) => {
|
||||||
|
if (needRefresh) {
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
}
|
||||||
|
state.artworkModalVisible = false;
|
||||||
|
};
|
||||||
|
const handleBatchUploadClose = () => {
|
||||||
|
state.tableConfig.refreshCount++;
|
||||||
|
state.batchUploadModalVisible = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.artwork-table :deep(.ant-table-thead th:first-child) {
|
||||||
|
border-radius: 23px 0px 0 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artwork-table :deep(.ant-table-thead th:last-child) {
|
||||||
|
border-radius: 0 23px 0 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader > .ant-upload {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-select-picture-card i {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-select-picture-card .ant-upload-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
:deep(.ant-switch-handle::before) {
|
||||||
|
background-color: #764cf6;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-switch-handle) {
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
border: 1px #c9c0e2 solid;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-switch-checked {
|
||||||
|
background-color: #764cf6;
|
||||||
|
|
||||||
|
:deep(.ant-switch-handle::before) {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.drag-img .preview-image .ant-image) {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.drag-img .ant-image-img) {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -72,9 +72,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<a-button class="col-10 fl-mt-sm"
|
<a-button class="col-10 fl-mt-sm"
|
||||||
type="primary"
|
|
||||||
shape="round"
|
shape="round"
|
||||||
style="border: none; color: #fff"
|
style="background: #370d9b; border: none; color: #fff"
|
||||||
:loading="state.btnLoading">导出excel</a-button>
|
:loading="state.btnLoading">导出excel</a-button>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
|
|
||||||
@ -113,8 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<a-button style="border: none; color: #fff"
|
<a-button style="background: #370d9b; border: none; color: #fff"
|
||||||
type="primary"
|
|
||||||
class="col-10 fl-mt-sm"
|
class="col-10 fl-mt-sm"
|
||||||
shape="round"
|
shape="round"
|
||||||
:loading="state.btnLoading">导出图片等资源</a-button>
|
:loading="state.btnLoading">导出图片等资源</a-button>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<!-- <quick v-if="state.type === 'quick'" /> -->
|
<quick v-if="state.type === 'quick'" />
|
||||||
<wyf v-if="state.type === 'wyf'" />
|
<wyf v-if="state.type === 'wyf'" />
|
||||||
<storeHouse v-if="state.type === 'storeHouse'" />
|
<storeHouse v-if="state.type === 'storeHouse'" />
|
||||||
<!-- <oa v-if="state.type === 'oa'" /> -->
|
<oa v-if="state.type === 'oa'" />
|
||||||
<artist-artwork-pro v-if="state.type === 'artworkpro'" />
|
<artist-artwork-pro v-if="state.type === 'artworkpro'" />
|
||||||
<customer-service-desk v-if="state.type === 'customerServiceDesk'" />
|
<customer-service-desk v-if="state.type === 'customerServiceDesk'" />
|
||||||
</div>
|
</div>
|
||||||
@ -12,9 +12,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||||
import { ref, reactive, onBeforeMount } from "vue";
|
import { ref, reactive, onBeforeMount } from "vue";
|
||||||
// import quick from "./components/quickIndex.vue";
|
import quick from "./components/quickIndex.vue";
|
||||||
import wyf from "./components/wyfIndex.vue";
|
import wyf from "./components/wyfIndex.vue";
|
||||||
// import oa from "./components/oaWorkbench.vue";
|
import oa from "./components/oaWorkbench.vue";
|
||||||
import artistArtworkPro from "./components/artistartworkpro.vue";
|
import artistArtworkPro from "./components/artistartworkpro.vue";
|
||||||
import { Local } from "@/utils/storage.js";
|
import { Local } from "@/utils/storage.js";
|
||||||
import storeHouse from "./components/storeHouse.vue";
|
import storeHouse from "./components/storeHouse.vue";
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export default {
|
|||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
primary: "#2730D0",
|
primary: "#BA4A8F",
|
||||||
mainColor: "#764CF6",
|
mainColor: "#764CF6",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -63,7 +63,7 @@ export default ({ mode }) => {
|
|||||||
createHtmlPlugin({
|
createHtmlPlugin({
|
||||||
inject: {
|
inject: {
|
||||||
data: {
|
data: {
|
||||||
title: env.VITE_APP_TITLE || "管理系统",
|
title: env.VITE_APP_TITLE || "丰链管理系统",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -110,6 +110,7 @@ export default ({ mode }) => {
|
|||||||
"vue-vendor": ["vue", "vue-router", "pinia"],
|
"vue-vendor": ["vue", "vue-router", "pinia"],
|
||||||
"naive-ui": ["naive-ui"],
|
"naive-ui": ["naive-ui"],
|
||||||
"element-plus": ["element-plus"],
|
"element-plus": ["element-plus"],
|
||||||
|
echarts: ["echarts"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user