-
+
+
+
+
@@ -25,17 +21,9 @@
@@ -46,10 +34,12 @@
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue
deleted file mode 100644
index 8e5a11cd..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue
+++ /dev/null
@@ -1,389 +0,0 @@
-
-
-
- * {{ attrs.label }}
-
-
-
-
- {}"
- @click.stop.prevent="() => {}"
- >
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/WCron.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/WCron.vue
deleted file mode 100644
index 72d6c819..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/WCron.vue
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-
- * {{ attrs.label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts
deleted file mode 100644
index f8ba5a69..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { EditorView, ViewPlugin, ViewUpdate, MatchDecorator, Decoration, DecorationSet, WidgetType } from '@codemirror/view';
-
-class PlaceholderWidget extends WidgetType {
- constructor(name) {
- super();
- this.name = name;
- }
-
- eq(other) {
- return this.name == other.name;
- }
-
- toDOM() {
- const container = document.createElement('span');
- container.className = 'px-0.5';
-
- const elt = document.createElement('span');
- elt.setAttribute('placeholder', true);
- elt.className = 'p-0.5 border border-gray-800 rounded-md';
- elt.textContent = this.name;
-
- container.appendChild(elt);
- return container;
- }
-
- ignoreEvent() {
- return false;
- }
-}
-
-const placeholderMatcher = new MatchDecorator({
- regexp: /\$\{(.+?)\}/g,
- decoration: (match) =>
- Decoration.replace({
- widget: new PlaceholderWidget(match[1]),
- }),
-});
-
-const placeholderPlugin = ViewPlugin.fromClass(
- class {
- placeholders: DecorationSet;
- constructor(view: EditorView) {
- this.placeholders = placeholderMatcher.createDeco(view);
- }
- update(update: ViewUpdate) {
- this.placeholders = placeholderMatcher.updateDeco(update, this.placeholders);
- }
- },
- {
- decorations: (instance) => instance.placeholders,
- provide: (plugin) =>
- EditorView.atomicRanges.of((view) => {
- return view.plugin(plugin)?.placeholders || Decoration.none;
- }),
- eventHandlers: {
- mouseover: (e, view) => {
- const target = e.target as HTMLElement;
- if (target.tagName.toLowerCase() === 'span' && target.getAttribute('placeholder')) {
- target.className = 'p-0.5 border border-orange-400 rounded-md';
- }
- },
- mouseout: (e, view) => {
- const target = e.target as HTMLElement;
- if (target.tagName.toLowerCase() === 'span' && target.getAttribute('placeholder')) {
- target.className = 'p-0.5 border border-gray-800 rounded-md';
- }
- },
- contextmenu: (e, view) => {
- e.preventDefault();
- console.log(view);
- },
- },
- },
-);
-
-export default placeholderPlugin;
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/DaySegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/DaySegment.vue
deleted file mode 100644
index 9af31937..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/DaySegment.vue
+++ /dev/null
@@ -1,251 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.day.per') }}
-
-
-
-
-
-
-
- {{ $t('cron.day.notSpecify') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.day.period.1') }}
-
- {{ $t('cron.day.period.2') }}
-
- {{ $t('cron.day.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.day.per2.1') }}
-
- {{ $t('cron.day.per2.2') }}
-
- {{ $t('cron.day.per2.3') }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.day.workDay.1') }}
-
- {{ $t('cron.day.workDay.2') }}
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.day.lastDay') }}
-
-
-
-
-
-
-
-
- {{ $t('cron.day.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/HourSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/HourSegment.vue
deleted file mode 100644
index 46cf0173..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/HourSegment.vue
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.hour.per') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.hour.period.1') }}
-
- {{ $t('cron.hour.period.2') }}
-
- {{ $t('cron.hour.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.hour.per2.1') }}
-
- {{ $t('cron.hour.per2.2') }}
-
- {{ $t('cron.hour.per2.3') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.hour.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MinuteSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MinuteSegment.vue
deleted file mode 100644
index 90e4f44f..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MinuteSegment.vue
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.minute.per') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.minute.period.1') }}
-
- {{ $t('cron.minute.period.2') }}
-
- {{ $t('cron.minute.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.minute.per2.1') }}
-
- {{ $t('cron.minute.per2.2') }}
-
- {{ $t('cron.minute.per2.3') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.minute.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MonthSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MonthSegment.vue
deleted file mode 100644
index 13604ef3..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/MonthSegment.vue
+++ /dev/null
@@ -1,197 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.month.per') }}
-
-
-
-
-
-
-
- {{ $t('cron.month.notSpecify') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.month.period.1') }}
-
- {{ $t('cron.month.period.2') }}
-
- {{ $t('cron.month.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.month.per2.1') }}
-
- {{ $t('cron.month.per2.2') }}
-
- {{ $t('cron.month.per2.3') }}
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.month.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/SecondSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/SecondSegment.vue
deleted file mode 100644
index c68291be..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/SecondSegment.vue
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.second.per') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.second.period.1') }}
-
- {{ $t('cron.second.period.2') }}
-
- {{ $t('cron.second.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.second.per2.1') }}
-
- {{ $t('cron.second.per2.2') }}
-
- {{ $t('cron.second.per2.3') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.second.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/WeekSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/WeekSegment.vue
deleted file mode 100644
index 6c07fa4b..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/WeekSegment.vue
+++ /dev/null
@@ -1,233 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.week.per') }}
-
-
-
-
-
-
-
- {{ $t('cron.week.notSpecify') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.week.period.1') }}
-
- {{ $t('cron.week.period.2') }}
-
- {{ $t('cron.week.period.3') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.week.weekOfYear.1') }}
-
- {{ $t('cron.week.weekOfYear.2') }}
-
- {{ $t('cron.week.weekOfYear.3') }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.week.lastDay.1') }}
-
- {{ $t('cron.week.lastDay.2') }}
-
-
-
-
-
-
-
-
-
-
- {{ $t('cron.week.specify') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/YearSegment.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/YearSegment.vue
deleted file mode 100644
index 25c18efb..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-cron-segment/YearSegment.vue
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('cron.year.per') }}
-
-
-
-
-
-
-
- {{ $t('cron.year.notSpecify') }}
-
-
-
-
-
-
-
-
-
- {{ $t('cron.year.period.1') }}
-
- {{ $t('cron.year.period.2') }}
-
- {{ $t('cron.year.period.3') }}
-
-
-
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-query-condition/WExpression.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-query-condition/WExpression.vue
deleted file mode 100644
index dfe22b68..00000000
--- a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-query-condition/WExpression.vue
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/ComputedManager.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/ComputedManager.ts
new file mode 100644
index 00000000..50c70523
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/ComputedManager.ts
@@ -0,0 +1,47 @@
+import { Screen } from 'quasar';
+import { computed } from 'vue';
+import { Form } from './Form';
+
+/**
+ * 计算属性管理器
+ */
+export class ComputedManager {
+ form: Form;
+
+ /**
+ * 不同屏幕断点下一行显示的字段数量
+ */
+ screenCols = { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 };
+
+ constructor(form_: Form) {
+ this.form = form_;
+ }
+
+ /**
+ * 根据屏幕断点,获得当前一行可显示的字段数量
+ */
+ screenColsNumComputed = computed(() => {
+ if (typeof this.form.props.colsNum === 'number' && this.form.props.colsNum > 0) {
+ return this.form.props.colsNum;
+ } else if (typeof this.form.props.colsNum === 'object') {
+ const screen = { ...this.screenCols, ...this.form.props.colsNum };
+ return screen[Screen.name];
+ }
+ return this.screenCols[Screen.name];
+ });
+
+ /**
+ * 表单布局样式
+ */
+ formLayoutStyleComputed = computed(() => {
+ const style = {};
+ if (typeof this.form.props.colsNum === 'number' && this.form.props.colsNum > 0) {
+ style['grid-template-columns'] = 'repeat(' + this.form.props.colsNum + ', minmax(0, 1fr))';
+ } else {
+ style['grid-template-columns'] = 'repeat(' + this.screenColsNumComputed.value + ', minmax(0, 1fr))';
+ }
+ style['column-gap'] = this.form.props.xGap + 'px';
+ style['row-gap'] = this.form.props.yGap + 'px';
+ return style;
+ });
+}
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/Constant.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/Constant.ts
new file mode 100644
index 00000000..fb9b171c
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/Constant.ts
@@ -0,0 +1,14 @@
+/**
+ * 常量
+ */
+export class Constant {
+ /**
+ * 新增状态
+ */
+ static STATUS_ADD = 'add';
+
+ /**
+ * 用于分组的字段类型
+ */
+ static GROUP_TYPE = 'w-form-group';
+}
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/ExposeApiManager.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/ExposeApiManager.ts
new file mode 100644
index 00000000..b5f36d8a
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/ExposeApiManager.ts
@@ -0,0 +1,189 @@
+import { toRaw } from 'vue';
+import { Tools, $t } from '@/platform';
+import { getDefaultValue } from '../FormField.ts';
+import { Form } from './Form.ts';
+import { ErrorType } from './types/ErrorType.ts';
+
+/**
+ * 对外暴露API管理器
+ */
+export class ExposeApiManager {
+ form: Form;
+
+ constructor(form_: Form) {
+ this.form = form_;
+
+ this.getData = this.getData.bind(this);
+ this.setData = this.setData.bind(this);
+ this.getStatus = this.getStatus.bind(this);
+ this.setStatus = this.setStatus.bind(this);
+ this.reset = this.reset.bind(this);
+ this.validate = this.validate.bind(this);
+ this.setFieldValue = this.setFieldValue.bind(this);
+ this.getFieldValue = this.getFieldValue.bind(this);
+ this.getColsNum = this.getColsNum.bind(this);
+ this.setValidationErrors = this.setValidationErrors.bind(this);
+ this.getFieldComponent = this.getFieldComponent.bind(this);
+ this.resetValidation = this.resetValidation.bind(this);
+ this.getFields = this.getFields.bind(this);
+ }
+
+ /**
+ * 获取表单数据
+ * @returns
+ */
+ getData() {
+ const data = { ...toRaw(this.form.data) };
+ if (!Tools.isEmpty(this.form.props.modelValue)) {
+ // 对于用户自定义绑定模型值的,为了避免页面未填写值的字段不会更新到模型值中,返回数据值时将其合并。
+ const modelValue = this.form.buildModelValueByFields();
+ return { ...modelValue, ...data };
+ }
+ return data;
+ }
+ /**
+ * 设置表单数据
+ * @param data 数据对象(JSON格式)
+ */
+ setData(data: any) {
+ Object.keys(this.form.fields).forEach((key: string) => {
+ if (Tools.hasOwnProperty(this.form.data, key)) {
+ if (Tools.isEmpty(data)) {
+ this.form.data[key] = getDefaultValue(this.form.fields[key]);
+ } else if (data[key] !== undefined) {
+ this.form.data[key] = data[key];
+ }
+ }
+ });
+ }
+
+ /**
+ * 获取表单状态
+ * @returns
+ */
+ getStatus() {
+ return this.form.status;
+ }
+ /**
+ * 设置表单状态
+ * @param status
+ */
+ setStatus(status: string) {
+ this.form.status = status;
+ }
+
+ /**
+ * 重置表单
+ */
+ reset() {
+ Object.keys(this.form.data).forEach((key) => {
+ this.form.data[key] = getDefaultValue(this.form.fields[key]);
+ });
+ }
+
+ /**
+ * 表单验证
+ */
+ async validate() {
+ const result = await this.formValidate();
+ return result;
+ }
+ private async formValidate() {
+ let validate = false;
+ await this.form.cf
+ .getFormRef()
+ .validate()
+ .then((success) => {
+ if (success) {
+ validate = true;
+ }
+ });
+ return validate;
+ }
+
+ /**
+ * 设置字段值
+ * @param fieldName
+ * @param value
+ */
+ setFieldValue(fieldName: string, value: any) {
+ this.form.data[fieldName] = value;
+ }
+ /**
+ * 获取字段值
+ * @param fieldName
+ * @returns
+ */
+ getFieldValue(fieldName: string) {
+ return this.form.data[fieldName];
+ }
+
+ /**
+ * 获取当前表单一行应该显示的元素个数
+ * @returns
+ */
+ getColsNum() {
+ return this.form.cm.screenColsNumComputed.value;
+ }
+
+ /**
+ * 设置后台校验错误信息
+ * @param errors
+ */
+ setValidationErrors(errors: ErrorType[]) {
+ if (errors && errors.length > 0) {
+ const grouped = {};
+ errors.map(({ fieldName, ...rest }) => {
+ grouped[fieldName] = grouped[fieldName] || [];
+ grouped[fieldName].push(rest);
+ });
+ for (const name in grouped) {
+ const field = this.form.fieldArrayFindByName(name);
+ if (field) {
+ field.error = true;
+ field.errorMessage = grouped[name]
+ .map((obj) => {
+ if (!Tools.isEmpty(obj['errorMessageI18nKey'])) {
+ return $t(obj['errorMessageI18nKey']);
+ }
+ return obj.errorMessage;
+ })
+ .join('、');
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取字段元素使用的组件实例
+ * @param fieldName
+ * @returns
+ */
+ getFieldComponent(fieldName: string) {
+ return this.form.componentRef[fieldName];
+ }
+
+ /**
+ * 重置验证
+ */
+ resetValidation() {
+ this.form.cf.getFormRef().resetValidation();
+ this.form.fieldArrayRecursiveHandler(this.form.fieldArray.value, (field: any) => {
+ if (Tools.hasOwnProperty(field, 'error') && field['error']) {
+ field['error'] = false;
+ }
+ });
+ }
+
+ /**
+ * 获取所有字段元素
+ * @returns
+ */
+ getFields() {
+ const result = {};
+ this.form.fieldArrayRecursiveHandler(this.form.fieldArray.value, (field: any) => {
+ result[field.name] = field;
+ });
+ return result;
+ }
+}
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/Form.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/Form.ts
new file mode 100644
index 00000000..f41353b8
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/Form.ts
@@ -0,0 +1,229 @@
+import { Reactive, Ref, ref, reactive } from 'vue';
+import { Tools } from '@/platform';
+import { getDefaultValue } from '../FormField.ts';
+import { Constant } from './Constant.ts';
+import { PropsType } from './types/PropsType.ts';
+import { ComputedManager } from './ComputedManager.ts';
+import { ExposeApiManager } from './ExposeApiManager.ts';
+import { ComponentFunctionsType } from './types/ComponentFunctionsType.ts';
+
+/**
+ * w-form组件类
+ */
+export class Form {
+ /**
+ * 组件实例
+ */
+ instance?: any;
+ /**
+ * 配置属性
+ */
+ props: PropsType;
+ /**
+ * 表单数据
+ */
+ data: Reactive
= reactive({});
+ /**
+ * 字段集合数组
+ */
+ fieldArray: Ref = ref([]);
+ /**
+ * 字段集合对象,方便快速获取字段信息( name 为 key,字段配置为 value ,排除无 name 配置的元素(如 w-form-group 类型)。
+ */
+ fields: Reactive = reactive({});
+ /**
+ * 表单状态(用以标识表单当前是新增、编辑、复制等不同状态,默认为新增,可通过 setStatus 方法设置,getStatus 方法获得)
+ */
+ status: string = Constant.STATUS_ADD;
+ /**
+ * 字段使用的组件 ref 对象(渲染时动态绑定 ref ,key 为字段 name )
+ */
+ componentRef: Reactive = reactive({});
+ /**
+ * 计算属性管理器
+ */
+ cm: ComputedManager;
+ /**
+ * 对外暴露API管理器
+ */
+ api: ExposeApiManager;
+ /**
+ * vue文件中定义的函数
+ */
+ cf: ComponentFunctionsType = {
+ getFormRef: () => {},
+ updateModelValue: () => {},
+ };
+
+ setInstance(instance_: any) {
+ this.instance = instance_;
+ }
+
+ constructor(props_: PropsType) {
+ this.props = props_;
+ // 初始化
+ this.cm = new ComputedManager(this);
+ this.api = new ExposeApiManager(this);
+ if (this.props.fields) {
+ this.buildFieldsAndData();
+ }
+
+ this.getFieldStyle = this.getFieldStyle.bind(this);
+ this.setComponentRef = this.setComponentRef.bind(this);
+ }
+
+ /**
+ * 设置字段组件的 ref
+ * @param el html元素对象
+ * @param fieldName 字段名
+ */
+ setComponentRef(el: Element, fieldName: string) {
+ if (el) {
+ this.componentRef[fieldName] = el;
+ }
+ }
+
+ /**
+ * 获取字段样式
+ * @param field 字段配置
+ * @returns
+ */
+ getFieldStyle(field: any) {
+ const style = {};
+ if (field) {
+ const screenColsNum = this.cm?.screenColsNumComputed.value;
+ if (field.firstCol) {
+ style['grid-column-start'] = 1;
+ if (field.colSpan === 'full' || (typeof field.colSpan === 'number' && screenColsNum < field.colSpan)) {
+ style['grid-column-end'] = `${screenColsNum + 1}`;
+ } else if (typeof field.colSpan === 'number' && field.colSpan > 0) {
+ style['grid-column-end'] = `${field.colSpan + 1}`;
+ }
+ } else {
+ if (field.colSpan === 'full') {
+ // col-span-${screenColsNumComputed.value}
+ style['grid-column'] = `span ${screenColsNum} / span ${screenColsNum}`;
+ } else {
+ if (field.colSpan && screenColsNum >= field.colSpan) {
+ // col-span-${field.colSpan}
+ style['grid-column'] = `span ${field.colSpan} / span ${field.colSpan}`;
+ } else {
+ // col-span-1
+ style['grid-column'] = 'span 1 / span 1';
+ }
+ }
+ }
+ }
+ return style;
+ }
+
+ /**
+ * 根据配置属性中的字段数组构建 Base 类中的 fields 与 fieldArray
+ */
+ buildFields() {
+ this.fieldArray.value = [];
+ this.fields = reactive({});
+ this.fieldsHandler(this.props.fields, true);
+ }
+ /**
+ * 根据配置属性中的字段数组构建 Base 类中的 fields 与 fieldArray 并重新初始化数据模型
+ */
+ buildFieldsAndData() {
+ this.buildFields();
+ this.buildData();
+ }
+ /**
+ * 字段处理
+ * @param arr
+ * @param isRoot
+ */
+ private fieldsHandler(arr: Array, isRoot: boolean) {
+ arr.forEach((field: any) => {
+ if (isRoot) {
+ this.fieldArray.value.push({ ...field });
+ }
+ if (field.type === Constant.GROUP_TYPE && field.fields) {
+ this.fieldsHandler(field.fields, false);
+ } else if (Tools.hasOwnProperty(field, 'name')) {
+ this.fields[field.name] = { ...field };
+ }
+ });
+ }
+
+ /**
+ * 构建表单初始数据对象
+ */
+ private buildData() {
+ if (!Tools.isEmpty(this.props.modelValue)) {
+ // 用户进行了双向绑定,数据以 modelValue 为准。
+ this.data = reactive(this.props.modelValue);
+ } else {
+ // 根据 fields 构建表单初始数据对象
+ const modelValue = this.buildModelValueByFields();
+ this.data = reactive(modelValue);
+ }
+ }
+
+ /**
+ * 根据当前字段构建模型值对象
+ * @returns
+ */
+ buildModelValueByFields() {
+ const modelValue = {};
+ Object.keys(this.fields).forEach((fieldName: string) => {
+ modelValue[fieldName] = getDefaultValue(this.fields[fieldName]);
+ });
+ return modelValue;
+ }
+
+ /**
+ * 根据字段名在字段集合中查找字段
+ * @param fieldName
+ * @returns
+ */
+ fieldArrayFindByName(fieldName: string) {
+ return this.recursiveGetField(this.fieldArray.value, fieldName);
+ }
+
+ /**
+ * 根据字段名在字段集合中递归获取
+ * @param arr 集合
+ * @param fieldName 字段名称
+ * @returns
+ */
+ private recursiveGetField(arr: Array, fieldName: string) {
+ let result: any = undefined;
+ arr.forEach((field: any) => {
+ if (field.type === Constant.GROUP_TYPE && field.fields) {
+ const field_ = this.recursiveGetField(field.fields, fieldName);
+ if (field_) {
+ result = field_;
+ }
+ } else if (Tools.hasOwnProperty(field, 'name') && field.name === fieldName) {
+ result = field;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * 字段集合递归处理
+ * @param arr 集合
+ * @param fieldName 若传递只处理该字段
+ * @param callBack 回调函数
+ * @returns
+ */
+ fieldArrayRecursiveHandler(arr: Array, callBack: any, fieldName?: string) {
+ arr.forEach((field: any) => {
+ if (field.type === Constant.GROUP_TYPE && field.fields) {
+ this.fieldArrayRecursiveHandler(field.fields, callBack, fieldName);
+ } else if (Tools.hasOwnProperty(field, 'name')) {
+ if (Tools.isEmpty(fieldName)) {
+ callBack(field);
+ } else if (field.name === fieldName) {
+ callBack(field);
+ }
+ }
+ });
+ }
+}
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ComponentFunctionsType.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ComponentFunctionsType.ts
new file mode 100644
index 00000000..91e79255
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ComponentFunctionsType.ts
@@ -0,0 +1,10 @@
+export type ComponentFunctionsType = {
+ /**
+ * 获取表单ref函数
+ */
+ getFormRef: Function;
+ /**
+ * 表单字段模型值更改触发函数
+ */
+ updateModelValue: Function;
+}
\ No newline at end of file
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ErrorType.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ErrorType.ts
new file mode 100644
index 00000000..82b8bdc7
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/ErrorType.ts
@@ -0,0 +1,4 @@
+export type ErrorType = {
+ fieldName: string;
+ errorMessage: string;
+}
\ No newline at end of file
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/ts/types/PropsType.ts b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/PropsType.ts
new file mode 100644
index 00000000..0dc8b48e
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/ts/types/PropsType.ts
@@ -0,0 +1,22 @@
+export type PropsType = {
+ /**
+ * form模型值
+ */
+ modelValue?: any,
+ /**
+ * 一行显示的字段数量,为0时根据屏幕断点自动显示
+ */
+ colsNum?: any,
+ /**
+ * 横向X轴两个元素间的空隙像素点
+ */
+ xGap?: number,
+ /**
+ * 纵向Y轴两个元素间的空隙像素点
+ */
+ yGap?: number,
+ /**
+ * 表单字段集合
+ */
+ fields: Array,
+}
\ No newline at end of file
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/Td.vue b/io.sc.platform.core.frontend/src/platform/components/grid/Td.vue
index 10f1100e..160cb0f1 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/Td.vue
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/Td.vue
@@ -75,7 +75,7 @@ const titleComputed = computed(() => {
return column['title'];
}
}
- if (props.col.classes?.indexOf('truncate') > -1 && !Tools.isEmpty(props.col.value) && typeof props.col.value !== 'object') {
+ if (!Tools.isEmpty(props.col.value) && typeof props.col.value !== 'object') {
return props.col.value;
}
return '';
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/ConfigPanel.vue b/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/ConfigPanel.vue
index e944e10e..e7e8df3c 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/ConfigPanel.vue
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/ConfigPanel.vue
@@ -14,6 +14,10 @@
+
+
+
+
@@ -40,14 +44,15 @@
import { inject, computed, ref } from 'vue';
import { useQuasar } from 'quasar';
import { Constant, GridTools } from '../../ts/index';
-import CheckboxSelection from './CheckboxSelection.vue';
-import Dense from './Dense.vue';
-import DisplayColumn from './DisplayColumn.vue';
-import Fullscreen from './Fullscreen.vue';
-import Separator from './Separator.vue';
-import SortNo from './SortNo.vue';
-import StickyColumn from './StickyColumn.vue';
-import AloneGorup from './AloneGroup.vue';
+import CheckboxSelection from './src/CheckboxSelection.vue';
+import Dense from './src/Dense.vue';
+import DisplayColumn from './src/DisplayColumn.vue';
+import Fullscreen from './src/Fullscreen.vue';
+import Separator from './src/Separator.vue';
+import SortNo from './src/SortNo.vue';
+import Stripe from './src/Stripe.vue';
+import StickyColumn from './src/StickyColumn.vue';
+import AloneGorup from './src/AloneGroup.vue';
const $q = useQuasar();
const tools = inject('tools');
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/AloneGroup.vue b/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/src/AloneGroup.vue
similarity index 96%
rename from io.sc.platform.core.frontend/src/platform/components/grid/extra/config/AloneGroup.vue
rename to io.sc.platform.core.frontend/src/platform/components/grid/extra/config/src/AloneGroup.vue
index 802f0c2a..96d04f16 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/AloneGroup.vue
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/extra/config/src/AloneGroup.vue
@@ -18,7 +18,7 @@
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/ts/GridTools.ts b/io.sc.platform.core.frontend/src/platform/components/grid/ts/GridTools.ts
index 65a60ee4..62b3b09e 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/ts/GridTools.ts
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/ts/GridTools.ts
@@ -146,6 +146,8 @@ export class GridTools {
stickyNum: props.stickyNum,
useCheckboxSelection: props.checkboxSelection,
showSortNo: props.sortNo,
+ stripe: props.stripe ? true : false,
+ stripeColor: typeof props.stripe === 'boolean' ? '#fafafa' : props.stripe,
dense: dense,
denseToolbar: props.denseToolbar !== undefined ? props.denseToolbar : false,
denseHeader: props.denseHeader !== undefined ? props.denseHeader : false,
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/ts/function/Operator.ts b/io.sc.platform.core.frontend/src/platform/components/grid/ts/function/Operator.ts
index 55fae7e0..d7fe860a 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/ts/function/Operator.ts
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/ts/function/Operator.ts
@@ -7,6 +7,11 @@ import { Constant, PropsType, TableType } from '../index';
* w-grid 表格操作函数
*/
export class Operator extends Base {
+ /**
+ * 斑马纹监听器是否已启动
+ */
+ stripeWatch: boolean = false;
+
constructor(props: PropsType, table: TableType) {
super(props, table);
this.tableFullscreen = this.tableFullscreen.bind(this);
@@ -106,13 +111,24 @@ export class Operator extends Base {
if (trArr.length > 0) {
for (let i = 0; i < trArr.length; i++) {
if (i % 2 !== 0) {
- trArr[i].style['background-color'] = typeof this.props.stripe === 'boolean' ? '#fafafa' : this.props.stripe;
+ trArr[i].style['background-color'] = this.table.configStore.stripeColor;
} else {
trArr[i].style['background-color'] = '';
}
}
}
}
+ /**
+ * 清除所有斑马纹样式
+ */
+ private cleanStripeStyle() {
+ const tbodyDom = this.getTbodyDom();
+ for (let i = 0; i < tbodyDom.children.length; i++) {
+ if (!tbodyDom.children[i].classList.contains('groupTr')) {
+ tbodyDom.children[i].style['background-color'] = '';
+ }
+ }
+ }
private getTbodyDom() {
const tableElement = this.instance.getHtmlElement();
@@ -136,8 +152,10 @@ export class Operator extends Base {
* 重新设置斑马纹样式(用于拖拽排序后等场景导致的斑马纹样式错乱)
*/
resetStripeStyle() {
- if (!Tools.isEmpty(this.props.stripe) && this.props.stripe !== false) {
+ if (this.table.configStore.stripe) {
this.setStripeStyle(this.getStripeTrArr());
+ } else {
+ this.cleanStripeStyle();
}
}
@@ -145,7 +163,7 @@ export class Operator extends Base {
* 设置斑马纹
*/
setStripe() {
- if (!Tools.isEmpty(this.props.stripe) && this.props.stripe !== false) {
+ if (this.table.configStore.stripe) {
const trArr = this.getStripeTrArr();
// 初始化时设置一遍样式
this.setStripeStyle(trArr);
@@ -154,7 +172,7 @@ export class Operator extends Base {
const observer = new MutationObserver((mutations) => {
const currentTrArr = this.getStripeTrArr();
const currentRowCount = currentTrArr.length;
- if (currentRowCount !== previousRowCount) {
+ if (currentRowCount !== previousRowCount && this.table.configStore.stripe) {
previousRowCount = currentRowCount;
this.setStripeStyle(currentTrArr);
}
@@ -165,6 +183,7 @@ export class Operator extends Base {
childList: true, // 监视子节点增删
subtree: false, // 若tr嵌套在更深层级需启用
});
+ this.stripeWatch = true;
}
}
diff --git a/io.sc.platform.core.frontend/src/platform/components/grid/ts/types/table/ConfigPanelStoreType.ts b/io.sc.platform.core.frontend/src/platform/components/grid/ts/types/table/ConfigPanelStoreType.ts
index dfc2943e..1166f3d0 100644
--- a/io.sc.platform.core.frontend/src/platform/components/grid/ts/types/table/ConfigPanelStoreType.ts
+++ b/io.sc.platform.core.frontend/src/platform/components/grid/ts/types/table/ConfigPanelStoreType.ts
@@ -26,6 +26,14 @@ export type ConfigPanelStoreType = {
* 是否显示前端序号列
*/
showSortNo: boolean,
+ /**
+ * 是否显示斑马纹
+ */
+ stripe: boolean,
+ /**
+ * 斑马纹颜色
+ */
+ stripeColor: string,
/**
* 表格整体紧凑
*/
diff --git a/io.sc.platform.core.frontend/src/views/likm/Form.vue b/io.sc.platform.core.frontend/src/views/likm/Form.vue
index 2e36db7e..39a90698 100644
--- a/io.sc.platform.core.frontend/src/views/likm/Form.vue
+++ b/io.sc.platform.core.frontend/src/views/likm/Form.vue
@@ -1,6 +1,6 @@
-
+
-
+
diff --git a/io.sc.platform.core.frontend/src/views/likm/Grid.vue b/io.sc.platform.core.frontend/src/views/likm/Grid.vue
index b7b8d409..1d97977c 100644
--- a/io.sc.platform.core.frontend/src/views/likm/Grid.vue
+++ b/io.sc.platform.core.frontend/src/views/likm/Grid.vue
@@ -1,54 +1,227 @@
-
+
+
+
+ {
+ refreshRelationshipComponents(args.row.id);
+ }
+ "
+ @before-request-data="
+ () => {
+ menuTreeGridRef?.clear();
+ userGridRef?.clear();
+ }
+ "
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/io.sc.platform.core.frontend/src/views/likm/SelectMenuTreeGrid.vue b/io.sc.platform.core.frontend/src/views/likm/SelectMenuTreeGrid.vue
new file mode 100644
index 00000000..425de10c
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/views/likm/SelectMenuTreeGrid.vue
@@ -0,0 +1,125 @@
+
+
+
+
diff --git a/io.sc.platform.core.frontend/src/views/likm/SelectUserDialog.vue b/io.sc.platform.core.frontend/src/views/likm/SelectUserDialog.vue
index 60b81fd9..1bee27ec 100644
--- a/io.sc.platform.core.frontend/src/views/likm/SelectUserDialog.vue
+++ b/io.sc.platform.core.frontend/src/views/likm/SelectUserDialog.vue
@@ -1,7 +1,7 @@
{
- const userIds = Tools.extractProperties(gridRef.getSelectedRows(), 'id');
- axios
- .post(Environment.apiContextPath('/api/system/role/addUsers'), {
- one: roleId,
- many: userIds,
- })
- .then((response) => {
- userGridRef?.refresh();
- close();
- });
+ const ids = Tools.extractProperties(gridRef.getSelectedRows(), 'id');
+ emit('afterSelected', ids, dialogRef);
},
},
]"
>
-
+
@@ -69,17 +64,28 @@
diff --git a/io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue b/io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue
index 4b327424..2714219d 100644
--- a/io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue
+++ b/io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue
@@ -7,7 +7,6 @@
:fetch-data-url="Environment.apiContextPath('api/system/menu/allMenus')"
:tree="true"
db-click-operation="expand"
- dnd-mode="server"
:columns="[
{
name: 'name',
diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/OrgSearchServiceImpl.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/OrgSearchServiceImpl.java
index 8c29df46..9b5d9c2e 100644
--- a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/OrgSearchServiceImpl.java
+++ b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/OrgSearchServiceImpl.java
@@ -1,10 +1,8 @@
package io.sc.platform.lcdp.frontend.component.service.impl;
import io.sc.platform.lcdp.frontend.component.service.OrgSearchService;
-import io.sc.platform.lcdp.frontend.component.service.UserSearchService;
-import io.sc.platform.lcdp.frontend.component.support.UserSearchConstant;
-import io.sc.platform.lcdp.frontend.component.vo.UserSearchVo;
-import io.sc.platform.orm.service.support.OperatorType;
+import io.sc.platform.lcdp.frontend.component.support.CriteriaHandler;
+import io.sc.platform.lcdp.frontend.component.support.SearchConstant;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
@@ -12,20 +10,16 @@ import io.sc.platform.orm.service.support.criteria.impl.InSet;
import io.sc.platform.orm.util.EntityVoUtil;
import io.sc.platform.security.util.SecurityUtil;
import io.sc.platform.system.api.org.OrgVo;
-import io.sc.platform.system.department.jpa.entity.DepartmentEntity;
import io.sc.platform.system.org.jpa.entity.OrgEntity;
import io.sc.platform.system.org.service.OrgService;
-import io.sc.platform.system.role.jpa.entity.RoleEntity;
-import io.sc.platform.system.role.service.RoleService;
-import io.sc.platform.system.user.jpa.entity.UserEntity;
-import io.sc.platform.system.user.service.UserService;
import io.sc.platform.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.stream.Collectors;
@Service
@@ -33,115 +27,129 @@ public class OrgSearchServiceImpl implements OrgSearchService {
@Autowired
private OrgService orgService;
- @Autowired
- private UserSearchServiceImpl userSearchServiceImpl;
@Override
public Page
queryOrg(QueryParameter queryParameter) throws Exception {
- if (existCondition(queryParameter)) {
- return existConditionQuery(queryParameter);
- } else {
- return noConditionQuery(queryParameter);
- }
+ QueryParameter searchParameter = criteriaHandler(queryParameter);
+ Page page = orgService.query(searchParameter);
+ return EntityVoUtil.toVo(page);
}
- private Page existConditionQuery(QueryParameter queryParameter) throws Exception {
- List orgCriteriaList = new ArrayList<>();
- /**
- * 前端已将 queryCriteria、使用用户默认机构查询等重新使用 and 操作进行组装,后端需提取特定 criteria 出来进行处理。
- * 只要存在查询条件,最外层一定是 { fieldName: null, operator: 'and', criteria: [...] };
- * 所以最外层无需处理,直接处理最外层的 criteria 数组。
- */
- List criterias = queryParameter.getCriterias().get(0).getCriteria();
- for (Criteria criteria: criterias) {
- if (criteria.getFieldName()!=null) {
- Boolean isOrgCriteria = Arrays.stream(UserSearchConstant.ORG_CRITERIA_FIELD_NAMES).anyMatch(criteria.getFieldName()::equals);
- if (!isOrgCriteria) {
- orgCriteriaList.add(criteria);
+ private QueryParameter criteriaHandler(QueryParameter queryParameter) throws Exception {
+ if (queryParameter.existsCriteria()) {
+ List orgCriteriaList = new ArrayList<>();
+ /**
+ * 前端已将 queryCriteria、使用用户默认机构查询等重新使用 and 操作进行组装,后端需提取特定 criteria 出来进行处理。
+ * 只要存在查询条件,最外层一定是 { fieldName: null, operator: 'and', criteria: [...] };
+ * 所以最外层无需处理,直接处理最外层的 criteria 数组。
+ */
+ List criterias = queryParameter.getCriterias().get(0).getCriteria();
+ for (Criteria criteria: criterias) {
+ if (criteria.getFieldName()!=null) {
+ Boolean isOrgCriteria = Arrays.stream(SearchConstant.ORG_CRITERIA_FIELD_NAMES).anyMatch(criteria.getFieldName()::equals);
+ if (!isOrgCriteria) {
+ orgCriteriaList.add(criteria);
+ } else {
+ // 当 criteria 中的 fieldName 为特定字段名时,进行特殊处理
+ List orgIds = findOrgIds(criteria.getFieldName(), criteria);
+ if (orgIds != null) {
+ // 不为 null 添加机构过滤逻辑。
+ CriteriaHandler.criteriaListAddInSet(orgCriteriaList, "id", orgIds);
+ }
+ }
} else {
- // 当 criteria 中的 fieldName 为特定字段名时,进行特殊处理
- orgHandler(criteria.getFieldName(), criteria, orgCriteriaList);
+ orgCriteriaList.add(criteria);
}
- } else {
- orgCriteriaList.add(criteria);
}
+ return CriteriaHandler.buildQueryParameter(queryParameter, orgCriteriaList);
+ } else {
+ return queryParameter;
}
- QueryParameter newQueryParameter = userSearchServiceImpl.rebuildQueryParameter(queryParameter, orgCriteriaList);
- Page page = orgService.query(newQueryParameter);
- return EntityVoUtil.toVo(page);
- }
-
- private Page noConditionQuery(QueryParameter queryParameter) throws Exception {
- Page page = orgService.query(queryParameter);
- return EntityVoUtil.toVo(page);
- }
-
- private Boolean existCondition(QueryParameter queryParameter) {
- List list = queryParameter.getCriterias();
- if (list !=null && list.size() > 0 && list.get(0).getCriteria() != null && list.get(0).getCriteria().size() > 0) {
- return true;
- }
- return false;
}
- private void orgHandler(String fieldName, Criteria criteria, List orgCriteriaList) throws Exception {
+ public List findOrgIds(String fieldName, Criteria criteria) throws Exception {
+ List orgIds = new ArrayList<>();
switch(fieldName) {
- case UserSearchConstant.FN_FINDBYORGIDWITHSUB:
- findByOrgIdWithSubHandler((InSet) criteria, orgCriteriaList);
+ case SearchConstant.FN_ORGCRITERIA:
+ orgIds = orgCriteriaHandler((Equals) criteria);
+ break;
+ case SearchConstant.FN_FINDBYORGIDWITHSUB:
+ orgIds = findByOrgIdHandler((InSet) criteria, true);
break;
- case UserSearchConstant.FN_FINDBYORGID:
- findByOrgIdHandler((InSet) criteria, orgCriteriaList);
+ case SearchConstant.FN_FINDBYORGID:
+ orgIds = findByOrgIdHandler((InSet) criteria, false);
break;
- case UserSearchConstant.FN_FINDBYDEFAULTORGWITHSUB:
- findByDefaultOrg(orgCriteriaList, true);
+ case SearchConstant.FN_FINDBYDEFAULTORGWITHSUB:
+ orgIds = findByDefaultOrg(true);
break;
- case UserSearchConstant.FN_FINDBYDEFAULTORG:
- findByDefaultOrg(orgCriteriaList, false);
+ case SearchConstant.FN_FINDBYDEFAULTORG:
+ orgIds = findByDefaultOrg(false);
break;
}
+ return orgIds;
}
- private void findByOrgIdWithSubHandler(InSet criteria, List orgCriteriaList) {
+ private List orgCriteriaHandler(Equals criteria) throws Exception {
+ QueryParameter queryParameter = new QueryParameter();
+ queryParameter.setCriteria(criteria.getValue());
+ queryParameter.setPageable(false);
+ List orgList = orgService.list(queryParameter);
+ List orgIds = new ArrayList<>();
+ if (orgList!=null && orgList.size() > 0) {
+ orgIds = orgList.stream().map(OrgEntity::getId).collect(Collectors.toList());
+ }
+ return orgIds;
+ }
+
+ private List findByOrgIdHandler(InSet criteria, Boolean withSub) {
String[] ids = criteria.getValue();
List list = orgService.getRepository().findAllById(Arrays.asList(ids));
List orgIds = new ArrayList<>();
if (list!=null && list.size()>0) {
for(OrgEntity org: list) {
orgIds.add(org.getId());
- userSearchServiceImpl.recursiveGetChildren(org, orgIds);
+ if (withSub) {
+ recursiveGetChildren(org, orgIds);
+ }
}
}
- userSearchServiceImpl.criteriaListAddInSet(orgCriteriaList, "id", orgIds);
- }
-
- private void findByOrgIdHandler(InSet criteria, List orgCriteriaList) {
- String[] ids = criteria.getValue();
- List list = orgService.getRepository().findAllById(Arrays.asList(ids));
- List orgIds = list.stream().map(OrgEntity::getId).collect(Collectors.toList());
- userSearchServiceImpl.criteriaListAddInSet(orgCriteriaList, "id", orgIds);
+ return orgIds;
}
- private void findByDefaultOrg(List orgCriteriaList, Boolean withSub) {
+ private List findByDefaultOrg(Boolean withSub) {
String orgId = SecurityUtil.getDefaultOrgId();
+ List orgIds = new ArrayList<>();
if (!StringUtil.isNullOrEmpty(orgId)) {
OrgEntity org = orgService.findById(orgId);
if (org!=null) {
- // TODO 机构是否为总行机构逻辑还需完善,目前判定 parent 为空为总行机构,多法人情况下该逻辑可能不适用。
if (org.getParent() != null) {
- // 非总行机构添加查询条件,总行机构不用添加,查所有用户
- List orgIds = new ArrayList<>();
+ // 非总行机构
orgIds.add(org.getId());
if (withSub) {
- userSearchServiceImpl.recursiveGetChildren(org, orgIds);
+ recursiveGetChildren(org, orgIds);
}
- userSearchServiceImpl.criteriaListAddInSet(orgCriteriaList, "id", orgIds);
+ } else {
+ // TODO 机构是否为总行机构逻辑还需完善,目前判定 parent 为空为总行机构,多法人情况下该逻辑可能不适用。
+ // 总行机构返回 null 表示不添加机构过滤逻辑。
+ return null;
}
- } else {
- // 默认机构为空不允许查询用户
- userSearchServiceImpl.criteriaListAddInSet(orgCriteriaList, "id", null);
}
- } else {
- userSearchServiceImpl.criteriaListAddInSet(orgCriteriaList, "id", null);
+ }
+ return orgIds;
+ }
+
+ /**
+ * 递归获取其所有孩子的ID
+ * @param org 机构
+ * @param ids 孩子机构ID集合
+ */
+ private void recursiveGetChildren(OrgEntity org, List ids) {
+ List children =org.getChildren();
+ if(children!=null && !children.isEmpty()){
+ for(OrgEntity child : children){
+ ids.add(child.getId());
+ recursiveGetChildren(child,ids);
+ }
}
}
}
diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/UserSearchServiceImpl.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/UserSearchServiceImpl.java
index f20c837a..bb3c1951 100644
--- a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/UserSearchServiceImpl.java
+++ b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/service/impl/UserSearchServiceImpl.java
@@ -1,26 +1,19 @@
package io.sc.platform.lcdp.frontend.component.service.impl;
import io.sc.platform.lcdp.frontend.component.service.UserSearchService;
-import io.sc.platform.lcdp.frontend.component.support.UserSearchConstant;
-import io.sc.platform.lcdp.frontend.component.support.UserSearchQueryParameter;
+import io.sc.platform.lcdp.frontend.component.support.CriteriaHandler;
+import io.sc.platform.lcdp.frontend.component.support.SearchConstant;
import io.sc.platform.lcdp.frontend.component.vo.UserSearchVo;
-import io.sc.platform.orm.service.support.OperatorType;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
-import io.sc.platform.orm.service.support.criteria.impl.InSet;
-import io.sc.platform.orm.util.EntityVoUtil;
-import io.sc.platform.security.util.SecurityUtil;
import io.sc.platform.system.department.jpa.entity.DepartmentEntity;
-import io.sc.platform.system.menu.jpa.entity.MenuEntity;
import io.sc.platform.system.org.jpa.entity.OrgEntity;
import io.sc.platform.system.org.service.OrgService;
import io.sc.platform.system.role.jpa.entity.RoleEntity;
import io.sc.platform.system.role.service.RoleService;
import io.sc.platform.system.user.jpa.entity.UserEntity;
import io.sc.platform.system.user.service.UserService;
-import io.sc.platform.util.StringUtil;
-import org.h2.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -38,175 +31,63 @@ public class UserSearchServiceImpl implements UserSearchService {
private OrgService orgService;
@Autowired
private RoleService roleService;
+ @Autowired
+ private OrgSearchServiceImpl orgSearchServiceImpl;
@Override
public Page queryUser(QueryParameter queryParameter) throws Exception {
- if (existCondition(queryParameter)) {
- return existConditionQuery(queryParameter);
- } else {
- return noConditionQuery(queryParameter);
- }
- }
-
- private Page existConditionQuery(QueryParameter queryParameter) throws Exception {
- List userCriteriaList = new ArrayList<>();
- /**
- * 前端已将【queryCriteria、机构查询条件、角色查询条件】重新使用 and 操作进行组装,后端需提取出来进行处理。
- * 只要存在查询条件,最外层一定是 { fieldName: null, operator: 'and', criteria: [...] };
- * 所以最外层无需处理,直接处理最外层的 criteria 数组。
- */
- List criterias = queryParameter.getCriterias().get(0).getCriteria();
- for (Criteria criteria: criterias) {
- if (criteria.getFieldName()!=null) {
- Boolean isOrgCriteria = Arrays.stream(UserSearchConstant.ORG_CRITERIA_FIELD_NAMES).anyMatch(criteria.getFieldName()::equals);
- Boolean isRoleCriteria = UserSearchConstant.FN_ROLECRITERIA.equals(criteria.getFieldName());
- if (!isOrgCriteria && !isRoleCriteria) {
- userCriteriaList.add(criteria);
- } else if (isOrgCriteria) {
- // 跟机构相关的查询条件处理
- orgHandler(criteria.getFieldName(), criteria, userCriteriaList);
- } else if (isRoleCriteria) {
- // 角色的查询条件处理
- roleCriteriaHandler((Equals) criteria, userCriteriaList);
- }
- } else {
- // 非特定 fieldName 添加进用户查询的 criteria 中
- userCriteriaList.add(criteria);
- }
- }
- Page page = userService.query(rebuildQueryParameter(queryParameter, userCriteriaList));
+ QueryParameter searchParameter = criteriaHandler(queryParameter);
+ Page page = userService.query(searchParameter);
return userEntityPage2UserSearchVoPage(page);
}
- private Page noConditionQuery(QueryParameter queryParameter) throws Exception {
- Page page = userService.query(queryParameter);
- return userEntityPage2UserSearchVoPage(page);
- }
-
- private Boolean existCondition(QueryParameter queryParameter) {
- List list = queryParameter.getCriterias();
- if (list !=null && list.size() > 0 && list.get(0).getCriteria() != null && list.get(0).getCriteria().size() > 0) {
- return true;
- }
- return false;
- }
-
- private void orgHandler(String fieldName, Criteria criteria, List userCriteriaList) throws Exception {
- switch(fieldName) {
- case UserSearchConstant.FN_ORGCRITERIA:
- orgCriteriaHandler((Equals) criteria, userCriteriaList);
- break;
- case UserSearchConstant.FN_FINDBYORGIDWITHSUB:
- findByOrgIdWithSubHandler((InSet) criteria, userCriteriaList);
- break;
- case UserSearchConstant.FN_FINDBYORGID:
- findByOrgIdHandler((InSet) criteria, userCriteriaList);
- break;
- case UserSearchConstant.FN_FINDBYDEFAULTORGWITHSUB:
- findByDefaultOrg(userCriteriaList, true);
- break;
- case UserSearchConstant.FN_FINDBYDEFAULTORG:
- findByDefaultOrg(userCriteriaList, false);
- break;
- }
- }
-
- private void orgCriteriaHandler(Equals criteria, List userCriteriaList) throws Exception {
- QueryParameter queryParameter = new QueryParameter();
- queryParameter.setCriteria(criteria.getValue());
- queryParameter.setPageable(false);
- List orgList = orgService.list(queryParameter);
- List orgIds = orgList.stream().map(OrgEntity::getId).collect(Collectors.toList());
- criteriaListAddInSet(userCriteriaList, "orgs", orgIds);
- }
-
- private void findByOrgIdWithSubHandler(InSet criteria, List userCriteriaList) {
- String[] ids = criteria.getValue();
- List list = orgService.getRepository().findAllById(Arrays.asList(ids));
- List orgIds = new ArrayList<>();
- if (list!=null && list.size()>0) {
- for(OrgEntity org: list) {
- orgIds.add(org.getId());
- recursiveGetChildren(org, orgIds);
- }
- }
- criteriaListAddInSet(userCriteriaList, "orgs", orgIds);
- }
-
- private void findByOrgIdHandler(InSet criteria, List userCriteriaList) {
- String[] ids = criteria.getValue();
- List list = orgService.getRepository().findAllById(Arrays.asList(ids));
- List orgIds = list.stream().map(OrgEntity::getId).collect(Collectors.toList());
- criteriaListAddInSet(userCriteriaList, "orgs", orgIds);
- }
-
- private void findByDefaultOrg(List userCriteriaList, Boolean withSub) {
- String orgId = SecurityUtil.getDefaultOrgId();
- String fieldName = "orgs";
- if (!StringUtil.isNullOrEmpty(orgId)) {
- OrgEntity org = orgService.findById(orgId);
- if (org!=null) {
- // TODO 机构是否为总行机构逻辑还需完善,目前判定 parent 为空为总行机构,多法人情况下该逻辑可能不适用。
- if (org.getParent() != null) {
- // 非总行机构添加查询条件,总行机构不用添加,查所有用户
- List orgIds = new ArrayList<>();
- orgIds.add(org.getId());
- if (withSub) {
- recursiveGetChildren(org, orgIds);
+ private QueryParameter criteriaHandler(QueryParameter queryParameter) throws Exception {
+ if (queryParameter.existsCriteria()) {
+ List userCriteriaList = new ArrayList<>();
+ /**
+ * 前端已将【queryCriteria、机构查询条件、角色查询条件】重新使用 and 操作进行组装,后端需提取出来进行处理。
+ * 只要存在查询条件,最外层一定是 { fieldName: null, operator: 'and', criteria: [...] };
+ * 所以最外层无需处理,直接处理最外层的 criteria 数组。
+ */
+ List criterias = queryParameter.getCriterias().get(0).getCriteria();
+ for (Criteria criteria: criterias) {
+ if (criteria.getFieldName()!=null) {
+ Boolean isOrgCriteria = Arrays.stream(SearchConstant.ORG_CRITERIA_FIELD_NAMES).anyMatch(criteria.getFieldName()::equals);
+ Boolean isRoleCriteria = SearchConstant.FN_ROLECRITERIA.equals(criteria.getFieldName());
+ if (!isOrgCriteria && !isRoleCriteria) {
+ userCriteriaList.add(criteria);
+ } else if (isOrgCriteria) {
+ // 跟机构相关的查询条件处理
+ List orgIds = orgSearchServiceImpl.findOrgIds(criteria.getFieldName(), criteria);
+ if (orgIds != null) {
+ // 不为 null 添加机构过滤逻辑
+ CriteriaHandler.criteriaListAddInSet(userCriteriaList, "orgs", orgIds);
+ }
+ } else if (isRoleCriteria) {
+ // 角色的查询条件处理
+ roleCriteriaHandler((Equals) criteria, userCriteriaList);
}
- criteriaListAddInSet(userCriteriaList, fieldName, orgIds);
+ } else {
+ // 非特定 fieldName 添加进用户查询的 criteria 中
+ userCriteriaList.add(criteria);
}
- } else {
- // 默认机构为空不允许查询用户
- criteriaListAddInSet(userCriteriaList, fieldName, null);
}
+ return CriteriaHandler.buildQueryParameter(queryParameter, userCriteriaList);
} else {
- criteriaListAddInSet(userCriteriaList, fieldName, null);
+ return queryParameter;
}
}
- public void recursiveGetChildren(OrgEntity org, List ids) {
- List children =org.getChildren();
- if(children!=null && !children.isEmpty()){
- for(OrgEntity child : children){
- ids.add(child.getId());
- recursiveGetChildren(child,ids);
- }
- }
- }
-
- public void criteriaListAddInSet(List criteriaList, String fieldName, List value) {
- InSet inSet = new InSet();
- inSet.setFieldName(fieldName);
- inSet.setOperator(OperatorType.inSet);
- if (value!=null && value.size()>0) {
- inSet.setValue(value.toArray(new String[0]));
- } else {
- // 如果传入的value为空,设置一个无法匹配到数据的数组
- inSet.setValue(new String[]{Long.toString(System.currentTimeMillis())});
- }
- criteriaList.add(inSet);
- }
-
private void roleCriteriaHandler(Equals roleCriteria, List userCriteriaList) throws Exception {
QueryParameter roleQueryParameter = new QueryParameter();
roleQueryParameter.setCriteria(roleCriteria.getValue());
roleQueryParameter.setPageable(false);
List roleList = roleService.list(roleQueryParameter);
- List roleIds = roleList.stream().map(RoleEntity::getId).collect(Collectors.toList());
- criteriaListAddInSet(userCriteriaList, "roles", roleIds);
- }
-
- public QueryParameter rebuildQueryParameter(QueryParameter oldQueryParameter, List userCriteriaList) {
- QueryParameter queryParameter = new QueryParameter();
- queryParameter.setCriterias(userCriteriaList);
- queryParameter.setSortBy(oldQueryParameter.getSortBy());
- queryParameter.setPageable(oldQueryParameter.getPageable());
- queryParameter.setPage(oldQueryParameter.getPage());
- queryParameter.setOperator(oldQueryParameter.getOperator());
- queryParameter.setSize(oldQueryParameter.getSize());
- queryParameter.setExportFilename(oldQueryParameter.getExportFilename());
- return queryParameter;
+ List roleIds = new ArrayList<>();
+ if (roleList!=null && roleList.size() >0) {
+ roleIds = roleList.stream().map(RoleEntity::getId).collect(Collectors.toList());
+ }
+ CriteriaHandler.criteriaListAddInSet(userCriteriaList, "roles", roleIds);
}
private Page userEntityPage2UserSearchVoPage(Page page) throws Exception {
diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/CriteriaHandler.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/CriteriaHandler.java
new file mode 100644
index 00000000..d8fc4cda
--- /dev/null
+++ b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/CriteriaHandler.java
@@ -0,0 +1,48 @@
+package io.sc.platform.lcdp.frontend.component.support;
+
+import io.sc.platform.orm.service.support.OperatorType;
+import io.sc.platform.orm.service.support.QueryParameter;
+import io.sc.platform.orm.service.support.criteria.Criteria;
+import io.sc.platform.orm.service.support.criteria.impl.InSet;
+
+import java.util.List;
+
+public class CriteriaHandler {
+
+ /**
+ * 根据 criteria条件集合与原始 QueryParameter 中的分页、页码等参数构建一个新的 QueryParameter
+ * @param queryParameter 原始QueryParameter
+ * @param criterias criteria条件集合
+ * @return
+ */
+ public static QueryParameter buildQueryParameter(QueryParameter queryParameter, List criterias) {
+ QueryParameter newQueryParameter = new QueryParameter();
+ newQueryParameter.setCriterias(criterias);
+ newQueryParameter.setSortBy(queryParameter.getSortBy());
+ newQueryParameter.setPageable(queryParameter.getPageable());
+ newQueryParameter.setPage(queryParameter.getPage());
+ newQueryParameter.setOperator(queryParameter.getOperator());
+ newQueryParameter.setSize(queryParameter.getSize());
+ newQueryParameter.setExportFilename(queryParameter.getExportFilename());
+ return newQueryParameter;
+ }
+
+ /**
+ * 给criteria集合增加 inset 操作
+ * @param criteriaList 要增加的集合
+ * @param fieldName inset操作字段名
+ * @param value inset操作字段值
+ */
+ public static void criteriaListAddInSet(List criteriaList, String fieldName, List value) {
+ InSet inSet = new InSet();
+ inSet.setFieldName(fieldName);
+ inSet.setOperator(OperatorType.inSet);
+ if (value!=null && value.size()>0) {
+ inSet.setValue(value.toArray(new String[0]));
+ } else {
+ // 如果传入的value为空,设置一个无法匹配到数据的数组
+ inSet.setValue(new String[]{Long.toString(System.currentTimeMillis())});
+ }
+ criteriaList.add(inSet);
+ }
+}
diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchConstant.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/SearchConstant.java
similarity index 66%
rename from io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchConstant.java
rename to io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/SearchConstant.java
index 98d7892d..abbe56e5 100644
--- a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchConstant.java
+++ b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/SearchConstant.java
@@ -1,6 +1,6 @@
package io.sc.platform.lcdp.frontend.component.support;
-public class UserSearchConstant {
+public class SearchConstant {
/**
* 角色criteria查询条件
@@ -12,23 +12,23 @@ public class UserSearchConstant {
*/
public final static String FN_ORGCRITERIA = "orgCriteria";
/**
- * 可选用户根据机构ID数组并包含数组中的所有子机构进行过滤
+ * 根据机构ID数组并包含数组中的所有子机构进行过滤
*/
public final static String FN_FINDBYORGIDWITHSUB = "findByOrgIdWithSub";
/**
- * 可选用户根据机构ID数组进行过滤
+ * 根据机构ID数组进行过滤
*/
public final static String FN_FINDBYORGID = "findByOrgId";
/**
- * 可选用户根据当前登录用户的默认机构及机构下的所有子机构进行过滤
- * 若默认机构为空无法选择用户
- * 为总行的用户可选全部用户
+ * 根据当前登录用户的默认机构及机构下的所有子机构进行过滤
+ * 若默认机构为空返回空集合
+ * 为总行的用户可选全部数据
*/
public final static String FN_FINDBYDEFAULTORGWITHSUB = "findByDefaultOrgWithSub";
/**
- * 可选用户根据当前登录用户的默认机构机构进行过滤
- * 若默认机构为空无法选择用户
- * 为总行的用户可选全部用户
+ * 根据当前登录用户的默认机构机构进行过滤
+ * 若默认机构为空返回空集合
+ * 为总行的用户可选全部数据
*/
public final static String FN_FINDBYDEFAULTORG = "findByDefaultOrg";
/**
diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchQueryParameter.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchQueryParameter.java
deleted file mode 100644
index 00ecfc45..00000000
--- a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/frontend/component/support/UserSearchQueryParameter.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package io.sc.platform.lcdp.frontend.component.support;
-
-import io.sc.platform.orm.service.support.QueryParameter;
-
-/**
- * 前端-用户选择组件-用户查询请求入参
- */
-public class UserSearchQueryParameter {
-
- /**
- * 用户列表查询参数
- */
- private QueryParameter queryParameter;
- /**
- * 机构查询参数
- */
- private QueryParameter orgQueryParameter;
- /**
- * 角色查询参数
- */
- private QueryParameter roleQueryParameter;
-
- public QueryParameter getQueryParameter() {
- return queryParameter;
- }
-
- public void setQueryParameter(QueryParameter queryParameter) {
- this.queryParameter = queryParameter;
- }
-
- public QueryParameter getOrgQueryParameter() {
- return orgQueryParameter;
- }
-
- public void setOrgQueryParameter(QueryParameter orgQueryParameter) {
- this.orgQueryParameter = orgQueryParameter;
- }
-
- public QueryParameter getRoleQueryParameter() {
- return roleQueryParameter;
- }
-
- public void setRoleQueryParameter(QueryParameter roleQueryParameter) {
- this.roleQueryParameter = roleQueryParameter;
- }
-}