48 changed files with 1950 additions and 2905 deletions
@ -0,0 +1,38 @@ |
|||
<template> |
|||
<template v-if="field.name"> |
|||
<component |
|||
:is="field.type" |
|||
:ref="(el) => form.setComponentRef(el, field.name)" |
|||
v-model="form.data[field.name]" |
|||
v-bind="field" |
|||
:form="form.instance" |
|||
:style="form.getFieldStyle(field)" |
|||
@update:model-value="form.cf.updateModelValue(field.name, form.data[field.name])" |
|||
></component> |
|||
</template> |
|||
<template v-else> |
|||
<component |
|||
:is="field.type" |
|||
:ref="(el) => form.setComponentRef(el, field.name)" |
|||
v-bind="field" |
|||
:form="form.instance" |
|||
:style="form.getFieldStyle(field)" |
|||
></component> |
|||
</template> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { inject } from 'vue'; |
|||
import { Form } from './ts/Form'; |
|||
|
|||
const form = <Form>inject('form'); |
|||
|
|||
const props = defineProps({ |
|||
field: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
}); |
|||
</script> |
@ -0,0 +1,35 @@ |
|||
<template> |
|||
<template v-if="field.type === Constant.GROUP_TYPE"> |
|||
<FormGroup v-if="showFormGroupComputed" v-bind="field" :fields="field.fields" :style="form.getFieldStyle(field)"></FormGroup> |
|||
</template> |
|||
<template v-else> |
|||
<Field :field="props.field"></Field> |
|||
</template> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { inject, computed } from 'vue'; |
|||
import { Form } from './ts/Form'; |
|||
import { Constant } from './ts/Constant'; |
|||
import Field from './Field.vue'; |
|||
import FormGroup from './FormGroup.vue'; |
|||
|
|||
const form = <Form>inject('form'); |
|||
|
|||
const props = defineProps({ |
|||
field: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
const showFormGroupComputed = computed(() => { |
|||
if (props.field.fields && Array.isArray(props.field.fields) && props.field.fields.length > 0) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
</script> |
@ -0,0 +1,124 @@ |
|||
<template> |
|||
<div> |
|||
<q-card flat bordered> |
|||
<q-item dense style="padding: 0px"> |
|||
<q-item-section> |
|||
<q-item-label header :style="headerStyleComputed"> |
|||
<q-icon v-if="props.icon" :name="props.icon" size="sm" v-bind="props.iconAttrs" /> |
|||
<span style="margin-left: 5px">{{ label }}</span> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-separator /> |
|||
<q-card-section style="padding: 8px"> |
|||
<div class="grid" :style="layoutStyleComputed"> |
|||
<template v-for="(field, index) in fields as any" :key="String(index)"> |
|||
<FormElement :field="field"></FormElement> |
|||
</template> |
|||
</div> |
|||
</q-card-section> |
|||
</q-card> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { inject, computed } from 'vue'; |
|||
import { useQuasar } from 'quasar'; |
|||
import { Form } from './ts/Form'; |
|||
import FormElement from './FormElement.vue'; |
|||
|
|||
const $q = useQuasar(); |
|||
const form = <Form>inject('form'); |
|||
|
|||
// 颜色透明度 |
|||
const colorOpacity = 0.048; |
|||
const colors = [ |
|||
// 红色 |
|||
'rgba(255, 0, 0, ' + colorOpacity + ')', |
|||
// 橙色 |
|||
'rgba(255, 149, 0, ' + colorOpacity + ')', |
|||
// 黄色 |
|||
'rgba(255, 255, 0, ' + colorOpacity + ')', |
|||
// 绿色 |
|||
'rgba(4, 255, 0, ' + colorOpacity + ')', |
|||
// 青色 |
|||
'rgba(0, 255, 255, ' + colorOpacity + ')', |
|||
// 蓝色 |
|||
'rgba(0, 38, 255, ' + colorOpacity + ')', |
|||
// 紫色 |
|||
'rgba(255, 0, 247, ' + colorOpacity + ')', |
|||
// 灰色 |
|||
'rgba(0, 0, 0, ' + colorOpacity + ')', |
|||
]; |
|||
|
|||
const props = defineProps({ |
|||
// 分组标签名 |
|||
label: { type: String, default: '' }, |
|||
// 分组头背景色 |
|||
color: { type: String, default: undefined }, |
|||
// 分组图标 |
|||
icon: { type: String, default: undefined }, |
|||
// 分组图标其余属性 |
|||
iconAttrs: { type: Object, default: undefined }, |
|||
// 分组内一行放几个字段,与 form 保持一致,可配置具体值,也可配置屏幕断点显示值 |
|||
colsNum: { type: [Number, Object], default: 0 }, |
|||
// 字段集合 |
|||
fields: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
const headerStyleComputed = computed(() => { |
|||
const style = { |
|||
// 垂直居中 |
|||
display: 'flex', |
|||
alignItems: 'center', |
|||
// 文字颜色 |
|||
color: '#000', |
|||
padding: '5px', |
|||
}; |
|||
if (props.color) { |
|||
// 背景颜色 |
|||
if (props.color === 'auto') { |
|||
const index = form.fieldArray.value.findIndex((item) => item.label === props.label); |
|||
let colorIndex = index > -1 && index < colors.length ? index : getRandomInt(); |
|||
style['background-color'] = colors[colorIndex]; |
|||
} else { |
|||
style['background-color'] = props.color; |
|||
} |
|||
} |
|||
return style; |
|||
}); |
|||
|
|||
// 随机取颜色数组下标 |
|||
const getRandomInt = () => { |
|||
const min = 0; |
|||
const max = colors.length - 1; |
|||
return Math.floor(Math.random() * (max - min + 1) + min); |
|||
}; |
|||
|
|||
const screenColsNumComputed = computed(() => { |
|||
if (typeof props.colsNum === 'number' && props.colsNum > 0) { |
|||
return props.colsNum; |
|||
} else if (typeof props.colsNum === 'object') { |
|||
const screen = { ...form.cm.screenCols, ...props.colsNum }; |
|||
return screen[$q.screen.name]; |
|||
} |
|||
return form.cm.screenCols[$q.screen.name]; |
|||
}); |
|||
|
|||
const layoutStyleComputed = computed(() => { |
|||
const style = {}; |
|||
if (typeof props.colsNum === 'number' && props.colsNum > 0) { |
|||
style['grid-template-columns'] = 'repeat(' + props.colsNum + ', minmax(0, 1fr))'; |
|||
} else { |
|||
style['grid-template-columns'] = 'repeat(' + screenColsNumComputed.value + ', minmax(0, 1fr))'; |
|||
} |
|||
style['column-gap'] = form.props.xGap + 'px'; |
|||
style['row-gap'] = form.props.yGap + 'px'; |
|||
return style; |
|||
}); |
|||
</script> |
@ -1,389 +0,0 @@ |
|||
<template> |
|||
<div v-show="showIfComputed"> |
|||
<q-field |
|||
ref="fieldRef" |
|||
:hide-bottom-space="true" |
|||
:hide-hint="true" |
|||
:outlined="true" |
|||
:dense="true" |
|||
v-bind="attrs" |
|||
:stack-label="stackLabelRef" |
|||
:rules="rulesComputed" |
|||
:readonly="readonlyIfComputed" |
|||
:disable="disableIfComputed" |
|||
style="position: relative" |
|||
@focus.stop.prevent="focus" |
|||
@blur.stop.prevent="blur" |
|||
> |
|||
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
|||
<template #control> |
|||
<div v-if="editable && toolbar" class="w-full pt-2 border-b border-b-gray-200"> |
|||
<Toolbar :source-code-editor="editorView" :user-defined-functions="userDefinedFunctions"></Toolbar> |
|||
</div> |
|||
<div |
|||
ref="codemirrorRef" |
|||
:style="`width:100%; padding-top: ${lineNumber ? 4 : 2}px; overflow: auto;`" |
|||
@focus.stop.prevent="() => {}" |
|||
@click.stop.prevent="() => {}" |
|||
></div> |
|||
</template> |
|||
<template v-if="!Tools.isEmpty(modelValueRef) && attrs.button" #append> |
|||
<q-btn |
|||
round |
|||
dense |
|||
flat |
|||
v-bind="attrs.button" |
|||
:style="{ |
|||
content: '', |
|||
position: 'absolute', |
|||
bottom: '5px', |
|||
right: '5px', |
|||
}" |
|||
@click.stop.prevent="buttonClick(attrs.button)" |
|||
/> |
|||
</template> |
|||
</q-field> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, onMounted, onUnmounted, onUpdated, watch, computed, toRaw } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
import { FormValidators } from '@/platform/components'; |
|||
import { EditorView } from '@codemirror/view'; |
|||
import { EditorState, StateEffect, Compartment } from '@codemirror/state'; |
|||
import * as view from '@codemirror/view'; |
|||
import * as language from '@codemirror/language'; |
|||
import * as commands from '@codemirror/commands'; |
|||
import * as search from '@codemirror/search'; |
|||
import * as autocomplete from '@codemirror/autocomplete'; |
|||
|
|||
import { LanguageSupport } from '@codemirror/language'; |
|||
import { html, htmlLanguage } from '@codemirror/lang-html'; |
|||
import { java, javaLanguage } from '@codemirror/lang-java'; |
|||
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript'; |
|||
import { json, jsonLanguage } from '@codemirror/lang-json'; |
|||
import { sql } from '@codemirror/lang-sql'; |
|||
import { xml, xmlLanguage } from '@codemirror/lang-xml'; |
|||
|
|||
import PlaceholderPlugin from './w-code-mirror/PlaceholderPlugin'; |
|||
import Toolbar from '@/platform/components/math/toolbar/Toolbar.vue'; |
|||
|
|||
const modelValueRef = defineModel({ type: String, default: '' }); |
|||
|
|||
const attrs = useAttrs(); |
|||
const rules = attrs.rules; |
|||
const fieldRef = ref(); |
|||
const props = defineProps({ |
|||
onChange: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
// 语言 |
|||
lang: { type: String, default: 'json' }, |
|||
// 宽度 |
|||
width: { type: [Number, String], default: '100%' }, |
|||
// 高度 |
|||
height: { type: [Number, String], default: undefined }, |
|||
// 行高 |
|||
lineHeight: { type: [Number, String], default: 20 }, |
|||
// 行数 |
|||
rows: { type: Number, default: 4 }, |
|||
// 是否包含工具条 |
|||
toolbar: { type: Boolean, default: true }, |
|||
// 是否可编辑 |
|||
editable: { type: Boolean, default: true }, |
|||
// 是否允许自动换行 |
|||
lineWrap: { type: Boolean, default: false }, |
|||
// tab size |
|||
tabSize: { type: Number, default: 4 }, |
|||
// 是否显示行号 |
|||
lineNumber: { type: Boolean, default: false }, |
|||
// 是否允许回车换行 |
|||
lineBreak: { type: Boolean, default: true }, |
|||
// 是否开启自动完成 |
|||
//autoCompletion: { type: Boolean, default: false }, |
|||
// 是否开启变量替换 |
|||
placeholder: { type: Boolean, default: false }, |
|||
autoCompletion: { |
|||
type: Function, |
|||
default: undefined, |
|||
}, |
|||
userDefinedFunctions: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
showIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return true; |
|||
}, |
|||
}, |
|||
required: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
requiredIf: { |
|||
type: Function, |
|||
default: undefined, |
|||
}, |
|||
readOnlyIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
disableIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
form: { |
|||
type: Object, |
|||
default: undefined, |
|||
}, |
|||
}); |
|||
|
|||
const rulesComputed = computed(() => { |
|||
let result = rules || <any>[]; |
|||
if (showIfComputed.value && requiredIfComputed.value) { |
|||
result.push(FormValidators.required()); |
|||
} else if (!showIfComputed.value) { |
|||
result = []; |
|||
} |
|||
if (fieldRef?.value) { |
|||
fieldRef.value.resetValidation(); |
|||
} |
|||
return result; |
|||
}); |
|||
|
|||
const showIfComputed = computed(() => { |
|||
return props.showIf({ |
|||
value: modelValueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const requiredIfComputed = computed(() => { |
|||
if (props.requiredIf) { |
|||
return ( |
|||
props.requiredIf({ |
|||
value: modelValueRef.value, |
|||
form: props.form, |
|||
}) || false |
|||
); |
|||
} else if (props.required) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}); |
|||
const readonlyIfComputed = computed(() => { |
|||
if (props.form && props.form.getStatus() === 'view') { |
|||
return true; |
|||
} |
|||
return props.readOnlyIf({ |
|||
value: modelValueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const disableIfComputed = computed(() => { |
|||
return props.disableIf({ |
|||
value: modelValueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
|
|||
const basicSetup = [ |
|||
EditorState.allowMultipleSelections.of(true), |
|||
|
|||
//view.lineNumbers(), |
|||
//view.highlightActiveLine(), |
|||
view.highlightActiveLineGutter(), |
|||
view.highlightSpecialChars(), |
|||
view.drawSelection(), |
|||
view.dropCursor(), |
|||
view.rectangularSelection(), |
|||
view.crosshairCursor(), |
|||
|
|||
commands.history(), |
|||
|
|||
//language.foldGutter(), |
|||
language.indentOnInput(), |
|||
language.syntaxHighlighting(language.defaultHighlightStyle, { fallback: true }), |
|||
language.bracketMatching(), |
|||
|
|||
//search.highlightSelectionMatches(), |
|||
|
|||
view.keymap.of([ |
|||
...commands.defaultKeymap, |
|||
...commands.historyKeymap, |
|||
...language.foldKeymap, |
|||
...autocomplete.completionKeymap, |
|||
...autocomplete.closeBracketsKeymap, |
|||
...search.searchKeymap, |
|||
commands.indentWithTab, |
|||
]), |
|||
]; |
|||
|
|||
const getLanguage = (lang: string): LanguageSupport => { |
|||
lang = lang || 'json'; |
|||
switch (lang.toLowerCase()) { |
|||
case 'html': |
|||
return html(); |
|||
case 'java': |
|||
return java(); |
|||
case 'javascript': |
|||
return javascript(); |
|||
case 'json': |
|||
return json(); |
|||
case 'sql': |
|||
return sql(); |
|||
case 'xml': |
|||
return xml(); |
|||
default: |
|||
return json(); |
|||
} |
|||
}; |
|||
|
|||
const codemirrorRef = ref(); |
|||
// q-field 的 stack-label 属性是对 field 的 label 进行设置效果 |
|||
// 如果 field 有值时, 无论是否获得焦点 label 都缩小显示 |
|||
// 如果 field 无值时, 如果 field 获得焦点 label 就缩小显示, 否则 label 放大显示 |
|||
const stackLabelRef = ref(!Tools.isUndefinedOrNull(modelValueRef.value)); |
|||
|
|||
let editorView; |
|||
let isFocus = false; |
|||
|
|||
if (props.lineNumber) { |
|||
// 行号 |
|||
basicSetup.push(view.lineNumbers()); |
|||
} |
|||
if (props.autoCompletion) { |
|||
// 自动完成 |
|||
basicSetup.push(autocomplete.closeBrackets()); |
|||
basicSetup.push( |
|||
autocomplete.autocompletion({ override: [props.autoCompletion], activateOnCompletion: props.activateOnCompletion, maxRenderedOptions: 1000 }), |
|||
); |
|||
} |
|||
if (props.placeholder) { |
|||
// 变量标识替换 |
|||
basicSetup.push(PlaceholderPlugin); |
|||
} |
|||
|
|||
if (props.lineWrap) { |
|||
basicSetup.push(EditorView.lineWrapping); |
|||
} |
|||
|
|||
// 是否可编辑 |
|||
basicSetup.push(EditorView.editable.of(props.editable)); |
|||
|
|||
onMounted(() => { |
|||
if (codemirrorRef.value) { |
|||
let language = new Compartment(); |
|||
let tabSize = new Compartment(); |
|||
editorView = new EditorView({ |
|||
extensions: [ |
|||
basicSetup, |
|||
language.of(getLanguage(props.lang)), |
|||
tabSize.of(EditorState.tabSize.of(props.tabSize)), |
|||
EditorState.readOnly.of(props.readOnlyIf(props.form)), |
|||
EditorView.theme({ |
|||
'&': { |
|||
outline: 'none !important', |
|||
width: Tools.px(props.width), |
|||
height: props.height ? Tools.px(props.height) : props.rows * 20 + (props.lineNumber ? 8 : 6) + 'px', |
|||
}, |
|||
'.cm-content': { |
|||
'line-height': props.lineHeight + 'px', |
|||
}, |
|||
}), |
|||
|
|||
// 以下代码可以添加内容变化后的操作, 为避免重复操作, 更新操作放到 blur 方法中了 |
|||
EditorView.updateListener.of(function (e) { |
|||
// emits('update:modelValue', e.state.doc.toString()); |
|||
let content = e.state.doc.toString(); |
|||
if (!props.lineBreak) { |
|||
content = content?.replace(/[\r\n]/g, ''); |
|||
} |
|||
//updateModelValue(content); |
|||
}), |
|||
], |
|||
parent: codemirrorRef.value, |
|||
doc: modelValueRef.value, |
|||
}); |
|||
watch( |
|||
() => modelValueRef.value, |
|||
() => { |
|||
// 当未获得焦点时,更新变更, 当获得焦点时不能更新 |
|||
if (!isFocus) { |
|||
let content = modelValueRef.value; |
|||
if (!props.lineBreak) { |
|||
content = content.replace(/[\r\n]/g, ''); |
|||
} |
|||
editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: content } }); |
|||
} |
|||
}, |
|||
); |
|||
} |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
editorView.destroy(); |
|||
}); |
|||
|
|||
const focus = () => { |
|||
isFocus = true; |
|||
stackLabelRef.value = true; |
|||
}; |
|||
|
|||
const blur = () => { |
|||
isFocus = false; |
|||
let content = editorView.state.doc.toString(); |
|||
if (Tools.isUndefinedOrNull(content)) { |
|||
modelValueRef.value = ''; |
|||
} |
|||
const reg = /\$\{(.+?)\}\.\$\{(.+?)\}/g; |
|||
while (reg.test(content)) { |
|||
content = content.replace(reg, '${$1.$2}'); |
|||
} |
|||
modelValueRef.value = content; |
|||
if (content) { |
|||
stackLabelRef.value = true; |
|||
} else { |
|||
stackLabelRef.value = false; |
|||
} |
|||
}; |
|||
|
|||
const getValue = () => { |
|||
return editorView.state.doc.toString(); |
|||
}; |
|||
|
|||
const setValue = (value: string) => { |
|||
editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: value } }); |
|||
}; |
|||
|
|||
const configure = (values) => { |
|||
editorView.dispatch({ effects: StateEffect.reconfigure.of(values) }); |
|||
}; |
|||
|
|||
const buttonClick = (button) => { |
|||
if (button.click) { |
|||
button.click({ |
|||
value: modelValueRef.value, |
|||
form: props.form, |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const validate = () => { |
|||
return fieldRef.value.validate(); |
|||
}; |
|||
|
|||
defineExpose({ |
|||
getValue, |
|||
setValue, |
|||
configure, |
|||
validate, |
|||
}); |
|||
</script> |
@ -1,218 +0,0 @@ |
|||
<template> |
|||
<div v-show="showIfComputed"> |
|||
<q-input |
|||
ref="cronRef" |
|||
v-model="valueRef" |
|||
:hide-bottom-space="true" |
|||
:hide-hint="true" |
|||
:outlined="true" |
|||
:dense="true" |
|||
v-bind="attrs" |
|||
:rules="rulesComputed" |
|||
:readonly="readonlyIfComputed" |
|||
:disable="disableIfComputed" |
|||
:v-bind="attrs" |
|||
@update:model-value="updateModelValue" |
|||
@change="changeValue" |
|||
> |
|||
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }} </template> |
|||
<template v-if="!props.form || (props.form && props.form.getStatus() !== 'view')" #append> |
|||
<!-- 选择颜色按钮 --> |
|||
<q-btn icon="bi-pencil-square" padding="2px" flat square unelevated :title="$t('select')"> |
|||
<q-popup-proxy v-model:model-value="isShow" anchor="bottom right" self="top right" :offset="[0, 10]" style="width: 800px"> |
|||
<q-tabs v-model="selectedTab" no-caps> |
|||
<q-tab name="second" :label="$t('second')" /> |
|||
<q-tab name="minute" :label="$t('minute')" /> |
|||
<q-tab name="hour" :label="$t('hour')" /> |
|||
<q-tab name="day" :label="$t('day')" /> |
|||
<q-tab name="month" :label="$t('month')" /> |
|||
<q-tab name="week" :label="$t('week')" /> |
|||
<q-tab name="year" :label="$t('year')" /> |
|||
</q-tabs> |
|||
|
|||
<q-tab-panels v-model="selectedTab" animated swipeable vertical transition-prev="jump-up" transition-next="jump-up" :keep-alive="true"> |
|||
<q-tab-panel name="second"> |
|||
<SecondSegment v-model="secondValueRef" @update:model-value="valueChanged"></SecondSegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="minute"> |
|||
<MinuteSegment v-model="minuteValueRef" @update:model-value="valueChanged"></MinuteSegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="hour"> |
|||
<HourSegment v-model="hourValueRef" @update:model-value="valueChanged"></HourSegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="day"> |
|||
<DaySegment v-model="dayValueRef" @update:model-value="valueChanged"></DaySegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="month"> |
|||
<MonthSegment v-model="monthValueRef" @update:model-value="valueChanged"></MonthSegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="week"> |
|||
<WeekSegment v-model="weekValueRef" @update:model-value="valueChanged"></WeekSegment> |
|||
</q-tab-panel> |
|||
<q-tab-panel name="year"> |
|||
<YearSegment v-model="yearValueRef" @update:model-value="valueChanged"></YearSegment> |
|||
</q-tab-panel> |
|||
</q-tab-panels> |
|||
</q-popup-proxy> |
|||
</q-btn> |
|||
</template> |
|||
</q-input> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, watch, computed } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
import { FormValidators } from '@/platform/components'; |
|||
import SecondSegment from './w-cron-segment/SecondSegment.vue'; |
|||
import MinuteSegment from './w-cron-segment/MinuteSegment.vue'; |
|||
import HourSegment from './w-cron-segment/HourSegment.vue'; |
|||
import DaySegment from './w-cron-segment/DaySegment.vue'; |
|||
import MonthSegment from './w-cron-segment/MonthSegment.vue'; |
|||
import WeekSegment from './w-cron-segment/WeekSegment.vue'; |
|||
import YearSegment from './w-cron-segment/YearSegment.vue'; |
|||
|
|||
const attrs = useAttrs(); |
|||
const rules = attrs.rules; |
|||
const cronRef = ref(); |
|||
const props = defineProps({ |
|||
onChange: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
modelValue: { type: String, default: '' }, |
|||
showIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return true; |
|||
}, |
|||
}, |
|||
required: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
requiredIf: { |
|||
type: Function, |
|||
default: undefined, |
|||
}, |
|||
readOnlyIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
disableIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
form: { |
|||
type: Object, |
|||
default: undefined, |
|||
}, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue', 'change']); |
|||
|
|||
const isShow = ref(false); |
|||
const selectedTab = ref('second'); |
|||
|
|||
const valueRef = ref(props.modelValue || ''); |
|||
const splits = (props.modelValue || '').split(' '); |
|||
const secondValueRef = ref(splits[0]); |
|||
const minuteValueRef = ref(splits[1]); |
|||
const hourValueRef = ref(splits[2]); |
|||
const dayValueRef = ref(splits[3]); |
|||
const monthValueRef = ref(splits[4]); |
|||
const weekValueRef = ref(splits[5]); |
|||
const yearValueRef = ref(splits[6]); |
|||
|
|||
watch( |
|||
() => props.modelValue, |
|||
(newVal, oldVal) => { |
|||
valueRef.value = newVal; |
|||
}, |
|||
); |
|||
|
|||
const rulesComputed = computed(() => { |
|||
let result = rules || <any>[]; |
|||
if (showIfComputed.value && requiredIfComputed.value) { |
|||
result.push(FormValidators.required()); |
|||
} else if (!showIfComputed.value) { |
|||
result = []; |
|||
} |
|||
if (cronRef?.value) { |
|||
cronRef.value.resetValidation(); |
|||
} |
|||
return result; |
|||
}); |
|||
|
|||
const showIfComputed = computed(() => { |
|||
return props.showIf({ |
|||
value: valueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const requiredIfComputed = computed(() => { |
|||
if (props.requiredIf) { |
|||
return ( |
|||
props.requiredIf({ |
|||
value: valueRef.value, |
|||
form: props.form, |
|||
}) || false |
|||
); |
|||
} else if (props.required) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}); |
|||
const readonlyIfComputed = computed(() => { |
|||
if (props.form && props.form.getStatus() === 'view') { |
|||
return true; |
|||
} |
|||
return props.readOnlyIf({ |
|||
value: valueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const disableIfComputed = computed(() => { |
|||
return props.disableIf({ |
|||
value: valueRef.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
|
|||
const valueChanged = () => { |
|||
const values = []; |
|||
values.push(secondValueRef.value ? secondValueRef.value : '*'); |
|||
values.push(minuteValueRef.value ? minuteValueRef.value : '*'); |
|||
values.push(hourValueRef.value ? hourValueRef.value : '*'); |
|||
values.push(dayValueRef.value ? dayValueRef.value : '*'); |
|||
values.push(monthValueRef.value ? monthValueRef.value : '*'); |
|||
values.push(weekValueRef.value ? weekValueRef.value : '*'); |
|||
values.push(yearValueRef.value ? yearValueRef.value : '*'); |
|||
|
|||
const result = Tools.join(values, ' '); |
|||
valueRef.value = result; |
|||
emit('update:modelValue', result); |
|||
changeValue(result); |
|||
}; |
|||
|
|||
const updateModelValue = (value) => { |
|||
valueRef.value = value; |
|||
emit('update:modelValue', value); |
|||
}; |
|||
const changeValue = (value) => { |
|||
emit('change', { |
|||
value: value, |
|||
form: props.form, |
|||
}); |
|||
}; |
|||
|
|||
const validate = () => { |
|||
return cronRef.value.validate(); |
|||
}; |
|||
|
|||
defineExpose({ |
|||
validate, |
|||
}); |
|||
</script> |
@ -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; |
@ -1,251 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.day.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="notSpecify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.day.notSpecify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.day.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.day.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.day.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per2" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.day.per2.1') }}</span> |
|||
<q-input |
|||
v-model="per2FromRef" |
|||
type="number" |
|||
:disable="!per2FromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.day.per2.2') }}</span> |
|||
<q-input |
|||
v-model="per2PerRef" |
|||
type="number" |
|||
:disable="!per2PerEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.day.per2.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="workDay" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.day.workDay.1') }}</span> |
|||
<q-input |
|||
v-model="workDayRef" |
|||
type="number" |
|||
:disable="!workDayEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.day.workDay.2') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="lastDay" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.day.lastDay') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.day.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 31" :key="index"> |
|||
<template v-if="index % 10 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + index" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 10 === 0"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const per2FromEnableRef = ref(false); |
|||
const per2FromRef = ref(''); |
|||
|
|||
const per2PerEnableRef = ref(false); |
|||
const per2PerRef = ref(''); |
|||
|
|||
const workDayEnableRef = ref(false); |
|||
const workDayRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 31; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
workDayEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
workDayEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'per2') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = true; |
|||
per2PerEnableRef.value = true; |
|||
workDayEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'workDay') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
workDayEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'lastDay') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
workDayEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
workDayEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'per2') { |
|||
valueRef.value = per2FromRef.value + '/' + per2PerRef.value; |
|||
} else if (modeRef.value === 'workDay') { |
|||
valueRef.value = workDayRef.value + 'W'; |
|||
} else if (modeRef.value === 'lastDay') { |
|||
valueRef.value = 'L'; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 31; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i + 1); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,185 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.hour.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.hour.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.hour.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.hour.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per2" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.hour.per2.1') }}</span> |
|||
<q-input |
|||
v-model="per2FromRef" |
|||
type="number" |
|||
:disable="!per2FromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.hour.per2.2') }}</span> |
|||
<q-input |
|||
v-model="per2PerRef" |
|||
type="number" |
|||
:disable="!per2PerEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.hour.per2.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.hour.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 24" :key="index"> |
|||
<template v-if="index % 8 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + (index - 1)" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 8 === 0"> |
|||
<div class="col-3"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const per2FromEnableRef = ref(false); |
|||
const per2FromRef = ref(''); |
|||
|
|||
const per2PerEnableRef = ref(false); |
|||
const per2PerRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 24; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'per2') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = true; |
|||
per2PerEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'per2') { |
|||
valueRef.value = per2FromRef.value + '/' + per2PerRef.value; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 24; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,185 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.minute.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.minute.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.minute.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.minute.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per2" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.minute.per2.1') }}</span> |
|||
<q-input |
|||
v-model="per2FromRef" |
|||
type="number" |
|||
:disable="!per2FromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.minute.per2.2') }}</span> |
|||
<q-input |
|||
v-model="per2PerRef" |
|||
type="number" |
|||
:disable="!per2PerEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.minute.per2.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.minute.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 60" :key="index"> |
|||
<template v-if="index % 10 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + (index - 1)" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 10 === 0"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const per2FromEnableRef = ref(false); |
|||
const per2FromRef = ref(''); |
|||
|
|||
const per2PerEnableRef = ref(false); |
|||
const per2PerRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 60; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'per2') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = true; |
|||
per2PerEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'per2') { |
|||
valueRef.value = per2FromRef.value + '/' + per2PerRef.value; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 60; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,197 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.month.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="notSpecify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.month.notSpecify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.month.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.month.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.month.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per2" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.month.per2.1') }}</span> |
|||
<q-input |
|||
v-model="per2FromRef" |
|||
type="number" |
|||
:disable="!per2FromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.month.per2.2') }}</span> |
|||
<q-input |
|||
v-model="per2PerRef" |
|||
type="number" |
|||
:disable="!per2PerEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.month.per2.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.month.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 12" :key="index"> |
|||
<template v-if="index % 6 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + index" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 6 === 0"> |
|||
<div class="col-5"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const per2FromEnableRef = ref(false); |
|||
const per2FromRef = ref(''); |
|||
|
|||
const per2PerEnableRef = ref(false); |
|||
const per2PerRef = ref(''); |
|||
|
|||
const workDayEnableRef = ref(false); |
|||
const workDayRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 12; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'per2') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = true; |
|||
per2PerEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'per2') { |
|||
valueRef.value = per2FromRef.value + '/' + per2PerRef.value; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 12; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i + 1); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,185 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.second.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.second.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.second.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.second.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per2" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.second.per2.1') }}</span> |
|||
<q-input |
|||
v-model="per2FromRef" |
|||
type="number" |
|||
:disable="!per2FromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.second.per2.2') }}</span> |
|||
<q-input |
|||
v-model="per2PerRef" |
|||
type="number" |
|||
:disable="!per2PerEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.second.per2.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.second.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 60" :key="index"> |
|||
<template v-if="index % 10 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + (index - 1)" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 10 === 0"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const per2FromEnableRef = ref(false); |
|||
const per2FromRef = ref(''); |
|||
|
|||
const per2PerEnableRef = ref(false); |
|||
const per2PerRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 60; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'per2') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = true; |
|||
per2PerEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
per2FromEnableRef.value = false; |
|||
per2PerEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'per2') { |
|||
valueRef.value = per2FromRef.value + '/' + per2PerRef.value; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 60; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,233 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.week.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="notSpecify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.week.notSpecify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.week.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.week.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.week.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="weekOfYear" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.week.weekOfYear.1') }}</span> |
|||
<q-input |
|||
v-model="weekOfYearRef" |
|||
type="number" |
|||
:disable="!weekOfYearEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.week.weekOfYear.2') }}</span> |
|||
<q-input |
|||
v-model="dayOfWeekRef" |
|||
type="number" |
|||
:disable="!dayOfWeekEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.week.weekOfYear.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="lastWeek" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.week.lastDay.1') }}</span> |
|||
<q-input |
|||
v-model="lastWeekRef" |
|||
type="number" |
|||
:disable="!lastWeekEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.week.lastDay.2') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
|
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="specify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.week.specify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row"> |
|||
<template v-for="index in 7" :key="index"> |
|||
<template v-if="index % 7 === 1"> |
|||
<div class="col-1"></div> |
|||
</template> |
|||
<div class="col-1"> |
|||
<q-checkbox |
|||
v-model="optionsRef[index - 1]" |
|||
dense |
|||
:label="'' + index" |
|||
:disable="!optionsEnableRef" |
|||
@update:model-value="valueChanged" |
|||
></q-checkbox> |
|||
</div> |
|||
<template v-if="index % 7 === 0"> |
|||
<div class="col-5"></div> |
|||
</template> |
|||
</template> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const weekOfYearEnableRef = ref(false); |
|||
const weekOfYearRef = ref(''); |
|||
|
|||
const dayOfWeekEnableRef = ref(false); |
|||
const dayOfWeekRef = ref(''); |
|||
|
|||
const lastWeekEnableRef = ref(false); |
|||
const lastWeekRef = ref(''); |
|||
|
|||
const optionsEnableRef = ref(false); |
|||
const optionsRef = ref([]); |
|||
for (let i = 0; i < 7; i++) { |
|||
optionsRef.value.push(false); |
|||
} |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
weekOfYearEnableRef.value = false; |
|||
dayOfWeekEnableRef.value = false; |
|||
lastWeekEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
weekOfYearEnableRef.value = false; |
|||
dayOfWeekEnableRef.value = false; |
|||
lastWeekEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'weekOfYear') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
weekOfYearEnableRef.value = true; |
|||
dayOfWeekEnableRef.value = true; |
|||
lastWeekEnableRef.value = false; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'lastWeek') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
weekOfYearEnableRef.value = false; |
|||
dayOfWeekEnableRef.value = false; |
|||
lastWeekEnableRef.value = true; |
|||
optionsEnableRef.value = false; |
|||
} else if (modeRef.value === 'specify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
weekOfYearEnableRef.value = false; |
|||
dayOfWeekEnableRef.value = false; |
|||
lastWeekEnableRef.value = false; |
|||
optionsEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} else if (modeRef.value === 'weekOfYear') { |
|||
valueRef.value = weekOfYearRef.value + '/' + dayOfWeekRef.value; |
|||
} else if (modeRef.value === 'lastWeek') { |
|||
valueRef.value = lastWeekRef.value + 'L'; |
|||
} else if (modeRef.value === 'specify') { |
|||
let seconds = []; |
|||
for (let i = 0; i < 7; i++) { |
|||
if (optionsRef.value[i]) { |
|||
seconds.push(i + 1); |
|||
} |
|||
} |
|||
valueRef.value = Tools.join(seconds, ','); |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,93 +0,0 @@ |
|||
<template> |
|||
<q-list dense style="width: 100%"> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="per" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.year.per') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="notSpecify" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label>{{ $t('cron.year.notSpecify') }}</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
<q-item> |
|||
<q-item-section avatar> |
|||
<q-radio v-model="modeRef" val="period" @update:model-value="valueChanged" /> |
|||
</q-item-section> |
|||
<q-item-section> |
|||
<q-item-label> |
|||
<div class="row no-wrap items-center"> |
|||
<span class="pr-2">{{ $t('cron.year.period.1') }}</span> |
|||
<q-input |
|||
v-model="periodFromRef" |
|||
type="number" |
|||
:disable="!periodFromEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.year.period.2') }}</span> |
|||
<q-input |
|||
v-model="periodToRef" |
|||
type="number" |
|||
:disable="!periodToEnableRef" |
|||
outlined |
|||
dense |
|||
style="width: 100px" |
|||
@update:model-value="valueChanged" |
|||
></q-input> |
|||
<span class="px-2">{{ $t('cron.year.period.3') }}</span> |
|||
</div> |
|||
</q-item-label> |
|||
</q-item-section> |
|||
</q-item> |
|||
</q-list> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
|
|||
const props = defineProps({ |
|||
modelValue: { type: String, default: '' }, |
|||
}); |
|||
const emit = defineEmits(['update:modelValue']); |
|||
|
|||
const valueRef = ref(props.modelValue); |
|||
const modeRef = ref(''); |
|||
|
|||
const periodFromEnableRef = ref(false); |
|||
const periodFromRef = ref(''); |
|||
|
|||
const periodToEnableRef = ref(false); |
|||
const periodToRef = ref(''); |
|||
|
|||
const valueChanged = () => { |
|||
if (modeRef.value === 'per') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
} else if (modeRef.value === 'notSpecify') { |
|||
periodFromEnableRef.value = false; |
|||
periodToEnableRef.value = false; |
|||
} else if (modeRef.value === 'period') { |
|||
periodFromEnableRef.value = true; |
|||
periodToEnableRef.value = true; |
|||
} |
|||
|
|||
if (modeRef.value === 'per') { |
|||
valueRef.value = '*'; |
|||
} else if (modeRef.value === 'notSpecify') { |
|||
valueRef.value = ''; |
|||
} else if (modeRef.value === 'period') { |
|||
valueRef.value = periodFromRef.value + '-' + periodToRef.value; |
|||
} |
|||
|
|||
emit('update:modelValue', valueRef.value); |
|||
}; |
|||
</script> |
@ -1,5 +0,0 @@ |
|||
<template> |
|||
<div></div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
</script> |
@ -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; |
|||
}); |
|||
} |
@ -0,0 +1,14 @@ |
|||
/** |
|||
* 常量 |
|||
*/ |
|||
export class Constant { |
|||
/** |
|||
* 新增状态 |
|||
*/ |
|||
static STATUS_ADD = 'add'; |
|||
|
|||
/** |
|||
* 用于分组的字段类型 |
|||
*/ |
|||
static GROUP_TYPE = 'w-form-group'; |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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<any> = reactive({}); |
|||
/** |
|||
* 字段集合数组 |
|||
*/ |
|||
fieldArray: Ref = ref([]); |
|||
/** |
|||
* 字段集合对象,方便快速获取字段信息( name 为 key,字段配置为 value ,排除无 name 配置的元素(如 w-form-group 类型)。 |
|||
*/ |
|||
fields: Reactive<any> = reactive({}); |
|||
/** |
|||
* 表单状态(用以标识表单当前是新增、编辑、复制等不同状态,默认为新增,可通过 setStatus 方法设置,getStatus 方法获得) |
|||
*/ |
|||
status: string = Constant.STATUS_ADD; |
|||
/** |
|||
* 字段使用的组件 ref 对象(渲染时动态绑定 ref ,key 为字段 name ) |
|||
*/ |
|||
componentRef: Reactive<any> = 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<any>, 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<any>, 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<any>, 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); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
export type ComponentFunctionsType = { |
|||
/** |
|||
* 获取表单ref函数 |
|||
*/ |
|||
getFormRef: Function; |
|||
/** |
|||
* 表单字段模型值更改触发函数 |
|||
*/ |
|||
updateModelValue: Function; |
|||
} |
@ -0,0 +1,4 @@ |
|||
export type ErrorType = { |
|||
fieldName: string; |
|||
errorMessage: string; |
|||
} |
@ -0,0 +1,22 @@ |
|||
export type PropsType = { |
|||
/** |
|||
* form模型值 |
|||
*/ |
|||
modelValue?: any, |
|||
/** |
|||
* 一行显示的字段数量,为0时根据屏幕断点自动显示 |
|||
*/ |
|||
colsNum?: any, |
|||
/** |
|||
* 横向X轴两个元素间的空隙像素点 |
|||
*/ |
|||
xGap?: number, |
|||
/** |
|||
* 纵向Y轴两个元素间的空隙像素点 |
|||
*/ |
|||
yGap?: number, |
|||
/** |
|||
* 表单字段集合 |
|||
*/ |
|||
fields: Array<any>, |
|||
} |
@ -0,0 +1,39 @@ |
|||
<template> |
|||
<q-item :clickable="true" @click="click"> |
|||
<q-item-section> |
|||
<q-item-label>斑马纹</q-item-label> |
|||
</q-item-section> |
|||
<q-item-section side> |
|||
<q-btn-group outline flat dense unelevated spread> |
|||
<q-btn |
|||
:color="tools.table.configStore.stripe ? 'primary' : ''" |
|||
:outline="tools.table.configStore.stripe ? false : true" |
|||
dense |
|||
label="显示" |
|||
unelevated |
|||
/> |
|||
<q-btn |
|||
:color="tools.table.configStore.stripe ? '' : 'primary'" |
|||
:outline="tools.table.configStore.stripe ? true : false" |
|||
dense |
|||
label="隐藏" |
|||
unelevated |
|||
/> |
|||
</q-btn-group> |
|||
</q-item-section> |
|||
</q-item> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { inject } from 'vue'; |
|||
import { GridTools } from '../../../ts/index'; |
|||
|
|||
const tools = <GridTools>inject('tools'); |
|||
const click = () => { |
|||
tools.table.configStore.stripe = !tools.table.configStore.stripe; |
|||
if (tools.table.configStore.stripe && !tools.opFM.stripeWatch) { |
|||
tools.opFM.setStripe(); |
|||
} else { |
|||
tools.opFM.resetStripeStyle(); |
|||
} |
|||
}; |
|||
</script> |
@ -1,54 +1,227 @@ |
|||
<template> |
|||
<w-grid |
|||
title="用户列表" |
|||
:checkbox-selection="false" |
|||
:data-url="Environment.apiContextPath('/api/system/user')" |
|||
:pageable="false" |
|||
:toolbar-actions="[ |
|||
'query', |
|||
'reset', |
|||
'separator', |
|||
'add', |
|||
'edit', |
|||
'remove', |
|||
'expand', |
|||
[ |
|||
{ |
|||
name: 'ddd', |
|||
icon: 'add', |
|||
label: $t('loginName'), |
|||
}, |
|||
'addTop', |
|||
['addChild', 'cellEdit', 'clone'], |
|||
], |
|||
]" |
|||
:advanced-query="true" |
|||
:stripe="true" |
|||
:query-form-fields="[ |
|||
{ name: 'defaultOrgId', label: '所属机构', type: 'w-org-select', multiple: true }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate'), type: 'w-date-range' }, |
|||
{ name: 'loginName', label: $t('loginName'), type: 'w-text', showIf: true }, |
|||
{ name: 'userName', label: $t('userName'), type: 'w-text' }, |
|||
]" |
|||
:columns="[ |
|||
{ name: 'loginName', label: '很长很长的表头可绕地球一圈', width: 100, title: 'dfdf' }, |
|||
{ name: 'userName', label: $t('userName') }, |
|||
{ name: 'lastModifier', label: '最后修改人' }, |
|||
{ |
|||
name: 'lastModifyDate', |
|||
label: $t('lastModifyDate'), |
|||
}, |
|||
]" |
|||
:editor="{ |
|||
form: { |
|||
fields: [ |
|||
{ name: 'loginName', label: $t('loginName'), type: 'w-text' }, |
|||
{ name: 'userName', label: $t('userName'), type: 'w-text' }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
<q-splitter :model-value="60" class="w-full" style="height: 100%"> |
|||
<template #before> |
|||
<div class="pr-1" style="height: 100%"> |
|||
<w-grid |
|||
ref="roleGridRef" |
|||
:title="$t('system.role.grid.title')" |
|||
:config-button="true" |
|||
selection="multiple" |
|||
db-click-operation="edit" |
|||
:checkbox-selection="true" |
|||
:data-url="Environment.apiContextPath('/api/system/role')" |
|||
:pagination="{ |
|||
sortBy: 'name', |
|||
descending: false, |
|||
}" |
|||
:query-form-cols-num="3" |
|||
:query-form-fields="[ |
|||
{ name: 'code', label: $t('code'), type: 'w-text' }, |
|||
{ name: 'name', label: $t('name'), type: 'w-text' }, |
|||
{ name: 'enable', label: $t('isEnable'), type: 'w-select', options: Options.yesNo() }, |
|||
]" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'separator', 'export']" |
|||
:columns="[ |
|||
{ width: 200, name: 'code', label: $t('code') }, |
|||
{ width: '100%', name: 'name', label: $t('name') }, |
|||
{ width: 70, name: 'enable', label: $t('status'), align: 'center', format: Formater.enableTag() }, |
|||
{ |
|||
width: 200, |
|||
name: 'corporationCode', |
|||
label: $t('corporation'), |
|||
showIf: SessionManager.isPrimaryCorporation(), |
|||
format: (value) => { |
|||
return corporationMapRef[value]; |
|||
}, |
|||
}, |
|||
]" |
|||
:editor="{ |
|||
dialog: { |
|||
width: '600px', |
|||
}, |
|||
form: { |
|||
colsNum: 1, |
|||
fields: [ |
|||
{ name: 'code', label: $t('code'), type: 'w-text', requiredIf: true }, |
|||
{ name: 'name', label: $t('name'), type: 'w-text', requiredIf: true }, |
|||
{ name: 'description', label: $t('description'), type: 'w-textarea', rows: 1 }, |
|||
{ |
|||
name: 'corporationCode', |
|||
label: $t('corporation'), |
|||
type: 'w-select', |
|||
options: corporationOptionRef, |
|||
showIf: () => { |
|||
return SessionManager.isPrimaryCorporation(); |
|||
}, |
|||
}, |
|||
{ name: 'enable', label: $t('enable'), type: 'w-checkbox', defaultValue: true }, |
|||
], |
|||
}, |
|||
}" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: $t('id') }, |
|||
{ name: 'code', label: $t('code') }, |
|||
{ name: 'name', label: $t('name') }, |
|||
{ name: 'description', label: $t('description') }, |
|||
{ name: 'enable', label: $t('enable'), format: Formater.none() }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom') }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() }, |
|||
{ name: 'corporationCode', label: $t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
@row-click=" |
|||
(args) => { |
|||
refreshRelationshipComponents(args.row.id); |
|||
} |
|||
" |
|||
@before-request-data=" |
|||
() => { |
|||
menuTreeGridRef?.clear(); |
|||
userGridRef?.clear(); |
|||
} |
|||
" |
|||
> |
|||
</w-grid> |
|||
</div> |
|||
</template> |
|||
<template #after> |
|||
<div class="pl-1" style="height: 100%"> |
|||
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps> |
|||
<q-tab name="menu" icon="bi-menu-app" :label="$t('menu')" /> |
|||
<q-tab name="user" icon="bi-person" :label="$t('user')" /> |
|||
</q-tabs> |
|||
|
|||
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)"> |
|||
<q-tab-panel name="menu" class="px-0 pb-0" style="height: 100%; padding-left: 0px; padding-right: 0px; padding-bottom: 0px"> |
|||
<SelectMenuTreeGrid |
|||
ref="menuTreeGridRef" |
|||
:fetch-data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByRole')" |
|||
foreign-key="roleId" |
|||
:foreign-value="currentSelectedRoleId" |
|||
@update="update" |
|||
></SelectMenuTreeGrid> |
|||
</q-tab-panel> |
|||
|
|||
<q-tab-panel name="user" class="px-0 pb-0" style="height: 100%; padding-left: 0px; padding-right: 0px; padding-bottom: 0px"> |
|||
<SelectUserGrid |
|||
ref="userGridRef" |
|||
:fetch-data-url="Environment.apiContextPath('/api/system/user/queryUsersByRole')" |
|||
:fetch-other-data-url="Environment.apiContextPath('/api/system/user/queryOtherUsersByRole')" |
|||
foreign-key="roleId" |
|||
:foreign-value="currentSelectedRoleId" |
|||
@select-in="selectIn" |
|||
@select-out="selectOut" |
|||
@select-all-in="selectAllIn" |
|||
@select-all-out="selectAllOut" |
|||
> |
|||
</SelectUserGrid> |
|||
</q-tab-panel> |
|||
</q-tab-panels> |
|||
</div> |
|||
</template> |
|||
</q-splitter> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { Environment, Formater, $t } from '@/platform'; |
|||
import { ref, onActivated } from 'vue'; |
|||
import { Environment, axios, Options, Formater, SessionManager } from '@/platform'; |
|||
import SelectUserGrid from './SelectUserGrid.vue'; |
|||
import SelectMenuTreeGrid from './SelectMenuTreeGrid.vue'; |
|||
|
|||
const corporationMapRef = ref({}); |
|||
const corporationOptionRef = ref([]); |
|||
const roleGridRef = ref(); |
|||
const userGridRef = ref(); |
|||
const menuTreeGridRef = ref(); |
|||
|
|||
const selectedTabRef = ref('menu'); |
|||
const currentSelectedRoleId = ref(''); |
|||
|
|||
const refreshRelationshipComponents = (id) => { |
|||
currentSelectedRoleId.value = id; |
|||
menuTreeGridRef.value?.refresh(); |
|||
userGridRef.value?.refresh(); |
|||
}; |
|||
|
|||
const selectIn = (ids: string[], gridComponent, dialogComponent) => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/addUsers'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: ids, |
|||
}) |
|||
.then(() => { |
|||
gridComponent?.refresh(); |
|||
dialogComponent?.close(); |
|||
}); |
|||
}; |
|||
|
|||
const selectOut = (ids, gridComponent) => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/removeUsers'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: ids, |
|||
}) |
|||
.then(() => { |
|||
gridComponent?.refresh(); |
|||
}); |
|||
}; |
|||
|
|||
const selectAllIn = (gridComponent) => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/addAllUsers'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: [], |
|||
}) |
|||
.then(() => { |
|||
gridComponent?.refresh(); |
|||
}); |
|||
}; |
|||
|
|||
const selectAllOut = (gridComponent) => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/removeAllUsers'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: [], |
|||
}) |
|||
.then(() => { |
|||
gridComponent?.refresh(); |
|||
}); |
|||
}; |
|||
|
|||
const update = (ids, gridComponent) => { |
|||
axios |
|||
.post(Environment.apiContextPath('/api/system/role/updateMenus'), { |
|||
one: roleGridRef.value.getSelectedRows()[0].id, |
|||
many: ids, |
|||
}) |
|||
.then(() => { |
|||
gridComponent.refresh(); |
|||
}); |
|||
}; |
|||
|
|||
onActivated(() => { |
|||
menuTreeGridRef.value?.refresh(); |
|||
userGridRef.value?.refresh(); |
|||
if (SessionManager.isPrimaryCorporation()) { |
|||
axios.get(Environment.apiContextPath('/api/system/corporation?pageable=false')).then((response) => { |
|||
const options = []; |
|||
const corporationMap = {}; |
|||
if (response.data?.content && response.data?.content.length > 0) { |
|||
for (const item of response.data.content) { |
|||
options.push({ label: item.name, value: item.code }); |
|||
corporationMap[item.code] = item.name; |
|||
} |
|||
} |
|||
corporationOptionRef.value = options; |
|||
corporationMapRef.value = corporationMap; |
|||
}); |
|||
} |
|||
}); |
|||
</script> |
|||
|
@ -0,0 +1,125 @@ |
|||
<template> |
|||
<w-grid |
|||
ref="treeGridRef" |
|||
:title="$t('system.shared.selectMenu.grid.title')" |
|||
hide-bottom |
|||
:config-button="false" |
|||
:tree="true" |
|||
selection="multiple" |
|||
:checkbox-selection="true" |
|||
tree-tick-strategy="strict" |
|||
:tree-icon=" |
|||
(row) => { |
|||
if (row.type === 'SEPARATOR') { |
|||
return { name: 'bi-dash-lg' }; |
|||
} else if (row.type === 'ROUTE_ACTION') { |
|||
return { name: 'sym_o_crop_16_9' }; |
|||
} else { |
|||
return { name: row.icon }; |
|||
} |
|||
} |
|||
" |
|||
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue" |
|||
:auto-fetch-data="true" |
|||
:pageable="false" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
extend: 'expand', |
|||
enableIf: () => { |
|||
return foreignValue && treeGridRef?.getRows()?.length > 0; |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'save', |
|||
label: $t('save'), |
|||
icon: 'bi-floppy', |
|||
enableIf: () => { |
|||
return foreignValue && treeGridRef?.getRows()?.length > 0; |
|||
}, |
|||
click: (arg) => { |
|||
DialogManager.confirm($t('system.shared.selectMenu.grid.toolbar.save.tip'), () => { |
|||
const ids = Tools.extractProperties(treeGridRef.getTickedRows(true), 'id'); |
|||
emit('update', ids, treeGridRef); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
]" |
|||
:columns="[ |
|||
{ |
|||
width: '100%', |
|||
name: 'titleI18nKey', |
|||
label: $t('name'), |
|||
sortable: false, |
|||
format: (value, row) => { |
|||
if (row.type === 'SEPARATOR') { |
|||
return `<hr style='width:100px'/>`; |
|||
} else if (row.type === 'ROUTE_ACTION') { |
|||
return $t(row.i18nKey); |
|||
} else { |
|||
return $t(value); |
|||
} |
|||
}, |
|||
}, |
|||
{ width: 70, name: 'enable', label: $t('status'), format: Formater.enableTag(), sortable: false }, |
|||
]" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: $t('id') }, |
|||
{ name: 'type', label: $t('type') }, |
|||
{ name: 'name', label: $t('name') }, |
|||
{ name: 'titleI18nKey', label: $t('titleI18nKey') }, |
|||
{ name: 'icon', label: $t('icon') }, |
|||
{ name: 'enable', label: $t('enable') }, |
|||
{ name: 'order', label: $t('order') }, |
|||
{ name: 'javaScript', label: $t('javaScript') }, |
|||
{ name: 'url', label: $t('url') }, |
|||
{ name: 'urlOpenType', label: $t('urlOpenType') }, |
|||
{ name: 'routeName', label: $t('routeName') }, |
|||
{ name: 'routeQuery', label: $t('routeQuery') }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom') }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: $t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { DialogManager, Formater, Tools } from '@/platform'; |
|||
|
|||
defineProps({ |
|||
fetchDataUrl: { type: String, default: '' }, |
|||
foreignKey: { type: String, default: '' }, |
|||
foreignValue: { type: String, default: '' }, |
|||
}); |
|||
|
|||
const emit = defineEmits<{ |
|||
(e: 'update', ids: string[], gridComponent: any): void; |
|||
}>(); |
|||
|
|||
const treeGridRef = ref(); |
|||
|
|||
const refresh = () => { |
|||
treeGridRef.value?.refresh(); |
|||
}; |
|||
|
|||
const clear = () => { |
|||
treeGridRef.value?.setLocalData([]); |
|||
}; |
|||
|
|||
defineExpose({ |
|||
refresh, |
|||
clear, |
|||
}); |
|||
</script> |
@ -0,0 +1,165 @@ |
|||
<template> |
|||
<w-grid |
|||
ref="gridRef" |
|||
:title="$t('system.shared.selectUser.grid.title')" |
|||
:config-button="false" |
|||
selection="multiple" |
|||
:checkbox-selection="true" |
|||
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue" |
|||
:auto-fetch-data="true" |
|||
:toolbar-configure="{ noIcon: false }" |
|||
:toolbar-actions="[ |
|||
'refresh', |
|||
'separator', |
|||
{ |
|||
name: 'selectIn', |
|||
label: $t('system.shared.selectUser.grid.toolbar.selectIn'), |
|||
icon: 'bi-download', |
|||
enableIf: () => { |
|||
return foreignValue ? true : false; |
|||
}, |
|||
click: () => { |
|||
dialogRef.open(foreignValue); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'selectOut', |
|||
label: $t('system.shared.selectUser.grid.toolbar.selectOut'), |
|||
icon: 'bi-upload', |
|||
enableIf: () => { |
|||
return foreignValue && gridRef?.getSelectedRows()?.length > 0; |
|||
}, |
|||
click: (arg) => { |
|||
const ids = Tools.extractProperties(arg.selecteds, 'id'); |
|||
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectOut.tip'), () => { |
|||
emit('selectOut', ids, gridRef); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
{ |
|||
name: 'selectAllIn', |
|||
label: $t('system.shared.selectUser.grid.toolbar.selectAllIn'), |
|||
icon: 'bi-box-arrow-in-down', |
|||
enableIf: () => { |
|||
return foreignValue ? true : false; |
|||
}, |
|||
click: () => { |
|||
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllIn.tip'), () => { |
|||
emit('selectAllIn', gridRef); |
|||
}); |
|||
}, |
|||
}, |
|||
{ |
|||
name: 'selectAllOut', |
|||
label: $t('system.shared.selectUser.grid.toolbar.selectAllOut'), |
|||
icon: 'bi-box-arrow-up', |
|||
enableIf: () => { |
|||
return foreignValue && gridRef?.getRows()?.length > 0; |
|||
}, |
|||
click: () => { |
|||
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllOut.tip'), () => { |
|||
emit('selectAllOut', gridRef); |
|||
}); |
|||
}, |
|||
}, |
|||
'separator', |
|||
'view', |
|||
]" |
|||
:columns="[ |
|||
{ width: 150, name: 'loginName', label: $t('loginName') }, |
|||
{ width: '100%', name: 'userName', label: $t('userName') }, |
|||
{ |
|||
width: 150, |
|||
name: 'enable', |
|||
label: $t('status'), |
|||
format: (value, row) => { |
|||
return { |
|||
componentType: UserStatusTag, |
|||
attrs: row, |
|||
}; |
|||
}, |
|||
}, |
|||
]" |
|||
:viewer="{ |
|||
panel: { |
|||
columnNum: 1, |
|||
fields: [ |
|||
{ name: 'id', label: $t('id') }, |
|||
{ name: 'loginName', label: $t('loginName') }, |
|||
{ name: 'userName', label: $t('userName') }, |
|||
{ name: 'description', label: $t('description') }, |
|||
{ |
|||
name: 'enable', |
|||
label: $t('enable'), |
|||
format: (value) => { |
|||
return value; |
|||
}, |
|||
}, |
|||
{ name: 'accountExpired', label: $t('accountExpired') }, |
|||
{ name: 'accountLocked', label: $t('accountLocked') }, |
|||
{ name: 'credentialsExpired', label: $t('credentialsExpired') }, |
|||
{ name: 'email', label: $t('email') }, |
|||
{ name: 'phone', label: $t('phone') }, |
|||
{ name: 'mobile', label: $t('mobile') }, |
|||
{ name: 'weixin', label: $t('weixin') }, |
|||
{ name: 'qq', label: $t('qq') }, |
|||
{ name: 'dataComeFrom', label: $t('dataComeFrom') }, |
|||
{ name: 'creator', label: $t('creator') }, |
|||
{ name: 'createDate', label: $t('createDate') }, |
|||
{ name: 'lastModifier', label: $t('lastModifier') }, |
|||
{ name: 'lastModifyDate', label: $t('lastModifyDate') }, |
|||
{ name: 'corporationCode', label: $t('corporationCode') }, |
|||
], |
|||
}, |
|||
}" |
|||
></w-grid> |
|||
<SelectUserDialog |
|||
ref="dialogRef" |
|||
:opener="gridRef" |
|||
:fetch-data-url="fetchOtherDataUrl" |
|||
:foreign-key="foreignKey" |
|||
:foreign-value="foreignValue" |
|||
@after-selected=" |
|||
(ids: string[]) => { |
|||
emit('selectIn', ids, gridRef, dialogRef); |
|||
} |
|||
" |
|||
></SelectUserDialog> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue'; |
|||
import { DialogManager, Tools } from '@/platform'; |
|||
import SelectUserDialog from './SelectUserDialog.vue'; |
|||
import UserStatusTag from './UserStatusTag.vue'; |
|||
|
|||
defineProps({ |
|||
fetchDataUrl: { type: String, default: '' }, |
|||
fetchOtherDataUrl: { type: String, default: '' }, |
|||
foreignKey: { type: String, default: '' }, |
|||
foreignValue: { type: String, default: '' }, |
|||
}); |
|||
|
|||
const emit = defineEmits<{ |
|||
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void; |
|||
(e: 'selectOut', ids: string[], gridComponent: any): void; |
|||
(e: 'selectAllIn', gridComponent: any): void; |
|||
(e: 'selectAllOut', gridComponent: any): void; |
|||
}>(); |
|||
|
|||
const gridRef = ref(); |
|||
const dialogRef = ref(); |
|||
|
|||
const refresh = () => { |
|||
gridRef.value?.refresh(); |
|||
}; |
|||
|
|||
const clear = () => { |
|||
gridRef.value?.setLocalData([]); |
|||
}; |
|||
|
|||
defineExpose({ |
|||
refresh, |
|||
clear, |
|||
}); |
|||
</script> |
@ -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<Criteria> 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<Criteria> criteriaList, String fieldName, List<String> 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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
Loading…
Reference in new issue