mirror of
https://github.com/TangSengDaoDao/TangSengDaoDaoManager
synced 2024-12-14 20:39:59 +00:00
feat: ✨初始化工程
This commit is contained in:
commit
da6329608b
15
.editorconfig
Executable file
15
.editorconfig
Executable file
@ -0,0 +1,15 @@
|
||||
# @see: http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*] # 表示所有文件适用
|
||||
charset = utf-8 # 设置文件字符集为 utf-8
|
||||
end_of_line = lf # 控制换行类型(lf | cr | crlf)
|
||||
insert_final_newline = true # 始终在文件末尾插入一个新行
|
||||
indent_style = space # 缩进风格(tab | space)
|
||||
indent_size = 2 # 缩进大小
|
||||
max_line_length = 130 # 最大行长度
|
||||
|
||||
[*.md] # 表示仅对 md 文件适用以下规则
|
||||
max_line_length = off # 关闭最大行长度限制
|
||||
trim_trailing_whitespace = false # 关闭末尾空格修剪
|
3
.eslintignore
Executable file
3
.eslintignore
Executable file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
public
|
||||
dist
|
49
.eslintrc.js
Executable file
49
.eslintrc.js
Executable file
@ -0,0 +1,49 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es2021: true
|
||||
},
|
||||
parser: 'vue-eslint-parser',
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
// eslint-config-prettier 的缩写
|
||||
'prettier',
|
||||
'vue-global-api'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
},
|
||||
// eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写
|
||||
plugins: ['vue', '@typescript-eslint', 'prettier'],
|
||||
rules: {
|
||||
'@typescript-eslint/ban-ts-ignore': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'no-undef': 'off'
|
||||
},
|
||||
globals: {
|
||||
defineProps: 'readonly',
|
||||
defineEmits: 'readonly',
|
||||
defineExpose: 'readonly',
|
||||
withDefaults: 'readonly'
|
||||
}
|
||||
};
|
24
.gitignore
vendored
Executable file
24
.gitignore
vendored
Executable file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
21
.prettierrc.js
Executable file
21
.prettierrc.js
Executable file
@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
printWidth: 130, // 超过最大值换行
|
||||
tabWidth: 2, // 缩进字节数
|
||||
useTabs: false, // 缩进使用tab,不使用空格
|
||||
semi: true, // 句尾添加分号
|
||||
singleQuote: true, // 使用单引号代替双引号
|
||||
proseWrap: "preserve", // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
|
||||
arrowParens: "avoid", // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
|
||||
bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
|
||||
endOfLine: "auto", // 结尾是 \n \r \n\r auto
|
||||
jsxSingleQuote: false, // 在jsx中使用单引号代替双引号
|
||||
trailingComma: "none", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
|
||||
overrides: [
|
||||
{
|
||||
files: "*.html",
|
||||
options: {
|
||||
parser: "html",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
3
.vscode/extensions.json
vendored
Executable file
3
.vscode/extensions.json
vendored
Executable file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
50
README.md
Executable file
50
README.md
Executable file
@ -0,0 +1,50 @@
|
||||
# dentist-fe
|
||||
* NODE_ENV node环境变量
|
||||
* APP_ENV 应用环境变量
|
||||
|
||||
## 安装
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## 本地开发
|
||||
|
||||
``` sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## 编译
|
||||
|
||||
``` sh
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 本地预览
|
||||
> 先执行编译再执行该命令
|
||||
|
||||
``` sh
|
||||
pnpm serve
|
||||
```
|
||||
## eslint检测
|
||||
|
||||
``` sh
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
## eslint修复
|
||||
|
||||
``` sh
|
||||
pnpm lint:fix
|
||||
```
|
||||
## prettier检测
|
||||
|
||||
```sh
|
||||
pnpm format
|
||||
```
|
||||
|
||||
## Git commit
|
||||
|
||||
``` sh
|
||||
pnpm cz
|
||||
```
|
58
package.json
Executable file
58
package.json
Executable file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "tsdd-control",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"new": "plop",
|
||||
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx,",
|
||||
"lint:prettier": "prettier --write src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"axios": "^1.4.0",
|
||||
"element-plus": "^2.3.7",
|
||||
"mitt": "^3.0.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.36",
|
||||
"pinia-plugin-persistedstate": "^3.1.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"vue": "^3.3.4",
|
||||
"vue-color-kit": "^1.0.5",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/sortablejs": "^1.15.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.5",
|
||||
"@typescript-eslint/parser": "^5.59.5",
|
||||
"@unocss/preset-uno": "^0.51.12",
|
||||
"@unocss/vite": "^0.51.12",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.12.0",
|
||||
"plop": "^3.1.2",
|
||||
"prettier": "^2.8.8",
|
||||
"sass": "^1.62.1",
|
||||
"typescript": "^5.0.4",
|
||||
"unplugin-auto-import": "^0.16.4",
|
||||
"unplugin-vue-components": "^0.25.1",
|
||||
"unplugin-vue-router": "^0.6.4",
|
||||
"unplugin-vue-setup-extend-plus": "^1.0.0",
|
||||
"vite": "^4.4.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html-template": "^1.1.5",
|
||||
"vite-plugin-pages": "^0.31.0",
|
||||
"vite-plugin-vue-devtools": "^0.4.14",
|
||||
"vite-plugin-vue-meta-layouts": "^0.2.2",
|
||||
"vue-global-api": "^0.4.1",
|
||||
"vue-tsc": "^1.6.4"
|
||||
}
|
||||
}
|
13
plop-templates/component/index.hbs
Executable file
13
plop-templates/component/index.hbs
Executable file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 布局 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup{{#if isGlobal}} name="{{ properCase name }}"{{/if}}>
|
||||
// 逻辑代码
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
</style>
|
63
plop-templates/component/prompt.js
Executable file
63
plop-templates/component/prompt.js
Executable file
@ -0,0 +1,63 @@
|
||||
const fs = require('fs');
|
||||
|
||||
function getFolder(path) {
|
||||
const components = [];
|
||||
const files = fs.readdirSync(path);
|
||||
files.forEach(item => {
|
||||
const stat = fs.lstatSync(`${path}/${item}`);
|
||||
if (stat.isDirectory() === true && item !== 'components') {
|
||||
components.push(`${path}/${item}`);
|
||||
components.push(...getFolder(`${path}/${item}`));
|
||||
}
|
||||
});
|
||||
return components;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
description: '创建组件',
|
||||
prompts: [
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'isGlobal',
|
||||
message: '是否为全局组件',
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'path',
|
||||
message: '请选择组件创建目录',
|
||||
choices: getFolder('src/pages'),
|
||||
when: answers => {
|
||||
return !answers.isGlobal;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: '请输入组件名称',
|
||||
validate: v => {
|
||||
if (!v || v.trim === '') {
|
||||
return '组件名称不能为空';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
actions: data => {
|
||||
let path = '';
|
||||
if (data.isGlobal) {
|
||||
path = 'src/components/{{properCase name}}/index.vue';
|
||||
} else {
|
||||
path = `${data.path}/components/{{properCase name}}/index.vue`;
|
||||
}
|
||||
const actions = [
|
||||
{
|
||||
type: 'add',
|
||||
path,
|
||||
templateFile: 'plop-templates/component/index.hbs'
|
||||
}
|
||||
];
|
||||
return actions;
|
||||
}
|
||||
};
|
20
plop-templates/page/index.hbs
Executable file
20
plop-templates/page/index.hbs
Executable file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 布局 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{{#if isFilesystem}}
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
title: 页面标题
|
||||
</route>
|
||||
{{/if}}
|
||||
|
||||
<script lang="ts" setup name="{{ properCase componentName }}">
|
||||
// 逻辑代码
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式
|
||||
</style>
|
59
plop-templates/page/prompt.js
Executable file
59
plop-templates/page/prompt.js
Executable file
@ -0,0 +1,59 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
function getFolder(path) {
|
||||
const components = [];
|
||||
const files = fs.readdirSync(path);
|
||||
files.forEach(item => {
|
||||
const stat = fs.lstatSync(`${path}/${item}`);
|
||||
if (stat.isDirectory() === true && item !== 'components') {
|
||||
components.push(`${path}/${item}`);
|
||||
components.push(...getFolder(`${path}/${item}`));
|
||||
}
|
||||
});
|
||||
return components;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
description: '创建页面',
|
||||
prompts: [
|
||||
{
|
||||
type: 'list',
|
||||
name: 'path',
|
||||
message: '请选择页面创建目录',
|
||||
choices: getFolder('src/pages')
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: '请输入文件名',
|
||||
validate: v => {
|
||||
if (!v || v.trim === '') {
|
||||
return '文件名不能为空';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'isFilesystem',
|
||||
message: '是否为基于文件系统的路由页面',
|
||||
default: false
|
||||
}
|
||||
],
|
||||
actions: data => {
|
||||
const relativePath = path.relative('src/pages', data.path);
|
||||
const actions = [
|
||||
{
|
||||
type: 'add',
|
||||
path: `${data.path}/{{dotCase name}}.vue`,
|
||||
templateFile: 'plop-templates/page/index.hbs',
|
||||
data: {
|
||||
componentName: `${relativePath} ${data.name}`
|
||||
}
|
||||
}
|
||||
];
|
||||
return actions;
|
||||
}
|
||||
};
|
11
plop-templates/store/index.hbs
Executable file
11
plop-templates/store/index.hbs
Executable file
@ -0,0 +1,11 @@
|
||||
const use{{ properCase name }}Store = defineStore(
|
||||
// 唯一ID
|
||||
'{{ camelCase name }}',
|
||||
{
|
||||
state: () => ({}),
|
||||
getters: {},
|
||||
actions: {},
|
||||
},
|
||||
)
|
||||
|
||||
export default use{{ properCase name }}Store
|
27
plop-templates/store/prompt.js
Executable file
27
plop-templates/store/prompt.js
Executable file
@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
description: '创建全局状态',
|
||||
prompts: [
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: '请输入模块名称',
|
||||
validate: v => {
|
||||
if (!v || v.trim === '') {
|
||||
return '模块名称不能为空';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
actions: () => {
|
||||
const actions = [
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/store/modules/{{camelCase name}}.ts',
|
||||
templateFile: 'plop-templates/store/index.hbs'
|
||||
}
|
||||
];
|
||||
return actions;
|
||||
}
|
||||
};
|
6
plopfile.js
Executable file
6
plopfile.js
Executable file
@ -0,0 +1,6 @@
|
||||
module.exports = function (plop) {
|
||||
plop.setWelcomeMessage('请选择需要创建的模式:');
|
||||
plop.setGenerator('page', require('./plop-templates/page/prompt'));
|
||||
plop.setGenerator('component', require('./plop-templates/component/prompt'));
|
||||
plop.setGenerator('store', require('./plop-templates/store/prompt'));
|
||||
};
|
5473
pnpm-lock.yaml
Normal file
5473
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
15
public/index.html
Executable file
15
public/index.html
Executable file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title><%- title %></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 242 KiB |
1
public/vite.svg
Executable file
1
public/vite.svg
Executable file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
53
src/App.vue
Executable file
53
src/App.vue
Executable file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<el-config-provider :locale="locale" :size="assemblySize" :button="buttonConfig">
|
||||
<router-view></router-view>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getBrowserLang } from '@/utils';
|
||||
import { useGlobalStore } from '@/stores/modules/global';
|
||||
import en from 'element-plus/es/locale/lang/en';
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import { LanguageType } from '@/stores/interface';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
// init theme
|
||||
const { initTheme } = useTheme();
|
||||
initTheme();
|
||||
|
||||
const i18n = useI18n();
|
||||
onMounted(() => {
|
||||
const language = globalStore.language ?? getBrowserLang();
|
||||
i18n.locale.value = language;
|
||||
globalStore.setGlobalState('language', language as LanguageType);
|
||||
});
|
||||
|
||||
const locale = computed(() => {
|
||||
if (globalStore.language == 'zh') return zhCn;
|
||||
if (globalStore.language == 'en') return en;
|
||||
return getBrowserLang() == 'zh' ? zhCn : en;
|
||||
});
|
||||
|
||||
const assemblySize = computed(() => globalStore.assemblySize);
|
||||
|
||||
const buttonConfig = reactive({ autoInsertSpace: false });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.vue:hover {
|
||||
filter: drop-shadow(0 0 2em #42b883aa);
|
||||
}
|
||||
</style>
|
10
src/api/basic.ts
Normal file
10
src/api/basic.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 登录
|
||||
export function loginPost(data: any) {
|
||||
return request({
|
||||
url: '/manager/login',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
10
src/api/user.ts
Normal file
10
src/api/user.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import request from '@/utils/axios';
|
||||
|
||||
// 用户列表
|
||||
export function userListGet(params: any) {
|
||||
return request({
|
||||
url: '/manager/user/list',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
BIN
src/assets/heder.png
Normal file
BIN
src/assets/heder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 528 KiB |
3701
src/assets/images/bg.svg
Executable file
3701
src/assets/images/bg.svg
Executable file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 272 KiB |
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 242 KiB |
1
src/assets/vue.svg
Executable file
1
src/assets/vue.svg
Executable file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
After Width: | Height: | Size: 496 B |
37
src/components/HelloWorld.vue
Executable file
37
src/components/HelloWorld.vue
Executable file
@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
defineProps<{ msg: string }>();
|
||||
|
||||
const count = ref(0);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<button type="button" @click="count++">count is {{ count }}</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test HMR
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out
|
||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite starter
|
||||
</p>
|
||||
<p>
|
||||
Install
|
||||
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
|
||||
in your IDE for a better DX
|
||||
</p>
|
||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
||||
<el-button>我是 ElButton</el-button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
12
src/components/SwitchDark/index.vue
Executable file
12
src/components/SwitchDark/index.vue
Executable file
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<el-switch v-model="globalStore.isDark" inline-prompt :active-icon="Sunny" :inactive-icon="Moon" @change="switchDark" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="SwitchDark">
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
import { useGlobalStore } from '@/stores/modules/global';
|
||||
import { Sunny, Moon } from '@element-plus/icons-vue';
|
||||
|
||||
const { switchDark } = useTheme();
|
||||
const globalStore = useGlobalStore();
|
||||
</script>
|
462
src/components/bdWorkflow/index.vue
Executable file
462
src/components/bdWorkflow/index.vue
Executable file
@ -0,0 +1,462 @@
|
||||
<template>
|
||||
<div class="sc-workflow-design">
|
||||
<div class="box-scale">
|
||||
<!-- <node-wrap v-if="nodeConfig" v-model="nodeConfig"></node-wrap> -->
|
||||
<div class="end-node">
|
||||
<div class="end-node-circle"></div>
|
||||
<div class="end-node-text">流程结束</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <use-select v-if="selectVisible" ref="useselect" @closed="selectVisible = false"></use-select> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sc-workflow-design {
|
||||
width: 100%;
|
||||
}
|
||||
.sc-workflow-design .box-scale {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 54.5px 0px;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
min-width: min-content;
|
||||
}
|
||||
|
||||
.sc-workflow-design {
|
||||
.node-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
flex-flow: column wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 0px 50px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.node-wrap-box {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 220px;
|
||||
min-height: 72px;
|
||||
flex-shrink: 0;
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.node-wrap-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0px;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 4px;
|
||||
border-color: rgb(202, 202, 202) transparent transparent;
|
||||
background: #f6f8f9;
|
||||
}
|
||||
.node-wrap-box.start-node:before {
|
||||
content: none;
|
||||
}
|
||||
.node-wrap-box .title {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
padding-left: 16px;
|
||||
padding-right: 30px;
|
||||
border-radius: 4px 4px 0 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.node-wrap-box .title .icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.node-wrap-box .title .close {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
display: none;
|
||||
}
|
||||
.node-wrap-box .content {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
}
|
||||
.node-wrap-box .content .placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.node-wrap-box:hover .close {
|
||||
display: block;
|
||||
}
|
||||
.add-node-btn-box {
|
||||
width: 240px;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.add-node-btn-box:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: -1;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: rgb(202, 202, 202);
|
||||
}
|
||||
.add-node-btn {
|
||||
user-select: none;
|
||||
width: 240px;
|
||||
padding: 20px 0px 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.add-node-btn span {
|
||||
}
|
||||
.add-branch {
|
||||
justify-content: center;
|
||||
padding: 0px 10px;
|
||||
position: absolute;
|
||||
top: -16px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transform-origin: center center;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.branch-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
}
|
||||
.branch-box-wrap {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: center;
|
||||
min-height: 270px;
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.col-box {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
background: #f6f8f9;
|
||||
}
|
||||
.branch-box {
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
min-height: 180px;
|
||||
height: auto;
|
||||
border-bottom: 2px solid #ccc;
|
||||
border-top: 2px solid #ccc;
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.branch-box .col-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 0;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: rgb(202, 202, 202);
|
||||
}
|
||||
.condition-node {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
min-height: 220px;
|
||||
}
|
||||
.condition-node-box {
|
||||
padding-top: 30px;
|
||||
padding-right: 50px;
|
||||
padding-left: 50px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.condition-node-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: rgb(202, 202, 202);
|
||||
}
|
||||
.auto-judge {
|
||||
position: relative;
|
||||
width: 220px;
|
||||
min-height: 72px;
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 4px;
|
||||
padding: 15px 15px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.auto-judge::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0px;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 4px;
|
||||
border-color: rgb(202, 202, 202) transparent transparent;
|
||||
background: rgb(245, 245, 247);
|
||||
}
|
||||
.auto-judge .title {
|
||||
line-height: 16px;
|
||||
}
|
||||
.auto-judge .title .node-title {
|
||||
color: #15bc83;
|
||||
}
|
||||
.auto-judge .title .close {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #999;
|
||||
display: none;
|
||||
}
|
||||
.auto-judge .title .priority-title {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #999;
|
||||
}
|
||||
.auto-judge .content {
|
||||
position: relative;
|
||||
padding-top: 15px;
|
||||
}
|
||||
.auto-judge .content .placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.auto-judge:hover {
|
||||
.close {
|
||||
display: block;
|
||||
}
|
||||
.priority-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.top-left-cover-line,
|
||||
.top-right-cover-line {
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: 50%;
|
||||
background-color: #f6f8f9;
|
||||
top: -2px;
|
||||
}
|
||||
.bottom-left-cover-line,
|
||||
.bottom-right-cover-line {
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: 50%;
|
||||
background-color: #f6f8f9;
|
||||
bottom: -2px;
|
||||
}
|
||||
.top-left-cover-line {
|
||||
left: -1px;
|
||||
}
|
||||
.top-right-cover-line {
|
||||
right: -1px;
|
||||
}
|
||||
.bottom-left-cover-line {
|
||||
left: -1px;
|
||||
}
|
||||
.bottom-right-cover-line {
|
||||
right: -1px;
|
||||
}
|
||||
.end-node {
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
color: rgba(25, 31, 37, 0.4);
|
||||
text-align: left;
|
||||
}
|
||||
.end-node-circle {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: auto;
|
||||
border-radius: 50%;
|
||||
background: #dbdcdc;
|
||||
}
|
||||
.end-node-text {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.auto-judge:hover {
|
||||
.sort-left {
|
||||
display: flex;
|
||||
}
|
||||
.sort-right {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.auto-judge .sort-left {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.auto-judge .sort-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.auto-judge .sort-left:hover,
|
||||
.auto-judge .sort-right:hover {
|
||||
background: #eee;
|
||||
}
|
||||
.auto-judge:after {
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
border-radius: 4px;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
.auto-judge:hover:after {
|
||||
border: 1px solid #3296fa;
|
||||
box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
|
||||
}
|
||||
.node-wrap-box:after {
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
border-radius: 4px;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
.node-wrap-box:hover:after {
|
||||
border: 1px solid #3296fa;
|
||||
box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.tags-list {
|
||||
margin-top: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
.add-node-popover-body {
|
||||
}
|
||||
.add-node-popover-body li {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.add-node-popover-body li i {
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 38px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-node-popover-body li i:hover {
|
||||
border: 1px solid #3296fa;
|
||||
background: #3296fa;
|
||||
color: #fff !important;
|
||||
}
|
||||
.add-node-popover-body li p {
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.node-wrap-drawer__title {
|
||||
padding-right: 40px;
|
||||
}
|
||||
.node-wrap-drawer__title label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.node-wrap-drawer__title label:hover {
|
||||
border-bottom: 1px dashed #409eff;
|
||||
}
|
||||
.node-wrap-drawer__title .node-wrap-drawer__title-edit {
|
||||
color: #409eff;
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.dark .sc-workflow-design {
|
||||
.node-wrap-box,
|
||||
.auto-judge {
|
||||
background: #2b2b2b;
|
||||
}
|
||||
.col-box {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.top-left-cover-line,
|
||||
.top-right-cover-line,
|
||||
.bottom-left-cover-line,
|
||||
.bottom-right-cover-line {
|
||||
background-color: var(--el-bg-color);
|
||||
}
|
||||
.node-wrap-box::before,
|
||||
.auto-judge::before {
|
||||
background-color: var(--el-bg-color);
|
||||
}
|
||||
.branch-box .add-branch {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.end-node .end-node-text {
|
||||
color: #d0d0d0;
|
||||
}
|
||||
.auto-judge .sort-left:hover,
|
||||
.auto-judge .sort-right:hover {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
}
|
||||
</style>
|
53
src/components/bdWorkflow/nodeWrap.vue
Executable file
53
src/components/bdWorkflow/nodeWrap.vue
Executable file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<promoter v-if="nodeConfig.type == 0" v-model="nodeConfig"></promoter>
|
||||
|
||||
<approver v-if="nodeConfig.type == 1" v-model="nodeConfig"></approver>
|
||||
|
||||
<send v-if="nodeConfig.type == 2" v-model="nodeConfig"></send>
|
||||
|
||||
<branch v-if="nodeConfig.type == 4" v-model="nodeConfig">
|
||||
<template v-slot="slot">
|
||||
<node-wrap v-if="slot.node" v-model="slot.node.childNode"></node-wrap>
|
||||
</template>
|
||||
</branch>
|
||||
|
||||
<node-wrap v-if="nodeConfig.childNode" v-model="nodeConfig.childNode"></node-wrap>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import approver from './nodes/approver.vue';
|
||||
import promoter from './nodes/promoter.vue';
|
||||
import branch from './nodes/branch.vue';
|
||||
import send from './nodes/send.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} }
|
||||
},
|
||||
components: {
|
||||
approver,
|
||||
promoter,
|
||||
branch,
|
||||
send
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nodeConfig: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.nodeConfig = val;
|
||||
},
|
||||
nodeConfig(val) {
|
||||
this.$emit('update:modelValue', val);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.nodeConfig = this.modelValue;
|
||||
},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
95
src/components/bdWorkflow/nodes/addNode.vue
Executable file
95
src/components/bdWorkflow/nodes/addNode.vue
Executable file
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="add-node-btn-box">
|
||||
<div class="add-node-btn">
|
||||
<el-popover placement="right-start" :width="270" trigger="click" :hide-after="0" :show-after="0">
|
||||
<template #reference>
|
||||
<el-button type="primary" icon="el-icon-plus" circle></el-button>
|
||||
</template>
|
||||
<div class="add-node-popover-body">
|
||||
<ul>
|
||||
<li>
|
||||
<el-icon style="color: #ff943e" @click="addType(1)"><el-icon-user-filled /></el-icon>
|
||||
<p>审批节点</p>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon style="color: #3296fa" @click="addType(2)"><el-icon-promotion /></el-icon>
|
||||
<p>抄送节点</p>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon style="color: #15bc83" @click="addType(4)"><el-icon-share /></el-icon>
|
||||
<p>条件分支</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
addType(type) {
|
||||
var node = {};
|
||||
if (type == 1) {
|
||||
node = {
|
||||
nodeName: '审核人',
|
||||
type: 1, //节点类型
|
||||
setType: 1, //审核人类型
|
||||
nodeUserList: [], //审核人成员
|
||||
nodeRoleList: [], //审核角色
|
||||
examineLevel: 1, //指定主管层级
|
||||
directorLevel: 1, //自定义连续主管审批层级
|
||||
selectMode: 1, //发起人自选类型
|
||||
termAuto: false, //审批期限超时自动审批
|
||||
term: 0, //审批期限
|
||||
termMode: 1, //审批期限超时后执行类型
|
||||
examineMode: 1, //多人审批时审批方式
|
||||
directorMode: 0, //连续主管审批方式
|
||||
childNode: this.modelValue
|
||||
};
|
||||
} else if (type == 2) {
|
||||
node = {
|
||||
nodeName: '抄送人',
|
||||
type: 2,
|
||||
userSelectFlag: true,
|
||||
nodeUserList: [],
|
||||
childNode: this.modelValue
|
||||
};
|
||||
} else if (type == 4) {
|
||||
node = {
|
||||
nodeName: '条件路由',
|
||||
type: 4,
|
||||
conditionNodes: [
|
||||
{
|
||||
nodeName: '条件1',
|
||||
type: 3,
|
||||
priorityLevel: 1,
|
||||
conditionMode: 1,
|
||||
conditionList: []
|
||||
},
|
||||
{
|
||||
nodeName: '条件2',
|
||||
type: 3,
|
||||
priorityLevel: 2,
|
||||
conditionMode: 1,
|
||||
conditionList: []
|
||||
}
|
||||
],
|
||||
childNode: this.modelValue
|
||||
};
|
||||
}
|
||||
this.$emit('update:modelValue', node);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
204
src/components/bdWorkflow/nodes/approver.vue
Executable file
204
src/components/bdWorkflow/nodes/approver.vue
Executable file
@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<div class="node-wrap-box" @click="show">
|
||||
<div class="title" style="background: #ff943e">
|
||||
<el-icon class="icon"><el-icon-user-filled /></el-icon>
|
||||
<span>{{ nodeConfig.nodeName }}</span>
|
||||
<el-icon class="close" @click.stop="delNode()"><el-icon-close /></el-icon>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(nodeConfig)">{{ toText(nodeConfig) }}</span>
|
||||
<span v-else class="placeholder">请选择</span>
|
||||
</div>
|
||||
</div>
|
||||
<add-node v-model="nodeConfig.childNode"></add-node>
|
||||
<el-drawer v-model="drawer" title="审批人设置" destroy-on-close append-to-body :size="500">
|
||||
<template #header>
|
||||
<div class="node-wrap-drawer__title">
|
||||
<label v-if="!isEditTitle" @click="editTitle">
|
||||
{{ form.nodeName }}
|
||||
<el-icon class="node-wrap-drawer__title-edit"> <el-icon-edit /></el-icon>
|
||||
</label>
|
||||
<el-input
|
||||
v-if="isEditTitle"
|
||||
ref="nodeTitle"
|
||||
v-model="form.nodeName"
|
||||
clearable
|
||||
@blur="saveTitle"
|
||||
@keyup.enter="saveTitle"
|
||||
></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-main style="padding: 0 20px 20px 20px">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="审批人员类型">
|
||||
<el-select v-model="form.setType">
|
||||
<el-option :value="1" label="指定成员"></el-option>
|
||||
<el-option :value="2" label="主管"></el-option>
|
||||
<el-option :value="3" label="角色"></el-option>
|
||||
<el-option :value="4" label="发起人自选"></el-option>
|
||||
<el-option :value="5" label="发起人自己"></el-option>
|
||||
<el-option :value="7" label="连续多级主管"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.setType == 1" label="选择成员">
|
||||
<el-button type="primary" icon="el-icon-plus" round @click="selectHandle(1, form.nodeUserList)">选择人员</el-button>
|
||||
<div class="tags-list">
|
||||
<el-tag v-for="(user, index) in form.nodeUserList" :key="user.id" closable @close="delUser(index)">{{
|
||||
user.name
|
||||
}}</el-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.setType == 2" label="指定主管">
|
||||
发起人的第 <el-input-number v-model="form.examineLevel" :min="1" /> 级主管
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.setType == 3" label="选择角色">
|
||||
<el-button type="primary" icon="el-icon-plus" round @click="selectHandle(2, form.nodeRoleList)">选择角色</el-button>
|
||||
<div class="tags-list">
|
||||
<el-tag v-for="(role, index) in form.nodeRoleList" :key="role.id" type="info" closable @close="delRole(index)">{{
|
||||
role.name
|
||||
}}</el-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.setType == 4" label="发起人自选">
|
||||
<el-radio-group v-model="form.selectMode">
|
||||
<el-radio :label="1">自选一个人</el-radio>
|
||||
<el-radio :label="2">自选多个人</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.setType == 7" label="连续主管审批终点">
|
||||
<el-radio-group v-model="form.directorMode">
|
||||
<el-radio :label="0">直到最上层主管</el-radio>
|
||||
<el-radio :label="1">自定义审批终点</el-radio>
|
||||
</el-radio-group>
|
||||
<p v-if="form.directorMode == 1">直到发起人的第 <el-input-number v-model="form.directorLevel" :min="1" /> 级主管</p>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider></el-divider>
|
||||
<el-form-item label="">
|
||||
<el-checkbox v-model="form.termAuto" label="超时自动审批"></el-checkbox>
|
||||
</el-form-item>
|
||||
<template v-if="form.termAuto">
|
||||
<el-form-item label="审批期限(为 0 则不生效)">
|
||||
<el-input-number v-model="form.term" :min="0" /> 小时
|
||||
</el-form-item>
|
||||
<el-form-item label="审批期限超时后执行">
|
||||
<el-radio-group v-model="form.termMode">
|
||||
<el-radio :label="0">自动通过</el-radio>
|
||||
<el-radio :label="1">自动拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-divider></el-divider>
|
||||
<el-form-item label="多人审批时审批方式">
|
||||
<el-radio-group v-model="form.examineMode">
|
||||
<p style="width: 100%"><el-radio :label="1">按顺序依次审批</el-radio></p>
|
||||
<p style="width: 100%"><el-radio :label="2">会签 (可同时审批,每个人必须审批通过)</el-radio></p>
|
||||
<p style="width: 100%"><el-radio :label="3">或签 (有一人审批通过即可)</el-radio></p>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-main>
|
||||
<el-footer>
|
||||
<el-button type="primary" @click="save">保存</el-button>
|
||||
<el-button @click="drawer = false">取消</el-button>
|
||||
</el-footer>
|
||||
</el-container>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNode from './addNode.vue';
|
||||
|
||||
export default {
|
||||
inject: ['select'],
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} }
|
||||
},
|
||||
components: {
|
||||
addNode
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nodeConfig: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
form: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this |