rcs5.0 commit

This commit is contained in:
wangxinfei
2025-05-19 17:29:51 +08:00
commit e8af49b0f5
720 changed files with 175022 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
require("@erayt/titanOne-electron")
+6
View File
@@ -0,0 +1,6 @@
PORT=8098
appName=app
BUILD_TYPE=M
UMI_UI=none
BROWSER=none
appPath="packages/titanOne-design-pro"
+5
View File
@@ -0,0 +1,5 @@
build/*.js
src/assets
public
dist
babel.config.js
+208
View File
@@ -0,0 +1,208 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
// it is base on https://github.com/vuejs/eslint-config-vue
rules: {
'no-debugger': 'on',
// 'prettier/prettier': 'warn', // prettier 检测到的标红展示
'vue/max-attributes-per-line': 2,
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/name-property-casing': ['error', 'PascalCase'],
'vue/no-v-html': 'off',
'vue/multi-word-component-names': 'off',
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true,
}], // 要求箭头函数之前之后有空格
'block-spacing': [2, 'always'], // 强制在代码块中开括号前和闭括号后有空格
'brace-style': [2, '1tbs', {
'allowSingleLine': true,
}], // 大括号风格要求
'camelcase': [0, {
'properties': 'always',
}], // 强制属性名称为驼峰风格
'comma-dangle': [2, 'always-multiline'], // 要求或禁止使用拖尾逗号,这里 当最后一个元素或属性与闭括号 ] 或 } 在 不同的行时,要求使用拖尾逗号;当在 同一行时,禁止使用拖尾逗号
'comma-spacing': [2, {
'before': false,
'after': true,
}], // 禁止在逗号前使用空格,要求在逗号后使用空格
'comma-style': [2, 'last'], // 要求逗号放在数组元素、对象属性或变量声明之后,且在同一行
'constructor-super': 2, // 派生类中的构造函数必须调用 super()。非派生类的构造函数不能调用 super()JavaScript 引擎将引发一个运行时错误该规则检查是否有一个有效的 super() 调用。
'curly': [2, 'multi-line'], // 强制所有控制语句使用一致的括号风格
'dot-location': [2, 'property'], // 点操作符和属性放在同一行。
'eol-last': 2, // 强制使用换行 (LF)
'eqeqeq': ['error', 'always', { 'null': 'ignore' }], // 强制在任何情况下都使用 === 和 !== (你选择对 null 做忽略处理])
'generator-star-spacing': [2, {
'before': true,
'after': true,
}], // 强制 generator 函数中 * 号周围使用一致的空格
/* function loadData (error, data) {
if (error) {
console.log(error.stack);
}
doSomething();
*/
'handle-callback-err': [2, '^(err|error)$'], // 期望当你在 Node.js 中使用回调模式时,你将处理错误
'indent': [2, 2, {
'SwitchCase': 1,
}], // 强制使用 2空格缩进,强制 switch 语句中的 case 子句的缩进级别为警告
'jsx-quotes': [2, 'prefer-single'], // 强制所有不包含单引号的 JSX 属性值使用单引号
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true,
}], // 强制在对象字面量的属性中键和值之间使用一致的间距,beforeColon禁止在对象字面量的键和冒号之间存在空格,afterColon要求在对象字面量的冒号和值之间存在至少有一个空格
'keyword-spacing': [2, {
'before': true,
'after': true,
}], // 要求在关键字之前和之后至少有一个空格
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false,
}], // newIsCap 要求调用 new 操作符时有首字母大小的函数,capIsNew允许调用首字母大写的函数时没有 new 操作符。
'new-parens': 2, // 强制调用无参构造函数时有圆括号
'no-array-constructor': 2, // 该规则禁止使用 Array 构造函数
'no-caller': 2, // 禁止使用 arguments.caller 和 arguments.callee来阻止使用不推荐的和次优化的代码
// 'no-console': process.env.NODE_ENV === 'production' ? 2 : 0, // 禁用 console
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'no-class-assign': 2, // 不允许修改类声明的变量
'no-cond-assign': 2, // 禁止条件表达式中出现赋值操作符
'no-const-assign': 2, // 禁止修改 const 声明的变量
'no-control-regex': 0, // 允许在正则表达式中使用控制字符
'no-delete-var': 2, // 禁止删除变量,delete
// 'no-dupe-args': 2, // 禁止 function 定义中出现重名参数
// 'no-dupe-class-members': 2, // 禁止类成员中出现重复的名称
// 'no-dupe-keys': 2, // 禁止对象字面量中出现重复的 key
'no-duplicate-case': 2, // 禁止出现重复的 case 标签
'no-empty-character-class': 2, // 禁止在正则表达式中使用空字符集
'no-empty-pattern': 2, // 禁止使用空解构模式 ,错误var {} = foo;var {a: {}} = foo; 正确 var {a = {}} = foo;
'no-eval': 2, // 禁用 eval()
'no-ex-assign': 2, // 禁止对 catch 子句中的异常重新赋值。
'no-extend-native': 2, // 禁止扩展原生类型
'no-extra-bind': 2, // 禁止不必要的 .bind() 调用
'no-extra-boolean-cast': 2, // 禁止不必要的布尔转换
'no-extra-parens': [2, 'functions'], // 只在 函数表达式周围禁止不必要的圆括号
'no-fallthrough': 2, // 禁止 case 语句落空
'no-floating-decimal': 2, // 消除浮动小数点,并且,当数值的小数点之前或之后缺少数字时,该规则将发出警告
'no-func-assign': 2, // 禁止对 function 声明重新赋值
'no-implied-eval': 2, // 禁止使用类似 eval() 的方法
'no-inner-declarations': [2, 'functions'], // 禁止 function 声明出现在嵌套的语句块中
'no-invalid-regexp': 2, // 禁止 RegExp 构造函数中存在无效的正则表达式字符串
'no-irregular-whitespace': 2, // 禁止不规则的空白
'no-iterator': 2, // 禁用 __iterator__ 属性
'no-label-var': 2, // 不允许标签与变量同名
/** * "allowLoop" (boolean,默认是 false) - 如果这个选项被设置为 true,该规则忽略循环语句中的标签。
"allowSwitch" (boolean,默认是 false) - 如果这个选项被设置为 true,该规则忽略 switch 语句中的标签 */
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false,
}], // 禁用标签语句
'no-lone-blocks': 2, // 禁用不必要的嵌套块
'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
'no-multi-spaces': 2, // 禁止出现多个空格
'no-multi-str': 2, // 禁止使用多行字符串
'no-multiple-empty-lines': [2, {
'max': 1,
}], // 禁止出现多个空行,最多一个
'no-native-reassign': 2, // 禁止对原生对象或只读的全局对象进行赋值
'no-negated-in-lhs': 2, // 禁止对关系运算符的左操作数使用否定操作符
'no-new-object': 2, // 禁用 Object 的构造函数
'no-new-require': 2, // 禁止调用 require 时使用 new 操作符
'no-new-symbol': 2, // 禁止 Symbolnew 操作符和 new 一起使用
'no-new-wrappers': 2, // 禁止对 StringNumber 和 Boolean 使用 new 操作符
'no-obj-calls': 2, // 禁止把全局对象作为函数调用
'no-octal': 2, // 禁用八进制字面量
'no-octal-escape': 2, // 禁止在字符串中使用八进制转义序列
'no-path-concat': 2, // 禁止对 __dirname 和 __filename 进行字符串连接
'no-proto': 2, // 禁用 __proto__ 属性
'no-redeclare': 2, // 禁止多次声明同一变量
'no-regex-spaces': 2, // 禁止正则表达式字面量中出现多个空格
'no-return-assign': [2, 'except-parens'], // return 后禁止出现赋值语句,除非使用括号把它们括起来。
'no-self-assign': 2, // 禁止自我赋值
'no-self-compare': 2, // 禁止自身比较
'no-sequences': 2, // 禁用逗号操作符
'no-shadow-restricted-names': 2, // 禁止将标识符定义为受限的名字
'no-spaced-func': 2, // 要求或禁止在函数标识符和其调用之间有空格
'no-sparse-arrays': 2, // 禁用稀疏数组,稀疏数组包括很多空位置,经常是由于在数组字面量中使用多个逗号造成的
'no-this-before-super': 2, // 禁止在构造函数中,在调用 super() 之前使用 this 或 super
'no-throw-literal': 2, // 禁止抛出异常字面量
'no-trailing-spaces': 2, // 禁用行尾空格
'no-undef': 2, // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到
'no-undef-init': 2, // 禁止将变量初始化为 undefined
'no-unexpected-multiline': 2, // 禁止出现令人困惑的多行表达式
'no-unmodified-loop-condition': 2, // 禁用一成不变的循环条件
'no-unneeded-ternary': [2, {
'defaultAssignment': false,
}], // 禁止条件表达式作为默认的赋值模式
'no-unreachable': 2, // 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
'no-unsafe-finally': 2, // 禁止在 finally 语句块中出现控制流语句
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none',
}], // 禁止未使用过的变量,'vars': 'all' 检测所有变量,包括全局环境中的变量。'args': 'none'不检查参数
'no-useless-call': 2, // 禁止不必要的 .call() 和 .apply()
'no-useless-computed-key': 2, // 禁止在对象中使用不必要的计算属性
'no-useless-constructor': 2, // 禁用不必要的构造函数
'no-useless-escape': 0, // 允许不必要的转义字符
'no-whitespace-before-property': 2, // 禁止属性前有空白
'no-with': 2, // 禁用 with 语句
'one-var': [2, {
'initialized': 'never',
}], // 强制函数中的变量在一起声明或分开声明, 要求每个作用域的初始化的变量有多个变量声明
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before',
},
}], // 强制操作符使用一致的换行符,"after" 要求把换行符放在操作符后面覆盖对指定的操作的全局设置、 默认配置为 "after", { "overrides": { "?": "before", ":": "before" } }
'padded-blocks': [2, 'never'], // 要求或禁止块内填充
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true,
}], // 强制使用一致的反勾号、双引号或单引号, single 要求尽可能地使用单引号
'semi': [2, 'always'], // (默认) 要求在语句末尾使用分号
'semi-spacing': [2, {
'before': false,
'after': true,
}], // 这个是默认选项,它强制分号之后有空格,禁止分号之前有空格。
'space-before-blocks': [2, 'always'], // 强制在块之前使用一致的空格
'space-before-function-paren': [2, 'never'], // 允许在 function的左括号之前不使用空格
'space-in-parens': [2, 'never'], // (默认) 强制圆括号内没有空格
'space-infix-ops': 2, // 要求操作符周围有空格
/*
words - 适用于单词类一元操作符,例如:new、delete、typeof、void、yield
nonwords - 适用于这些一元操作符: -、+、--、++、!、!!
*/
'space-unary-ops': [2, {
'words': true,
'nonwords': false,
}], // 比如 new 操作符之后禁用空格,++ 操作左右要求有空格。
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','],
}], // 要求在注释前有空白, "always"// 或 /* 必须跟随至少一个空白,"markers"的值是一个字符串形式的数组,这些字符串也就是块级注释的标记,例如一个额外的 /,被用来表示是由 doxygen、vsdoc 等系统读取的文档,这些系统必须有额外的字符。 不管第一个参数是 "always" 还是 "never"、"markers"数组都会起作用。。
'template-curly-spacing': [2, 'never'], // 禁止花括号内出现空格。
'use-isnan': 2, // 要求调用 isNaN()检查 NaN,该规则禁止与 ‘NaN’ 的比较。
'valid-typeof': 2, // 强制 typeof 表达式与有效的字符串进行比较
'wrap-iife': [2, 'any'], // 需要把立即执行的函数包裹起来,any 强制总是包裹,但允许其它风格
'yield-star-spacing': [2, 'both'], // 强制在 yield* 表达式中 * 周围使用空格
/**
* Yoda 条件被如此命名,是因为在条件判断中字面量在先而变量在第二的位置。例如,以下是 Yoda 条件:
if ("red" === color) {
// ...
}
*/
'yoda': [2, 'never'], // "never" 那么比较绝,不能是一个 Yoda 条件
'prefer-const': 2, // 如果一个变量不会被重新赋值,最好使用const进行声明。
'object-curly-spacing': [2, 'always', {
objectsInObjects: false,
}], // 强制在花括号中使用一致的空格."objectsInObjects": false 禁止以对象元素开始或结尾的对象的花括号中有空格 (当第一个选项为 always 时生效)
'array-bracket-spacing': [2, 'never'], // 禁止在数组括号内出现空格
},
};
+9
View File
@@ -0,0 +1,9 @@
/*
* @Date: 2019-12-10 14:27:16
* @Author: Scm <chengqiuhua@erayt.com>
* @Copyright: 2015-2019 Erayt, Inc.
* @Description: If you have some questions, please contact: chengqiuhua@erayt.com.
*/
export default {
cjs: { type: 'babel', lazy: true },
};
+2
View File
@@ -0,0 +1,2 @@
import '@erayt/titanOne-vue/lib/main.js';
import '../src/main.js';
+21
View File
@@ -0,0 +1,21 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
],
plugins: ['transform-remove-strict-mode',
[
'@babel/transform-runtime', {
absoluteRuntime: false,
}],
'@babel/plugin-proposal-optional-chaining',  // 可选链 ?.
'@babel/plugin-proposal-nullish-coalescing-operator', // 空值合并 ??
],
env: {
development: {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
plugins: ['dynamic-import-node'],
},
},
};
+1
View File
@@ -0,0 +1 @@
module.exports = {};
+3
View File
@@ -0,0 +1,3 @@
import routes from '../src/router/index'
export default routes;
+1
View File
@@ -0,0 +1 @@
[0421/114546.067:ERROR:directory_reader_win.cc(43)] FindFirstFile +C:\Users\15869\AppData\Local\Chrome\User Data\Crashpad\attachments: 系统找不到指定的路径。 (0x3)
+24
View File
@@ -0,0 +1,24 @@
# ESlint使用说明
## 1. vscode配置
1. 安装拓展ESlint
2. vscode点击设置
2. 打开setting.json文件编辑
3. 输入配置
```
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
},
"vue"
],
"eslint.autoFixOnSave": true
```
4. 保存重启
+4
View File
@@ -0,0 +1,4 @@
@import "@erayt/titanOne-vue/lib/styles/variable.scss";
@import "@erayt/titanOne-vue/lib/styles/mixinThemify.scss";
@import "@erayt/titanOne-vue/lib/themes/index.scss"
+19
View File
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}
+9
View File
@@ -0,0 +1,9 @@
module.exports = function (app, Mock) {
app.post('/test', (req, res) => {
res.json({
code: '0',
result: {
}
})
})
}
+249
View File
@@ -0,0 +1,249 @@
[
{
"bankId": "00001",
"desktopContent": [
{
"id": "page-600162",
"singleTrigger": false,
"workBenchName": "menu.forexDesktop",
"workBenchWidget": [
{
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 10,
"customCls": "customCls",
"items": [
{
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 6,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 6,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 3,
"customCls": "customCls",
"menus": [
{
"id": 24
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 3,
"customCls": "customCls",
"menus": [
{
"id": 25
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 3,
"customCls": "customCls",
"menus": [
{
"id": 26
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 3,
"customCls": "customCls",
"menus": [
{
"id": 27
}
]
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 6,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"customCls": "customCls",
"menus": [
{
"id":29
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"customCls": "customCls",
"menus": [
{
"id":31
}
]
}
]
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 6,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 7,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"customCls": "customCls",
"menus": [
{
"id":32
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"customCls": "customCls",
"menus": [
{
"id":33
}
]
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 5,
"customCls": "customCls",
"menus": [
{
"id":34
}
]
}
]
}
]
},
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 2,
"customCls": "customCls",
"items": [
{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 2,
"customCls": "customCls",
"menus": [
{
"id": 28
}
]
},{
"title": "",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 10,
"customCls": "customCls",
"menus": [
{
"id":30
}
]
}
]
}
]
}
],
"desktopId": "des-744859",
"desktopName": "交易员桌面",
"desktopNum": "1",
"logonId": "wangkai"
}
]
File diff suppressed because it is too large Load Diff
+318
View File
@@ -0,0 +1,318 @@
[
{
"id": "page-600160",
"singleTrigger": false,
"workBenchName": "menu.tradeUserDesktop",
"workBenchWidget": [
{
"title": "投资组合",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "row",
"pro": 1,
"customCls": "customCls",
"menus": [
{
"id": 18,
"tabId": "tab-10000"
}
]
},
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 5,
"name": "row-4",
"customCls": "customCls",
"items": [
{
"title": "日成交交易查询",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 9,
"name": "col-9",
"customCls": "customCls",
"menus": [
{
"id": 11,
"tabId": "tab-100111"
}
]
},
{
"title": "提醒事项",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 3,
"name": "col-3",
"customCls": "customCls",
"menus": [
{
"id": 12,
"tabId": "tab-9011"
}
]
}
]
},
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 3,
"customCls": "customCls",
"items": [
{
"title": "市场数据",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"name": "col-6",
"customCls": "customCls",
"menus": [
{
"id": 15,
"tabId": "tab-100111"
}
]
},
{
"title": "资产状况",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"name": "col-6",
"customCls": "customCls",
"menus": [
{
"id": 19,
"tabId": "tab-9011"
}
]
}
]
},
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 3,
"customCls": "customCls",
"items": [
{
"title": "风险头寸",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"name": "col-6",
"customCls": "customCls",
"menus": [
{
"id": 13,
"tabId": "tab-100111"
}
]
},
{
"title": "损益变动",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 6,
"name": "col-6",
"customCls": "customCls",
"menus": [
{
"id": 16,
"tabId": "tab-9011"
}
]
}
]
}
]
},
{
"id": "page-600161",
"singleTrigger": false,
"workBenchName": "menu.managementOperationWorkbench",
"workBenchWidget": [
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 5,
"customCls": "customCls",
"items": [
{
"title": "日成交交易查询",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 10,
"name": "col-9",
"customCls": "customCls",
"styles": {
"width": "75%"
},
"menus": [
{
"id": 17,
"tabId": "tab-100111"
}
]
},
{
"title": "提醒事项",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 2,
"name": "col-3",
"styles": {
"width": "25%"
},
"customCls": "customCls",
"menus": [
{
"id": 12,
"tabId": "tab-9011"
}
]
}
]
},
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 4,
"customCls": "customCls",
"items": [
{
"title": "结算发报",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 10,
"customCls": "customCls",
"styles": {
"width": "75%"
},
"menus": [
{
"id": 20,
"tabId": "tab-100112"
}
]
},
{
"title": "收付审批",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 2,
"customCls": "customCls",
"styles": {
"width": "25%"
},
"menus": [
{
"id": 21,
"tabId": "tab-100114"
}
]
}
]
},
{
"showTab": false,
"showTitle": false,
"showButton": false,
"type": "row",
"pro": 3,
"customCls": "customCls",
"items": [
{
"title": "当日全量",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 5,
"customCls": "customCls",
"styles": {
"width": "37.5%"
},
"menus": [
{
"id": 23,
"tabId": "tab-100120",
"dateKey": "T"
}
]
},
{
"title": "当日全量",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 5,
"customCls": "customCls",
"styles": {
"width": "37.5%"
},
"menus": [
{
"id": 23,
"tabId": "tab-100121",
"dateKey": "T+0"
}
]
},
{
"title": "接口通讯情况",
"showTab": false,
"showTitle": false,
"showButton": true,
"type": "col",
"pro": 2,
"customCls": "customCls",
"styles": {
"width": "25%"
},
"menus": [
{
"id": 22,
"tabId": "tab-100115"
}
]
}
]
}
]
}
]
+67
View File
@@ -0,0 +1,67 @@
{
"name": "rcs_5.0",
"description": "description",
"authors": "author",
"version": "1.0.0",
"main": "pathToMain",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"build:electron": "cross-env IDE=electron vue-cli-service build",
"start:electron": "cross-env IDE=electron vue-cli-service serve",
"start:main:dev": " electron ./.electron.js"
},
"dependencies": {
"@erayt/language": "^1.0.0",
"@erayt/titanOne-component-vue": "^1.0.0",
"@erayt/titanOne-kernel": "^1.0.0",
"@erayt/titanOne-observer": "^5.0.0",
"@erayt/titanOne-vue": "^0.1.1",
"axios": "0.27.2",
"core-js": "3.31.0",
"dayjs": "^1.10.7",
"echarts": "5.3.3",
"element-ui": "2.15.13",
"js-cookie": "3.0.1",
"lodash": "^4.6.1",
"nprogress": "0.2.0",
"vue": "2.7.14",
"vue-i18n": "8.22.2",
"vue-router": "3.6.5",
"vuedraggable": "2.24.3",
"vuex": "3.6.2"
},
"devDependencies": {
"@babel/core": "7.21.8",
"@babel/eslint-parser": "7.21.8",
"@erayt/element-customize-themes": "^2.15.19",
"@erayt/eui2-themes": "3.2.32",
"@erayt/eui3.5-customize-themes": "^1.0.9",
"@erayt/titanOne-dll": "^3.2.33",
"@erayt/titanOne-electron": "^3.1.69",
"@erayt/titanOne3.0-electron-login": "^3.1.65",
"@erayt/titanOne3.0-web-login": "^3.0.0",
"@erayt/vue-cli-plugin-mock": "^1.0.0",
"@erayt/vue-cli-plugin-titanOne": "^1.0.0",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"babel-plugin-transform-remove-strict-mode": "0.0.2",
"cache-loader": "4.1.0",
"copy-webpack-plugin": "11.0.0",
"cross-env": "^7.0.3",
"eslint": "7.32.0",
"eslint-plugin-vue": "8.7.1",
"path-browserify": "1.0.1",
"prettier": "2.8.7",
"sass": "1.63.4",
"sass-loader": "12.6.0",
"sass-resources-loader": "2.2.5",
"stylus-loader": "6.2.0",
"vue-dynamic": "^1.0.57",
"vue-dynamic-theme": "^1.0.9",
"vue-template-compiler": "2.7.14"
}
}
+316
View File
@@ -0,0 +1,316 @@
## 安装依赖说明
- 切换源,使用http://192.168.30.37:7001/ 此为临时源,如果源有问题请联系楼呈祥
- 全局安装lerna 最新版本,旧版本针对本地依赖引用有问题
- titanOne3.5-core中执行yarn
- 在titanOne3.5-core 目录中执行lerna bootstrap
- titanOne-design-pro-vue 中执行yarn serve
## 菜单和桌面数据配置说明
菜单数据配置在router下的menus.js文件中,桌面数据配置在router下的desktops.js文件中,结构同之前。
## 文件结构说明
## 项目依赖说明
### "core-js": "^3.8.3",
- 它是JavaScript标准库的polyfill
- 它尽可能的进行模块化,让你能选择你需要的功能
- 它可以不污染全局空间
- 它和babel高度集成,可以对core-js的引入进行最大程度的优化
### "element-ui": "^2.15.13",
elementui 库,TODO: 未来替换为公司库
### "js-cookie": "^3.0.1",
设置cookie,使用方式如下
- 设置cookie
```
Cookies.set('name', 'value', { expires: 7, path: '' }); //7天过期
Cookies.set('name', { foo: 'bar' }); //设置一个json
```
- 读取cookie
```
Cookies.get('name'); //获取cookie
Cookies.get(); //读取所有的cookie
```
- 删除cookie
```
Cookies.remove('name'); //删除cookie时必须是同一个路径。
```
### "nprogress": "^0.2.0",
主要用于页面跳转时展示的顶部进度条
### "vue": "^2.6.14",≠
### "vue-router": "^3.5.3",
### "vuedraggable": "^2.24.3",
### "vuex": "^3.6.2",
### "vue-i18n": "8.22.2",
## 集成ecas|egate login
1. 引入titanOne login
```
yarn add @erayt/titanOne3.0-web-login@^3.0.0 --dev
```
2. 引入 titanOne login的依赖包
```
"@erayt/titanOne3.0-web-login": "^3.0.0",
"@erayt/eui3.5-customize-themes":"^1.0.9",
"@erayt/titanOne-dll":"^3.2.33",
"@erayt/eui2-themes":"3.2.32"
```
login跳转为静态页面跳转,依赖不需要在dependency中
3. 引入@erayt/loginSub
```
yarn add @erayt/loginSub --dev
```
这个包主要是为了配置dev环境,登录页需要配置的配置内容
引入后,我们需要将对应的配置内容注入到vue.config.js中
```
devServer: {
port: 9527,
...loginConfig.devServerConfig
},
```
其他依赖配置
```
...
chainWebpack: (config) => {
// 添加login 模块
loginConfig.chainConfig(config);
// 配置sourcemap
const needSourcemap = isDev? 'source-map': false
config.devtool(needSourcemap);
...
```
再次启动yarn serve
## 引入ecas相关api
比如消息盒子,比如自定义存储,ecas权限功能,webnet,通讯加密等
因为相关功能都是以Eui相关api开发的,所以若需要使用上述某一功能,则需要引入Eui底层相关包,
### 引入titanOne-combination
这个包是底层api的封装工具包,主要为一些基础函数做封装
```
yarn add @erayt/titanOne-combination
```
### 引入Observer
如果要实现ipc通讯,那么需要引入observer包
```
yarn add @erayt/titanOne-observer
```
## 多语言配置
文件路径为 src/lang/locale/
需要分别配置en 或者zh里面的index.js 文件
### 框架语言包
若使用框架组件,那么需要引入框架语言包,@erayt/language
### 路径说明
|- lang // 多语言文件夹
|--- index.js // 添加了集成框架语言包代码
|--- locale
|----- en
|------- index.js // 英文翻译文件
|------- message.js // 错误提示的英文文件
|----- zh
|------- index.js // 中文翻译文件
|------- message.js // 错误提示英文文件
### 如何使用框架多语言包
在lang/index.js文件中需要调整如下代码
```
// 如果需要使用框架的多语言文件,则需要引入@erayt/language包
import lang, {mergeToolTip} from '@erayt/language'
Vue.use(VueI18n);
const messages = {
en: {
...lang.en,
...customEN,
},
zh: {
...lang.zh,
...customZH
}
}
// 引入框架的错误码后,需要调用mergeToolTip进行合并数据,此数据会加入到Eui.Messager.messages中
mergeToolTip({
en_US: toolTipEn,
zh_CN: toolTipZh
})
```
还需要调用mergeToolTip 函数,因为框架在后台错误码处理时有特殊的规则,所以错误码需要写在message.js中,如果不引入框架的请求,则全部写在index.js中即可。
### 在Vue中如何使用
多语言使用规则,参照 Vue-i18n的使用规则
- 语法: $t('属性名')
```
<p>{{ $t('message.hello') }}</p>
// 输出 <p>您好!</p>
```
- 可变参数
```
// zh 语言文件中这样配置
{
name: '名字 {0} {1}'
}
```
使用时只要传入参数即可,参数可以是对象也可以是数组
```
// array
$t('name', ['Jack', 'Job'])
// object
$t('name', {'0':'Jack', '1': 'Job'])
```
vue-i18n 还提供了金额格式化:$n,日期格式化 $d ,等功能,这里就不说明了,
- 默认语言设置
如果en语言包中不存在的内容,使用zh中的值
```
const i18n = new VueI18n({
locale: 'en',
fallbackLocale: 'zh',
messages
})
```
- 切换语言
```
// 不使用框架
this.$i18n.local = zh |en
// 使用框架,则只需使用框架的切换语言按钮即可
```
### 框架错误码解析
## 多主题
### 动态换肤
### 多套主题包
本地存放多套主题,两者有不同的命名空间,如写两套主题,一套叫 custom-theme ,一套叫 custom-eui-theme custom-theme 主题都在一个 .custom-theme的命名空间下,我们动态的在 body 上 add .custom-theme ; remove .custom-theme。
## 升级vue-cli 修改部分
vue-cli 内置了css-loader, style-loader, scss-loader, 所以配置文件中不再需要配置
项目中有使用css-module的变量导出,供组件使用css变量,所以需要将 element-variables.scss中的导出变量移到element-variables.module.scss
同时,在main.js中,需要引入element-variables.scss文件
## 网络库使用
- @erayt/networkManager
## service 插件化开发
## 低代码开发说明
项目中默认安装低代码的组件的依赖包,vue-dynamic
- route.config.js,引用相应路由
```
import VueDynamic from 'vue-dynamic'
export default [
{
path: '/dynamic',
component: VueDynamic.Viewer
}
];
```
- menu.json中配置菜单,在对应attributes属性中设置path,pageName和projectName
```
"attributes": {
"client": {
"loadMode": "component",
"path": "/dynamic", // 路由
"extraParams":{
"pageName":"dataImport", // 对应页面英文名称
"projectName":"sds" // 对应项目名称
}
}
}
```
- main.js中注册插件
```
import rxd from 'vue-dynamic';
import 'vue-dynamic/dist/Dynamic.css';
rxd.titan.init();
```
- vue.config.js中配置低代码服务地址
```
'/phoenix': {
target: 'http://192.168.193.94:8011',
},
```
- 安装低代码样式包 vue-dynamic-theme
```
main.js中引入
import "vue-dynamic-theme"
```
- 注册多语言
1. lang/index.js中引入低代码多语言包
```
import Vuedynamic from 'vue-dynamic'
const messages = {
en_US: {
...其它多语言文件,
...Vuedynamic.lang.en // 低代码英文
},
zh_CN: {
...其它多语言文件,
...Vuedynamic.lang.zh // 低代码中文
}
}
export default messages;
```
2.main.js引入多语言
```
import { messages } from "./lang";
service.registerApplication("myproject", {
routeConfig,
getters,
modules,
i18n: messages, // 注册多语言
});
```
+570
View File
@@ -0,0 +1,570 @@
import request from '@/http/request.js';
import {
callGetFile,
} from '@/http/api.call';
// 使用示例: const res = await this.$apis.pubQueryComboxData(data)
// 交易簿记/ 现金流预览
export const getdcsPreviewCashflows = (data) => {
return request({
url: 'dcs/flow/previewCashflows.action',
method: 'post',
data,
});
};
// 交易簿记/ 新增获取id
export const getdcsDealNo = (data) => {
return request({
url: 'dcs/dcs/getDealNo.action',
method: 'post',
data,
});
};
// 交易簿记/ 操作风险
export const getdcsdealActionFlow = (data) => {
return request({
url: 'dcs/flow/dealActionFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 快速查询列表
export const getdealQueryqueryPage = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryPage.action',
method: 'post',
data,
});
};
// 交易簿记/ 现金流 现金流
export const getdcsQueryCashFlowList = (data) => {
return request({
url: 'dcs/dcs/queryCashFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 现金流 定盘
export const getdcsQueryObserveList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryObserveList.action',
method: 'post',
data,
});
};
// 交易簿记/ 提交
export const handledcsdealActionFlow = (data) => {
return request({
url: 'dcs/flow/dealActionFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 是否节假日
export const getdcsisHolidayByUnderlying = (data) => {
return request({
url: 'dcs/dcs/isHolidayByUnderlying.action',
method: 'post',
data,
});
};
// 交易簿记/ 按钮权限
export const getdcsdoGetFolderAuth = (data) => {
return request({
url: 'dcs/dcs/doGetFolderAuth.action',
method: 'post',
data,
});
};
// 交易簿记/账户信息
export const getDCSqueryCptyName = (data) => {
return request({
url: 'dcs/dcs/queryCptyName.action',
method: 'post',
data,
});
};
// 交易簿记/交易对手
export const getDCSqueryFolderById = (data) => {
return request({
url: 'dcs/dcs/queryFolderById.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDCSdoEvaluation = (data) => {
return request({
url: 'dcs/dcs/doEvaluation.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDCSgetSystemDate = (data) => {
return request({
url: 'dcs/dcs/getSystemDate.action',
method: 'post',
data,
});
};
// 交易簿记
export const querySettle = (data) => {
return request({
url: 'settle6-web/query_settle.action',
method: 'post',
data,
});
};
// 交易簿记
export const getdealQueryQueryList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryList.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDcsOptions = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data,
});
};
// 交易簿记 获取即期汇率
export const getdcsPairInfo = (data) => {
return request({
url: 'dcs/dcs/getPairInfo.action',
method: 'post',
data,
});
};
// 交易簿记 获取起息日
export const getdcsValueDate = (data) => {
return request({
url: 'dcs/dcs/getValueDate.action',
method: 'post',
data,
});
};
// 参数审批-统计接口
export const getParamsStaList = (data) => {
return request({
url: 'eflow/flow/doQueryNumber.action',
method: 'post',
data,
});
};
// 参数审批-待处理接口
export const getParamsList = (data) => {
return request({
url: 'eflow/flow/doQueryPageWaiting.action',
method: 'post',
data,
});
};
// 参数审批-已处理接口
export const getFinishList = (data) => {
return request({
url: 'eflow/flow/doQueryPageFinish.action',
method: 'post',
data,
});
};
// 参数审批-已拒绝接口
export const getRefuseList = (data) => {
return request({
url: 'eflow/flow/doQueryPageRefuse.action',
method: 'post',
data,
});
};
// 参数审批-我发起接口
export const getInitiateList = (data) => {
return request({
url: 'eflow/flow/doQueryPageMine.action',
method: 'post',
data,
});
};
// 参数审批-批量审核
export const batchCheck = (data) => {
return request({
url: 'eflow/flow/approveBatch.action',
method: 'post',
data,
});
};
// 参数审批-审批状态字典
export const getApproveData = (data) => {
return request({
url: 'eflow/flow/queryComboxData.action',
method: 'post',
data,
});
};
// 参数审批-获取流程操作按钮
export const getUserFlowOperations = (data) => {
return request({
url: 'eflow/flow/getUserFlowOperations.action',
method: 'post',
data,
});
};
// 参数审批-获取审批流程日志
export const getFlowLogBySerialNoRepeat = (data) => {
return request({
url: 'eflow/flow/getFlowLogBySerialNoRepeat.action',
method: 'post',
data,
});
};
// 参数审批-获取变更数据
export const getFlowCompareData = (data) => {
return request({
url: 'pub/pub/eflowCompareData.action', // ?dealNo=174194761864137
method: 'post',
data,
});
};
// 参数审批-退回发起下拉获取
export const getBackList = (data) => {
return request({
url: 'eflow/flow/queryComboxData.action',
method: 'post',
data,
});
};
// 参数审批-退回发起提交
export const backSubmit = (data) => {
return request({
url: 'eflow/flow/approve.action',
method: 'post',
data,
});
};
// 存续期事件管理 列表查询
export const getEventList = (data) => {
return request({
url: 'dcs/dcs/queryPage.action',
method: 'post',
data,
});
};
// 存续期事件管理 撤销
export const batchRevoke = (data) => {
return request({
url: '',
method: 'post',
data,
});
};
// 发送异常管理 补发
export const batchSendAgain = (data) => {
return request({
url: 'dcs/pub/sendExceptionReissue.action',
method: 'post',
data,
});
};
// 发送异常管理 报文内容保存
export const messageSave = (data) => {
return request({
url: 'dcs/dcs/doUpdate.action',
method: 'post',
data,
});
};
// queryParam.moduleName:"pubSendExceptionManager","queryParam.domain":"{"id":"20250327_1df210eb-a865-4a6b-accf-8db487d2508c","messageContent":{}}
// 获取数据源-通用
export const queryComboxData = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data: data,
});
};
// 获取数据源-债券检索
export const queryBondList = (data) => {
return request({
url: 'dcs/dcs/queryBondList.action',
method: 'post',
data: data,
});
};
// 获取数据源-交易对手
export const queryCptyPage = (data) => {
return request({
url: 'dcs/dcs/queryCptyPage.action',
method: 'post',
data: data,
});
};
// 获取数据源-账户/账户组
export const queryFolderQueryAuthList = (data) => {
return request({
url: 'dcs/dcs/queryFolderQueryAuthList.action',
method: 'post',
data: data,
});
};
// 自定义交易查询接口
export const dcsQueryPage = (data) => {
return request({
url: 'dcs/dcs/queryPage.action',
method: 'post',
data: data,
});
};
// 自定义交易查询结果-产品表头
export const queryFieldByProduct = (data) => {
return request({
url: 'dcs/dcs/queryFieldByProduct.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-获取自定义查询组合
export const queryList = (data) => {
return request({
url: 'dcs/dcs/queryList.action',
method: 'post',
data: data,
});
};
//
export const pubqueryList = (data) => {
return request({
url: 'pub/pub/queryList.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-保存自定义查询组合
export const doSave = (data) => {
return request({
url: 'dcs/dcs/doSave.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-删除自定义查询组合
export const doDelete = (data) => {
return request({
url: 'dcs/dcs/doDelete.action',
method: 'post',
data: data,
});
};
// 自定义交易查询结果-账户详情
export const getFolderInfo = (data) => {
return request({
url: 'dcs/dcs/getFolderInfo.action',
method: 'post',
data: data,
});
};
// 导出
export const exportData = (data) => {
return request({
url: 'dcs/baseQuery/exportAll.action',
method: 'post',
// headers: { 'Content-Type': 'multipart/form-data' },
data,
});
};
// 下载模板
export const downLoadTemplate = callGetFile('pub/baseData/downloadTemplate.action');
// export const downLoadTemplate = (data) => {
// return axios.request({
// url: 'pub/baseData/downloadTemplate.action',
// method: 'get',
// data,
// });
// };
// 导入校验
export const importCheck = (data) => {
return request({
url: 'pub/baseData/importCheck.action',
method: 'post',
// headers: { 'Content-Type': 'multipart/form-data' },
data,
});
};
// 确认导入
export const importData = (data) => {
return request({
url: 'pub/baseData/importData.action',
method: 'post',
data,
});
};
// 查询导入结果
export const getProcess = (data) => {
return request({
url: 'pub/baseData/queryResult.action',
method: 'post',
data,
});
};
export const getPosOptions = (data) => {
return request({
url: 'pos/pos/queryComboxData.action',
method: 'post',
data,
});
};
// 外汇账户明细字典
export const getForList = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action?codifierGrpCodes=static_currencies,FolderStatus,AccountingSection,HomeType',
method: 'get',
data,
});
};
// 自定义交易查询结果-账户详情
export const queryDealOperateLog = (data) => {
return request({
url: 'dcs/dcs/queryDealOperateLog.action',
method: 'post',
data: data,
});
};
// 交易模块查询历史版本
export const getCompareVersionLog = (data) => {
return request({
url: 'dcs/getCompareVersionLog.action',
method: 'get',
data,
});
};
// 公共模块查询历史版本详细信息
export const compareVersionLog = (data) => {
return request({
url: 'dcs/compareVersionLog.action',
method: 'post',
data,
});
};
// 获取历史版本版本号列表
export const versionsLogCombox = (data) => {
return request({
url: 'dcs/versionsLogCombox.action',
method: 'post',
data,
});
};
// 获取历史头寸配置
export const getOneQueryComponent = (data) => {
return request({
url: 'pos/pub/getOneQueryComponent.action',
method: 'post',
data,
});
};
// 获取登录账户
export const getUserInfo = (data) => {
return request({
url: 'pos/pos/getUserInfo.action',
method: 'post',
data,
});
};
// 获取登录用户信息
export const findPreferenceDtoByUserIdAndType = (data) => {
return request({
url: 'pos/pos/findPreferenceDtoByUserIdAndType.action',
method: 'post',
data,
});
};
// 历史头寸获取时间
export const getPosSystemDate = (data) => {
return request({
url: 'pos/baseRcs/getSystemDate.action',
method: 'post',
data,
});
};
// 交易主要信息
export const getQueryMainInfo = (data) => {
return request({
url: 'dcs/dcs/queryMainInfo.action',
method: 'post',
data,
});
};
// 交易派生信息
export const getQueryDeriveInfo = (data) => {
return request({
url: 'dcs/dcs/queryDeriveInfo.action',
method: 'post',
data,
});
};
// 交易审批信息
export const getQueryAuditInfo = (data) => {
return request({
url: 'dcs/dcs/queryAuditInfo.action',
method: 'post',
data,
});
};
// 交易收据模板
export const queryDealReceipt = (data) => {
return request({
url: 'dcs/dcs/queryDealReceipt.action',
method: 'post',
data,
});
};
// 交易跟踪记录
export const queryDealTrace = (data) => {
return request({
url: 'dcs/dcs/queryDealTrace.action',
method: 'post',
data,
});
};
// 交易收据数据
export const queryDealQueryList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryList.action',
method: 'post',
data,
});
};
+21
View File
@@ -0,0 +1,21 @@
// 导入所有模块api
const modules = require.context('./', true, /.js/);
const apis = {};
modules.keys().forEach(item => {
if (item !== './index.js') {
let api = modules(item);
if (api.default) {
api = { ...api, ...api.default };
delete api.default;
}
for (const key in api) {
if (apis[key]) { // 请求方法名不能重复
throw new Error(`error: api method repeat!!! method---->${key}`);
} else {
apis[key] = api[key];
}
}
}
});
export default apis;
+118
View File
@@ -0,0 +1,118 @@
import request from '@/http/request.js';
/**
* 评级信息列表获取
* @returns
*/
export const msdQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action',
method: 'post',
data,
});
};
/** 评级目标 */
export const msdQueryComboxData = (data) => {
return request({
url: 'mds/baseRcs/queryComboxData.action',
method: 'post',
data,
});
};
/** 交易对手评级 */
export const mdsFindAllCptysi18n = () => {
return request({
url: 'mds/sdscounterparty/findAllCptysi18n.action',
method: 'post',
});
};
/** 发行人评级 */
export const mdsFindAllIssuerCptysi18n = () => {
return request({
url: 'mds/sdscounterparty/findAllIssuerCptysi18n.action',
method: 'post',
});
};
/** 债券评级 */
export const mdsFindAllbonds = () => {
return request({
url: 'mds/sdsbonds/findAllbonds.action',
method: 'post',
});
};
/** 国家评级 */
export const mdsFindAllCountries = () => {
return request({
url: 'mds/sdsthirdparty/findAllCountries.action',
method: 'post',
});
};
/** 担保人评级 */
export const mdsFindAllGuarantees = () => {
return request({
url: 'mds/sdscounterparty/findAllGuarantees.action',
method: 'post',
});
};
/** 评级机构 */
export const msdFindRatingAgenciesByContainsTermRating = () => {
return request({
url: 'mds/sdsrating/findRatingAgenciesByContainsTermRating.action',
method: 'post',
});
};
export const msdFindRatingByAgencyIdAndTerm = (data) => {
return request({
url: 'mds/sdsrating/findRatingByAgencyIdAndTerm.action',
method: 'post',
data,
});
};
export const msdHistoryQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action?queryParam.moduleName=mdsTargetRatingsHistory',
method: 'post',
data,
});
};
// 数据集查询
export const msdFindAllDataSet = () => {
return request({
url: 'mds/mds/findAllDataSet.action',
method: 'post',
});
};
// 数据类型
export const msdQueryComboxDataAction = (data) => {
return request({
url: `mds/baseRcs/queryComboxData.action?codifierGrpCodes=${data}`,
method: 'post',
});
};
// 数据集管理列表
export const msdBaseQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action?queryParam.moduleName=mdsDataRicSetService',
method: 'post',
data,
});
};
// 数据源
export const mdsFindAllDataSource = () => {
return request({
url: 'mds/mds/findAllDataSource.action',
method: 'post',
});
};
+220
View File
@@ -0,0 +1,220 @@
import request from '@/http/request.js';
// 获取数据源-通用
export const pmsQueryComboxData = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data: data
})
}
// 查询数据源PMS服务
export const queryComboxDataPMS = (data) => {
return request({
url: 'pms/baseRcs/queryComboxData.action',
method: 'post',
data: data
})
}
// 获取系统日期
export const getSystemDate = (data) => {
return request({
url: 'pub/desktop/getSystemDate.action',
method: 'post',
data
})
}
// pms服务获取系统日期
export const getSystemDatePMS = (data) => {
return request({
url: 'pms/getSystemDate.action',
method: 'post',
data
})
}
// 期权计算器-获取日期
export const getValueDate = (data) => {
return request({
url: 'dcs/dcs/getValueDate.action',
method: 'post',
data
})
}
// pms服务获取日期
export const getValueDatePMS = (data) => {
return request({
url: 'pms/getValueDate.action',
method: 'post',
data
})
}
// 期权计算器-获取日期间隔
export const getbetweenDays = (data) => {
return request({
url: 'dcs/dcs/getbetweenDays.action',
method: 'post',
data
})
}
// pms服务查询日期间隔
export const getbetweenDaysPMS = (data) => {
return request({
url: 'pms/getbetweenDays.action',
method: 'post',
data
})
}
// 期权计算器-获取金额
export const getPairInfo = (data) => {
return request({
url: 'dcs/dcs/getPairInfo.action',
method: 'post',
data
})
}
// pms服务查询金额
export const getPairInfoPMS = (data) => {
return request({
url: 'pms/getPairInfo.action',
method: 'post',
data
})
}
// 期权计算器-获取QuantoPairs
export const getQuantoPairs = (data) => {
return request({
url: 'dcs/dcs/getQuantoPairs.action',
method: 'post',
data
})
}
// 期权计算器-获取Model
export const getModelByParam = (data) => {
return request({
url: 'pms/getModelByParam.action',
method: 'post',
data
})
}
// 期权计算器-获取市场数据
export const findMarketInfoForAnalysis = (data) => {
return request({
url: 'mds/mds/findMarketInfoForAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-获取市场价格
export const findMarketPriceForValAnalysis = (data) => {
return request({
url: 'mds/findMarketPriceForValAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-保存市场价格
export const saveMarketPriceForValAnalysis = (data) => {
return request({
url: 'mds/saveMarketPriceForValAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-估值
export const simulationValuationAnalysis = (data) => {
return request({
url: 'mds/simulationValuationAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-试算
export const simulateDealWithVlParam = (data) => {
return request({
url: 'mds/simulateDealWithVlParam.action',
method: 'post',
data
})
}
// 期权计算器-获取定价列表
export const createObs = (data) => {
return request({
url: 'pms/createObs.action',
method: 'post',
data
})
}
// 期权计算器-获取执行价
export const getPoints = (data) => {
return request({
url: 'dcs/dcs/getPoints.action',
method: 'post',
data
})
}
// pms服务查询执行价
export const getPointsPMS = (data) => {
return request({
url: 'pms/getForwardRate.action',
method: 'post',
data
})
}
// 逐笔估值结果查询-获取数据源
export const baseRcsQueryComboxData = (data) => {
return request({
url: 'pms/baseRcs/queryComboxData.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-获取列表
export const pmsQueryPage = (data) => {
return request({
url: 'pms/pmsone/queryPage.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-重估值
export const reDoCalcFont = (data) => {
return request({
url: 'pms/pms/reDoCalcFont.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-查看估值中间数据
export const pmsFindPmsResultDetail = (data) => {
return request({
url: 'pms/pmsFindPmsResultDetailNew.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
+59
View File
@@ -0,0 +1,59 @@
import request from '@/http/request.js';
import { callPostFormFile, callPostAll, callPostFile } from '@/http/api.call';
// 外汇即期单货币头寸
export const getForeignCurrencyList = (data) => {
return request({
url: 'pos/equery.action',
method: 'post',
data,
});
};
// 导出
export const exportForData = callPostFormFile('/pos/equery.action');
// pv01头寸
export const getPv01DataList = (data) => {
return request({
url: 'pos/pos/pv01DataQuery.action',
method: 'post',
data,
});
};
// 外汇现金流查询
export const getTtCashFlowList = (data) => {
return request({
url: 'pos/pos/queryTtCashFlow.action',
method: 'post',
data,
});
};
// 期限列设置
export const queryTerm = (data) => {
return request({
url: 'pos/pos/queryTerm.action',
method: 'post',
data,
});
};
// 获取现金流期限列设置
export const findPreferenceDtoByUserId = (data) => {
return request({
url: 'pos/pos/findPreferenceDtoByUserIdAndType.action',
method: 'post',
data,
});
};
// 保存期限列设置
export const updatePreferenceDto = (data) => {
return request({
url: 'pos/pos/updatePreferenceDto.action',
method: 'post',
data,
});
};
+103
View File
@@ -0,0 +1,103 @@
import request from '@/http/request.js';
// 使用示例: const res = await this.$apis.pubQueryComboxData(data)
// 获取数据源-公共
export const pubQueryComboxData = (data) => {
return request({
url: 'pub/pub/queryComboxData.action',
method: 'post',
data,
});
};
// 货币-查询接口
export const queryPage = (data) => {
return request({
url: 'pub/pub/queryPage.action',
method: 'post',
data,
});
};
// 公共模块查询历史版本
export const getCompareVersion = (data) => {
return request({
url: 'pub/pub/getCompareVersion.action',
method: 'get',
data,
});
};
// 公共模块查询历史版本详细信息
export const compare = (data) => {
return request({
url: 'pub/compare.action',
method: 'post',
data,
});
};
// 获取历史版本版本号列表
export const versionsCombox = (data) => {
return request({
url: 'pub/pub/versionsCombox.action',
method: 'post',
data,
});
};
// 货币查询id
export const findStaticDataId = (data) => {
return request({
url: 'pub/sdsthirdparty/findStaticDataId.action',
method: 'post',
data,
});
};
// 节假日查询
export const queryAll = (data) => {
return request({
url: 'pub/pub/queryAll.action',
method: 'post',
data,
});
};
// 公共新增接口
export const pubDoSave = (data) => {
return request({
url: 'pub/pub/doSave.action',
method: 'post',
data,
});
};
// 公共编辑接口
export const pubDoUpdate = (data) => {
return request({
url: 'pub/pub/doUpdate.action',
method: 'post',
data,
});
};
// 接入数据管理-左侧树形数据
export const getPacketTree = (data) => {
return request({
url: 'pub/pub/getPacketTree.action',
method: 'post',
data,
});
};
// 获取数据源-交易对手
export const queryCptyPage1 = (data) => {
return request({
url: 'dcs/dcs/queryCptyPage.action',
method: 'post',
data: data,
});
};
+198
View File
@@ -0,0 +1,198 @@
import request from '@/http/request.js';
// 消息提醒获取数据
export const queryNormalMessageList = (data) => {
return request({
url: 'pub/desktop/queryNormalMessageList.action',
method: 'post',
data,
});
};
// 获取异常消息处理
export const queryErrorMessageList = (data) => {
return request({
url: 'pub/desktop/queryErrorMessageList.action',
method: 'post',
data,
});
};
// 获取日成交交易table数据
export const getDailyTradeQuery = (data) => {
return request({
url: 'dcs/dailyTradeQuery.action',
method: 'post',
data,
});
};
// 获取风险头寸图表数据
export const queryRiskPositionByType = (data) => {
return request({
url: 'rsk-new/rsk/queryRiskPositionByType.action',
method: 'post',
data,
});
};
// 获取市场风险图表数据
export const getMarketRiskChart = (data) => {
return request({
url: 'pub/desktop/getMarketRiskChart',
method: 'post',
data,
});
};
// 获取信用额度图表数据
export const getCreditLimitChart = (data) => {
return request({
url: 'pub/desktop/getCreditLimitChart',
method: 'post',
data,
});
};
// 获取授权占比图表数据
export const getEmpowerChart = (data) => {
return request({
url: 'pub/desktop/getEmpowerChart',
method: 'post',
data,
});
};
// 获取市场数据货币对价格
export const queryPriceList = (data) => {
return request({
url: 'mds/desktop/queryPriceList.action',
method: 'post',
data,
});
};
// 获取货币对对应的历史数据
export const queryHistoryPriceList = (data) => {
return request({
url: 'mds/hisprice/client/desktop/queryHistoryPriceList.action',
method: 'post',
data,
});
};
// 获取损益变动图表数据
export const queryPlByType = (data) => {
return request({
url: 'rsk-new/rsk/queryPlByType.action',
method: 'post',
data,
});
};
// 获取账户列表数据
export const queryAllFolderInfo = (data) => {
return request({
url: 'pub/desktop/getFolderTree.action',
method: 'post',
data,
});
};
// 获取损益货币
export const getFolderPlCcy = (data) => {
return request({
url: 'pub/desktop/getFolderPlCcy.action',
method: 'post',
data,
});
};
// 获取资产情况表格数据
export const queryPlChartByType = (data) => {
return request({
url: 'pos/queryPlChartByType.action',
method: 'post',
data,
});
};
// 获取资产情况期限数据
export const queryTermCash = (data) => {
return request({
url: 'dcs/queryCashFlowSumAmount.action',
method: 'post',
data,
});
};
// 获取超限事件表格数据
export const getOverEventChart = (data) => {
return request({
url: 'pub/desktop/queryEventList.action',
method: 'post',
data,
});
};
// 获取交易审批table数据
export const queryCommunicationMessage = (data) => {
return request({
url: 'pub/desktop/queryCommunicationMessage.action',
method: 'post',
data,
});
};
// 获取结算发报table数据
export const queryPaymentFlowProcessList = (data) => {
return request({
url: 'settle6-web/desktop/queryPaymentFlowProcessList.action',
method: 'post',
data,
});
};
// 获取收付审批列表
export const queryPaymentFlowAuditList = (data) => {
return request({
url: 'settle6-web/desktop/queryPaymentFlowAuditList.action',
method: 'post',
data,
});
};
// 获取接口通讯列表
export const getApiStatus = (data) => {
return request({
url: 'settle6-web/desktop/getApiStatus.action',
method: 'post',
data,
});
};
// 获取当日全量数据
export const queryDealAuditNum = (data) => {
return request({
url: 'settle6-web/desktop/queryDealAuditNum.action',
method: 'post',
data,
});
};
// 获取机构
export const querySiteList = (data) => {
return request({
url: 'pub/desktop/querySiteList.action',
method: 'post',
data,
});
};
// 日成交交易
export const queryDealPage = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryPage.action',
method: 'post',
data,
});
};
+539
View File
@@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
File diff suppressed because it is too large Load Diff
+297
View File
@@ -0,0 +1,297 @@
@font-face {
font-family: "iconfont"; /* Project id 4894712 */
/* Color fonts */
src:
url('iconfont.woff2?t=1746004916794') format('woff2'),
url('iconfont.woff?t=1746004916794') format('woff'),
url('iconfont.ttf?t=1746004916794') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-copy:before {
content: "\e79e";
}
.icon-email:before {
content: "\e78a";
}
.icon-calendar:before {
content: "\e7ed";
}
.icon-folder-add:before {
content: "\e80d";
}
.icon-folder:before {
content: "\e7f9";
}
.icon-layers:before {
content: "\e83c";
}
.icon-dollar:before {
content: "\e8b6";
}
.icon-monitor:before {
content: "\e985";
}
.icon-link1:before {
content: "\e789";
}
.icon-information-query:before {
content: "\e90b";
}
.icon-batch-search:before {
content: "\e977";
}
.icon-a-marketrisk:before {
content: "\e72f";
}
.icon-trending-up:before {
content: "\e7ae";
}
.icon-trending-down:before {
content: "\e7a9";
}
.icon-liedingzhi:before {
content: "\e787";
}
.icon-research:before {
content: "\e8b2";
}
.icon-bank-card-fill:before {
content: "\e9c6";
}
.icon-fund-fill:before {
content: "\e9b4";
}
.icon-term-exposure-fill:before {
content: "\e994";
}
.icon-bank-card:before {
content: "\e7e5";
}
.icon-date-time:before {
content: "\e7ef";
}
.icon-doc-edit:before {
content: "\e80c";
}
.icon-chart-combo:before {
content: "\e886";
}
.icon-account:before {
content: "\e8c4";
}
.icon-bank:before {
content: "\e8bd";
}
.icon-trend1:before {
content: "\e8b9";
}
.icon-credit-risk:before {
content: "\e98c";
}
.icon-market-risk:before {
content: "\e98a";
}
.icon-operational-risk:before {
content: "\e988";
}
.icon-chaxunguanli:before {
content: "\e783";
}
.icon-toucunguanli:before {
content: "\e784";
}
.icon-jisuangongjv:before {
content: "\e786";
}
.icon-home:before {
content: "\e731";
}
.icon-refresh1:before {
content: "\e72c";
}
.icon-delete:before {
content: "\e78c";
}
.icon-filter:before {
content: "\e790";
}
.icon-save:before {
content: "\e785";
}
.icon-search:before {
content: "\e788";
}
.icon-user1:before {
content: "\e7d9";
}
.icon-batch-failure:before {
content: "\e96f";
}
.icon-components:before {
content: "\e965";
}
.icon-application1-fill:before {
content: "\e9cd";
}
.icon-edit-fill:before {
content: "\e9bd";
}
.icon-home-fill:before {
content: "\e9ba";
}
.icon-rmb-fill:before {
content: "\e9a5";
}
.icon-parameter-fill:before {
content: "\e99f";
}
.icon-yijujue:before {
content: "\e781";
}
.icon-yitongguo:before {
content: "\e780";
}
.icon-daishenpi:before {
content: "\e782";
}
.icon-yituihui:before {
content: "\e77f";
}
.icon-more2:before {
content: "\e729";
}
.icon-remind:before {
content: "\e712";
}
.icon-add:before {
content: "\e79f";
}
.icon-double_right:before {
content: "\e7d0";
}
.icon-double-left:before {
content: "\e7d6";
}
.icon-down:before {
content: "\e7cb";
}
.icon-down1:before {
content: "\e7bd";
}
.icon-left1:before {
content: "\e7c6";
}
.icon-left:before {
content: "\e7a8";
}
.icon-right:before {
content: "\e7c1";
}
.icon-right1:before {
content: "\e7b8";
}
.icon-attention:before {
content: "\e867";
}
.icon-fail:before {
content: "\e868";
}
.icon-help:before {
content: "\e869";
}
.icon-success:before {
content: "\e86b";
}
.icon-caution:before {
content: "\e86c";
}
.icon-info:before {
content: "\e86d";
}
.icon-EUR:before {
content: "\e633";
}
.icon-meiguoguoqi:before {
content: "\e610";
}
.icon-zhongguoguoqi:before {
content: "\e632";
}
File diff suppressed because one or more lines are too long
+499
View File
@@ -0,0 +1,499 @@
{
"id": "4894712",
"name": "RCS-5.0",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "40904218",
"name": "copy",
"font_class": "copy",
"unicode": "e79e",
"unicode_decimal": 59294
},
{
"icon_id": "40904240",
"name": "email",
"font_class": "email",
"unicode": "e78a",
"unicode_decimal": 59274
},
{
"icon_id": "40904567",
"name": "calendar",
"font_class": "calendar",
"unicode": "e7ed",
"unicode_decimal": 59373
},
{
"icon_id": "40904659",
"name": "folder-add",
"font_class": "folder-add",
"unicode": "e80d",
"unicode_decimal": 59405
},
{
"icon_id": "40904674",
"name": "folder",
"font_class": "folder",
"unicode": "e7f9",
"unicode_decimal": 59385
},
{
"icon_id": "40905078",
"name": "layers",
"font_class": "layers",
"unicode": "e83c",
"unicode_decimal": 59452
},
{
"icon_id": "40906322",
"name": "dollar",
"font_class": "dollar",
"unicode": "e8b6",
"unicode_decimal": 59574
},
{
"icon_id": "40907675",
"name": "monitor",
"font_class": "monitor",
"unicode": "e985",
"unicode_decimal": 59781
},
{
"icon_id": "40904247",
"name": "link1",
"font_class": "link1",
"unicode": "e789",
"unicode_decimal": 59273
},
{
"icon_id": "40907403",
"name": "information-query",
"font_class": "information-query",
"unicode": "e90b",
"unicode_decimal": 59659
},
{
"icon_id": "40907711",
"name": "batch-search",
"font_class": "batch-search",
"unicode": "e977",
"unicode_decimal": 59767
},
{
"icon_id": "32459477",
"name": "market-risk",
"font_class": "a-marketrisk",
"unicode": "e72f",
"unicode_decimal": 59183
},
{
"icon_id": "40904404",
"name": "trending-up",
"font_class": "trending-up",
"unicode": "e7ae",
"unicode_decimal": 59310
},
{
"icon_id": "40904409",
"name": "trending-down",
"font_class": "trending-down",
"unicode": "e7a9",
"unicode_decimal": 59305
},
{
"icon_id": "44054370",
"name": "liedingzhi",
"font_class": "liedingzhi",
"unicode": "e787",
"unicode_decimal": 59271
},
{
"icon_id": "40906335",
"name": "research",
"font_class": "research",
"unicode": "e8b2",
"unicode_decimal": 59570
},
{
"icon_id": "40907821",
"name": "bank-card-fill",
"font_class": "bank-card-fill",
"unicode": "e9c6",
"unicode_decimal": 59846
},
{
"icon_id": "40907834",
"name": "fund-fill",
"font_class": "fund-fill",
"unicode": "e9b4",
"unicode_decimal": 59828
},
{
"icon_id": "40907871",
"name": "term-exposure-fill",
"font_class": "term-exposure-fill",
"unicode": "e994",
"unicode_decimal": 59796
},
{
"icon_id": "40904437",
"name": "bank-card",
"font_class": "bank-card",
"unicode": "e7e5",
"unicode_decimal": 59365
},
{
"icon_id": "40904566",
"name": "date-time",
"font_class": "date-time",
"unicode": "e7ef",
"unicode_decimal": 59375
},
{
"icon_id": "40904652",
"name": "doc-edit",
"font_class": "doc-edit",
"unicode": "e80c",
"unicode_decimal": 59404
},
{
"icon_id": "40905885",
"name": "chart-combo",
"font_class": "chart-combo",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "40906317",
"name": "account",
"font_class": "account",
"unicode": "e8c4",
"unicode_decimal": 59588
},
{
"icon_id": "40906320",
"name": "bank",
"font_class": "bank",
"unicode": "e8bd",
"unicode_decimal": 59581
},
{
"icon_id": "40906329",
"name": "trend1",
"font_class": "trend1",
"unicode": "e8b9",
"unicode_decimal": 59577
},
{
"icon_id": "40907667",
"name": "credit-risk",
"font_class": "credit-risk",
"unicode": "e98c",
"unicode_decimal": 59788
},
{
"icon_id": "40907670",
"name": "market-risk",
"font_class": "market-risk",
"unicode": "e98a",
"unicode_decimal": 59786
},
{
"icon_id": "40907672",
"name": "operational-risk",
"font_class": "operational-risk",
"unicode": "e988",
"unicode_decimal": 59784
},
{
"icon_id": "44024976",
"name": "chaxunguanli",
"font_class": "chaxunguanli",
"unicode": "e783",
"unicode_decimal": 59267
},
{
"icon_id": "44024975",
"name": "toucunguanli",
"font_class": "toucunguanli",
"unicode": "e784",
"unicode_decimal": 59268
},
{
"icon_id": "44024977",
"name": "jisuangongjv",
"font_class": "jisuangongjv",
"unicode": "e786",
"unicode_decimal": 59270
},
{
"icon_id": "40903893",
"name": "home",
"font_class": "home",
"unicode": "e731",
"unicode_decimal": 59185
},
{
"icon_id": "40903911",
"name": "refresh1",
"font_class": "refresh1",
"unicode": "e72c",
"unicode_decimal": 59180
},
{
"icon_id": "40904228",
"name": "delete",
"font_class": "delete",
"unicode": "e78c",
"unicode_decimal": 59276
},
{
"icon_id": "40904232",
"name": "filter",
"font_class": "filter",
"unicode": "e790",
"unicode_decimal": 59280
},
{
"icon_id": "40904238",
"name": "save",
"font_class": "save",
"unicode": "e785",
"unicode_decimal": 59269
},
{
"icon_id": "40904242",
"name": "search",
"font_class": "search",
"unicode": "e788",
"unicode_decimal": 59272
},
{
"icon_id": "40904447",
"name": "user1",
"font_class": "user1",
"unicode": "e7d9",
"unicode_decimal": 59353
},
{
"icon_id": "40907708",
"name": "batch-failure",
"font_class": "batch-failure",
"unicode": "e96f",
"unicode_decimal": 59759
},
{
"icon_id": "40907732",
"name": "components",
"font_class": "components",
"unicode": "e965",
"unicode_decimal": 59749
},
{
"icon_id": "40907812",
"name": "application1-fill",
"font_class": "application1-fill",
"unicode": "e9cd",
"unicode_decimal": 59853
},
{
"icon_id": "40907832",
"name": "edit-fill",
"font_class": "edit-fill",
"unicode": "e9bd",
"unicode_decimal": 59837
},
{
"icon_id": "40907837",
"name": "home-fill",
"font_class": "home-fill",
"unicode": "e9ba",
"unicode_decimal": 59834
},
{
"icon_id": "40907851",
"name": "rmb-fill",
"font_class": "rmb-fill",
"unicode": "e9a5",
"unicode_decimal": 59813
},
{
"icon_id": "40907853",
"name": "parameter-fill",
"font_class": "parameter-fill",
"unicode": "e99f",
"unicode_decimal": 59807
},
{
"icon_id": "44024793",
"name": "yijujue",
"font_class": "yijujue",
"unicode": "e781",
"unicode_decimal": 59265
},
{
"icon_id": "44024789",
"name": "yitongguo",
"font_class": "yitongguo",
"unicode": "e780",
"unicode_decimal": 59264
},
{
"icon_id": "44024790",
"name": "daishenpi",
"font_class": "daishenpi",
"unicode": "e782",
"unicode_decimal": 59266
},
{
"icon_id": "44024751",
"name": "yituihui",
"font_class": "yituihui",
"unicode": "e77f",
"unicode_decimal": 59263
},
{
"icon_id": "40903907",
"name": "more2",
"font_class": "more2",
"unicode": "e729",
"unicode_decimal": 59177
},
{
"icon_id": "40903914",
"name": "remind",
"font_class": "remind",
"unicode": "e712",
"unicode_decimal": 59154
},
{
"icon_id": "40904214",
"name": "add",
"font_class": "add",
"unicode": "e79f",
"unicode_decimal": 59295
},
{
"icon_id": "40904365",
"name": "double_right",
"font_class": "double_right",
"unicode": "e7d0",
"unicode_decimal": 59344
},
{
"icon_id": "40904369",
"name": "double-left",
"font_class": "double-left",
"unicode": "e7d6",
"unicode_decimal": 59350
},
{
"icon_id": "40904373",
"name": "down",
"font_class": "down",
"unicode": "e7cb",
"unicode_decimal": 59339
},
{
"icon_id": "40904376",
"name": "down1",
"font_class": "down1",
"unicode": "e7bd",
"unicode_decimal": 59325
},
{
"icon_id": "40904380",
"name": "left1",
"font_class": "left1",
"unicode": "e7c6",
"unicode_decimal": 59334
},
{
"icon_id": "40904383",
"name": "left",
"font_class": "left",
"unicode": "e7a8",
"unicode_decimal": 59304
},
{
"icon_id": "40904386",
"name": "right",
"font_class": "right",
"unicode": "e7c1",
"unicode_decimal": 59329
},
{
"icon_id": "40904392",
"name": "right1",
"font_class": "right1",
"unicode": "e7b8",
"unicode_decimal": 59320
},
{
"icon_id": "40905242",
"name": "attention",
"font_class": "attention",
"unicode": "e867",
"unicode_decimal": 59495
},
{
"icon_id": "40905243",
"name": "fail",
"font_class": "fail",
"unicode": "e868",
"unicode_decimal": 59496
},
{
"icon_id": "40905244",
"name": "help",
"font_class": "help",
"unicode": "e869",
"unicode_decimal": 59497
},
{
"icon_id": "40905246",
"name": "success",
"font_class": "success",
"unicode": "e86b",
"unicode_decimal": 59499
},
{
"icon_id": "40905247",
"name": "caution",
"font_class": "caution",
"unicode": "e86c",
"unicode_decimal": 59500
},
{
"icon_id": "40905248",
"name": "info",
"font_class": "info",
"unicode": "e86d",
"unicode_decimal": 59501
},
{
"icon_id": "7524460",
"name": "EUR",
"font_class": "EUR",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "10956897",
"name": "美国国旗",
"font_class": "meiguoguoqi",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "41751543",
"name": "中国国旗",
"font_class": "zhongguoguoqi",
"unicode": "e632",
"unicode_decimal": 58930
}
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+109
View File
@@ -0,0 +1,109 @@
<template>
<el-dialog
v-bind="$attrs"
:class="{'rcs_dialog': true, 'padding_empty': $attrs.paddingempty, 'hidden_title': $attrs.hiddentitle}"
>
<template
v-for="(_, name) in $slots"
#[name]
>
<slot :name="name" />
</template>
<template #title>
<div class="title">
<div class="context">{{ $attrs.title }}</div>
<div class="right">
<slot name="title-right" />
</div>
</div>
</template>
</el-dialog>
</template>
<script>
export default {
name: 'RCSDialog',
data() {
return {};
},
mounted() {
},
methods: {
},
};
</script>
<style lang="scss" scoped>
.rcs_dialog {
// el-dialog
::v-deep .el-dialog {
background-color: var(--bg-color-main-2);
}
::v-deep .el-dialog__header {
padding: 0;
}
::v-deep .el-dialog__headerbtn {
right: 16px;
}
::v-deep .el-dialog__footer {
border-top: 1px solid var(--application-color-8);
padding: 10px 16px;
min-height: 48px;
}
::v-deep .el-dialog__body {
// TODO 滚动栏宽度有 10 px。开启 overflow: scroll 之后 增加 UI 兼容处理 padding-right - 10px
padding: 12px 2px 12px 12px !important;
max-height: 522px;
overflow: scroll;
}
}
.padding_empty {
::v-deep .el-dialog__body {
padding: 0 !important;
scrollbar-width: none; /* 隐藏滚动条 */
}
::v-deep .el-dialog__body::-webkit-scrollbar {
display: none; // 隐藏滚动条
width: 0; // 置滚动条的宽度为 0 来隐藏
}
}
.hidden_title {
::v-deep .el-dialog__header {
height: 0px !important;
.title {
display: none;
}
}
}
// el-button
::v-deep .el-button {
width: 51px;
height: 24px;
font-size: 12px;
padding: 0;
}
.title {
padding: 8px 16px 8px 16px;
min-height: 40px;
display: flex;
align-items: center;
flex-direction: row;
border-bottom: 1px solid var(--application-color-8);
.context {
font-size: 14px;
line-height: 22px;
color: var(--application-color-2);
flex: 1;
text-align: left;
}
.right {
flex: 1;
margin-right: 20px;
}
}
</style>
+530
View File
@@ -0,0 +1,530 @@
<template>
<div class="transfer-container">
<div class="transfer-modal">
<div class="transfer-header">
<span class="transfer-title">{{ title }}</span>
<span
class="transfer-close"
@click="onClose"
>×</span>
</div>
<div class="transfer-content">
<div class="transfer-panel source-panel">
<div class="panel-header">
<div class="panel-header-inner">
<span class="checkbox-wrapper">
<input
ref="allCheckbox"
type="checkbox"
:checked="isAllSourceChecked"
:indeterminate="isIndeterminate"
@change="toggleAllSource"
>
<span :class="{'checkbox-label': true, 'checkbox-select': sourceCheckedCount }">{{ sourceCheckedCount }}/{{ sourceData.length }} </span>
</span>
</div>
</div>
<div class="panel-search">
<input
v-model="sourceSearchText"
type="text"
placeholder="请输入搜索内容"
>
<span class="search-icon"></span>
</div>
<div class="panel-body">
<div
v-for="(item, index) in filteredSourceData"
:key="'source-' + item.value"
class="panel-item"
>
<label class="checkbox-item">
<input
type="checkbox"
:checked="item.checked"
@change="toggleItem(item)"
>
<span :class="{'item-label': true, 'item-select': item.checked}">{{ item.label }}</span>
</label>
</div>
</div>
<div class="panel-footer">
<button
class="btn-reset"
@click="resetToPreset"
>重置</button>
</div>
</div>
<div class="transfer-panel target-panel">
<div class="panel-header">
<div class="panel-header-inner">
<span>已选 {{ displayTargetData.length }} </span>
<button
class="btn-clear"
@click="clearTarget"
>全部清空</button>
</div>
</div>
<div class="panel-body">
<div
v-for="(item, index) in displayTargetData"
:key="'target-' + item.value"
class="panel-item"
>
<span class="item-icon"></span>
<span class="item-label">{{ item.label }}</span>
<span
class="item-remove"
@click="removeItem(item)"
>×</span>
</div>
</div>
</div>
</div>
<div class="transfer-footer">
<button
class="btn-cancel"
@click="onClose"
>取消</button>
<button
class="btn-confirm"
@click="onConfirm"
>确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TransferList',
props: {
title: {
type: String,
default: '',
},
value: {
type: Array,
default: () => [],
},
data: {
type: Array,
default: () => [],
},
presetSelected: {
type: Array,
default: () => [],
},
},
data() {
return {
sourceData: [],
targetData: [],
sourceSearchText: '',
};
},
computed: {
filteredSourceData() {
if (!this.sourceSearchText) {
return this.sourceData;
}
return this.sourceData.filter(item =>
item.label.toLowerCase().includes(this.sourceSearchText.toLowerCase()),
);
},
sourceCheckedCount() {
return this.sourceData.filter(item => item.checked).length;
},
isAllSourceChecked() {
return this.sourceData.length > 0 && this.sourceData.every(item => item.checked);
},
isIndeterminate() {
const checkedCount = this.sourceCheckedCount;
return checkedCount > 0 && checkedCount < this.sourceData.length;
},
displayTargetData() {
const checkedSourceItems = this.sourceData
.filter(item => item.checked)
.map(item => ({ ...item, fromSource: true }));
const targetKeys = this.targetData.map(item => item.value);
const uniqueCheckedItems = checkedSourceItems.filter(item => !targetKeys.includes(item.value));
return [...this.targetData, ...uniqueCheckedItems];
},
},
watch: {
data: {
immediate: true,
handler() {
this.initData();
},
},
isIndeterminate: {
handler(val) {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = val;
}
},
},
},
mounted() {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
}
},
updated() {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
}
},
methods: {
initData() {
const selectedKeys = this.value && this.value.length ? this.value : this.presetSelected || [];
this.targetData = this.data
.filter(item => selectedKeys.includes(item.value))
.map(item => ({ ...item }));
this.sourceData = this.data.map(item => ({
...item,
checked: selectedKeys.includes(item.value),
}));
},
toggleItem(item) {
item.checked = !item.checked;
this.syncTargetWithChecked();
this.emitChange();
},
toggleAllSource() {
const newCheckedState = !this.isAllSourceChecked;
this.sourceData.forEach(item => {
item.checked = newCheckedState;
});
this.syncTargetWithChecked();
this.emitChange();
},
syncTargetWithChecked() {
const checkedKeys = this.sourceData
.filter(item => item.checked)
.map(item => item.value);
this.targetData = this.data
.filter(item => checkedKeys.includes(item.value))
.map(item => ({ ...item }));
},
resetToPreset() {
const presetKeys = this.presetSelected || [];
this.sourceData.forEach(item => {
item.checked = presetKeys.includes(item.value);
});
this.targetData = this.data
.filter(item => presetKeys.includes(item.value))
.map(item => ({ ...item }));
this.sourceSearchText = '';
this.emitChange();
},
clearTarget() {
this.targetData = [];
this.sourceData.forEach(item => {
item.checked = false;
});
this.emitChange();
},
removeItem(item) {
const sourceItem = this.sourceData.find(sourceItem => sourceItem.value === item.value);
if (sourceItem) {
sourceItem.checked = false;
}
const targetIndex = this.targetData.findIndex(targetItem => targetItem.value === item.value);
if (targetIndex !== -1) {
this.targetData.splice(targetIndex, 1);
}
this.emitChange();
},
emitChange() {
const selectedKeys = [];
const selectedLabels = [];
this.targetData.forEach(item => {
selectedKeys.push(item.value);
selectedLabels.push(item.label);
});
this.$emit('input', selectedKeys, selectedLabels);
this.$emit('change', selectedKeys, selectedLabels);
},
onConfirm() {
this.syncTargetWithChecked();
this.$emit('confirm', this.targetData.map(item => item.value));
},
onClose() {
this.$emit('cancel');
},
},
};
</script>
<style lang="scss" scoped>
.transfer-container {
// 预留 css variables
--primary-color: #6AB2FF;
--bg-color: #151e2e;
--text-color: rgb(255, 255, 255, 0.9);
--border-color: #434343;
--item-hover-bg: #262626;
--panel-bg: #1f1f1f;
--button-primary-bg: #3389FF;
--button-primary-color: rgb(255, 255, 255, 0.9);
--button-default-bg: #151e2e;
--button-default-color: rgb(255, 255, 255, 0.7);
--modal-bg: #1f1f1f;
--modal-header-bg: #141414;
--checkbox-color: #177ddc;
--select-text-color: #6AB2FF;
}
.transfer {
&-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
}
&-modal {
width: 700px;
background-color: var(--modal-bg);
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.07);
box-shadow: 0px 8px 16px -8px rgba(0, 0, 0, 0.13), 0px 12px 32px rgba(0, 0, 0, 0.13), 0px 16px 48px rgba(0, 0, 0, 0.2);
background-color: rgba(20, 29, 40, 1);
}
&-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 9px 16px;
}
&-title {
font-size: 12px;
font-weight: 500;
color: var(--text-color);
}
&-close {
font-size: 22px;
color: var(--text-color);
opacity: 0.7;
cursor: pointer;
&:hover {
opacity: 1;
}
}
&-content {
display: flex;
padding: 16px;
gap: 12px;
font-size: 12px;
}
&-panel {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid var(--border-color);
border-radius: 4px;
height: 490px;
}
&-footer {
padding: 10px 16px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
}
.panel {
&-header {
padding: 8px 12px;
border-bottom: 1px solid var(--border-color);
&-inner {
display: flex;
justify-content: space-between;
align-items: center;
color: var(--text-color);
}
}
&-search {
padding: 8px 12px;
position: relative;
border-bottom: 1px solid var(--border-color);
input {
width: 100%;
box-sizing: border-box;
padding: 8px 12px;
padding-right: 30px;
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--bg-color);
color: var(--text-color);
}
}
&-body {
flex: 1;
overflow-y: auto;
padding: 8px 0;
}
&-item {
padding: 8px 12px;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
background-color: var(--item-hover-bg);
}
}
&-footer {
padding: 8px 12px;
display: flex;
justify-content: flex-start;
}
}
.search-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
color: var(--text-color);
opacity: 0.5;
}
.checkbox {
&-item {
display: flex;
align-items: center;
width: 100%;
cursor: pointer;
}
&-wrapper {
display: flex;
align-items: center;
}
&-label {
margin-left: 8px;
color: var(--text-color);
text-align: left;
}
&-select {
color: var(--select-text-color);
}
}
.item {
&-icon {
margin-right: 8px;
color: var(--text-color);
opacity: 0.5;
}
&-label {
flex: 1;
margin-left: 8px;
color: var(--text-color);
text-align: left;
}
&-remove {
color: var(--text-color);
opacity: 0.7;
cursor: pointer;
font-size: 12px;
&:hover {
opacity: 1;
}
}
&-select {
color: var(--select-text-color);
}
}
input[type="checkbox"] {
width: 16px;
height: 16px;
accent-color: var(--checkbox-color);
cursor: pointer;
}
.btn {
&-reset, &-cancel {
padding: 5px 16px;
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--button-default-bg);
color: var(--button-default-color);
cursor: pointer;
}
&-clear {
background: none;
border: none;
color: var(--primary-color);
cursor: pointer;
font-size: 12px;
padding: 0;
margin: 0;
}
&-confirm {
padding: 5px 16px;
border: none;
border-radius: 4px;
background-color: var(--button-primary-bg);
color: var(--button-primary-color);
cursor: pointer;
}
}
</style>
@@ -0,0 +1,657 @@
<template>
<div
v-if="visible"
class="dialog-overlay"
@click.self="handleCancel"
>
<div
class="dialog-container"
:class="{ 'theme-light': theme === 'light', 'theme-dark': theme === 'dark' }"
>
<div class="dialog-header">
<span class="dialog-title">{{ title }}</span>
<div class="header-actions">
<button
class="close-button"
@click="handleCancel"
>×</button>
</div>
</div>
<div class="dialog-tabs">
<div
class="tab"
:class="{ active: activeTab === 'account' }"
@click="activeTab = 'account'"
>
账户
</div>
<div
class="tab"
:class="{ active: activeTab === 'accountGroup' }"
@click="activeTab = 'accountGroup'"
>
账户组
</div>
</div>
<div class="search-container">
<div class="search-input">
<i class="search-icon"></i>
<div class="search-input-text">
<input
v-model="searchText"
type="text"
placeholder="输入关键词,可快速查找..."
@input="filterTree"
>
</div>
</div>
</div>
<!-- 账户标签内容 -->
<div
v-if="activeTab === 'account'"
class="dialog-content"
>
<div class="tree-container">
<el-tree
ref="accountTree"
:data="accountData"
:props="defaultProps"
:filter-node-method="filterNode"
node-key="id"
:expand-on-click-node="false"
:default-expanded-keys="defaultExpandedKeys"
@node-click="handleNodeClick"
>
<span
slot-scope="{ node, data }"
class="custom-tree-node"
@dblclick.stop="handleDoubleClick(data)"
>
<span class="node-title">{{ node.label.replace(/^.{1}@{2}/, '') }}</span>
<span
v-if="data.text"
class="node-subtitle"
>{{ data.text }}</span>
</span>
</el-tree>
</div>
</div>
<!-- 账户组标签内容 -->
<div
v-if="activeTab === 'accountGroup'"
class="dialog-content"
>
<div class="account-group-list">
<div
v-for="(item, index) in filteredAccountGroups"
:key="index"
class="account-group-item"
:class="{'selected': item.id == selectedItem?.id}"
@click="selectItem(item)"
@dblclick="handleDoubleClick(item)"
>
<span class="group-id">{{ item.value.replace(/^.{1}@{2}/, '') }}</span>
<span class="group-name">{{ item.text }}</span>
</div>
</div>
</div>
<div class="dialog-footer">
<button
class="btn-cancel"
@click="handleCancel"
>取消</button>
<button
class="btn-confirm"
@click="handleConfirm"
>确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TreeSearchDialog',
props: {
visible: {
type: Boolean,
default: false,
},
// 允许外部传入初始主题
initialTheme: {
type: String,
default: 'dark', // 默认为暗色主题
validator: (value) => ['dark', 'light'].includes(value),
},
accountData: {
type: Array,
default: () => [],
},
accountGroups: {
type: Array,
default: () => [],
},
title: {
type: String,
default: '',
},
// 默认展开的节点
defaultExpandedKeys: {
type: Array,
default: () => [],
},
},
data() {
return {
theme: this.initialTheme,
activeTab: 'account',
searchText: '',
selectedItem: null,
filteredAccountGroups: [],
defaultProps: {
children: 'children',
label: 'value',
},
};
},
watch: {
visible(val) {
if (val && this.$refs.accountTree) {
// 当对话框显示时,重置过滤器
this.$refs.accountTree.filter('');
this.searchText = '';
}
},
accountGroups: {
immediate: true,
handler() {
this.initDataGroup();
},
},
accountData: {
immediate: true,
handler() {
this.initData();
},
},
},
created() {
},
methods: {
initDataGroup() {
this.filteredAccountGroups = [...this.accountGroups];
},
initData() {
},
// 切换主题
toggleTheme() {
this.theme = this.theme === 'dark' ? 'light' : 'dark';
this.$emit('theme-change', this.theme);
},
// el-tree 的节点过滤方法
filterNode(value, data) {
if (!value) return true;
const searchTerm = value.toLowerCase();
// 检查节点标题和副标题
return data.value.toLowerCase().includes(searchTerm) ||
(data.text && data.text.toLowerCase().includes(searchTerm));
},
// 处理搜索输入
filterTree() {
if (this.activeTab === 'account' && this.$refs.accountTree) {
this.$refs.accountTree.filter(this.searchText);
} else if (this.activeTab === 'accountGroup') {
this.filterAccountGroups();
}
},
// 过滤账户组
filterAccountGroups() {
if (!this.searchText) {
this.filteredAccountGroups = [...this.accountGroups];
return;
}
const searchTerm = this.searchText.toLowerCase();
this.filteredAccountGroups = this.accountGroups.filter(group =>
group.id.toLowerCase().includes(searchTerm) ||
group.value.toLowerCase().includes(searchTerm) ||
group.text.toLowerCase().includes(searchTerm),
);
},
// 处理节点点击
handleNodeClick(data) {
this.selectedItem = data;
},
// 选择项目
selectItem(data) {
this.selectedItem = data;
},
// 处理双击事件
handleDoubleClick(data) {
this.selectedItem = data;
this.handleConfirm();
},
// 取消按钮
handleCancel() {
this.$emit('cancel');
},
// 确认按钮
handleConfirm() {
this.$emit('confirm', this.selectedItem);
},
},
};
</script>
<style lang="scss" scoped>
/* 全局主题变量 */
.dialog-overlay {
/* 暗色主题变量 */
--dark-bg-primary: #141D28;
--dark-bg-secondary: #2c3347;
--dark-bg-tertiary: #3a4257;
--dark-tab-bg-primary: #212b39;
--dark-text-primary: #ffffff;
--dark-text-secondary: #8e8e8e;
--dark-border: #2c3347;
--dark-accent: #3a8ee6;
--dark-hover: rgba(255, 255, 255, 0.05);
--dark-selected: rgba(255, 255, 255, 0.1);
/* 亮色主题变量 */
--light-bg-primary: #ffffff;
--light-bg-secondary: #f5f7fa;
--light-bg-tertiary: #e4e7ed;
--light-tab-bg-primary: #ffffff;
--light-text-primary: #303133;
--light-text-secondary: #606266;
--light-border: #dcdfe6;
--light-accent: #409eff;
--light-hover: rgba(0, 0, 0, 0.05);
--light-selected: rgba(0, 0, 0, 0.1);
}
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
/* 主题相关样式 */
.dialog-container {
width: 90%;
max-width: 500px;
max-height: 90vh;
border-radius: 4px;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* 暗色主题 */
.theme-dark {
background-color: var(--dark-bg-primary);
color: var(--dark-text-primary);
}
/* 亮色主题 */
.theme-light {
background-color: var(--light-bg-primary);
color: var(--light-text-primary);
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
}
.theme-dark .dialog-header {
border-bottom: 1px solid var(--dark-border);
}
.theme-light .dialog-header {
border-bottom: 1px solid var(--light-border);
}
.dialog-title {
font-size: 14px;
font-weight: 500;
}
.header-actions {
display: flex;
align-items: center;
}
.theme-toggle {
background: none;
border: none;
cursor: pointer;
font-size: 22px;
}
.close-button {
background: none;
border: none;
font-size: 30px;
cursor: pointer;
padding: 0;
margin: 0;
}
.theme-dark .close-button {
color: var(--dark-text-secondary);
}
.theme-light .close-button {
color: var(--light-text-secondary);
}
.dialog-tabs {
display: flex;
padding: 2px;
margin: 12px 16px;
border-radius: 2px;
font-size: 12px;
}
.theme-dark .dialog-tabs {
background-color: var(--dark-tab-bg-primary);
}
.theme-light .dialog-tabs {
background-color: var(--light-tab-bg-primary);
}
.tab {
cursor: pointer;
flex: 1;
text-align: center;
border-radius: 2px;
}
.theme-dark .tab {
background-color: transparent;
color: var(--dark-text-secondary);
}
.theme-light .tab {
background-color: transparent;
color: var(--light-text-secondary);
}
.theme-dark .tab.active {
background-color: var(--dark-bg-secondary);
color: var(--dark-text-primary);
}
.theme-light .tab.active {
background-color: var(--light-bg-secondary);
color: var(--light-text-primary);
}
.search-container {
padding: 12px 16px;
}
.search-input {
position: relative;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.search-icon {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.search-input-text {
width: 100%;
display: flex;
}
.theme-dark .search-icon {
color: var(--dark-text-secondary);
}
.theme-light .search-icon {
color: var(--light-text-secondary);
}
.search-input input {
font-size: 12px;
width: 100%;
padding: 8px 8px 8px 36px;
border-radius: 4px;
border: none;
}
.theme-dark .search-input input {
background-color: transparent;
color: var(--dark-text-primary);
}
.theme-light .search-input input {
background-color: transparent;
color: var(--light-text-primary);
}
.theme-dark .search-input input::placeholder {
color: var(--dark-text-secondary);
}
.theme-light .search-input input::placeholder {
color: var(--light-text-secondary);
}
.dialog-content {
flex: 1;
overflow-y: auto;
max-height: calc(90vh - 180px);
}
.tree-container {
padding: 0 16px;
font-size: 12px;
}
/* 自定义 el-tree 样式 */
.theme-dark :deep(.el-tree) {
background-color: transparent !important;
color: var(--dark-text-primary) !important;
}
.theme-light :deep(.el-tree) {
background-color: transparent !important;
color: var(--light-text-primary) !important;
}
.theme-dark :deep(.el-tree-node__content) {
background-color: transparent !important;
}
.theme-light :deep(.el-tree-node__content) {
background-color: transparent !important;
}
.theme-dark :deep(.el-tree-node__content:hover) {
background-color: var(--dark-hover) !important;
}
.theme-light :deep(.el-tree-node__content:hover) {
background-color: var(--light-hover) !important;
}
.theme-dark :deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: var(--dark-selected) !important;
}
.theme-light :deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: var(--light-selected) !important;
}
.theme-dark :deep(.el-tree-node__expand-icon) {
color: var(--dark-text-secondary);
}
.theme-light :deep(.el-tree-node__expand-icon) {
color: var(--light-text-secondary) !important;
}
.theme-dark :deep(.el-tree-node__expand-icon.expanded) {
color: var(--dark-text-primary) !important;
}
.theme-light :deep(.el-tree-node__expand-icon.expanded) {
color: var(--light-text-primary) !important;
}
.custom-tree-node {
display: flex;
align-items: center;
width: 100%;
padding-right: 8px;
}
.node-title {
font-weight: 500;
margin-right: 8px;
}
.theme-dark .node-subtitle {
color: var(--dark-text-secondary);
}
.theme-light .node-subtitle {
color: var(--light-text-secondary);
}
.account-group-list {
padding: 0 16px;
font-size: 12px;
}
.account-group-item {
display: flex;
padding: 10px 0;
cursor: pointer;
}
.theme-dark .account-group-item {
border-bottom: 1px solid var(--dark-border);
}
.theme-light .account-group-item {
border-bottom: 1px solid var(--light-border);
}
.theme-dark .account-group-item:hover {
background-color: var(--dark-hover);
}
.theme-light .account-group-item:hover {
background-color: var(--light-hover);
}
.theme-dark .account-group-item.selected {
background-color: var(--dark-selected);
}
.theme-light .account-group-item.selected {
background-color: var(--light-selected);
}
.theme-dark .account-group-item.highlighted {
color: var(--dark-accent);
}
.theme-light .account-group-item.highlighted {
color: var(--light-accent);
}
.group-id {
margin-right: 12px;
font-weight: 500;
}
.theme-dark .group-name, .theme-dark .group-desc {
color: var(--dark-text-secondary);
margin-right: 8px;
}
.theme-light .group-name, .theme-light .group-desc {
color: var(--light-text-secondary);
margin-right: 8px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
padding: 12px 16px;
}
.theme-dark .dialog-footer {
border-top: 1px solid var(--dark-border);
}
.theme-light .dialog-footer {
border-top: 1px solid var(--light-border);
}
.btn-cancel, .btn-confirm {
padding: 6px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
margin-left: 8px;
font-size: 12px;
}
.theme-dark .btn-cancel {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--dark-text-primary);
}
.theme-light .btn-cancel {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--light-text-primary);
}
.theme-dark .btn-confirm {
background-color: var(--dark-accent);
color: var(--dark-text-primary);
}
.theme-light .btn-confirm {
background-color: var(--light-accent);
color: #ffffff;
}
</style>
+117
View File
@@ -0,0 +1,117 @@
<template>
<el-dialog
:visible.sync="show"
:title="configData.title"
:modal-append-to-body="false"
:width="`${percentWidth}%`"
@close="handleCancel"
>
<PublicForm
ref="publicForm"
:form-arr="formArr"
:form-data="formData"
@outOperation="outOperation"
/>
<span
slot="footer"
class="dialog-footer"
>
<slot name="footerBtn" />
<el-button
type="default"
:size="$buttonSize"
@click="handleCancel"
> </el-button>
<el-button
type="primary"
:size="$buttonSize"
@click="dialogOK"
> </el-button>
</span>
</el-dialog>
</template>
<script>
import PublicForm from '@/components/form/index.vue';
export default {
components: {
PublicForm,
},
props: {
visible: { // 是否展示弹窗
type: Boolean,
default: false,
},
formArr: { // 配置数组
type: Array,
required: true,
},
percentWidth: { // 弹窗宽度
type: Number,
default: 30,
},
formData: { // 表单数据
type: Object,
default: () => {},
},
/**
* 配置对象
* title 标题
* addApi 新增接口
* editApi 修改接口
* type 1 新增 2 编辑
* transFormData 参数处理方法
* 默认 transformRequest: (params) => {
return params;
}
*/
configData: {
type: Object,
default: () => ({}),
},
},
data() {
return {
show: false,
};
},
watch: {
visible: {
handler(nv) {
this.show = nv;
},
},
},
methods: {
handleCancel() {
console.log('我是formArr', this.formArr);
this.$emit('handleCancel');
},
outOperation(val, index, prop, num) {
console.log('我是outOperation', val, index, prop, num);
},
dialogOK() {
// 判断表单验证是否通过
if (this.$refs.publicForm.submitForm()) {
console.log('success');
console.log(this.formData);
const api = { 1: this.$apis[this.configData.addApi], 2: this.$apis[this.configData.editApi] };
const params = this.configData.transFormData(this.formData);
api[this.configData.type](params).then(res => {
this.$message.success('操作成功');
this.$emit('dialogOK', res);
});
} else {
console.log('error');
this.$emit('dialogCancel');
}
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .titiebox .titieboxlabel {
white-space: nowrap;
}
</style>
+63
View File
@@ -0,0 +1,63 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
v-on="formItems.events"
@change="handleInput"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
v-on="formItems.events"
@change="handleChange($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
+297
View File
@@ -0,0 +1,297 @@
<template>
<el-dialog
title="列定制"
:visible.sync="visibleDialog"
width="640px"
@close="columnClose"
>
<div class="content">
<div class="left-box">
<div class="left-select">
<el-checkbox
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>{{ checkedItems.length }} / {{ tableColumn.length }}</el-checkbox>
<el-checkbox-group
v-model="checkedItems"
class="check-list"
@change="handleCheckedCitiesChange"
>
<el-checkbox
v-for="item in tableColumn"
:key="item.label"
:label="item.label"
>{{ item.label }}</el-checkbox>
</el-checkbox-group>
</div>
<div class="left-bottom">
<el-button
:size="$buttonSize"
@click="resetColumn"
>恢复默认</el-button>
</div>
</div>
<div class="right-box">
<div class="right-top">
已选{{ checkedItems.length }}
<el-button
type="text"
:size="$buttonSize"
@click="clearSelect"
>全部清空</el-button>
</div>
<el-input
v-model="searchParams"
placeholder="请输入搜索内容"
>
<template #suffix>
<i
class="search-icon el-icon-search"
@click="searchColumns"
/>
</template>
</el-input>
<div class="select-columns">
<div
v-for="(item,index) in showItems"
:key="item"
class="select-li"
draggable="true"
@dragstart="onDragStart(index)"
@dragover.prevent
@drop="onDrop(index)"
>
<div class="li-left">
<i class="el-icon-s-grid" />
<div class="li-label">{{ item }}</div>
</div>
<!-- <img src="../../../public/images/close.svg"> -->
<div class="icon-groups">
<i
class="el-icon-close"
style="cursor:pointer;font-size:16px"
@click="deleteItem(item)"
/>
<i
class="el-icon-top"
style="cursor:pointer;font-size:16px"
@click="sortItem(item,index)"
/></div>
</div>
</div>
</div>
</div>
<div
slot="footer"
class="dialog-footer"
>
<el-button
:size="$buttonSize"
class="drawer-footer-cancel-btn"
@click="columnClose"
> </el-button>
<el-button
:size="$buttonSize"
class="drawer-footer-confirm-btn"
type="primary"
@click="handleCustomColumnConfirm"
>保存</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
showDialog: {
type: Boolean,
default: false,
},
tableColumn: {
type: Array,
default: () => [],
},
},
data() {
return {
visibleDialog: false,
columnDialog: false,
checked: false,
checkAll: false,
isIndeterminate: false,
checkedItems: [],
showItems: [],
searchParams: '',
draggedIndex: '',
};
},
watch: {
showDialog: {
handler(nv) {
this.visibleDialog = nv;
},
},
},
mounted() {},
methods: {
onDragStart(index) {
this.draggedIndex = index;
this.$nextTick(() => {
const draggedItem = this.$el.querySelector(`.draggable-item:nth-child(${index + 1})`);
draggedItem.classList.add('dragging');
});
console.log(index, 'dropStart');
},
onDrop(index) {
console.log(index, 'drop');
if (this.draggedIndex !== index) {
const draggedItem = this.items.splice(this.draggedIndex, 1)[0];
this.items.splice(index, 0, draggedItem);
this.draggedIndex = null;
// 保存新顺序到服务器或本地存储
// this.saveOrder();
}
},
handleCheckAllChange(val) {
this.checkedItems = val ? this.tableColumn.map(v => v.label) : [];
this.showItems = [...this.checkedItems];
this.isIndeterminate = false;
},
handleCheckedCitiesChange(value) {
const checkedCount = value.length;
this.showItems = [...this.checkedItems];
this.checkAll = checkedCount === this.tableColumn.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.tableColumn.length;
},
resetColumn() { // 恢复默认
},
searchColumns() {
console.log(this.searchParams, 'searchParams');
if (this.searchParams) {
this.showItems = this.checkedItems.filter(v => v.includes(this.searchParams));
} else {
this.showItems = [...this.checkedItems];
}
},
clearSelect() {
this.checkedItems = [];
this.showItems = [];
this.isIndeterminate = false;
this.checkAll = this.checkedItems === this.tableColumn.length;
},
columnClose() {
this.visibleDialog = false;
this.$emit('update:showDialog', false);
this.searchParams = '';
this.clearSelect();
},
deleteItem(item) {
this.checkedItems = this.checkedItems.filter(v => v !== item);
this.showItems = [...this.checkedItems];
this.checkAll = this.checkedItems === this.tableColumn.length;
this.isIndeterminate = this.checkedItems.length > 0 && this.checkedItems.length < this.tableColumn.length;
},
sortItem(item, index) {
if (index > 0) {
const arr = this.checkedItems;
arr.splice(index - 1, 1, ...arr.splice(index, 1, arr[index - 1]));
this.showItems = [...this.checkedItems];
}
},
handleCustomColumnConfirm() {
console.log(this.checkedItems, 'checkItems');
this.columnClose();
// this.$emit('customColumnChange', this.tableData);
},
},
};
</script>
<style lang="scss" scoped>
.content{
display: flex;
}
.left-box {
width:360px;
height:490px;
.left-select{
padding: 8px 0 0 16px;
border-radius: 2px;
border: 1px solid var(--input-border);
background-color: var(--desktop-bg-color-1);
height:456px;
.check-list{
height:420px;
line-height:20px;
overflow:auto;
margin-top:10px
}
}
.left-bottom{
border-radius: 0px 0px 2px 2px;
border-left: 1px solid var(--input-border);
border-right: 1px solid var(--input-border);
border-bottom: 1px solid var(--input-border);
padding:5px 12px
}
}
.right-box{
border-radius: 2px;
border: 1px solid var(--input-border);
opacity: 1;
width:240px;
height:490px;
background:var(--desktop-bg-color-1);
margin-left:8px;
padding:5px 12px;
.right-top{
display:flex;
justify-content: space-between;
color:var(--text-color-1);
font-family: "SourceHanSansSC-Regular";
font-size: 12px;
font-weight: 400;
font-style: Regular;
letter-spacing: 0px;
text-align: left;
line-height: 20px;
}
.select-columns{
height:424px;
overflow:auto;
margin-top:8px;
.select-li{
height:28px;
display: flex;
align-items: center;
justify-content: space-between;
}
.li-left{
display:flex;
align-items: center;
}
.select-li:hover{
border-radius: 2px;
background-color: rgba(0, 0, 0, 0.05);
.icon-groups{
display: block;
}
}
.icon-groups{
display: none;
i+i{
margin-left:5px
}
}
}
}
.search-icon{
font-size:16px;
line-height: 30px;
cursor:pointer;
color:var(--text-color-1)
}
</style>
+160
View File
@@ -0,0 +1,160 @@
<template>
<el-dialog
title="导出"
:visible.sync="visibleDialog"
width="400px"
class="export-dialog"
@close="close"
>
<el-form
ref="form"
:model="form"
label-width="60px"
>
<el-row>
<el-form-item label="范围">
<el-radio-group v-model="form.exportScope">
<el-radio label="page">导出当前页</el-radio>
<el-radio label="all">导出全部</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="类型">
<el-radio-group v-model="form.exportType">
<el-radio label="xls">Excel</el-radio>
<el-radio label="csv">CSV</el-radio>
<el-radio label="txt">TxT</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
</el-form>
<div
slot="footer"
class="dialog-footer"
>
<el-button
type="primary"
class="btn"
@click="submitExport"
>{{
$t("button.confirm")
}}</el-button>
</div>
</el-dialog>
</template>
<script>
import { commonMore } from '../../utils/index';
export default {
props: {
showDialog: {
type: Boolean,
default: false,
},
exportParams: {
type: Object,
default: () => {},
},
},
data() {
return {
visibleDialog: false,
form: {
exportType: 'csv',
exportScope: 'all',
},
};
},
watch: {
showDialog: {
handler(nv) {
this.visibleDialog = nv;
},
},
},
mounted() {},
methods: {
close() {
console.log('关闭了');
this.visibleDialog = false;
this.$emit('update:showDialog', false);
this.form = {
exportType: 'csv',
exportScope: 'all',
};
},
async submitExport() {
const params = { ...this.form, ...this.exportParams };
if (this.form.exportScope === 'all') {
delete params.pageStart;
delete params.pageLimit;
}
console.log(params, 'ppp');
const exportParams = commonMore.dataHandler(params);
const res = await this.$apis.exportData(exportParams);
console.log(res, 'res');
this.download(res.data.result);
},
download(ticket) {
const action = window.origin.replace(/^https?:/, '') + '/dcs/baseQuery/download.action';
// ticket = '8572f582-f927-40f1-b487-27ce3b4e5119'
const url = `${action}?queryParam.ticket=${ticket}`;
console.log(action, 'aaa');
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/vnd.ms-excel;charset=UTF-8',
},
})
.then(async(response) => {
if (!response.ok) {
const text = await response.text();
throw new Error(text);
}
// 关键:确保服务器暴露 Content-Disposition 头
const contentDisposition = response.headers.get(
'Content-Disposition',
);
let filename = '导出文件.csv'; // 默认值
if (contentDisposition) {
// 关键步骤:提取并解码 Java URLEncoder 编码的文件名
const filenameMatch = contentDisposition.match(
/filename=("?)([^";]+)\1/i,
);
if (filenameMatch && filenameMatch[2]) {
// 替换 "+" 为 "%20"(解决 Java URLEncoder 的空格编码问题)
const encodedName = filenameMatch[2].replace(/\+/g, '%20');
// 解码 URL 编码
filename = decodeURIComponent(encodedName);
}
}
return response.blob().then((blob) => ({ blob, filename }));
})
.then(({ blob, filename }) => {
console.log(blob, filename, '文件信息');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename; // 动态设置文件名
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
})
.catch((error) => {
console.error('下载失败:', error);
});
},
},
};
</script>
<style lang="scss" scoped>
.export-dialog{
:deep(.el-form-item__content){
line-height:40px
}
}
</style>
+158
View File
@@ -0,0 +1,158 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@blur="handleBlur"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
// 使用的小数位数的最小数目,可能的值是从 0 到 20
minimumFractionDigits: {
type: Number,
default: 2,
},
// 使用的小数位数的最大数目。可能的值是从 0 到 20
maximumFractionDigits: {
type: Number,
default: 20,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
watch: {
value(nVal) {
if (nVal) {
const val = nVal.toString();
this.inputValue = this.inputValueCopy = this.changePercentile(val);
} else {
this.inputValue = this.inputValueCopy = '';
}
},
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
this.$emit('input', this.inputValue);
},
handleBlur() {
this.delcomma();
let inputValue = this.inputValue;
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
inputValue = num * Math.pow(10, unit);
this.inputValue = this.changePercentile(inputValue);
}
console.log('blurNUm', inputValue);
this.$emit('input', inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.delcomma();
},
// 转换千分位
changePercentile(val) {
return val.toLocaleString('en-US', {
minimumFractionDigits: this.minimumFractionDigits,
maximumFractionDigits: this.maximumFractionDigits,
});
},
// 去掉","号
delcomma() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
+114
View File
@@ -0,0 +1,114 @@
<template>
<div class="foldbox">
<div
class="header"
@click="$emit('click')"
>
<div class="header-icon"><icon-font
:name="titleIcon"
size="11"
/></div>
<div class="header-title">{{ title }}</div>
<div class="header-rotate">
<i
v-if="!isOpen"
class="el-icon-arrow-right"
/>
<i
v-if="isOpen"
class="el-icon-arrow-down"
/>
</div>
</div>
<div
class="content"
/>
<slot :row="row" />
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: 'title',
},
titleIcon: {
type: String,
default: 'icon-research',
},
isOpen: {
type: Boolean,
default: false,
},
row: {
type: Object,
default: () => {},
},
},
data() {
return {
};
},
watch: {
row: {
handler(nVal) {
console.log('nValnVal---row11111122', nVal);
},
deep: true,
immediate: true,
},
},
};
</script>
<style scoped lang="scss">
.foldbox {
margin-bottom: 8px;
width: 100%;
padding: 12px;
border-radius: 4px;
background-color: var(--card-bg);
}
.header {
display: flex;
width: 100%;
font-weight: 800;
align-items: center;
height: 24px;
.header-icon {
width: 20px;
height: 20px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.13);
display: flex;
align-items: center;
justify-content: center;
}
.header-title {
margin-left: 8px;
font-size: 14px;
}
.header-rotate {
margin-left: 14px;
}
}
.content {
margin-top: 10px;
padding-top: 7px;
width: 100%;
border-top: 1px solid var(--card-border);
}
.fade-enter-active {
transition: opacity 2s ease, height 2s ease;
}
.fade-leave-active {
transition: opacity 0s, height 0s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
+336
View File
@@ -0,0 +1,336 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type === 'input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 自定义列展示 -->
<CSelectLabel
v-if="formItems.type==='selectLabel'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 周选择器 -->
<CPickerWeek
v-if="formItems.type==='pickerWeek'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 月选择器 -->
<CPickerMonth
v-if="formItems.type==='pickerMonth'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 年选择器 -->
<CPickerYear
v-if="formItems.type==='pickerYear'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间范围选择器 -->
<CPickerTimeRange
v-if="formItems.type==='pickerTimeRange'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期时间选择器 -->
<CPickerDateTime
v-if="formItems.type==='pickerDateTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期时间范围选择器 -->
<CPickerDateTimeRange
v-if="formItems.type==='pickerDateTimeRange'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择-选择 -->
<CSelectSelect
v-if="formItems.type==='selectSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本输入-选择 -->
<CInputSelect
v-if="formItems.type==='inputSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 下拉懒加载 -->
<CSelectLazyLoading
v-if="formItems.type==='selectLazyLoading'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器拆分单个日期 -->
<CPickerDateSingle
v-if="formItems.type==='pickerDateSingle'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<CSelectTable
v-if="formItems.type==='selectTable'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
<!-- 穿梭框 -->
<CSelectTransfer
v-if="formItems.type==='selectTransfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 树结构 -->
<CSelectTreeTable
v-if="formItems.type==='selectTreeTable'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
</div>
</template>
<script>
import CInput from '../input';
import CTextarea from '../textarea';
import CSelect from '../select';
import CSelectLabel from '../selectLabel';
import CSelectApi from '../selectApi';
import CSelectTree from '../selectTree';
import CSelectTreeApi from '../selectTreeApi';
import CInputNumber from '../inputNumber';
import CInputFinance from '../finance';
import CInputDate from '../inputDate';
import CPickerDate from '../pickerDate';
import CPickerTime from '../pickerTime';
import CPickerTimeRange from '../pickerTimeRange';
import CPickerDateTime from '../pickerDateTime';
import CPickerDateTimeRange from '../pickerDateTimeRange';
import CPickerWeek from '../pickerWeek';
import CPickerMonth from '../pickerMonth';
import CPickerYear from '../pickerYear';
import CRadio from '../radio';
import CCheckbox from '../checkbox';
import CSwitch from '../switch';
import CCascader from '../cascader';
import CTransfer from '../transfer';
import CSelectSelect from '../select-select';
import CInputNumber2 from '../inputNumber2';
import CInputSelect from '../input-select';
import CSelectLazyLoading from '../selectLazyLoading';
import CPickerDateSingle from '../pickerDateSingle';
import CSelectTable from '../selectTable/index';
import CSelectTransfer from '../selectTransfer/index';
import CSelectTreeTable from '../selectTreeTable/index';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CPickerTimeRange,
CPickerDateTime,
CPickerDateTimeRange,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CSelectSelect,
CInputNumber2,
CInputSelect,
CSelectLazyLoading,
CPickerDateSingle,
CSelectLabel,
CPickerYear,
CPickerWeek,
CPickerMonth,
CSelectTable,
CSelectTransfer,
CSelectTreeTable,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
data() {
return {
// formItems: {},
// formData: {},
};
},
watch: {
// formItems(newval) {
// this.formItems = newval;
// },
// formData(newval) {
// this.formData = newval;
// },
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
+268
View File
@@ -0,0 +1,268 @@
<template>
<el-form ref="ruleForm" :model="formData" class="demo-ruleForm" inline>
<el-row>
<el-col
v-for="(formItems, index) in formObj"
v-show="!formItems.notShow"
:span="formItems.span"
:key="index"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
label-width="80px"
>
<!-- 文件上传 -->
<!-- 如果对象有值就回显没有值就为空 -->
<el-upload
v-if="formobj.upload"
:ref="formobj.prop"
:accept="formobj.accept ? formobj.accept : 'PNG,JPEG'"
:file-list="formData[formobj.prop] ? formData[formobj.prop] : []"
:action="`${uploadUrl}${
formobj.uploadObj.fileType ? formobj.uploadObj.fileType : ''
}`"
:limit="formobj.uploadObj.limit"
:class="{
hide:
formobj.uploadObj.hideUpload ||
formData[formobj.prop].length == formobj.uploadObj.limit,
}"
:on-preview="handlePictureCardPreview"
:on-remove="
(file, fileList) =>
handleRemove(
file,
fileList,
formobj.uploadObj.limit,
formobj.prop,
index
)
"
:on-success="
(response, file, fileList) =>
uploadSuccess(
response,
file,
fileList,
formobj.uploadObj.limit,
formobj.prop,
index
)
"
list-type="picture-card"
:auto-upload="true"
>
<i slot="default" class="el-icon-plus" />
</el-upload>
<el-dialog
v-if="formobj.upload"
:visible.sync="dialogVisible"
:append-to-body="true"
width="40%"
>
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<!-- text展示 -->
<span v-if="formobj.text" v-text="formData[formobj.prop]" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import FormItem from "./formItem.vue";
export default {
components: {
FormItem,
},
props: {
formObj: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
searchSelectOptionsCb: {
type: Array,
},
},
data() {
return {
uploadUrl: "",
dialogImageUrl: "",
searchSelectLoading: false,
dialogVisible: false,
disabled: false,
searchShow: "", //高德地图input收索联想
setSearchVal: [], //高德地图赋值搜索内容
};
},
created() {},
watch: {},
methods: {
//select变化调用
selectChange(value, index, prop) {
this.$emit("selectChange", value, index, prop);
},
// input的input事件
inputINPUT(value, index, prop) {
this.$emit("inputINPUT", value, index, prop);
},
// input的change事件
inputChange(value, index, prop) {
this.$emit("inputChange", value, index, prop);
},
// 搜索类型select搜索
remoteMethod(query, index, prop) {
if (query) {
this.searchSelectLoading = true;
this.$emit("querySelectValue", query, index, prop);
setTimeout(() => {
this.formObj[index].options = this.searchSelectOptionsCb;
this.searchSelectLoading = false;
}, 500);
} else {
this.searchSelectOptios = [];
}
},
//switch变化
formSwitchChange(val, index, prop) {
this.$emit("formSwitchChange", val, index, prop);
},
//按钮点击事件
buttonClick(prop, index) {
this.$emit("buttonClick", prop, index);
},
//文件上传成功回调
uploadSuccess(response, file, fileList, limit, prop, index) {
this.formObj[index].uploadObj.hideUpload = fileList.length == limit; //文件列表变化后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮
this.pushUpload(file, fileList, limit, prop);
},
//文件删除
handleRemove(file, fileList, limit, prop, index) {
this.formObj[index].uploadObj.hideUpload = fileList.length == limit; //文件删除后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮
this.pushUpload(file, fileList, limit, prop);
},
// 文件预览
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
//提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning("请把信息填写完整");
formValidate = false;
}
});
return formValidate;
},
/* 清空表单
逻辑:
1 、如果要清空文件上传列表,要传入要清空的upload的字段名,假如多个upload用for循环,调用清空方法!
2、清空upload之后,还要把upload上传框展示出来,通过字段名比对,获取到在formObj中的下标,通过下标操作对象属性,进行展示
*/
resetForm(uploadArr) {
this.$refs.ruleForm.resetFields();
if (uploadArr) {
for (let i = 0; i < uploadArr.length; i++) {
this.$refs[uploadArr[i]][0].clearFiles();
let index = this.formObj.findIndex(
(item) => item.prop == uploadArr[i]
);
this.formObj[index].uploadObj.hideUpload = false;
}
}
},
// 单个字段验证
validateFieldProp(prop) {
let formValidate = Boolean;
this.$refs.ruleForm.validateField(prop, (valid) => {
if (!valid) {
formValidate = true;
} else {
formValidate = false;
}
});
return formValidate;
},
// 对文件上传,删除进行赋值,调用form验证
pushUpload(file, fileList, limit, prop) {
if (fileList.length > 0) {
this.formData[prop] = fileList;
} else {
// 表示没有数据,把字段置空
this.formData[prop] = "";
}
this.$refs.ruleForm.validateField(prop); //调用验证form表单的文件上传
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-input,
::v-deep.el-select,
::v-deep.el-date-editor.el-input {
width: 208px;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-date-editor .el-range-separator {
width: 20px !important;
}
::v-deep.el-range-editor--small.el-input__inner {
width: 400px;
}
.el-textarea {
width: 400px;
}
.hide {
::v-deep .el-upload--picture-card {
display: none;
}
}
.amap_div {
overflow: hidden;
height: 400px;
width: 600px;
position: relative;
.sreach_ul {
position: absolute;
top: 1;
background-color: white;
z-index: 9;
min-width: 210px;
float: auto;
height: 200px;
overflow: auto;
padding: 0 20px;
line-height: 24px;
}
}
</style>
+99
View File
@@ -0,0 +1,99 @@
<template>
<el-form
ref="ruleForm"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index) in formArr"
v-show="!formItems.notShow"
:key="index"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems.prop,num)"
@getRequestData="getRequestData(index,formItems.prop)"
/>
</el-form-item>
</el-col>
<slot />
</el-row>
</el-form>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
watch: {},
created() {},
methods: {
// select 请求接口
// val返回值,index表单上第几个组件,prop组件名,num一行的组件里的第几个值
outOperation(val, index, prop, num) {
this.$emit('outOperation', val, index, prop, num);
},
// 提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
return formValidate;
},
getRequestData(index, prop) {
if (prop === 'selectLazyLoading') {
this.$emit('getRequestData', index, true);
}
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 17px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
+200
View File
@@ -0,0 +1,200 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type==='input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
</div>
</template>
<script>
import CInput from '../input';
import CTextarea from '../textarea';
import CSelect from '../select';
import CSelectApi from '../selectApi';
import CSelectTree from '../selectTree';
import CSelectTreeApi from '../selectTreeApi';
import CInputNumber from '../inputNumber';
import CInputFinance from '../finance';
import CInputDate from '../inputDate';
import CPickerDate from '../pickerDate';
import CPickerTime from '../pickerTime';
import CRadio from '../radio';
import CCheckbox from '../checkbox';
import CSwitch from '../switch';
import CCascader from '../cascader';
import CTransfer from '../transfer';
import CInputNumber2 from '../inputNumber2';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CInputNumber2,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
+118
View File
@@ -0,0 +1,118 @@
<template>
<el-collapse
v-model="activeNames"
@change="collapseChange"
>
<el-collapse-item
v-for="(item,index) in formArr"
:key="index"
:title="item.title"
:name="index.toString()"
>
<el-form
:ref="`ruleForm${index}`"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index1) in item.formArr"
v-show="!formItems.notShow"
:key="index1"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems.prop,num)"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-collapse-item>
</el-collapse>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
computed: {
activeNames() {
return this.getActiveNames();
},
},
watch: {},
created() {},
methods: {
collapseChange(val) {
console.log(val);
},
outOperation(val, index, prop, num) {
this.$emit('outOperation', val, index, prop, num);
},
async submitForm() {
let formValidate = true;
this.formArr.forEach((_, index) => {
this.$refs[`ruleForm${index}`][0].validate((valid) => {
if (!valid) {
// this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
});
return formValidate;
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
getActiveNames() {
const arr = [];
for (const i in this.formArr) {
if (this.formArr[i].isActive) {
arr.push(i.toString());
}
}
return arr;
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 12px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
@change="handleChangeEvent"
@expand-change="handleExpandchangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
@@ -0,0 +1,58 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
@change="handleChangeEvent($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
@@ -0,0 +1,37 @@
export default {
computed: {
},
methods: {
// --------------------- 组件内部方法 begin ------------------//
handleInputEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleChangeEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleBlurEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleFocusEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleClearEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleExpandchangeEvent() {},
// --------------------- 组件内部方法 end ------------------//
// --------------------- 事件处理 begin ------------------//
// --------------------- 以上为组件支持外部调用的API方法 end ------------------//
},
};
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
this.inputValue = (num * Math.pow(10, unit)).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,151 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-input
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>
{{
formItems.attrs.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>
{{
formItems.attrs.append
}}
</template>
</el-input>
<el-select
v-model="value[1]"
size="mini"
style="margin-left:5px;"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange1(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,88 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInputEvent"
@blur="handleBlurEvent"
@change="handleChangeEvent"
@focus="handleFocusEvent"
@clear="handleClearEvent"
>
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>{{
formItems.attrs.prepend
}}</template>
<template
v-if="formItems.attrs?.append"
slot="append"
>{{
formItems.attrs.append
}}</template>
</el-input>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// d天 m月,y年,
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'd') {
unit = 1;
} else if (lastLetter === 'm') {
unit = 30;
} else if (lastLetter === 'y') {
unit = 365;
}
this.inputValue = (num * unit).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 22px;
line-height: 22px;
top: 2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,78 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:controls-position="formItems.attrs?.['controls-position'] || 'right'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 12px !important;
}
.el-input-number__increase{
top:2px;
}
}
::v-deep.el-input-number--mini.is-controls-right {
.el-input-number__decrease {
bottom:2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,56 @@
<template>
<div class="titiebox">
<div
v-if="label"
:style="{ width: width }"
class="titieboxlabel"
>
<span
v-if="needStar"
style="color: #f00"
>{{ "*" }}</span>{{ label }} <span>{{ ':' }}</span>
</div>
<div class="titieboxvalue">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
needStar: {
type: Boolean,
default: false,
},
width: {
type: String,
default: '80px',
},
},
};
</script>
<style lang="scss" scoped>
.titiebox {
display: flex;
flex-wrap: nowrap;
align-items: center;
font-size: 12px;
width: 100%;
.titieboxlabel {
padding-right: 12px;
height: 24px;
line-height: 24px;
text-align: right;
}
.titieboxvalue {
flex: 1;
box-sizing: border-box;
}
}
</style>
@@ -0,0 +1,195 @@
<template>
<div
class="operateCard"
:style="{width: foldCard ? '24px': width}"
>
<div
v-if="!foldCard"
class="card"
>
<div class="title">
<div class="left">
<el-tooltip
v-for="(item,index) in iconLeftList"
:key="index"
:content="item.text"
placement="bottom"
effect="dark"
class="custom-tooltip"
>
<i
:class="[item.type,'left-icon']"
@click="item.callback(value)"
/>
</el-tooltip>
</div>
<div class="center"><slot /></div>
<div class="right">
<i
v-for="(item,index) in iconRightList"
:key="index"
:class="[item.type,'right-icon']"
@click="item.callback()"
/>
<i
v-if="showFold"
:class="['el-icon-d-arrow-left','right-icon']"
@click="handlefoldCard(true)"
/>
</div>
</div>
<div class="content">
<el-tree
:data="formList"
:props="{
children: children,
label: label
}"
v-bind="operateCardTreeAttrs"
@node-click="handleNodeClick"
/>
</div>
</div>
<div
v-if="foldCard"
class="fold"
>
<i
v-if="showFold"
:class="['el-icon-d-arrow-right']"
@click="handlefoldCard(false)"
/>
</div>
</div>
</template>
<script>
export default {
name: 'OperatedCard',
props: {
iconLeftList: {
type: Array,
default: () => [],
},
iconRightList: {
type: Array,
default: () => [],
},
formList: {
type: Array,
default: () => [],
},
// 折叠按钮
showFold: {
type: Boolean,
default: false,
},
// 组件宽度
width: {
type: String,
default: '200px',
},
//
children: {
type: String,
default: 'children',
},
//
label: {
type: String,
default: 'label',
},
operateCardTreeAttrs: {
type: Object,
default: () => {},
},
},
data() {
return {
foldCard: false,
};
},
methods: {
handlefoldCard(bool) {
this.foldCard = bool;
},
handleNodeClick(row) {
this.$emit('handleNodeClick', row);
},
},
};
</script>
<style lang="scss" scoped>
.operateCard {
height: 100%;
.card {
width: 100%;
height: 100%;
background: var(--card-bg);
border: 1px solid var(--input-border);
.title {
width: 100%;
height: 30px;
padding: 0 5px;
border-bottom: 1px solid var(--input-border);
display: flex;
justify-content: space-between;
align-items: center;
.left-icon {
margin-right: 12px;
cursor: pointer;
}
.center {
font-size: 14px;
}
.right-icon {
cursor: pointer;
}
}
.content {
height: calc(100% - 30px);
// padding: 12px;
overflow: scroll;
.content-items {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
}
.content-items:hover {
background-color: #e6f2ff;
}
.content-items-selected {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
background: #7489ff;
color: #ffffff;
}
}
}
:deep(.el-tree>.el-tree-node){
min-width:100%;
display: inline-block;
}
.fold {
height: 100%;
text-align: center;
padding-left: 2px;
background: var(--card-bg);
border: 1px solid var(--input-border);
}
}
.custom-tooltip {
--el-tooltip-fill: #000000; /* 背景色 */
--el-tooltip-color: #ffffff; /* 文字颜色 */
}
</style>
@@ -0,0 +1,61 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
@blur="handleBlurEvent"
@focus="handleFocusEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
</style>
@@ -0,0 +1,88 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
value-format="yyyy-MM-dd"
@input="handleInputEvent"
@blur="handleBlurEvent"
@focus="handleFocusEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner,
.eui-theme-default .el-date-editor--timerange.el-input,
.eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
// 修复placeholder与日期图标重合的样式
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,70 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-radio-group
class="radio"
size="mini"
:value="value"
@input="handleInputEvent"
>
<el-radio
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-radio>
</el-radio-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.radio {
min-height: 30px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,195 @@
<template>
<div class="rcs-search">
<el-form
ref="form"
:model="form"
label-position="left"
:inline="true"
:rules="customRules || rules"
@submit.native.prevent
>
<template v-for=" (item,index) in search">
<template v-if="item.type === 'input'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-input
v-model.trim="form[item.name]"
:placeholder="item.placeholder||'请输入'"
:title="item.placeholder"
:maxlength="item.maxLength"
clearable
:style="item.styleWidth || defaultWidth"
@keyup.enter.native="doEnter(item.type)"
/>
</el-form-item>
</template>
<template v-if="item.type === 'select'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label&&(!item.isNoSign)?item.label+'':item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-select
v-model.trim="form[item.name]"
:disabled="item.disabled"
:placeholder="item.placeholder||'请选择'"
:filterable="item.filterable||true"
:multiple="item.multiple"
:collapse-tags="item.collapseTags"
:clearable="item.clearable||true"
:remote="item.remote||false"
:remote-method="(query)=>remoteMethod(query,item.name)"
:style="item.styleWidth || defaultWidth"
>
<el-option
v-for="inner in item.options"
:key="inner.value"
:label="inner.text"
:value="inner.value"
/>
</el-select>
</el-form-item>
</template>
<template v-if="item.type === 'date'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label&&(!item.isNoSign)?item.label+'':item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-date-picker
v-model.trim="form[item.name]"
type="date"
:value-format="item.format||'yyyy-MM-dd'"
:placeholder="item.placeholder||'请选择'"
/>
</el-form-item>
</template>
</template>
<el-form-item v-if="isShowExpandParams">
<el-button
v-if="!isExpand"
type="text"
@click="updateExpandParams(1)"
>+更多筛选</el-button>
<el-button
v-else
type="text"
@click="updateExpandParams(0)"
>-收起筛选</el-button>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="dosearch()"
>
</el-button>
</el-form-item>
<el-form-item v-if="isShowReset">
<el-button @click="reset()">
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'SearchForm',
props: {
search: {
type: Array,
default: () => [],
required: true,
},
labelWidth: {
type: [Number, String],
default: () => '70',
required: false,
},
defaultValues: {
type: Array,
default: () => [],
},
customRules: {
type: Object,
default: null,
},
isShowExpandParams: { // 扩展展开/收起功能 默认值false:没有展开收起功能
type: Boolean,
default: false,
},
isShowReset: {
type: Boolean,
default: true,
},
},
data() {
return {
form: null,
rules: {},
defaultWidth: {
width: '200px',
},
isExpand: false,
};
},
watch: {
defaultValues: {
handler(val) {
this.defaultValues.forEach(item => {
this.$set(this.form, item.key, item.value);
});
},
deep: true,
},
},
created() {
const obj = {};
for (const item of this.search) {
obj[item.name] = undefined;
if (item.isValid) { // 校验必选条件
const message = item.type === 'input' ? '请输入' : '请选择';
this.rules[item.name] = [
{ required: true, message: item.message ? item.message : message, trigger: 'change' },
];
} else if (item.regex) {
this.rules[item.name] = [
{ required: item.required ?? true, validator: item.validator || this.validator, trigger: 'change' }, // 规则校验:默认是必填,有配置required用配置的值
];
}
}
this.defaultValues.forEach(item => {
obj[item.key] = item.value;
});
this.form = obj;
},
mounted() {
console.log('this.form, this.rules------', this.form, this.rules);
},
methods: {
updateExpandParams(val) {
// val1 展开 0 收起
this.isExpand = !this.isExpand;
},
remoteMethod(query, prop) {
this.$emit('onRemote', query, prop);
},
},
};
</script>
<style lang="scss" scoped>
.rcs-search{
::v-deep .el-date-editor .el-input__inner{
padding-left: 30px;
}
}
</style>
@@ -0,0 +1,116 @@
<template>
<!-- formItems.attrs为假的时候会返空-->
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="select-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="(val)=> handleChange(val,0)"
>
<el-option
v-for="item in formItems.options1"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-model="value[1]"
size="mini"
style="margin-left:5px;"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="(val)=> handleChange(val,1)"
>
<el-option
v-for="item in formItems.options2"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val, i) {
this.value[i] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, i);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
.select-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
</style>
@@ -0,0 +1,85 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="handleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item[formItems.attrs?.optionLabel]||item.label||item.text"
:value="item[formItems.attrs?.optionValue]||item.value"
>
<span style="float: left">{{ item[formItems.attrs?.optionLabel]||item.label||item.text }}</span>
<span
v-if="formItems.attrs?.showValue"
>{{ item[formItems.attrs?.optionValue]||item.value }}</span>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,96 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
filterable
remote
reserve-keyword
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:remote-method="selectApi"
:loading="loading"
@focus="selectfocusApi"
@change="handleInput"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
loading: false,
};
},
methods: {
handleInput(value) {
this.$emit('input', value);
},
selectApi(val) {
// this.loading = true;
this.$emit('outOperation', val);
},
// 聚焦时候拿全部数据
selectfocusApi() {
// this.loading = true;
this.$emit('outOperation', undefined);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,174 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
popper-class="lazy-load-select"
remote
:loading="loading"
:remote-method="remoteMethod"
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<!-- 加载状态提示 -->
<div
v-if="formItems.attrs.loadingMore"
class="load-more-tip"
>
<i class="el-icon-loading" /> 加载中...
</div>
<div
v-if="formItems.attrs.noMore"
class="no-more-tip"
>没有更多数据了</div>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
// loading: false,
// loadingMore: false, //加载更多状态
// noMore: false, // 是否没有更多数据
// page: 1,
// pageSize: 10,
// total: 0,
scrollEl: null, // 保存滚动元素引用
};
},
watch: {
formItems(newval) {
this.formItems = newval;
console.log(formItems.attrs.loadingMore);
},
},
beforeDestroy() {
// 关键点5:组件销毁前移除监听
if (this.scrollEl) {
this.scrollEl.removeEventListener('scroll', this.handleScroll);
}
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
// 下拉框显示/隐藏状态变化
handleVisibleChange(visible) {
if (visible) {
this.$nextTick(() => {
// 关键点2:获取下拉框滚动元素
this.scrollEl = document.querySelector(
'.lazy-load-select .el-select-dropdown__wrap',
);
if (this.scrollEl) {
this.scrollEl.addEventListener('scroll', this.handleScroll);
}
});
} else if (this.scrollEl) {
// 移除监听
this.scrollEl.removeEventListener('scroll', this.handleScroll);
this.scrollEl = null;
}
},
// 滚动事件处理
handleScroll() {
if (!this.scrollEl) return;
const { scrollTop, scrollHeight, clientHeight } = this.scrollEl;
const threshold = 50; // 距离底部阈值(px)
// 关键点3:判断是否滚动到底部
if (scrollHeight - (scrollTop + clientHeight) < threshold) {
this.loadMoreData();
}
},
// 加载更多数据
loadMoreData() {
if (this.formItems.attrs.loadingMore || this.formItems.attrs.noMore) return;
// this.page++;
// this.loadData(true);
this.$emit('getRequestData');
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
/* 关键点6:自定义下拉框样式 */
::v-deep.lazy-load-select .el-select-dropdown__wrap {
max-height: 300px; /* 限制下拉框高度 */
}
/* 加载提示样式 */
.load-more-tip,
.no-more-tip {
padding: 8px 0;
text-align: center;
color: #999;
font-size: 12px;
}
.load-more-tip .el-icon-loading {
margin-right: 5px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'value',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'id',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,45 @@
<template>
<LabelBox
class="switch"
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-switch
v-model="value"
size="mini"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.switch {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,549 @@
<template>
<div class="table-box">
<div
v-if="tableTopButton.length > 0 || isNeedCustomcolumn"
class="need-btn-line"
>
<!-- 列定制按钮 -->
<el-button
v-if="isNeedCustomcolumn"
type="primary"
size="small"
@click="handlecustomcolumnOpen"
>列定制</el-button>
<!-- 自定义按钮 -->
<el-button
v-for="(value, i) in tableTopButton"
:key="'$' + i"
:style="{ fontSize: fontSize + 'px' }"
size="small"
:type="value.type || 'text'"
:icon="value.icon"
:class="value.class"
@click="value.callback(value)"
>{{ value.text }}</el-button>
</div>
<el-table
ref="tableData"
v-loading="loading"
size="default"
:row-key="rowKey"
:style="{ width: '100%', fontSize: fontSize + 'px' }"
:show-header="showHeader"
:data="tableData"
:height="tableHeight"
:cell-style="cellStyle"
:cell-class-name="tableCellClassName"
:span-method="arraySpanMethod"
:border="border"
:highlight-current-row="highlightCurrentRow"
v-bind="tableInfo"
:stripe="isStripe"
:tree-props="{
children: treePropsChildren,
hasChildren: treePropshasChildren,
}"
v-on="events"
@selection-change="handleSelectionChange"
@select-all="handleSelectionAllChange"
>
<slot name="expand" />
<!-- 多选 -->
<el-table-column
v-if="needSelect"
type="selection"
width="30"
:reserve-selection="isReserve"
/>
<!-- 序号 -->
<el-table-column
v-if="hasIndex"
label="序号"
width="50"
type="index"
/>
<template v-for="(item, index) in tableColumn">
<el-table-column
:key="'%' + index"
:show-overflow-tooltip="!item.notTooltip"
v-bind="item"
v-on="events"
>
<!-- 头部 -->
<template
slot="header"
slot-scope="scope"
>
<i
v-if="item.tableTopColumnIcon"
:class="item.tableTopColumnIcon"
@click="handleTableTopColumnIconClick(item,index)"
/>
{{ item.label }}
<span v-if="item.tableTopColumnCheck">
<el-checkbox
v-model="item.tableTopColumnCheckValue"
:v-bind="item.tableTopColumnCheckValue"
:indeterminate="false"
@change="(val)=>
handleTableTopColumncheckChange(item,index,val)"
/>
</span>
</template>
<template slot-scope="scope">
<!-- render 函数式 -->
<template v-if="item.render">
<ex-slot
:render="item.render"
:index="scope.$index"
:row="scope.row"
:column="item"
:class="item.prop"
:default-value="item.defaultValue"
/>
</template>
<!-- progress 进度条 -->
<template v-else-if="item.progress">
<el-progress :percentage="parseFloat(scope.row[item.prop])" />
</template>
<!-- formatter 自定义 -->
<template v-else-if="item.formatter">
<span v-html="item.formatter(scope.row, item)" />
</template>
<!-- checkbox -->
<template v-else-if="item.tableTopColumnCheck">
<el-checkbox
v-model="scope.row[item.prop]"
@change="(val)=>
handleTableTopColumnRowcheckChange(scope,index,val)"
/>
</template>
<!-- 正常列 -->
<template v-else>
<span>
{{ scope.row[item.prop] }}
</span>
</template>
</template>
</el-table-column>
</template>
<!-- 操作 -->
<el-table-column
v-if="hasOperation"
label="操作"
:min-width="operationWidth"
:fixed="operationFixed ? 'right' : false"
align="center"
>
<template
v-if="btnButton.length"
slot-scope="{ row, column, $index }"
>
<el-button
v-for="(value, i) in btnButton"
:key="'$' + i"
:style="{ fontSize: fontSize + 'px' }"
size="small"
:type="value.type || 'text'"
:icon="value.icon"
:class="value.class || 'el-text-color'"
@click="value.callback(row, column, $index)"
>{{ value.text }}</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div
v-if="isNeedPagination"
:style="{
display: 'flex',
justifyContent: operatedString ? 'space-between' : 'flex-end',
alignItems: 'center',
width: '100%',
}"
>
<div
v-if="operatedString"
class="operated"
>{{ operatedString }}</div>
<el-pagination
ref="pagination"
class="no-border-top"
:page-sizes="pageSizes"
:page-size.sync="computedPageSize"
:hide-on-single-page="isSinglePageHide"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="computedCurrentPage"
:total="total"
:small="small"
:pager-count="pagerCount"
@current-change="currentChange"
@size-change="sizeChange"
/>
</div>
<el-drawer
title="数据列"
:visible.sync="drawer"
direction="rtl"
:before-close="handlecustomcolumnClose"
>
<div
v-for="(item, index) in tableData"
:key="index"
class="drawer-custom"
>
<el-checkbox v-model="item.check">{{ item.label }}</el-checkbox>
</div>
<div class="drawer-footer">
<el-button
size="mini"
class="drawer-footer-confirm-btn"
type="primary"
@click="handlecustomcolumnConfirm"
>确定</el-button>
<el-button
size="mini"
class="drawer-footer-cancel-btn"
@click="handlecustomcolumnCancel"
> </el-button>
</div>
</el-drawer>
</div>
</template>
<script>
// 自定义组件的内容
const exSlot = {
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null,
},
},
render: (h, ctx) => {
const params = {
row: ctx.props.row,
index: ctx.props.index,
};
if (ctx.props.column) params.column = ctx.props.column;
return ctx.props.render(h, params);
},
};
export default {
name: 'PublicTable',
components: {
'ex-slot': exSlot,
},
props: {
// key(唯一key值,和reserve-selection搭配使用)
rowKey: {
type: [Object, Function],
default: () => ({}),
},
// 多选框是否记住上一页数据(必须与row-key唯一值搭配使用)
isReserve: {
type: Boolean,
default: false,
},
// 单元格的 style 的回调方法
cellStyle: {
type: [Object, Function],
default: () => ({}),
},
pagerCount: {
type: Number,
default: 7,
},
// 是否显示表头
showHeader: {
type: Boolean,
default: true,
},
// 是否要高亮当前行
highlightCurrentRow: {
type: Boolean,
default: true,
},
// 获取表格行列索引值
tableCellClassName: {
type: Function,
default: () => {},
},
// 合并行或列
arraySpanMethod: {
type: Function,
default: () => {},
},
// 是否需要多选
needSelect: {
type: Boolean,
default: false,
},
// 是否需要序号
hasIndex: {
type: Boolean,
default: false,
},
// 默认是否选中第一列
isSetCurrentRow: {
type: Boolean,
default: false,
},
// 是否需要分页
isNeedPagination: {
type: Boolean,
default: false,
},
// 是否需要 列定制 按钮
isNeedCustomcolumn: {
type: Boolean,
default: false,
},
// 是否单页隐藏,默认为true
isSinglePageHide: {
type: Boolean,
default: true,
},
// 当前页页码,支持.sync修饰符
currentPage: {
type: Number,
default: 1,
},
// 每页数据条数, 支持.sync修饰符默认为每页10条
pageSize: {
type: Number,
default: 20,
},
// 数据总条数
total: {
type: Number,
default: 0,
},
// 每页多少数据
pageSizes: {
type: Array,
required: false,
default: () => [10, 20, 50, 100],
},
tableInfo: {
type: Object,
default: () => {},
},
// 获取数据时是否需要加载loading
loading: {
type: Boolean,
default: false,
},
tableData: {
type: Array,
default: () => [],
},
// 表格展示数据
tableColumn: {
type: Array,
default: () => [],
},
// 是否需要操作列
hasOperation: {
type: Boolean,
default: true,
},
// 是否需要边框
border: {
type: Boolean,
default: false,
},
// 操作 自定义按钮
btnButton: {
type: Array,
default: () => [],
},
// 表格顶部自定义按钮
tableTopButton: {
type: Array,
default: () => [],
},
// 操作列宽度
operationWidth: {
type: String,
default: '60px',
},
// 固定操作栏
operationFixed: {
type: [Boolean, String],
default: false,
},
// 表格方法
events: {
type: Object,
default: () => {},
},
// 是否为斑马纹 table
isStripe: {
type: Boolean,
default: true,
},
// 树结构(树结构必须有rowKey)
treePropsChildren: {
type: String,
default: 'children',
},
// 树结构(树结构必须有rowKey)
treePropshasChildren: {
type: String,
default: 'hasChildren',
},
// 点击图标计算的值
operatedString: {
type: String,
default: '',
},
},
data() {
return {
fontSize: sessionStorage.getItem('fontSize') || '',
drawer: false,
checked: false,
};
},
computed: {
computedCurrentPage: {
get() {
return this.currentPage;
},
set(val) {
this.$emit('update:currentPage', val);
},
},
computedPageSize: {
get() {
return this.pageSize;
},
set(val) {
this.$emit('update:pageSize', val);
},
},
tableHeight() {
return this.tableInfo?.tableHeight ? this.tableInfo?.tableHeight : !this.isNeedPagination ? '100%' : 'calc(100% - 47px)';
},
},
watch: {
},
mounted() {
if (this.isSetCurrentRow) {
setTimeout(() => {
this.$refs.tableData.setCurrentRow(this.tableData[0]);
}, 500);
}
},
methods: {
getTableRef() {
return this.$refs.tableData;
},
currentChange(val) {
this.$emit('currentChange', val);
},
sizeChange(val) {
this.$emit('sizeChange', val);
},
handlecustomcolumnOpen() {
this.drawer = true;
},
handlecustomcolumnClose(done) {
done();
},
handlecustomcolumnCancel() {
this.drawer = false;
},
handlecustomcolumnConfirm() {
this.drawer = false;
this.$emit('customColumnChange', this.tableData);
},
handleTableTopColumnIconClick(item, index) {
this.$emit('handleTableTopColumnIconClick', item, index);
},
handleTableTopColumncheckChange(item, index, val) {
this.$emit('handleTableTopColumncheckChange', item, index, val);
},
handleTableTopColumnRowcheckChange(item, index, val) {
this.$emit('handleTableTopColumnRowcheckChange', item, index, val);
},
handleSelectionChange(row) {
this.$emit('handleSelectionChange', row);
},
handleSelectionAllChange(row) {
this.$emit('handleSelectionAllChange', row);
},
},
};
</script>
<style lang="scss" scoped>
.table-box {
margin-top: 12px;
background-color: #fff;
border: 1px solid #dfe6ec;
}
.need-btn-line {
padding: 8px;
}
::v-deep .el-table td {
padding: 0;
height: 40px;
}
// // table选中行高亮
// ::v-deep .el-table__body tr.current-row {
// .flex_div {
// background: rgba(21, 91, 212, 0.3) !important;
// }
// td {
// background: rgba(21, 91, 212, 0.3) !important;
// }
// td {
// background: rgba(21, 91, 212, 0.2) !important;
// }
// }
::v-deep .el-pagination {
margin-right: 8px;
}
.drawer-custom {
padding: 8px 16px;
}
.drawer-footer {
position: absolute;
display: flex;
flex-direction: row-reverse;
align-items: center;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
.drawer-footer-confirm-btn,
.drawer-footer-cancel-btn {
margin-right: 12px;
}
}
.operated {
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
width: 50%;
}
</style>
@@ -0,0 +1,51 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
type="textarea"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:value="value"
v-bind="formItems.attrs"
:autosize="{
minRows: formItems.attrs.minRows,
maxRows: formItems.attrs.maxRows,
}"
@input="handleInputEvent"
@blur="handleBlurEvent"
@change="handleChangeEvent"
@focus="handleFocusEvent"
@clear="handleClearEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-textarea .el-textarea__inner {
padding: 0 7px;
line-height: 22px;
}
</style>
@@ -0,0 +1,86 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-transfer
v-model="value"
class="transferBox"
:value="value"
:data="formItems.options"
v-bind="formItems.attrs"
@change="handleChange"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: [],
},
},
methods: {
handleChange(val, direction, movedKeys) {
this.$emit('input', val, direction, movedKeys);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
.transferBox {
display: flex;
flex-wrap: nowrap;
align-items: center;
}
::v-deep .el-transfer-panel {
flex: 1;
}
::v-deep.transferBox .el-transfer__buttons {
padding: 0 10px !important;
.el-button {
padding: 0 0;
}
}
::v-deep.transferBox {
line-height: 24px;
.el-transfer-panel__header {
height: 24px;
.el-checkbox {
height: 24px;
line-height: 24px;
.el-checkbox__label {
font-size: 12px;
}
}
}
.el-checkbox__label {
height: 24px;
line-height: 24px;
span {
font-size: 12px;
}
}
.el-checkbox__input {
// top: 8px;
}
}
</style>
@@ -0,0 +1,230 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type === 'input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择-选择 -->
<CSelectSelect
v-if="formItems.type==='selectSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本输入-选择 -->
<CInputSelect
v-if="formItems.type==='inputSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器拆分单个日期 -->
<CPickerDateSingle
v-if="formItems.type==='pickerDateSingle'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
</div>
</template>
<script>
import CInput from './components/input';
import CTextarea from './components/textarea';
import CSelect from './components/select';
import CSelectApi from './components/selectApi';
import CSelectTree from './components/selectTree';
import CSelectTreeApi from './components/selectTreeApi';
import CInputNumber from './components/inputNumber';
import CInputFinance from './components/finance';
import CInputDate from './components/inputDate';
import CPickerDate from './components/pickerDate';
import CPickerTime from './components/pickerTime';
import CRadio from './components/radio';
import CCheckbox from './components/checkbox';
import CSwitch from './components/switch';
import CCascader from './components/cascader';
import CTransfer from './components/transfer';
import CSelectSelect from './components/select-select';
import CInputNumber2 from './components/inputNumber2';
import CInputSelect from './components/input-select';
import CSelectLazyLoading from './components/selectLazyLoading';
import CPickerDateSingle from './components/pickerDateSingle';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CSelectSelect,
CInputNumber2,
CInputSelect,
CSelectLazyLoading,
CPickerDateSingle,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
@@ -0,0 +1,97 @@
<template>
<el-form
ref="ruleForm"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index) in formArr"
v-show="!formItems.notShow"
:key="index"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems,num)"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
watch: {},
created() {},
methods: {
outOperation(val, index, formItems, num) {
// console.log('val, index, formItems, num', val, index, formItems, num);
if (formItems.onchange) {
const changeFn = new Function('value', 'oldValue', formItems.onchange);
changeFn.call(this, val, index, formItems, num);
}
this.$emit('outOperation', val, index, formItems, num);
},
// 提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
return formValidate;
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 12px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
@@ -0,0 +1,60 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
v-on="formItems.events"
@change="handleChangeEvent"
@expand-change="handleExpandchangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
v-on="formItems.events"
@change="handleChangeEvent($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
@@ -0,0 +1,37 @@
export default {
computed: {
},
methods: {
// --------------------- 组件内部方法 begin ------------------//
handleInputEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleChangeEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleBlurEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleFocusEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleClearEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleExpandchangeEvent() {},
// --------------------- 组件内部方法 end ------------------//
// --------------------- 事件处理 begin ------------------//
// --------------------- 以上为组件支持外部调用的API方法 end ------------------//
},
};
@@ -0,0 +1,150 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-input
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>
{{
formItems.attrs.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>
{{
formItems.attrs.append
}}
</template>
</el-input>
<el-select
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange1(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 33px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,90 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInputEvent"
@change="handleChangeEvent"
@clear="handleClearEvent"
>
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>{{
formItems.attrs.prepend
}}</template>
<template
v-if="formItems.attrs?.append"
slot="append"
>{{
formItems.attrs.append
}}</template>
</el-input>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input .el-input__inner::placeholder {
color: #fff;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// d天 m月,y年,
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'd') {
unit = 1;
} else if (lastLetter === 'm') {
unit = 30;
} else if (lastLetter === 'y') {
unit = 365;
}
this.inputValue = (num * unit).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,146 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@blur="handleBlur"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
watch: {
value(nVal) {
if (nVal) {
const val = nVal.toString();
this.inputValue = this.inputValueCopy = this.changePercentile(val);
} else {
this.inputValue = this.inputValueCopy = '';
}
},
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
this.$emit('input', this.inputValue);
},
handleBlur() {
this.delcomma();
let inputValue = this.inputValue;
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
inputValue = num * Math.pow(10, unit);
}
this.inputValue = this.changePercentile(inputValue);
this.$emit('input', inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.delcomma();
},
// 转换千分位
changePercentile(val) {
return val.toLocaleString('en-US', {
minimumFractionDigits: this.formItems?.attrs?.precision || 2,
maximumFractionDigits: this.formItems?.attrs?.precision || 2,
});
},
// 去掉","号
delcomma() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,148 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="displayValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
@keydown="handleKeyDown"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: 0,
},
},
data() {
return {
isFocused: false,
localValue: this.parseValue(this.value),
};
},
computed: {
displayValue() {
if (this.isFocused) {
return this.localValue.toString();
}
return this.formatNumber(this.localValue);
},
},
watch: {
value(newVal) {
if (!this.isFocused) {
this.localValue = this.parseValue(newVal);
}
},
},
methods: {
parseValue(value) {
const num = parseFloat(value);
if (isNaN(num)) return 0;
return num;
},
formatNumber(num) {
if (isNaN(num)) return '0.00';
return num.toLocaleString('en-US', {
minimumFractionDigits: this.formItems?.attrs?.precision || 2,
maximumFractionDigits: this.formItems?.attrs?.precision || 2,
});
},
handleInput(e) {
let value = e
.replace(/[^\d.]/g, '') // 移除非数字和小数点
.replace(/\.{2,}/g, '.') // 只保留第一个小数点
.replace(/(\.\d*)\./g, '$1'); // 禁止输入多个小数点
// 处理开头的小数点
if (value.startsWith('.')) {
value = '0' + value;
}
// 拆分整数和小数部分
const parts = value.split('.');
const integerPart = parts[0].replace(/\D/g, '');
let decimalPart = parts[1] || '';
// 限制小数位数
if (decimalPart.length > (this.formItems?.attrs?.precision || 2)) {
decimalPart = decimalPart.substring(0, (this.formItems?.attrs?.precision || 2));
}
// 拼接最终值
const newValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
const numericValue = parseFloat(newValue) || 0;
// 更新本地值和触发事件
this.localValue = numericValue;
// console.log('this.localValue', this.localValue);
this.$emit('input', this.localValue);
},
handleFocus() {
this.isFocused = true;
},
handleBlur() {
this.isFocused = false;
this.localValue = this.parseValue(this.localValue);
this.$emit('input', this.localValue);
this.$emit('outOperation', this.localValue);
},
handleKeyDown(e) {
// 阻止非法字符输入
if (['e', 'E', '+', '-'].includes(e.key)) {
e.preventDefault();
}
},
},
};
</script>
<style scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 32px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 22px;
line-height: 22px;
top: 2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 32px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,78 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:controls-position="formItems.attrs?.['controls-position'] || 'right'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 32px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 12px !important;
}
.el-input-number__increase{
top:2px;
}
}
::v-deep.el-input-number--mini.is-controls-right {
.el-input-number__decrease {
bottom:2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 32px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,60 @@
<template>
<div class="titiebox">
<div
v-if="label"
:style="{ width: width }"
class="titieboxlabel"
>
{{ label }} <span
v-if="needStar"
style="color: #f00"
>{{ "*" }}</span>
</div>
<div class="titieboxvalue">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
needStar: {
type: Boolean,
default: false,
},
width: {
type: String,
default: '150px',
},
},
};
</script>
<style lang="scss" scoped>
.titiebox {
display: flex;
flex-wrap: nowrap;
align-items: center;
font-size: 12px;
border-left: 1px solid var(--card-border);
width: 100%;
.titieboxlabel {
border-top: 1px solid var(--card-border);
padding-left: 8px;
padding-right: 8px;
height: 32px;
line-height: 32px;
text-align: left;
background-color: var(--desktop-bg-color-2);
}
.titieboxvalue {
flex: 1;
box-sizing: border-box;
}
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor .el-input__inner {
height: 32px;
}
</style>
@@ -0,0 +1,87 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
format="yyyy-MM-dd"
value-format="yyyyMMdd"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner,
.eui-theme-default .el-date-editor--timerange.el-input,
.eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
// 修复placeholder与日期图标重合的样式
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
</style>
@@ -0,0 +1,70 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
format="hh:mm"
value-format="hhmm"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-radio-group
class="radio"
size="mini"
:value="value"
@input="handleInputEvent"
>
<el-radio
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-radio>
</el-radio-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.radio {
min-height: 30px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,150 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请填写'"
v-bind="formItems.attrs2"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs2?.prepend"
slot="prepend"
>
{{
formItems.attrs2.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs2?.append"
slot="append"
>
{{
formItems.attrs2.append
}}
</template>
</el-input>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange1(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 33px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,115 @@
<template>
<!-- formItems.attrs为假的时候会返空-->
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="select-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="(val)=> handleChange(val,0)"
>
<el-option
v-for="item in formItems.options1"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="(val)=> handleChange(val,1)"
>
<el-option
v-for="item in formItems.options2"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val, i) {
this.value[i] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, i);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.select-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
</style>
@@ -0,0 +1,86 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
v-on="formItems.events"
@change="handleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item[formItems.attrs?.optionLabel]||item.label||item.text"
:value="item[formItems.attrs?.optionValue]||item.value"
>
<span style="float: left">{{ item[formItems.attrs?.optionLabel]||item.label||item.text }}</span>
<span
v-if="formItems.attrs?.showValueName"
>{{ item[formItems.attrs?.showValueName]||item.value }}</span>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,96 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
filterable
remote
reserve-keyword
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:remote-method="selectApi"
:loading="loading"
@focus="selectfocusApi"
@change="handleInput"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
loading: false,
};
},
methods: {
handleInput(value) {
this.$emit('input', value);
},
selectApi(val) {
// this.loading = true;
this.$emit('outOperation', val);
},
// 聚焦时候拿全部数据
selectfocusApi() {
// this.loading = true;
this.$emit('outOperation', undefined);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,174 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
popper-class="lazy-load-select"
remote
:loading="loading"
:remote-method="remoteMethod"
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<!-- 加载状态提示 -->
<div
v-if="formItems.attrs.loadingMore"
class="load-more-tip"
>
<i class="el-icon-loading" /> 加载中...
</div>
<div
v-if="formItems.attrs.noMore"
class="no-more-tip"
>没有更多数据了</div>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
// loading: false,
// loadingMore: false, //加载更多状态
// noMore: false, // 是否没有更多数据
// page: 1,
// pageSize: 10,
// total: 0,
scrollEl: null, // 保存滚动元素引用
};
},
watch: {
formItems(newval) {
this.formItems = newval;
console.log(formItems.attrs.loadingMore);
},
},
beforeDestroy() {
// 关键点5:组件销毁前移除监听
if (this.scrollEl) {
this.scrollEl.removeEventListener('scroll', this.handleScroll);
}
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
// 下拉框显示/隐藏状态变化
handleVisibleChange(visible) {
if (visible) {
this.$nextTick(() => {
// 关键点2:获取下拉框滚动元素
this.scrollEl = document.querySelector(
'.lazy-load-select .el-select-dropdown__wrap',
);
if (this.scrollEl) {
this.scrollEl.addEventListener('scroll', this.handleScroll);
}
});
} else if (this.scrollEl) {
// 移除监听
this.scrollEl.removeEventListener('scroll', this.handleScroll);
this.scrollEl = null;
}
},
// 滚动事件处理
handleScroll() {
if (!this.scrollEl) return;
const { scrollTop, scrollHeight, clientHeight } = this.scrollEl;
const threshold = 50; // 距离底部阈值(px)
// 关键点3:判断是否滚动到底部
if (scrollHeight - (scrollTop + clientHeight) < threshold) {
this.loadMoreData();
}
},
// 加载更多数据
loadMoreData() {
if (this.formItems.attrs.loadingMore || this.formItems.attrs.noMore) return;
// this.page++;
// this.loadData(true);
this.$emit('getRequestData');
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
/* 关键点6:自定义下拉框样式 */
::v-deep.lazy-load-select .el-select-dropdown__wrap {
max-height: 300px; /* 限制下拉框高度 */
}
/* 加载提示样式 */
.load-more-tip,
.no-more-tip {
padding: 8px 0;
text-align: center;
color: #999;
font-size: 12px;
}
.load-more-tip .el-icon-loading {
margin-right: 5px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'value',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>

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