Browse Source

add theme update

main
wangshaoping 1 year ago
parent
commit
ec109f67a2
  1. 2
      app.platform/build.gradle
  2. 2
      gradle.properties
  3. 8
      io.sc.platform.core.frontend/.eslintrc.cjs
  4. 3
      io.sc.platform.core.frontend/babel.config.cjs
  5. 3
      io.sc.platform.core.frontend/package.json
  6. 528
      io.sc.platform.core.frontend/src/platform/components/form/PlatformForm.vue
  7. 4
      io.sc.platform.core.frontend/src/platform/components/form/WForm.vue
  8. 15
      io.sc.platform.core.frontend/src/platform/components/grid/EnableIcon.vue
  9. 2473
      io.sc.platform.core.frontend/src/platform/components/grid/PlatformGrid.vue
  10. 30
      io.sc.platform.core.frontend/src/platform/components/grid/PlatformGridTdDrag.vue
  11. 123
      io.sc.platform.core.frontend/src/platform/components/grid/TableAction.vue
  12. 53
      io.sc.platform.core.frontend/src/platform/components/grid/TableRow.vue
  13. 306
      io.sc.platform.core.frontend/src/platform/components/grid/WListGrid.vue
  14. 17
      io.sc.platform.core.frontend/src/platform/components/index.ts
  15. 19
      io.sc.platform.core.frontend/src/platform/index.ts
  16. 5
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue
  17. 20
      io.sc.platform.core.frontend/src/platform/utils/VueTools.ts
  18. 7
      io.sc.platform.core.frontend/src/views/Select.vue
  19. 13
      io.sc.platform.core.frontend/src/views/likm/Grid.vue
  20. 1
      io.sc.platform.core.frontend/src/views/likm/QuasarGrid.vue
  21. 8
      io.sc.platform.core.frontend/template-project/.eslintrc.cjs
  22. 3
      io.sc.platform.core.frontend/template-project/babel.config.cjs
  23. 5
      io.sc.platform.core.frontend/template-project/package.json
  24. 7
      io.sc.platform.core.frontend/template-project/src/views/Select.vue
  25. 1
      io.sc.platform.core.frontend/template-project/tsconfig.json
  26. 1
      io.sc.platform.core.frontend/tsconfig.json
  27. 5
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties
  28. 5
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties
  29. 5
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties
  30. 3
      io.sc.platform.developer.frontend/babel.config.cjs
  31. 5
      io.sc.platform.developer.frontend/package.json
  32. 3
      io.sc.platform.developer.frontend/tsconfig.json
  33. 3
      io.sc.platform.lcdp.frontend/babel.config.cjs
  34. 5
      io.sc.platform.lcdp.frontend/package.json
  35. 3
      io.sc.platform.lcdp.frontend/tsconfig.json
  36. 3
      io.sc.platform.mvc.frontend/babel.config.cjs
  37. 5
      io.sc.platform.mvc.frontend/package.json
  38. 3
      io.sc.platform.mvc.frontend/tsconfig.json
  39. 2
      io.sc.platform.security.frontend/package.json
  40. 3
      io.sc.platform.system.frontend/babel.config.cjs
  41. 5
      io.sc.platform.system.frontend/package.json
  42. 4
      io.sc.platform.system.frontend/src/i18n/messages.json
  43. 9
      io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json
  44. 9
      io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json
  45. 34
      io.sc.platform.system.frontend/src/views/user/Ok.vue
  46. 336
      io.sc.platform.system.frontend/src/views/user/User.vue
  47. 17
      io.sc.platform.system.frontend/src/views/user/UserStatusTag.vue
  48. 1
      io.sc.platform.system.frontend/tsconfig.json

2
app.platform/build.gradle

@ -12,7 +12,7 @@ dependencies {
dependencies { dependencies {
implementation ( implementation (
project(":io.sc.platform.app"), project(":io.sc.platform.app"),
//project(":io.sc.platform.developer"), project(":io.sc.platform.developer"),
//project(":io.sc.platform.job.core"), //project(":io.sc.platform.job.core"),
//project(":io.sc.platform.job.executor"), //project(":io.sc.platform.job.executor"),

2
gradle.properties

@ -38,7 +38,7 @@ application_version=1.0.0
platform_group=io.sc platform_group=io.sc
platform_version=8.1.20 platform_version=8.1.20
platform_plugin_version=8.1.13 platform_plugin_version=8.1.13
platform_core_frontend_version=8.1.55 platform_core_frontend_version=8.1.59
########################################################### ###########################################################
# dependencies version # dependencies version

8
io.sc.platform.core.frontend/.eslintrc.cjs

@ -7,11 +7,6 @@ module.exports = {
"vue/setup-compiler-macros": true, "vue/setup-compiler-macros": true,
}, },
parserOptions:{
ecmaVersion: 2022,
sourceType:"module",
},
extends:[ extends:[
"eslint:recommended", "eslint:recommended",
"plugin:vue/vue3-recommended", "plugin:vue/vue3-recommended",
@ -24,6 +19,9 @@ module.exports = {
ecmaVersion: 2022, ecmaVersion: 2022,
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
sourceType: "module", sourceType: "module",
ecmaFeatures: {
jsx : false
}
}, },
rules:{ rules:{

3
io.sc.platform.core.frontend/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

3
io.sc.platform.core.frontend/package.json

@ -1,6 +1,6 @@
{ {
"name": "platform-core", "name": "platform-core",
"version": "8.1.56", "version": "8.1.60",
"description": "前端核心包,用于快速构建前端的脚手架", "description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件", "//main": "库的主文件",
"main": "dist/platform-core.js", "main": "dist/platform-core.js",
@ -64,6 +64,7 @@
"@typescript-eslint/eslint-plugin": "6.17.0", "@typescript-eslint/eslint-plugin": "6.17.0",
"@typescript-eslint/parser": "6.17.0", "@typescript-eslint/parser": "6.17.0",
"@vue/compiler-sfc": "3.4.3", "@vue/compiler-sfc": "3.4.3",
"@vue/babel-plugin-jsx": "1.1.5",
"@webpack-cli/serve": "2.0.5", "@webpack-cli/serve": "2.0.5",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.16",
"babel-loader": "9.1.3", "babel-loader": "9.1.3",

528
io.sc.platform.core.frontend/src/platform/components/form/PlatformForm.vue

@ -1,528 +0,0 @@
<template>
<q-form ref="formRef" v-bind="extractFormProps(formProps)">
<div class="grid gap-2" :class="formLayoutComputed">
<template v-for="(field, index) in formFields as any" :key="String(index)">
<q-input
v-if="field.type === 'dateRange' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.fmtModelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template #append>
<q-icon :name="PlatformIconEnum.日期范围" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-date
v-model="formData[field.modelName]"
range
:mask="field.mask ? field.mask : 'YYYY-MM-DD'"
:readonly="formStatus === 'view' || field.readonly ? true : false"
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
v-else-if="field.type === 'date' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template #append>
<q-icon :name="PlatformIconEnum.日期" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-date
v-model="formData[field.modelName]"
today-btn
:mask="field.mask ? field.mask : 'YYYY-MM-DD'"
:readonly="formStatus === 'view' || field.readonly ? true : false"
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-select
v-else-if="field.type === 'select' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
@filter="field.filterFun"
@focus="field.focusFun"
>
<template v-if="field.afterButton" #after>
<q-btn
:round="field.afterButton.round"
:dense="field.afterButton.dense"
:flat="field.afterButton.flat"
:unelevated="field.afterButton.unelevated"
:outline="field.afterButton.outline"
:color="field.afterButton.color"
:icon="field.afterButton.icon"
:label="field.afterButton.label"
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false"
@click="field.afterButton.click"
/>
</template>
</q-select>
<q-checkbox
v-else-if="field.type === 'checkbox' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
/>
<div
v-else-if="field.type === 'optionGroup' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
class="border-solid border"
>
<span class="p-2.5">{{ field.label }}</span>
<q-option-group
v-model="formData[field.modelName]"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
/>
</div>
<q-input
v-else-if="index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template v-if="field.afterButton" #after>
<q-btn
round
dense
flat
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false"
:icon="field.afterButton.icon"
@click="field.afterButton.click"
/>
</template>
</q-input>
</template>
</div>
<slot></slot>
</q-form>
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed, toRaw, defineProps } from 'vue';
import {
extractFormProps,
extractFormItemComponentProps,
arrayToMap,
PlatformIconEnum,
FormComponentValidateEnum,
PageStatusEnum,
isEmpty,
} from '@/platform/components/utils';
const props = defineProps({
formProps: {
type: Object,
default: () => {
return { autofocus: false, greedy: true };
},
},
formColsNumber: { type: Number, default: 3 },
formColsAuto: { type: Boolean, default: true },
formFields: {
type: Array,
default: () => {
return [];
},
},
queryFormShowFieldNumber: { type: Number, default: 999 },
});
const formRef = ref();
const formStatus = ref('add');
const formFieldsMap = arrayToMap('modelName', props.formFields);
// class tailwind css
const formLayoutComputed = computed(() => {
let className = '';
switch (props.formColsNumber) {
case 1:
className = !props.formColsAuto ? 'grid-cols-1' : 'xs:grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4';
break;
case 2:
className = !props.formColsAuto ? 'grid-cols-2' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4';
break;
case 4:
className = !props.formColsAuto ? 'grid-cols-4' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-6';
break;
case 5:
className = !props.formColsAuto ? 'grid-cols-5' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-6';
break;
case 6:
className = !props.formColsAuto ? 'grid-cols-6' : 'xs:grid-cols-1 sm:grid-cols-3 md:grid-cols-6 lg:grid-cols-6 xl:grid-cols-6';
break;
case 7:
className = !props.formColsAuto ? 'grid-cols-7' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-7 lg:grid-cols-7 xl:grid-cols-7';
break;
case 8:
className = !props.formColsAuto ? 'grid-cols-8' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-8 lg:grid-cols-8 xl:grid-cols-8';
break;
case 9:
className = !props.formColsAuto ? 'grid-cols-9' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-9 lg:grid-cols-9 xl:grid-cols-9';
break;
case 10:
className = !props.formColsAuto ? 'grid-cols-10' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-10 lg:grid-cols-10 xl:grid-cols-10';
break;
case 11:
className = !props.formColsAuto ? 'grid-cols-11' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-11 lg:grid-cols-11 xl:grid-cols-11';
break;
case 12:
className = !props.formColsAuto ? 'grid-cols-12' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-12 lg:grid-cols-12 xl:grid-cols-12';
break;
default:
className = !props.formColsAuto ? 'grid-cols-3' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6';
}
return className;
});
const selectDefaultValue = (field) => {
if (field.hasOwnProperty('defaultValue') && field.defaultValue !== null) {
if (typeof field.defaultValue === 'string' || typeof field.defaultValue === 'boolean' || typeof field.defaultValue === 'number') {
const dftValue = field.options.filter((item) => {
return item.value === field.defaultValue;
});
if (dftValue && dftValue.length > 0) {
return field.multiple ? [dftValue[0]] : dftValue[0];
} else {
return field.multiple ? [] : '';
}
} else if (Array.isArray(field.defaultValue)) {
const dftValue = field.options.filter((item) => {
return field.defaultValue.filter((val) => {
return val === item.value;
});
});
return field.multiple ? dftValue : dftValue[0];
}
} else {
return field.multiple ? [] : '';
}
};
const numberDefaultValue = (field) => {
if (field.hasOwnProperty('defaultValue') && typeof field.defaultValue === 'number') {
return field.defaultValue;
} else {
return '';
}
};
const checkboxDefaultValue = (field) => {
if (field.hasOwnProperty('defaultValue')) {
return field.defaultValue;
} else {
return false;
}
};
const optionGroupDefaultValue = (field) => {
if (field.hasOwnProperty('defaultValue')) {
return field.defaultValue;
} else if (field.optionGroupType && field.optionGroupType === 'checkbox') {
return [];
} else {
return '';
}
};
const textDefaultValue = (field) => {
if (field.hasOwnProperty('defaultValue')) {
return field.defaultValue;
} else {
return '';
}
};
const formModel: any = {};
for (const field of props.formFields as any) {
if (field.type === 'dateRange') {
formModel[field.fmtModelName] = '';
} else if (field.type === 'select') {
formModel[field.modelName] = selectDefaultValue(field);
} else if (field.type === 'number') {
formModel[field.modelName] = numberDefaultValue(field);
} else if (field.type === 'checkbox') {
formModel[field.modelName] = checkboxDefaultValue(field);
} else if (field.type === 'optionGroup') {
formModel[field.modelName] = optionGroupDefaultValue(field);
} else {
formModel[field.modelName] = textDefaultValue(field);
}
}
const formData = reactive(formModel);
for (const field of props.formFields as any) {
if (field.type === 'dateRange') {
watch(
() => formData[field.modelName],
(newVal, oldVal) => {
if (!newVal || newVal.from === '') {
formData[field.fmtModelName] = '';
} else {
formData[field.fmtModelName] = newVal.from + ' 至 ' + newVal.to;
}
},
);
}
}
const isNumber = (num) => {
return !isNaN(parseFloat(num)) && isFinite(num);
};
const fieldRulesFun = (required, field) => {
let resultRules = <any>[];
if (field.type === 'select' && field.multiple && required) {
resultRules.push((val) => {
if (val !== null && val.length > 0) {
return true;
} else {
return '该字段为必填项';
}
});
} else if (required) {
resultRules.push((val) => (val !== null && val !== '') || '该字段为必填项');
}
if (field.rules && field.rules.length > 0) {
field.rules.forEach((rule) => {
if (typeof rule === 'string' && rule === FormComponentValidateEnum.字符串不能包含空格校验) {
//
resultRules.push((val) => {
if (isEmpty(val) || val.indexOf(' ') === -1) {
return true;
} else {
return '不能包含空格';
}
});
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.默认日期格式校验) {
resultRules.push((val) => {
if (isEmpty(val) || /^(\d{4})-(\d{2})-(\d{2})$/.test(val)) {
return true;
} else {
return '日期格式校验未通过';
}
});
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.必须为整数校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || (tmp.indexOf('.') === -1 && Number.isInteger(parseInt(tmp)))) {
return true;
} else {
return '只能输入整数';
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.字符串最大长度校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || tmp.length <= rule.value) {
return true;
} else {
return '最大允许输入的长度为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.最大小数位数校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || tmp.indexOf('.') === -1 || tmp.substring(tmp.indexOf('.') + 1).length <= rule.value) {
return true;
} else {
return '最大允许输入的小数位数为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最小值校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || parseFloat(tmp) >= rule.value) {
return true;
} else {
return '最小允许输入的值为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最大值校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || parseFloat(tmp) <= rule.value) {
return true;
} else {
return '最大允许输入的值为:' + rule.value;
}
});
} else {
resultRules.push(rule);
}
});
}
return resultRules;
};
const formValidateFun = async () => {
const v = await formValidate();
return v;
};
const formValidate = async () => {
let validate = false;
await formRef.value.validate().then((success) => {
if (success) {
validate = true;
}
});
return validate;
};
const getFormDataFun = () => {
const data = { ...toRaw(formData) };
const selectFields = props.formFields.filter((item: any) => {
return item.type === 'select';
});
selectFields.forEach((item: any) => {
let selectValues = '';
if (item.multiple && data[item.modelName] && data[item.modelName].length > 0) {
data[item.modelName].forEach((val) => {
selectValues = selectValues + ',' + val.value;
});
selectValues = selectValues.substring(1, selectValues.length);
} else if (data[item.modelName]) {
selectValues = data[item.modelName].value ?? data[item.modelName];
}
data[item.modelName] = selectValues;
});
return data;
};
const setFormDataFun = (record) => {
for (const field of props.formFields as any) {
if (field.type === 'select') {
if (field.multiple && record[field.modelName].indexOf(',') > -1) {
const recordSelectValues = record[field.modelName].split(',');
const selectValues = <any>[];
recordSelectValues.forEach((item) => {
selectValues.push(setSelectValue(field.options, item));
});
formData[field.modelName] = selectValues;
} else {
formData[field.modelName] = setSelectValue(field.options, record[field.modelName]);
}
} else if (field.type === 'optionGroup') {
if (record[field.modelName]) {
formData[field.modelName] = record[field.modelName];
} else {
formData[field.modelName] = [];
}
} else {
formData[field.modelName] = record[field.modelName];
}
}
};
const setSelectValue = (options, val) => {
const opt = options.filter((option) => {
return option.value === val;
});
if (opt && opt.length > 0) {
return opt[0];
} else {
return val;
}
};
const setFieldValueFun = (fieldName, value) => {
const field = formFieldsMap.get(fieldName);
if (field.type === 'select') {
if (field.multiple && Array.isArray(value)) {
const selectValues = <any>[];
value.forEach((item) => {
selectValues.push(setSelectValue(field.options, item));
});
formData[field.modelName] = selectValues;
} else {
formData[field.modelName] = setSelectValue(field.options, value);
}
} else {
formData[field.modelName] = value;
}
};
const getFieldValueFun = (fieldName) => {
return formData[fieldName];
};
const resetFormDataFun = () => {
Object.keys(formData).forEach((key) => {
switch (typeof formData[key]) {
case 'string':
formData[key] = '';
break;
case 'boolean':
formData[key] = false;
break;
case 'number':
formData[key] = '';
break;
default:
formData[key] = undefined;
break;
}
});
};
const setFormStatusFun = (status) => {
formStatus.value = status;
};
const getFormStatusFun = () => {
return toRaw(formStatus.value);
};
const getFormFieldMapFun = () => {
return formFieldsMap;
};
defineExpose({
formValidateFun,
getFormDataFun,
setFormDataFun,
getFormStatusFun,
setFormStatusFun,
resetFormDataFun,
setFieldValueFun,
getFieldValueFun,
getFormFieldMapFun,
});
</script>

4
io.sc.platform.core.frontend/src/platform/components/form/WForm.vue

@ -9,8 +9,8 @@
(field.colspan === 'full' (field.colspan === 'full'
? ' col-span-' + screenColsNumComputed ? ' col-span-' + screenColsNumComputed
: field.colspan && screenColsNumComputed >= field.colspan : field.colspan && screenColsNumComputed >= field.colspan
? ' col-span-' + field.colspan ? ' col-span-' + field.colspan
: ' col-span-1') : ' col-span-1')
" "
> >
<component <component

15
io.sc.platform.core.frontend/src/platform/components/grid/EnableIcon.vue

@ -1,15 +0,0 @@
<template>
<div>
<q-icon v-if="value" :name="IconEnum.是状态" color="green" size="sm"> </q-icon>
<q-icon v-else-if="!value && showNoEnable" :name="IconEnum.否状态" color="red" size="sm"> </q-icon>
</div>
</template>
<script lang="ts" setup>
import { IconEnum } from '@/platform/enums';
const props = defineProps({
value: { type: Boolean, default: false }, //
showNoEnable: { type: Boolean, default: false }, //
});
</script>

2473
io.sc.platform.core.frontend/src/platform/components/grid/PlatformGrid.vue

File diff suppressed because it is too large

30
io.sc.platform.core.frontend/src/platform/components/grid/PlatformGridTdDrag.vue

@ -1,30 +0,0 @@
<template>
<div :ref="(node) => drag(drop(node as any))" :class="borderClass">
<q-icon v-if="typeof tdValue[0] === 'boolean' && tdValue[0]" :name="PlatformIconEnum.是状态" color="green" size="sm"> </q-icon>
<template v-else-if="typeof tdValue[0] === 'boolean' && !tdValue[0]"> </template>
<template v-else>
{{ tdValue[0] }}
</template>
</div>
</template>
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { toRefs } from '@vueuse/core';
import { PlatformIconEnum } from '@/platform/components/utils';
const props = defineProps({
tdValue: {
type: Array,
default: () => {
return [];
},
},
rowIndex: { type: Number, default: 0 },
});
const emit = defineEmits(['tableSortFun']);
export interface DropResult {
name: string;
}
</script>

123
io.sc.platform.core.frontend/src/platform/components/grid/TableAction.vue

@ -1,123 +0,0 @@
<template>
<div class="flex flex-nowrap py-2">
<div ref="titleContainerRef" class="flex items-end text-subtitle2 text-no-wrap">{{ title }}</div>
<q-space />
<div ref="actionContainerRef" class="flex flex-nowrap">
<!-- baseActions -->
<template v-for="(action, index) in baseActions" :key="'baseAction_' + index">
<q-separator
v-if="action.separator"
vertical
class="class-action-item"
:style="{
'margin-left': '5px',
'margin-right': '5px',
}"
/>
<q-btn
v-else
v-bind="action"
:id="action.name"
:disable="action.enableIf ? !action.enableIf() : false"
no-wrap
class="class-action-item"
:style="{
'margin-left': '5px',
'margin-right': '5px',
}"
@click="action.click"
/>
</template>
<!-- moreActions -->
<q-btn-dropdown v-if="moreActions && moreActions.length > 0" :label="$t('more')" class="class-action-item" style="margin-left: 5px">
<q-list>
<template v-for="(action, index) in moreActions" :key="'moreAction_' + index">
<q-separator v-if="action.separator" />
<q-item v-else v-close-popup clickable @click="action.click">
<q-item-section avatar style="min-width: 28px; padding-right: 0px">
<q-icon :name="action.icon" size="20px" />
</q-item-section>
<q-item-section>
<q-item-label :v-bind="action">{{ action.label }}</q-item-label>
</q-item-section>
</q-item>
</template>
</q-list>
</q-btn-dropdown>
</div>
<q-resize-observer @resize="onResize" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Tools } from '@/platform/utils';
const props = defineProps({
title: { type: String, default: '' },
noActionIcon: { type: Boolean, default: false },
actions: {
type: Array,
default: () => {
return [];
},
},
});
const titleContainerRef = ref();
const actionContainerRef = ref();
const actions = props.actions;
if (actions && actions.length > 0 && props.noActionIcon) {
for (const action of actions) {
action.icon = undefined;
}
}
const baseActions = ref(actions);
const moreActions = ref([]);
const isActionWidthInitializedRef = ref(false);
const moreActionWidth = 100;
const onResize = (size) => {
if (Tools.isUndefinedOrNull(titleContainerRef.value) || Tools.isUndefinedOrNull(actionContainerRef.value)) {
return;
}
if (!isActionWidthInitializedRef.value) {
const nodes = actionContainerRef.value.getElementsByClassName('class-action-item');
for (let i = 0; i < actions.length; i++) {
actions[i].width = nodes[i].clientWidth + 10;
}
isActionWidthInitializedRef.value = true;
}
const _baseActions = [];
const _moreActions = [];
const length = actions.length;
let availableWidth = size.width - titleContainerRef.value.clientWidth;
let width = 0;
let index = 0;
for (; index < length; index++) {
if (width + actions[index].width > availableWidth) {
availableWidth -= moreActionWidth;
while (width > availableWidth) {
index--;
width -= actions[index].width;
_baseActions.pop();
}
break;
} else {
_baseActions.push(actions[index]);
width += actions[index].width;
}
}
for (; index < length; index++) {
_moreActions.push(actions[index]);
}
baseActions.value = _baseActions;
moreActions.value = _moreActions;
};
</script>

53
io.sc.platform.core.frontend/src/platform/components/grid/TableRow.vue

@ -1,53 +0,0 @@
<template>
<q-tr>
<q-td v-for="(col, index) in cols" :key="col.name" :style="{ 'padding-left': index == 0 ? '2px' : '7px' }">
<div class="flex flex-nowrap items-center">
<template v-if="index == 0">
<!--层级占位符-->
<span :style="`width:${27 * props.level}px;`"></span>
<!--展开按钮-->
<q-btn
v-if="data.children && data.children.length > 0"
flat
size="16px"
dense
padding="0px 0px"
:icon="data.expand ? 'bi-dash' : 'bi-plus'"
@click="data.expand = !data.expand"
/>
<!--展开按钮占位符-->
<span v-else style="width: 27px"></span>
<!--选择框-->
<q-checkbox v-model="data.selected" flat size="40px" dense />
<!--文件夹图标-->
<q-icon v-if="data.children && data.children.length > 0" name="sym_o_folder_open" size="20px" class="px-1"></q-icon>
<!--文件图标-->
<q-icon v-else name="bi-file-earmark" size="16px" class="px-1"></q-icon>
</template>
<div v-dompurify-html="col.format ? col.format(data[col.name], data) : col.value"></div>
</div>
</q-td>
</q-tr>
<template v-for="child in data.children" :key="child.id">
<TableRow v-if="data.expand" :cols="cols" :data="child" :level="props.level + 1"></TableRow>
</template>
</template>
<script setup lang="ts">
const props = defineProps({
level: { type: Number, default: 0 },
cols: {
type: Array,
default: () => {
return [];
},
},
data: {
type: Object,
default: () => {
return {};
},
},
});
const cols = props.cols;
const data = props.data;
</script>

306
io.sc.platform.core.frontend/src/platform/components/grid/WListGrid.vue

@ -1,306 +0,0 @@
<template>
<div>
<div class="row q-gutter-x-md q-gutter-y-sm">
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense :options="['ksdjlfsd', 'sdkjfklsd']" />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
<q-input label="loginName" outlined dense />
</div>
<TableAction title="User List" :no-action-icon="props.noActionIcon" :actions="tableActions"></TableAction>
<q-table flat bordered separator="cell" :rows="data" :columns="columns" row-key="name">
<template #header="headerProps">
<q-tr :props="headerProps">
<q-th v-for="col in headerProps.cols" :key="col.name" :props="headerProps">
{{ col.label }}
</q-th>
</q-tr>
</template>
<template #body="bodyProps">
<TableRow :cols="bodyProps.cols" :data="bodyProps.row"></TableRow>
</template>
</q-table>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { axios, Tools, TreeBuilder } from '@/platform';
import TableAction from './TableAction.vue';
import TableRow from './TableRow.vue';
const props = defineProps({
tree: { type: Boolean, default: false },
title: { type: String, default: '' },
noActionIcon: { type: Boolean, default: false },
targetObjectName: { type: String, default: '' },
actions: {
type: Array,
default: () => {
return [];
},
},
columns: {
type: Array,
default: () => {
return [];
},
},
autoFetchData: { type: Boolean, default: false },
dataUrl: { type: String, default: undefined },
fetchDataUrl: { type: String, default: undefined },
addDataUrl: { type: String, default: undefined },
removeDataUrl: { type: String, default: undefined },
updateDataUrl: { type: String, default: undefined },
});
const { t } = useI18n();
const defaultTableActions = {
separator: {
separator: true,
},
query: {
name: 'query',
label: t('query'),
icon: 'bi-search',
click: () => {
console.log('query');
},
},
refresh: {
name: 'refresh',
label: t('refresh'),
icon: 'bi-arrow-clockwise',
click: () => {
console.log('refresh');
},
},
add: {
name: 'add',
label: t('addNew'),
icon: 'bi-plus-lg',
click: () => {
console.log('add');
},
},
clone: {
name: 'clone',
label: t('clone'),
icon: 'content_copy',
click: () => {
console.log('clone');
},
},
edit: {
name: 'edit',
label: t('edit'),
icon: 'bi-pencil-square',
click: () => {
console.log('edit');
},
},
remove: {
name: 'remove',
label: t('delete'),
icon: 'bi-x-lg',
click: () => {
console.log('remove');
},
},
removeAll: {
name: 'removeAll',
label: t('deleteAll'),
click: () => {
console.log('removeAll');
},
},
detail: {
name: 'detail',
label: t('detail'),
icon: 'bi-info-circle',
click: () => {
console.log('detail');
},
},
expandAll: {
name: 'expandAll',
label: t('expandAll'),
icon: 'bi-plus-square',
click: () => {
console.log('expandAll');
},
},
selectAll: {
name: 'selectAll',
label: t('selectAll'),
icon: 'bi-check-square',
click: () => {
console.log('selectAll');
},
},
addTop: {
name: 'addTop',
label: t('addTop', { object: props.targetObjectName }),
icon: 'addTop',
click: () => {
console.log('addTop');
},
},
addChild: {
name: 'addChild',
label: t('addChild', { object: props.targetObjectName }),
icon: 'addChild',
click: () => {
console.log('addChild');
},
},
};
const tableActions = [];
if (props.actions && props.actions.length > 0) {
for (const action of props.actions) {
if (Tools.isString(action)) {
tableActions.push(defaultTableActions[action]);
} else if (Tools.isObject(action)) {
tableActions.push(action);
}
}
}
const data = ref([]);
if (props.autoFetchData) {
axios.get(props.fetchDataUrl ? props.fetchDataUrl : props.dataUrl).then((response) => {
if (props.tree) {
data.value = TreeBuilder.build(response.data);
}
});
}
const selected = ref([]);
const val2 = ref(true);
const rows = ref([
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%',
selected: true,
children: [
{
name: 'Ice cream sandwich3',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
sodium: 129,
calcium: '8%',
iron: '1%',
},
],
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
sodium: 129,
calcium: '8%',
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
sodium: 337,
calcium: '6%',
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
sodium: 413,
calcium: '3%',
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
sodium: 327,
calcium: '7%',
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
sodium: 50,
calcium: '0%',
iron: '0%',
},
{
name: '<span style="color: red">This should be red.</span>',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
sodium: 38,
calcium: '0%',
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
sodium: 562,
calcium: '0%',
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
sodium: 326,
calcium: '2%',
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
sodium: 54,
calcium: '12%',
iron: '6%',
},
]);
</script>

17
io.sc.platform.core.frontend/src/platform/components/index.ts

@ -10,11 +10,8 @@ import WCodemirror from './widget/codemirror/WCodemirror.vue';
import WTreeGrid from './tree/WTreeGrid.vue'; import WTreeGrid from './tree/WTreeGrid.vue';
import WDialog from './dialog/WDialog.vue'; import WDialog from './dialog/WDialog.vue';
import PlatformDialog from './dialog/PlatformDialog.vue';
import PlatformDrawer from './drawer/PlatformDrawer.vue';
import WDrawer from './drawer/WDrawer.vue'; import WDrawer from './drawer/WDrawer.vue';
import PlatformForm from './form/PlatformForm.vue';
import WForm from './form/WForm.vue'; import WForm from './form/WForm.vue';
import WText from './form/elements/WText.vue'; import WText from './form/elements/WText.vue';
import WNumber from './form/elements/WNumber.vue'; import WNumber from './form/elements/WNumber.vue';
@ -27,10 +24,7 @@ import WPassword from './form/elements/WPassword.vue';
import WInfoPanel from './panel/WInfoPanel.vue'; import WInfoPanel from './panel/WInfoPanel.vue';
import PlatformGrid from './grid/PlatformGrid.vue';
import WGrid from './grid/WGrid.vue'; import WGrid from './grid/WGrid.vue';
import PlatformGridTdDrag from './grid/PlatformGridTdDrag.vue';
import WToolbar from './toolbar/WToolbar.vue'; import WToolbar from './toolbar/WToolbar.vue';
export default { export default {
@ -47,9 +41,7 @@ export default {
app.component('WTreeGrid', WTreeGrid); app.component('WTreeGrid', WTreeGrid);
app.component('WDialog', WDialog); app.component('WDialog', WDialog);
app.component('PlatformDialog', PlatformDialog);
app.component('WDrawer', WDrawer); app.component('WDrawer', WDrawer);
app.component('PlatformDrawer', PlatformDrawer);
app.component('WForm', WForm); app.component('WForm', WForm);
app.component('WText', WText); app.component('WText', WText);
app.component('WNumber', WNumber); app.component('WNumber', WNumber);
@ -61,11 +53,7 @@ export default {
app.component('WInfoPanel', WInfoPanel); app.component('WInfoPanel', WInfoPanel);
app.component('PlatformForm', PlatformForm);
app.component('PlatformGrid', PlatformGrid);
app.component('WGrid', WGrid); app.component('WGrid', WGrid);
app.component('PlatformGridTdDrag', PlatformGridTdDrag);
app.component('WToolbar', WToolbar); app.component('WToolbar', WToolbar);
}, },
}; };
@ -81,10 +69,7 @@ export {
WSelect, WSelect,
WTreeGrid, WTreeGrid,
WDialog, WDialog,
PlatformDialog,
PlatformDrawer,
WDrawer, WDrawer,
PlatformForm,
WForm, WForm,
WText, WText,
WNumber, WNumber,
@ -93,9 +78,7 @@ export {
WCheckbox, WCheckbox,
WTextBtn, WTextBtn,
WPassword, WPassword,
PlatformGrid,
WGrid, WGrid,
PlatformGridTdDrag,
WToolbar, WToolbar,
}; };

19
io.sc.platform.core.frontend/src/platform/index.ts

@ -92,27 +92,12 @@ export { JavascriptLoader } from './utils';
export { QuasarTools } from './utils'; export { QuasarTools } from './utils';
export { Tools } from './utils'; export { Tools } from './utils';
export { TreeBuilder } from './utils'; export { TreeBuilder } from './utils';
export { VueTools } from './utils';
/** /**
* UI * UI
*/ */
export { export { WPlatformPage, WIconEmpty, WHScreenDiv, WColorInput, WColorInputPalette, WPosition, WCodemirror, WSelect, WGrid, WTreeGrid } from './components';
WPlatformPage,
WIconEmpty,
WHScreenDiv,
WColorInput,
WColorInputPalette,
WPosition,
WCodemirror,
WSelect,
// WListGrid,
WTreeGrid,
PlatformDialog,
PlatformDrawer,
PlatformForm,
PlatformGrid,
PlatformGridTdDrag,
} from './components';
export { PlatformIconEnum } from './components'; export { PlatformIconEnum } from './components';
export { PageStatusEnum } from './components'; export { PageStatusEnum } from './components';

5
io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue

@ -128,6 +128,11 @@
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-separator inset spaced /> <q-separator inset spaced />
<q-item v-close-popup clickable>
<q-item-section>
<q-item-label><q-icon name="verified_user" left size="20px"></q-icon>{{ t('changePassword') }}</q-item-label>
</q-item-section>
</q-item>
<q-item v-close-popup clickable> <q-item v-close-popup clickable>
<q-item-section> <q-item-section>
<q-item-label><q-icon name="group" left size="20px"></q-icon>{{ t('changeRole') }}</q-item-label> <q-item-label><q-icon name="group" left size="20px"></q-icon>{{ t('changeRole') }}</q-item-label>

20
io.sc.platform.core.frontend/src/platform/utils/VueTools.ts

@ -0,0 +1,20 @@
import { Tools } from '.';
class VueTools {
/**
* vue vue , 便使
* @param instance vue
*/
public static expose2Instance(instance: any): void {
const exposeds = instance.exposed || {};
for (const exposed in exposeds) {
if (Tools.isUndefinedOrNull(instance[exposed])) {
instance[exposed] = exposeds[exposed];
} else {
console.warn(exposed + ' already exists in component insatance!');
}
}
}
}
export { VueTools };

7
io.sc.platform.core.frontend/src/views/Select.vue

@ -4,13 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { BackendTools } from '@/platform'; import { EnumTools } from '@/platform';
import { QBtn } from 'quasar';
const { t } = useI18n(); const { t } = useI18n();
const model = ref('value-2'); const model = ref('value');
const options = ref(); const options = ref();
BackendTools.enmus('io.sc.platform.flowable.enums.ProcessStatus', t).then((data) => { EnumTools.fetch('io.sc.platform.flowable.enums.ProcessStatus', t).then((data) => {
console.log(data.map); console.log(data.map);
options.value = data.map; options.value = data.map;
}); });

13
io.sc.platform.core.frontend/src/views/likm/Grid.vue

@ -1,5 +1,6 @@
<template> <template>
<div> <div>
<component :is="aaa"></component>
<w-grid <w-grid
:title="testGrid.title" :title="testGrid.title"
draggable draggable
@ -19,7 +20,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'; import { ref, onMounted, nextTick, h } from 'vue';
import { QBtn } from 'quasar';
import { axios, Environment } from '@/platform'; import { axios, Environment } from '@/platform';
import EnableIcon from '@/platform/components/grid/EnableIcon.vue'; import EnableIcon from '@/platform/components/grid/EnableIcon.vue';
import { IconEnum } from '@/platform/enums'; import { IconEnum } from '@/platform/enums';
@ -101,7 +103,14 @@ const testGrid = {
label: '用户信息', label: '用户信息',
childrenColumns: [ childrenColumns: [
{ name: 'loginName', label: '登录名', align: 'right' }, { name: 'loginName', label: '登录名', align: 'right' },
{ name: 'userName', label: '用户名' }, {
name: 'userName',
label: '用户名',
format: () => {
const a = h(QBtn, { label: 'ok' }, 'OK');
console.log(a);
},
},
], ],
}, },
{ {

1
io.sc.platform.core.frontend/src/views/likm/QuasarGrid.vue

@ -10,7 +10,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import TableRow from '@/platform/components/grid/TableRow.vue';
const columns = [ const columns = [
{ {

8
io.sc.platform.core.frontend/template-project/.eslintrc.cjs

@ -7,11 +7,6 @@ module.exports = {
"vue/setup-compiler-macros": true, "vue/setup-compiler-macros": true,
}, },
parserOptions:{
ecmaVersion: 2022,
sourceType:"module",
},
extends:[ extends:[
"eslint:recommended", "eslint:recommended",
"plugin:vue/vue3-recommended", "plugin:vue/vue3-recommended",
@ -24,6 +19,9 @@ module.exports = {
ecmaVersion: 2022, ecmaVersion: 2022,
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
sourceType: "module", sourceType: "module",
ecmaFeatures: {
jsx : false
}
}, },
rules:{ rules:{

3
io.sc.platform.core.frontend/template-project/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

5
io.sc.platform.core.frontend/template-project/package.json

@ -1,6 +1,6 @@
{ {
"name": "platform-core", "name": "platform-core",
"version": "8.1.56", "version": "8.1.60",
"description": "前端核心包,用于快速构建前端的脚手架", "description": "前端核心包,用于快速构建前端的脚手架",
"private": false, "private": false,
"keywords": [], "keywords": [],
@ -36,6 +36,7 @@
"@typescript-eslint/eslint-plugin": "6.17.0", "@typescript-eslint/eslint-plugin": "6.17.0",
"@typescript-eslint/parser": "6.17.0", "@typescript-eslint/parser": "6.17.0",
"@vue/compiler-sfc": "3.4.3", "@vue/compiler-sfc": "3.4.3",
"@vue/babel-plugin-jsx": "1.1.5",
"@webpack-cli/serve": "2.0.5", "@webpack-cli/serve": "2.0.5",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.16",
"babel-loader": "9.1.3", "babel-loader": "9.1.3",
@ -91,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.56", "platform-core": "8.1.60",
"quasar": "2.14.2", "quasar": "2.14.2",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

7
io.sc.platform.core.frontend/template-project/src/views/Select.vue

@ -4,13 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { BackendTools } from 'platform-core'; import { EnumTools } from 'platform-core';
import { QBtn } from 'quasar';
const { t } = useI18n(); const { t } = useI18n();
const model = ref('value-2'); const model = ref('value');
const options = ref(); const options = ref();
BackendTools.enmus('io.sc.platform.flowable.enums.ProcessStatus', t).then((data) => { EnumTools.fetch('io.sc.platform.flowable.enums.ProcessStatus', t).then((data) => {
console.log(data.map); console.log(data.map);
options.value = data.map; options.value = data.map;
}); });

1
io.sc.platform.core.frontend/template-project/tsconfig.json

@ -5,6 +5,7 @@
"module": "node16", "module": "node16",
"strict": true, "strict": true,
"jsx": "preserve", "jsx": "preserve",
"jsxImportSource": "vue",
"noEmit": true, "noEmit": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"noImplicitAny": false, "noImplicitAny": false,

1
io.sc.platform.core.frontend/tsconfig.json

@ -12,6 +12,7 @@
"module": "node16", /* Specify what module code is generated. */ "module": "node16", /* Specify what module code is generated. */
"strict": true, /* Enable all strict type-checking options. */ "strict": true, /* Enable all strict type-checking options. */
"jsx": "preserve", /* Specify what JSX code is generated. */ "jsx": "preserve", /* Specify what JSX code is generated. */
"jsxImportSource": "vue",
"noEmit":true, /* Disable emitting files from a compilation. */ "noEmit":true, /* Disable emitting files from a compilation. */
"allowImportingTsExtensions":true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ "allowImportingTsExtensions":true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
"noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied 'any' type. */

5
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties

@ -10,6 +10,7 @@ bottom-right=Bottom Right
bottom=Bottom bottom=Bottom
cancel=Cancel cancel=Cancel
center=Center center=Center
changePassword=Change Password
changeRole=Change Role changeRole=Change Role
className=Class className=Class
clone=Clone clone=Clone
@ -18,6 +19,8 @@ code=Code
confirm=Confirm confirm=Confirm
confirmPassword=Confirm Password confirmPassword=Confirm Password
content=Content content=Content
corporation=Corporation
corporationCode=Corporation Code
createDate=Create Date createDate=Create Date
creator=Creator creator=Creator
dataComeFrom=Data Come From dataComeFrom=Data Come From
@ -26,6 +29,7 @@ delete=Delete
deleteAll=Delete All deleteAll=Delete All
description=Description description=Description
detail=Detail detail=Detail
disable=Disable
displayValue=Display Value displayValue=Display Value
download=Download download=Download
edit=Edit edit=Edit
@ -82,6 +86,7 @@ newValue=New Value
next=Next next=Next
nextPage=Next Page nextPage=Next Page
no=No no=No
normal=Normal
oldValue=Old Value oldValue=Old Value
order=Order order=Order
org=Org org=Org

5
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties

@ -10,6 +10,7 @@ bottom-right=\u53F3\u4E0B
bottom=\u4E0B\u908A bottom=\u4E0B\u908A
cancel=\u53D6\u6D88 cancel=\u53D6\u6D88
center=\u4E2D\u5FC3 center=\u4E2D\u5FC3
changePassword=\u4FEE\u6539\u767B\u9304\u5BC6\u78BC
changeRole=\u5207\u63DB\u89D2\u8272 changeRole=\u5207\u63DB\u89D2\u8272
className=\u985E\u540D className=\u985E\u540D
clone=\u8907\u88FD clone=\u8907\u88FD
@ -18,6 +19,8 @@ code=\u4EE3\u78BC
confirm=\u78BA\u5B9A confirm=\u78BA\u5B9A
confirmPassword=\u78BA\u8A8D\u5BC6\u78BC confirmPassword=\u78BA\u8A8D\u5BC6\u78BC
content=\u5167\u5BB9 content=\u5167\u5BB9
corporation=\u6CD5\u4EBA
corporationCode=\u6CD5\u4EBA\u4EE3\u78BC
createDate=\u5275\u5EFA\u65E5\u671F createDate=\u5275\u5EFA\u65E5\u671F
creator=\u5275\u5EFA\u4EBA creator=\u5275\u5EFA\u4EBA
dataComeFrom=\u6578\u64DA\u4F86\u6E90 dataComeFrom=\u6578\u64DA\u4F86\u6E90
@ -26,6 +29,7 @@ delete=\u522A\u9664
deleteAll=\u522A\u9664\u5168\u90E8 deleteAll=\u522A\u9664\u5168\u90E8
description=\u63CF\u8FF0 description=\u63CF\u8FF0
detail=\u8A73\u60C5 detail=\u8A73\u60C5
disable=\u7981\u7528
displayValue=\u986F\u793A\u503C displayValue=\u986F\u793A\u503C
download=\u4E0B\u8F09 download=\u4E0B\u8F09
edit=\u7DE8\u8F2F edit=\u7DE8\u8F2F
@ -82,6 +86,7 @@ newValue=\u65B0\u503C
next=\u4E0B\u4E00 next=\u4E0B\u4E00
nextPage=\u4E0B\u4E00\u9801 nextPage=\u4E0B\u4E00\u9801
no=\u5426 no=\u5426
normal=\u6B63\u5E38
oldValue=\u539F\u503C oldValue=\u539F\u503C
order=\u9806\u5E8F order=\u9806\u5E8F
org=\u6A5F\u69CB org=\u6A5F\u69CB

5
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties

@ -10,6 +10,7 @@ bottom-right=\u53F3\u4E0B
bottom=\u4E0B\u8FB9 bottom=\u4E0B\u8FB9
cancel=\u53D6\u6D88 cancel=\u53D6\u6D88
center=\u4E2D\u5FC3 center=\u4E2D\u5FC3
changePassword=\u4FEE\u6539\u767B\u5F55\u5BC6\u7801
changeRole=\u5207\u6362\u89D2\u8272 changeRole=\u5207\u6362\u89D2\u8272
className=\u7C7B\u540D className=\u7C7B\u540D
clone=\u590D\u5236 clone=\u590D\u5236
@ -18,6 +19,8 @@ code=\u4EE3\u7801
confirm=\u786E\u5B9A confirm=\u786E\u5B9A
confirmPassword=\u786E\u8BA4\u5BC6\u7801 confirmPassword=\u786E\u8BA4\u5BC6\u7801
content=\u5185\u5BB9 content=\u5185\u5BB9
corporation=\u6CD5\u4EBA
corporationCode=\u6CD5\u4EBA\u4EE3\u7801
createDate=\u521B\u5EFA\u65E5\u671F createDate=\u521B\u5EFA\u65E5\u671F
creator=\u521B\u5EFA\u4EBA creator=\u521B\u5EFA\u4EBA
dataComeFrom=\u6570\u636E\u6765\u6E90 dataComeFrom=\u6570\u636E\u6765\u6E90
@ -26,6 +29,7 @@ delete=\u522A\u9664
deleteAll=\u5220\u9664\u5168\u90E8 deleteAll=\u5220\u9664\u5168\u90E8
description=\u63CF\u8FF0 description=\u63CF\u8FF0
detail=\u8BE6\u60C5 detail=\u8BE6\u60C5
disable=\u7981\u7528
displayValue=\u663E\u793A\u503C displayValue=\u663E\u793A\u503C
download=\u4E0B\u8F7D download=\u4E0B\u8F7D
edit=\u7F16\u8F91 edit=\u7F16\u8F91
@ -82,6 +86,7 @@ newValue=\u65B0\u503C
next=\u4E0B\u4E00 next=\u4E0B\u4E00
nextPage=\u4E0B\u4E00\u9875 nextPage=\u4E0B\u4E00\u9875
no=\u5426 no=\u5426
normal=\u6B63\u5E38
oldValue=\u539F\u503C oldValue=\u539F\u503C
order=\u987A\u5E8F order=\u987A\u5E8F
org=\u673A\u6784 org=\u673A\u6784

3
io.sc.platform.developer.frontend/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

5
io.sc.platform.developer.frontend/package.json

@ -64,7 +64,8 @@
"webpack-bundle-analyzer": "4.10.1", "webpack-bundle-analyzer": "4.10.1",
"webpack-cli": "5.1.4", "webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1", "webpack-dev-server": "4.15.1",
"webpack-merge": "5.10.0" "webpack-merge": "5.10.0",
"@vue/babel-plugin-jsx": "1.1.5"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.16.9", "@quasar/extras": "1.16.9",
@ -77,7 +78,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.55", "platform-core": "8.1.59",
"quasar": "2.14.2", "quasar": "2.14.2",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

3
io.sc.platform.developer.frontend/tsconfig.json

@ -15,6 +15,7 @@
"@/*": [ "@/*": [
"src/*" "src/*"
] ]
} },
"jsxImportSource": "vue"
} }
} }

3
io.sc.platform.lcdp.frontend/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

5
io.sc.platform.lcdp.frontend/package.json

@ -64,7 +64,8 @@
"webpack-bundle-analyzer": "4.10.1", "webpack-bundle-analyzer": "4.10.1",
"webpack-cli": "5.1.4", "webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1", "webpack-dev-server": "4.15.1",
"webpack-merge": "5.10.0" "webpack-merge": "5.10.0",
"@vue/babel-plugin-jsx": "1.1.5"
}, },
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "6.11.1", "@codemirror/autocomplete": "6.11.1",
@ -90,7 +91,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.55", "platform-core": "8.1.59",
"quasar": "2.14.2", "quasar": "2.14.2",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

3
io.sc.platform.lcdp.frontend/tsconfig.json

@ -15,6 +15,7 @@
"@/*": [ "@/*": [
"src/*" "src/*"
] ]
} },
"jsxImportSource": "vue"
} }
} }

3
io.sc.platform.mvc.frontend/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

5
io.sc.platform.mvc.frontend/package.json

@ -64,7 +64,8 @@
"webpack-bundle-analyzer": "4.10.1", "webpack-bundle-analyzer": "4.10.1",
"webpack-cli": "5.1.4", "webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1", "webpack-dev-server": "4.15.1",
"webpack-merge": "5.10.0" "webpack-merge": "5.10.0",
"@vue/babel-plugin-jsx": "1.1.5"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.16.9", "@quasar/extras": "1.16.9",
@ -77,7 +78,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.55", "platform-core": "8.1.59",
"quasar": "2.14.2", "quasar": "2.14.2",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

3
io.sc.platform.mvc.frontend/tsconfig.json

@ -15,6 +15,7 @@
"@/*": [ "@/*": [
"src/*" "src/*"
] ]
} },
"jsxImportSource": "vue"
} }
} }

2
io.sc.platform.security.frontend/package.json

@ -99,6 +99,6 @@
"vue-dompurify-html": "5.0.1", "vue-dompurify-html": "5.0.1",
"vue-i18n": "9.8.0", "vue-i18n": "9.8.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"platform-core": "8.1.55" "platform-core": "8.1.59"
} }
} }

3
io.sc.platform.system.frontend/babel.config.cjs

@ -10,6 +10,7 @@ module.exports = {
], ],
plugins: [ plugins: [
"@babel/plugin-transform-class-properties", "@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread" "@babel/plugin-transform-object-rest-spread",
"@vue/babel-plugin-jsx",
] ]
} }

5
io.sc.platform.system.frontend/package.json

@ -64,7 +64,8 @@
"webpack-bundle-analyzer": "4.10.1", "webpack-bundle-analyzer": "4.10.1",
"webpack-cli": "5.1.4", "webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1", "webpack-dev-server": "4.15.1",
"webpack-merge": "5.10.0" "webpack-merge": "5.10.0",
"@vue/babel-plugin-jsx": "1.1.5"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.16.9", "@quasar/extras": "1.16.9",
@ -77,7 +78,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.56", "platform-core": "8.1.60",
"quasar": "2.14.2", "quasar": "2.14.2",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

4
io.sc.platform.system.frontend/src/i18n/messages.json

@ -45,7 +45,9 @@
"system.monitor.log.tab.download":"Log Download", "system.monitor.log.tab.download":"Log Download",
"system.monitor.log.tab.level":"Log Level", "system.monitor.log.tab.level":"Log Level",
"rawPassword": "Raw Password",
"newPassword": "New Password",
"confirmNewPassword": "Confirm New Password",
"accountExpired": "Expired", "accountExpired": "Expired",
"accountLocked": "Locked", "accountLocked": "Locked",
"credentialsExpired": "Credentials Expired", "credentialsExpired": "Credentials Expired",

9
io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json

@ -44,9 +44,12 @@
"system.monitor.log.tab.download":"日誌下載", "system.monitor.log.tab.download":"日誌下載",
"system.monitor.log.tab.level":"日誌級別", "system.monitor.log.tab.level":"日誌級別",
"accountExpired": "是否過期", "rawPassword": "原密碼",
"accountLocked": "是否鎖定", "newPassword": "新密碼",
"credentialsExpired": "是否密碼過期", "confirmNewPassword": "確認新密碼",
"accountExpired": "過期",
"accountLocked": "鎖定",
"credentialsExpired": "密碼過期",
"parameter.system":"系統", "parameter.system":"系統",
"parameter.system.homePage":"首頁", "parameter.system.homePage":"首頁",

9
io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json

@ -45,9 +45,12 @@
"system.monitor.log.tab.level":"日志级别", "system.monitor.log.tab.level":"日志级别",
"accountExpired": "是否过期", "rawPassword": "原密码",
"accountLocked": "是否锁定", "newPassword": "新密码",
"credentialsExpired": "是否密码过期", "confirmNewPassword": "确认新密码",
"accountExpired": "过期",
"accountLocked": "锁定",
"credentialsExpired": "密码过期",
"parameter.system":"系统", "parameter.system":"系统",
"parameter.system.homePage":"首页", "parameter.system.homePage":"首页",

34
io.sc.platform.system.frontend/src/views/user/Ok.vue

@ -0,0 +1,34 @@
<template>
<q-btn label="OK" @click="click"></q-btn>
</template>
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
import { VueTools } from 'platform-core';
const emit = defineEmits<{
(
e: 'wsp', //
evt: Event, // JS
row: any, // ,
index: number, // ,
): void;
}>();
const click = () => {
emit('wsp', instance, 'kdsjlfj');
};
const ok = () => {
return 'ok';
};
const hello = 'hello';
defineExpose({
ok,
hello,
});
const instance = getCurrentInstance();
VueTools.expose2Instance(instance);
</script>

336
io.sc.platform.system.frontend/src/views/user/User.vue

@ -1,63 +1,101 @@
<template> <template>
<Ok @wsp="wsp"></Ok>
<q-splitter :model-value="70" class="w-full h-full"> <q-splitter :model-value="70" class="w-full h-full">
<template #before> <template #before>
<w-grid <div class="px-1">
ref="userGridRef" <w-grid
:title="userGrid.title" ref="userGridRef"
:query-form-fields="userGrid.queryFormFields" :title="userGrid.title"
:toolbar-actions="userGrid.actions" selection="multiple"
:data-url="userGrid.dataUrl" :query-form-fields="userGrid.queryFormFields"
:columns="userGrid.columns" :toolbar-actions="userGrid.toolbarActions"
:row-key="userGrid.rowKey" :toolbar-configure="userGrid.toolbarConfigure"
:editor="userGrid.editor" :data-url="userGrid.dataUrl"
:viewer="userGrid.viewer" :columns="userGrid.columns"
@row-click="userGrid.rowClick" :row-key="userGrid.rowKey"
></w-grid> :editor="userGrid.editor"
:viewer="userGrid.viewer"
@row-click="userGrid.rowClick"
></w-grid>
</div>
</template> </template>
<template #after> <template #after>
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0"> <div class="px-1">
<q-tab name="role" icon="bi-people" :label="$t('role')" /> <q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0">
<q-tab name="org" icon="bi-diagram-3" :label="$t('org')" /> <q-tab name="role" icon="bi-people" :label="$t('role')" />
</q-tabs> <q-tab name="org" icon="bi-diagram-3" :label="$t('org')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive> <q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="role"> <q-tab-panel name="role">
<platform-grid <platform-grid
ref="roleGridRef" ref="roleGridRef"
:table-props="{ borderded: false, flat: true }" :table-props="{ borderded: false, flat: true }"
:query-form-cols-number="roleConfigure.queryFormColsNumber" :query-form-cols-number="roleConfigure.queryFormColsNumber"
:hide-bottom="roleConfigure.hideBottom" :hide-bottom="roleConfigure.hideBottom"
:query-form-cols-auto="roleConfigure.queryFormColsAuto" :query-form-cols-auto="roleConfigure.queryFormColsAuto"
:table-title="roleConfigure.tableTitle" :table-title="roleConfigure.tableTitle"
:table-row-key="roleConfigure.tableRowKey" :table-row-key="roleConfigure.tableRowKey"
:table-init-load-data="roleConfigure.tableInitLoadData" :table-init-load-data="roleConfigure.tableInitLoadData"
:table-data-url="roleConfigure.tableDataUrl" :table-data-url="roleConfigure.tableDataUrl"
:table-show-sort-no="false" :table-show-sort-no="false"
:table-columns="roleConfigure.tableColumns" :table-columns="roleConfigure.tableColumns"
:table-left-column-sticky-number="roleConfigure.tableLeftColumnStickyNumber" :table-left-column-sticky-number="roleConfigure.tableLeftColumnStickyNumber"
:table-buttons="roleConfigure.tableButtons" :table-buttons="roleConfigure.tableButtons"
:query-form-fields="roleConfigure.queryFormFields" :query-form-fields="roleConfigure.queryFormFields"
:table-pagination="roleConfigure.tablePagination" :table-pagination="roleConfigure.tablePagination"
table-selection="multiple" table-selection="multiple"
:table-dense="false" :table-dense="false"
> >
</platform-grid> </platform-grid>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="org"> <q-tab-panel name="org">
<w-tree-grid ref="orgTreeGridRef" label-key="name" :actions="orgConfigure.actions" tick-strategy="leaf" /> <w-tree-grid ref="orgTreeGridRef" label-key="name" :actions="orgConfigure.actions" tick-strategy="leaf" />
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</div>
</template> </template>
<SelectRoleDialog ref="selectRoleDialog" title="可选角色列表" :maximized="false" width="50%" height="500px"></SelectRoleDialog> <SelectRoleDialog ref="selectRoleDialog" title="可选角色列表" :maximized="false" width="50%" height="500px"></SelectRoleDialog>
<ChangePasswordDialog ref="changePasswordDialog" title="修改密码" :maximized="false" width="450px" height="350px"></ChangePasswordDialog> <w-dialog
ref="changePasswordDialogRef"
title="修改密码"
width="500px"
height="250px"
:buttons="[
{
label: $t('submit'),
click: () => {
console.log(changePasswordFormRef.getData());
axios.post(Environment.apiContextPath('/api/system/user/changePassword'), changePasswordFormRef.getData()).then(() => {
changePasswordDialogRef.hide();
});
},
},
]"
>
<w-form
ref="changePasswordFormRef"
:cols-num="1"
:fields="[
{ name: 'rawPassword', label: $t('rawPassword'), type: 'password' },
{ name: 'newPassword', label: $t('newPassword'), type: 'password' },
{ name: 'confirmNewPassword', label: $t('confirmNewPassword'), type: 'password' },
]"
class="p-2"
></w-form>
</w-dialog>
<ChangePasswordDialog ref="changePasswordDialog2" title="修改密码" :maximized="false" width="450px" height="350px"></ChangePasswordDialog>
</q-splitter> </q-splitter>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref, toRaw } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { QBtn } from 'quasar';
import { Environment, axios, EnumTools } from 'platform-core'; import { Environment, axios, EnumTools } from 'platform-core';
import SelectRoleDialog from './SelectRoleDialog.vue'; import SelectRoleDialog from './SelectRoleDialog.vue';
import ChangePasswordDialog from './ChangePasswordDialog.vue'; import ChangePasswordDialog from './ChangePasswordDialog.vue';
import UserStatusTag from './UserStatusTag.vue';
import Ok from './Ok.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -66,49 +104,44 @@ const roleGridRef = ref();
const orgTreeGridRef = ref(); const orgTreeGridRef = ref();
const selectRoleDialog = ref(); const selectRoleDialog = ref();
const changePasswordDialog = ref(); const changePasswordDialogRef = ref();
const changePasswordFormRef = ref();
const selectedTabRef = ref('role'); const selectedTabRef = ref('role');
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom', t); const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom', t);
const YesNoEnum = EnumTools.yesno(t);
const wsp = (v1, ss) => {
console.log(v1.ok(), v1.hello, ss);
};
const userGrid = { const userGrid = {
title: t('system.user.gridTitle'), title: t('system.user.gridTitle'),
queryFormFields: [ queryFormFields: [
{ name: 'loginName', label: t('loginName'), type: 'text' }, { name: 'loginName', label: t('loginName'), type: 'text' },
{ name: 'userName', label: t('userName'), type: 'text' }, { name: 'userName', label: t('userName'), type: 'text' },
{ { name: 'enable', label: t('isEnable'), type: 'select', options: YesNoEnum.list },
name: 'enable', { name: 'dataComeFrom', label: t('dataComeFrom'), type: 'select', options: DataComeFromEnum.list },
label: t('enable'),
type: 'select',
options: [
{ value: true, label: '是' },
{ value: false, label: '否' },
],
},
{
name: 'dataComeFrom',
label: t('dataComeFrom'),
type: 'select',
options: DataComeFromEnum.list,
},
], ],
actions: [ toolbarConfigure: { noIcon: false },
toolbarActions: [
'query', 'query',
'refresh', 'refresh',
'separator', 'separator',
'add', 'add',
'edit', 'edit',
'clone',
'remove', 'remove',
'separator', 'separator',
{ {
name: 'setPassword', name: 'setPassword',
label: t('system.user.action.setPassword'), label: t('system.user.action.setPassword'),
icon: 'bi-shield-exclamation', icon: 'bi-shield-exclamation',
enableIf: function () {}, enableIf: function (selected) {
return selected.length > 0;
},
click: function () { click: function () {
changePasswordDialog.value.show(); changePasswordDialogRef.value.show();
}, },
}, },
'view', 'view',
@ -117,174 +150,83 @@ const userGrid = {
dataUrl: Environment.apiContextPath('/api/system/user'), dataUrl: Environment.apiContextPath('/api/system/user'),
rowKey: 'id', rowKey: 'id',
columns: [ columns: [
{ width: 100, name: 'loginName', label: t('loginName') }, { name: 'loginName', label: t('loginName') },
{ width: '100%', name: 'userName', label: t('userName') }, { name: 'userName', label: t('userName') },
{ width: 100, name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) }, //{ width: 100, name: 'enable', label: t('isEnable'), align: 'center', format: (value) => YesNoEnum.map[value] },
{ width: 100, name: 'dataComeFrom', label: t('dataComeFrom'), format: (value) => (value ? DataComeFromEnum.map[value] : '') }, //{ width: 100, name: 'accountExpired', label: t('accountExpired'), format: (value) => YesNoEnum.map[value] },
{ width: 100, name: 'accountExpired', label: t('accountExpired'), format: (value) => (value ? t('yes') : t('no')) }, //{ width: 100, name: 'accountLocked', label: t('accountLocked'), format: (value) => YesNoEnum.map[value] },
{ width: 100, name: 'accountLocked', label: t('accountLocked'), format: (value) => (value ? t('yes') : t('no')) }, //{ width: 160, name: 'credentialsExpired', label: t('credentialsExpired'), format: (value) => YesNoEnum.map[value] },
{ width: 120, name: 'credentialsExpired', label: t('credentialsExpired'), format: (value) => (value ? t('yes') : t('no')) }, {
{ width: 110, name: 'lastModifier', label: t('lastModifier') }, name: 'status',
{ width: 115, name: 'lastModifyDate', label: t('lastModifyDate') }, label: t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: (value) => DataComeFromEnum.map[value] },
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
], ],
editor: { editor: {
dialog: {}, dialog: {},
form: { form: {
colsNum: 1, colsNum: 2,
fields: [ fields: [
{ name: 'loginName', label: t('loginName'), type: 'text', required: true }, { name: 'loginName', label: t('loginName'), type: 'text', required: true },
{ name: 'userName', label: t('userName'), type: 'text', required: true }, { name: 'userName', label: t('userName'), type: 'text', required: true },
{ name: 'description', label: t('description'), type: 'textarea', colspan: 2, rows: 1 },
{ name: 'password', label: t('password'), type: 'password' }, { name: 'password', label: t('password'), type: 'password' },
{ name: 'confirmPassword', label: t('confirmPassword'), type: 'password' }, { name: 'confirmPassword', label: t('confirmPassword'), type: 'password' },
{ name: 'description', label: t('description'), type: 'textarea' },
{ name: 'email', label: t('email'), type: 'text' },
{ name: 'phone', label: t('phone'), type: 'text' },
{ name: 'mobile', label: t('mobile'), type: 'text' }, { name: 'mobile', label: t('mobile'), type: 'text' },
{ name: 'phone', label: t('phone'), type: 'text' },
{ name: 'email', label: t('email'), type: 'text' },
{ name: 'weixin', label: t('weixin'), type: 'text' }, { name: 'weixin', label: t('weixin'), type: 'text' },
{ name: 'qq', label: t('qq'), type: 'text' }, { name: 'qq', label: t('qq'), type: 'text' },
{ name: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true }, { name: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true, colsFirst: true },
{ name: 'accountExpired', label: t('accountExpired'), type: 'checkbox' }, { name: 'accountExpired', label: t('accountExpired'), type: 'checkbox', defaultValue: false, colsFirst: true },
{ name: 'accountLocked', label: t('accountLocked'), type: 'checkbox' }, { name: 'accountLocked', label: t('accountLocked'), type: 'checkbox', defaultValue: false, colsFirst: true },
{ name: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox' }, { name: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox', defaultValue: false, colsFirst: true },
], ],
}, },
}, },
viewer: { viewer: {
panel: { panel: {
columnNum: 2, columnNum: 1,
fields: [ fields: [
{ name: 'id', label: t('id') },
{ name: 'loginName', label: t('loginName') }, { name: 'loginName', label: t('loginName') },
{ name: 'userName', label: t('userName') }, { name: 'userName', label: t('userName') },
{ name: 'password', label: t('password') },
{ name: 'confirmPassword', label: t('confirmPassword') },
{ name: 'description', label: t('description') }, { name: 'description', label: t('description') },
{ name: 'enable', label: t('enable') },
{ name: 'accountExpired', label: t('accountExpired') },
{ name: 'accountLocked', label: t('accountLocked') },
{ name: 'credentialsExpired', label: t('credentialsExpired') },
{ name: 'email', label: t('email') }, { name: 'email', label: t('email') },
{ name: 'phone', label: t('phone') }, { name: 'phone', label: t('phone') },
{ name: 'mobile', label: t('mobile') }, { name: 'mobile', label: t('mobile') },
{ name: 'weixin', label: t('weixin') }, { name: 'weixin', label: t('weixin') },
{ name: 'qq', label: t('qq') }, { name: 'qq', label: t('qq') },
{ name: 'enable', label: t('enable') }, { name: 'dataComeFrom', label: t('dataComeFrom'), format: (value) => DataComeFromEnum.map[value] },
{ name: 'accountExpired', label: t('accountExpired') }, { name: 'creator', label: t('creator') },
{ name: 'accountLocked', label: t('accountLocked') }, { name: 'createDate', label: t('createDate') },
{ name: 'credentialsExpired', label: t('credentialsExpired') }, { name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
{ name: 'corporationCode', label: t('corporationCode') },
], ],
}, },
}, },
rowClick: (evt, row, index) => { rowClick: (evt, row, index) => {
if (roleGridRef.value) { if (roleGridRef.value) {
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id).then((response) => { axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id).then((response) => {
roleGridRef.value.replaceRowsFun(response.data.content); //roleGridRef.value.replaceRows(response.data.content);
});
}
if (orgTreeGridRef.value) {
axios.get(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id).then((response) => {
orgTreeGridRef.value.setNodes(response.data);
});
}
},
};
const userConfigure = {
queryFormColsNumber: 4,
queryFormColsAuto: false,
queryFormFields: [
{ label: t('loginName'), modelName: 'loginName', type: 'text' },
{ label: t('userName'), modelName: 'userName', type: 'text' },
{
label: t('enable'),
modelName: 'enable',
type: 'select',
options: [
{ value: true, label: '是' },
{ value: false, label: '否' },
],
},
{
label: t('dataComeFrom'),
modelName: 'dataComeFrom',
type: 'select',
options: [
{ value: 'INPUT', label: t('io.sc.platform.orm.api.enums.DataComeFrom.INPUT') },
{ value: 'IMPORT', label: t('io.sc.platform.orm.api.enums.DataComeFrom.IMPORT') },
],
},
],
hideBottom: false,
tableInitLoadData: true,
tableLeftColumnStickyNumber: 0,
tableTitle: t('system.user.gridTitle'),
tableRowKey: 'id',
tableDataUrl: Environment.apiContextPath('/api/system/user'),
tablePagination: {
sortBy: 'lastModifyDate',
descending: true,
reqPageStart: 0,
rowsPerPage: 10,
},
tableButtons: [
'query',
'reset',
'separator',
'refresh',
'add',
'edit',
'delete',
'separator',
'view',
'separator',
{
name: 'setPassword',
label: t('system.user.action.setPassword'),
icon: 'bi-shield-exclamation',
enableIf: function () {},
click: function () {
changePasswordDialog.value.show();
},
},
'inFullscreen',
],
tableColumns: [
{ width: 100, name: 'loginName', label: t('loginName') },
{ width: 100, name: 'userName', label: t('userName') },
{ width: 100, name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) },
{ width: 100, name: 'dataComeFrom', label: t('dataComeFrom'), format: (value) => DataComeFromEnum.map.get(value) },
{ width: 100, name: 'accountExpired', label: t('accountExpired'), format: (value) => (value ? t('yes') : t('no')) },
{ width: 100, name: 'accountLocked', label: t('accountLocked'), format: (value) => (value ? t('yes') : t('no')) },
{ width: 120, name: 'credentialsExpired', label: t('credentialsExpired'), format: (value) => (value ? t('yes') : t('no')) },
{ width: 110, name: 'lastModifier', label: t('lastModifier') },
{ width: 115, name: 'lastModifyDate', label: t('lastModifyDate') },
],
addFormProps: {
dialogInitWidth: '50%',
dialogInitHeight: '90%',
formColsNumber: 1,
formColsAuto: false,
formFields: [
{ modelName: 'loginName', label: t('loginName'), type: 'text', required: true },
{ modelName: 'userName', label: t('userName'), type: 'text', required: true },
{ modelName: 'password', label: t('password'), type: 'password' },
{ modelName: 'confirmPassword', label: t('confirmPassword'), type: 'password' },
{ modelName: 'description', label: t('description'), type: 'textarea' },
{ modelName: 'email', label: t('email'), type: 'text' },
{ modelName: 'phone', label: t('phone'), type: 'text' },
{ modelName: 'mobile', label: t('mobile'), type: 'text' },
{ modelName: 'weixin', label: t('weixin'), type: 'text' },
{ modelName: 'qq', label: t('qq'), type: 'text' },
{ modelName: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true },
{ modelName: 'accountExpired', label: t('accountExpired'), type: 'checkbox' },
{ modelName: 'accountLocked', label: t('accountLocked'), type: 'checkbox' },
{ modelName: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox' },
],
},
rowClickFun: (evt, row, index) => {
if (roleGridRef.value) {
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id).then((response) => {
roleGridRef.value.replaceRowsFun(response.data.content);
}); });
} }
if (orgTreeGridRef.value) { if (orgTreeGridRef.value) {
axios.get(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id).then((response) => { axios.get(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id).then((response) => {
orgTreeGridRef.value.setNodes(response.data); //orgTreeGridRef.value.setNodes(response.data);
}); });
} }
}, },

17
io.sc.platform.system.frontend/src/views/user/UserStatusTag.vue

@ -0,0 +1,17 @@
<template>
<div>
<q-chip v-if="enable && !accountExpired && !accountLocked && !credentialsExpired" color="green" text-color="white" :label="$t('normal')" dense></q-chip>
<q-chip v-if="!enable" color="red" text-color="white" :label="$t('disable')" dense></q-chip>
<q-chip v-if="accountExpired" color="red" text-color="white" :label="$t('accountExpired')" dense></q-chip>
<q-chip v-if="accountLocked" color="red" text-color="white" :label="$t('accountLocked')" dense></q-chip>
<q-chip v-if="credentialsExpired" color="red" text-color="white" :label="$t('credentialsExpired')" dense></q-chip>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
enable: { type: Boolean, default: true },
accountExpired: { type: Boolean, default: false },
accountLocked: { type: Boolean, default: false },
credentialsExpired: { type: Boolean, default: false },
});
</script>

1
io.sc.platform.system.frontend/tsconfig.json

@ -5,6 +5,7 @@
"module": "node16", "module": "node16",
"strict": true, "strict": true,
"jsx": "preserve", "jsx": "preserve",
"jsxImportSource": "vue",
"noEmit": true, "noEmit": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"noImplicitAny": false, "noImplicitAny": false,

Loading…
Cancel
Save