40 changed files with 5227 additions and 64 deletions
@ -1,9 +1,94 @@ |
|||||
<template> |
<template> |
||||
<div>{{ message }}</div> |
<div> |
||||
|
<PlatformGrid |
||||
|
ref="dataSupplementTypeGridRef" |
||||
|
:query-form-cols-number="dataSupplementTypeGrid.queryFormColsNumber" |
||||
|
:query-form-cols-auto="dataSupplementTypeGrid.queryFormColsAuto" |
||||
|
:table-title="dataSupplementTypeGrid.tableTitle" |
||||
|
:table-row-key="dataSupplementTypeGrid.tableRowKey" |
||||
|
:table-init-load-data="dataSupplementTypeGrid.tableInitLoadData" |
||||
|
:table-data-url="dataSupplementTypeGrid.tableDataUrl" |
||||
|
:table-row-drag="true" |
||||
|
:table-show-sort-no="dataSupplementTypeGrid.tableShowSortNo" |
||||
|
:table-columns="dataSupplementTypeGrid.tableColumns" |
||||
|
:table-left-column-sticky-number="dataSupplementTypeGrid.tableLeftColumnStickyNumber" |
||||
|
:table-buttons="dataSupplementTypeGrid.tableButtons" |
||||
|
:query-form-fields="dataSupplementTypeGrid.queryFormFields" |
||||
|
:table-pagination="dataSupplementTypeGrid.tablePagination" |
||||
|
:add-form-props="dataSupplementTypeGrid.addFormProps" |
||||
|
></PlatformGrid> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import { Environment, axios } from 'platform-core'; |
import { ref } from 'vue'; |
||||
|
import { Environment } from 'platform-core'; |
||||
|
import { PlatformGrid } from '@/platform'; |
||||
|
import { PlatformIconEnum } from '@/platform/utils'; |
||||
|
|
||||
|
const dataSupplementTypeGridRef = ref(); |
||||
|
const dataSupplementContentDialogRef = ref(); |
||||
|
|
||||
const response = await axios.post(Environment.apiContextPath('/api/sample/action2')); |
const dataSupplementTypeGrid = { |
||||
const message = response.data.message; |
queryFormColsNumber: 2, |
||||
|
queryFormColsAuto: false, |
||||
|
queryFormFields: [ |
||||
|
{ label: '数据补录类型名称', modelName: 'typeName', type: 'text' }, |
||||
|
{ label: '数据补录类型说明', modelName: 'typeDesc', type: 'text' }, |
||||
|
], |
||||
|
hideBottom: false, |
||||
|
tableInitLoadData: true, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: '数据补录类型列表', |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('api/data/supplement/type'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 10, |
||||
|
}, |
||||
|
tableButtons: [ |
||||
|
'query', |
||||
|
'reset', |
||||
|
'separator', |
||||
|
'add', |
||||
|
'edit', |
||||
|
'delete', |
||||
|
'separator', |
||||
|
{ |
||||
|
icon: PlatformIconEnum.扳手, |
||||
|
label: '补录内容管理', |
||||
|
enableIf: (tableSelected) => { |
||||
|
if (tableSelected && tableSelected.length > 0) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
click: (tableSelected) => { |
||||
|
dataSupplementContentDialogRef.value.dialogShow(tableSelected[0]); |
||||
|
}, |
||||
|
}, |
||||
|
'separator', |
||||
|
'inFullscreen', |
||||
|
], |
||||
|
tableShowSortNo: true, |
||||
|
tableColumns: [ |
||||
|
{ name: 'typeName', label: '数据补录类型名称' }, |
||||
|
{ name: 'typeDesc', label: '数据补录类型说明' }, |
||||
|
{ name: 'lastModifier', label: '最后修改人' }, |
||||
|
{ name: 'lastModifyDate', label: '最后修改时间' }, |
||||
|
], |
||||
|
addFormProps: { |
||||
|
dialogInitWidth: '60%', |
||||
|
dialogInitHeight: '50%', |
||||
|
formColsNumber: 1, |
||||
|
formColsAuto: false, |
||||
|
formFields: [ |
||||
|
{ label: '数据补录类型名称', modelName: 'typeName', type: 'text', required: true }, |
||||
|
{ label: '数据补录类型说明', modelName: 'typeDesc', type: 'textarea' }, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
</script> |
</script> |
||||
|
@ -0,0 +1,93 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-dialog v-model="drawer.show" position="right" v-bind="attrs" :maximized="true"> |
||||
|
<q-card :style="drawerStyleComputed"> |
||||
|
<div class="w-full h-full"> |
||||
|
<div style="height: 69px"> |
||||
|
<q-card-section> |
||||
|
<div class="flex justify-between"> |
||||
|
<div class="text-h6">{{ title }}</div> |
||||
|
<div class="flex justify-end gap-4"> |
||||
|
<template v-if="buttons && buttons.length > 0"> |
||||
|
<template v-for="(btn, index) in buttons as any" :key="index"> |
||||
|
<q-btn v-if="typeof btn === 'object'" :loading="false" :color="'primary'" v-bind="btn" @click="btn.click ? btn.click() : () => {}"> |
||||
|
</q-btn> |
||||
|
</template> |
||||
|
</template> |
||||
|
<slot name="buttons"></slot> |
||||
|
<q-btn |
||||
|
v-if="canMaximized" |
||||
|
dense |
||||
|
flat |
||||
|
:icon="!drawer.actualMaximizedToggle ? IconEnum.全屏 : IconEnum.退出全屏" |
||||
|
@click="drawerMaximizeBtnClick" |
||||
|
> |
||||
|
<q-tooltip v-if="!drawer.actualMaximizedToggle">全屏</q-tooltip> |
||||
|
<q-tooltip v-else-if="drawer.actualMaximizedToggle">退出全屏</q-tooltip> |
||||
|
</q-btn> |
||||
|
<q-btn v-close-popup dense flat :icon="IconEnum.关闭"> |
||||
|
<q-tooltip>关闭</q-tooltip> |
||||
|
</q-btn> |
||||
|
</div> |
||||
|
</div> |
||||
|
</q-card-section> |
||||
|
<q-separator /> |
||||
|
</div> |
||||
|
<div style="height: calc(100% - 69px)"> |
||||
|
<q-card-section style="height: 100%; padding: 0px" class="scroll"> |
||||
|
<slot></slot> |
||||
|
</q-card-section> |
||||
|
</div> |
||||
|
</div> |
||||
|
</q-card> |
||||
|
</q-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { reactive, computed, useAttrs } from 'vue'; |
||||
|
import { IconEnum } from '@/platform/enums'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const props = defineProps({ |
||||
|
title: { type: String, default: '' }, |
||||
|
width: { type: String, default: '50vw' }, |
||||
|
height: { type: String, default: '100vh' }, |
||||
|
canMaximized: { type: Boolean, default: true }, |
||||
|
buttons: { type: Array, default: () => [] }, |
||||
|
}); |
||||
|
|
||||
|
const drawer = reactive({ |
||||
|
show: false, |
||||
|
/** |
||||
|
* 实际全屏属性,Drawer 使用的 dialog 进行封装,而 dialog 的非全屏模式, |
||||
|
* 不管高宽给到多少,Quasar 内置的 css 样式都会有一个 padding: 24px 的属性, |
||||
|
* 所以封装 Drawer 时默认就是 dialog 的全屏模式,同时希望提供全屏的功能,所以需要一个实际是否全屏的属性。 |
||||
|
*/ |
||||
|
actualMaximizedToggle: false, |
||||
|
}); |
||||
|
|
||||
|
const drawerMaximizeBtnClick = () => { |
||||
|
drawer.actualMaximizedToggle = !drawer.actualMaximizedToggle; |
||||
|
}; |
||||
|
|
||||
|
const drawerStyleComputed = computed(() => { |
||||
|
if (!drawer.actualMaximizedToggle) { |
||||
|
return { width: props.width, 'max-width': '100vw', height: props.height, 'max-height': '100vh' }; |
||||
|
} else { |
||||
|
return { width: '100vw', 'max-width': '100vw', height: '100vh', 'max-height': '100vh' }; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const show = () => { |
||||
|
drawer.show = true; |
||||
|
}; |
||||
|
const hide = () => { |
||||
|
drawer.show = false; |
||||
|
}; |
||||
|
|
||||
|
defineExpose({ |
||||
|
show, |
||||
|
hide, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,197 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-form ref="formRef" :autofocus="false" :greedy="true" v-bind="attrs"> |
||||
|
<div class="grid" :class="formLayoutComputed"> |
||||
|
<template v-for="(field, index) in fields as any" :key="String(index)"> |
||||
|
<div |
||||
|
:class=" |
||||
|
(field.colsFirst ? 'col-start-1 ' : ' ') + |
||||
|
(field.colspan === 'full' |
||||
|
? ' col-span-' + screenColsNumComputed |
||||
|
: field.colspan && screenColsNumComputed >= field.colspan |
||||
|
? ' col-span-' + field.colspan |
||||
|
: ' col-span-1') |
||||
|
" |
||||
|
> |
||||
|
<component :is="field.type" v-if="field.name" v-model="formData[field.name]" v-bind="field" :form-data="formData"></component> |
||||
|
<component :is="field.type" v-else :form-ref="formRef" v-bind="field" :form-data="formData"></component> |
||||
|
</div> |
||||
|
</template> |
||||
|
</div> |
||||
|
<slot></slot> |
||||
|
</q-form> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive, watch, computed, toRaw, defineProps, useAttrs } from 'vue'; |
||||
|
import { useQuasar } from 'quasar'; |
||||
|
import { PageStatusEnum } from '@/platform/components/utils'; |
||||
|
|
||||
|
const $q = useQuasar(); |
||||
|
const attrs = useAttrs(); |
||||
|
const props = defineProps({ |
||||
|
colsNum: { type: Number, default: 0 }, |
||||
|
// 不同屏幕尺寸下 colsNum 为 0 时一行显示的字段个数 |
||||
|
screenCols: { |
||||
|
type: Object, |
||||
|
default: () => { |
||||
|
return { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 }; |
||||
|
}, |
||||
|
}, |
||||
|
colsXGap: { type: Number, default: 8 }, |
||||
|
colsYGap: { type: Number, default: 4 }, |
||||
|
fields: { |
||||
|
type: Array, |
||||
|
default: () => { |
||||
|
return []; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const formRef = ref(); |
||||
|
const formStatus = ref(PageStatusEnum.新增); |
||||
|
const formModel: any = {}; |
||||
|
const formFieldsMap = new Map(); |
||||
|
|
||||
|
const defaultValueHandler = (field) => { |
||||
|
if (field.hasOwnProperty('defaultValue') && field.defaultValue !== null && field.defaultValue !== undefined) { |
||||
|
return field.defaultValue; |
||||
|
} else if (field.type === 'w-checkbox') { |
||||
|
return false; |
||||
|
} |
||||
|
return null; |
||||
|
}; |
||||
|
|
||||
|
watch( |
||||
|
() => props.fields, |
||||
|
(newVal, oldVal) => { |
||||
|
if (newVal) { |
||||
|
for (const field of props.fields as any) { |
||||
|
if (field.name) { |
||||
|
formModel[field.name] = defaultValueHandler(field); |
||||
|
formFieldsMap.set(field.name, field); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
for (const field of props.fields as any) { |
||||
|
if (field.name) { |
||||
|
formModel[field.name] = defaultValueHandler(field); |
||||
|
formFieldsMap.set(field.name, field); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const formData = reactive(formModel); |
||||
|
|
||||
|
const screenColsNumComputed = computed(() => { |
||||
|
if (props.colsNum > 0) { |
||||
|
return props.colsNum; |
||||
|
} else { |
||||
|
return props.screenCols[$q.screen.name]; |
||||
|
} |
||||
|
}); |
||||
|
const formLayoutComputed = computed(() => { |
||||
|
let className = ''; |
||||
|
if (props.colsNum > 0) { |
||||
|
className = 'grid-cols-' + props.colsNum; |
||||
|
} else { |
||||
|
className = 'grid-cols-' + screenColsNumComputed.value; |
||||
|
} |
||||
|
className += ' gap-x-[' + props.colsXGap + 'px]'; |
||||
|
className += ' gap-y-[' + props.colsYGap + 'px]'; |
||||
|
return className; |
||||
|
}); |
||||
|
|
||||
|
/** |
||||
|
* 对外暴露方法-获取form所有数据 |
||||
|
*/ |
||||
|
const getData = () => { |
||||
|
const data = { ...toRaw(formData) }; |
||||
|
return data; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-设置form所有字段值 |
||||
|
* @param data 数据对象(JSON格式) |
||||
|
*/ |
||||
|
const setData = (data) => { |
||||
|
for (const field of props.fields as any) { |
||||
|
formData[field.name] = data[field.name]; |
||||
|
} |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-重置表单 |
||||
|
*/ |
||||
|
const reset = () => { |
||||
|
Object.keys(formData).forEach((key) => { |
||||
|
formData[key] = defaultValueHandler(formFieldsMap.get(key)); |
||||
|
}); |
||||
|
}; |
||||
|
const formValidate = async () => { |
||||
|
let validate = false; |
||||
|
await formRef.value.validate().then((success) => { |
||||
|
if (success) { |
||||
|
validate = true; |
||||
|
} |
||||
|
}); |
||||
|
return validate; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-表单验证 |
||||
|
*/ |
||||
|
const validate = async () => { |
||||
|
const v = await formValidate(); |
||||
|
return v; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-设置字段值 |
||||
|
* @param fieldName 字段name |
||||
|
* @param value 字段值 |
||||
|
*/ |
||||
|
const setFieldValue = (fieldName, value) => { |
||||
|
const field = formFieldsMap.get(fieldName); |
||||
|
formData[field.name] = value; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-获取字段值 |
||||
|
* @param fieldName 字段name |
||||
|
*/ |
||||
|
const getFieldValue = (fieldName) => { |
||||
|
return formData[fieldName]; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-设置form状态 |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
const setStatus = (status) => { |
||||
|
formStatus.value = status; |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-获取form状态 |
||||
|
*/ |
||||
|
const getStatus = () => { |
||||
|
return toRaw(formStatus.value); |
||||
|
}; |
||||
|
/** |
||||
|
* 对外暴露方法-获取当前一行应该显示的元素个数 |
||||
|
*/ |
||||
|
const getRowColsNum = () => { |
||||
|
return screenColsNumComputed.value; |
||||
|
}; |
||||
|
|
||||
|
defineExpose({ |
||||
|
data: formData, |
||||
|
fieldsMap: formFieldsMap, |
||||
|
getData, |
||||
|
setData, |
||||
|
reset, |
||||
|
validate, |
||||
|
getFieldValue, |
||||
|
setFieldValue, |
||||
|
setStatus, |
||||
|
getStatus, |
||||
|
getRowColsNum, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,39 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-checkbox v-show="!hideIfComputed" v-bind="attrs" :rules="rulesComputed" :disable="disableIfComputed"></q-checkbox> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
// import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,94 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-input |
||||
|
v-show="!hideIfComputed" |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
<template #append> |
||||
|
<q-icon :name="IconEnum.日期" class="cursor-pointer"> |
||||
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale"> |
||||
|
<q-date v-model="date" today-btn mask="YYYY-MM-DD"> |
||||
|
<div class="row items-center justify-end"> |
||||
|
<q-btn v-close-popup label="关闭" color="primary" flat /> |
||||
|
</div> |
||||
|
</q-date> |
||||
|
</q-popup-proxy> |
||||
|
</q-icon> |
||||
|
</template> |
||||
|
</q-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref, computed, defineProps, useAttrs, watch } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
import { IconEnum } from '@/platform/enums'; |
||||
|
|
||||
|
const date = ref(null); |
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
watch( |
||||
|
() => date.value, |
||||
|
(newVal, oldVal) => { |
||||
|
attrs['form-data'][attrs.name] = newVal; |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,78 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-input |
||||
|
v-show="!hideIfComputed" |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
type="number" |
||||
|
title="" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
</q-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
precision: { type: Number, default: 0 }, |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
rules.push(FormValidators.maxPrecision(props.precision)); |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,76 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-select |
||||
|
v-show="!hideIfComputed" |
||||
|
emit-value |
||||
|
map-options |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
</q-select> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,75 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-input |
||||
|
v-show="!hideIfComputed" |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
type="text" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
</q-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,87 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-input |
||||
|
v-show="!hideIfComputed" |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
type="text" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
<template v-if="attrs.button && attrs.buttonPosition === 'prepend'" #prepend> |
||||
|
<q-btn round dense flat v-bind="attrs.button" @click="attrs.button.click" /> |
||||
|
</template> |
||||
|
<template v-else-if="attrs.button && attrs.buttonPosition === 'before'" #before> |
||||
|
<q-btn round dense flat v-bind="attrs.button" @click="attrs.button.click" /> |
||||
|
</template> |
||||
|
<template v-else-if="attrs.button && attrs.buttonPosition === 'after'" #after> |
||||
|
<q-btn round dense flat v-bind="attrs.button" @click="attrs.button.click" /> |
||||
|
</template> |
||||
|
<template v-else-if="attrs.button" #append> |
||||
|
<q-btn round dense flat v-bind="attrs.button" @click="attrs.button.click" /> |
||||
|
</template> |
||||
|
</q-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return true; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,75 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-input |
||||
|
v-show="!hideIfComputed" |
||||
|
:hide-bottom-space="true" |
||||
|
:hide-hint="true" |
||||
|
:outlined="true" |
||||
|
:dense="true" |
||||
|
v-bind="attrs" |
||||
|
type="textarea" |
||||
|
:rules="rulesComputed" |
||||
|
:readonly="readonlyIfComputed" |
||||
|
:disable="disableIfComputed" |
||||
|
> |
||||
|
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
||||
|
</q-input> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, defineProps, useAttrs } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const inRules = attrs.rules; |
||||
|
const props = defineProps({ |
||||
|
hideIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
requiredIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
readonlyIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
disableIf: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const rulesComputed = computed(() => { |
||||
|
let rules = inRules || <any>[]; |
||||
|
if (!hideIfComputed.value && requiredIfComputed.value) { |
||||
|
rules.push(FormValidators.required()); |
||||
|
} else { |
||||
|
rules.splice(rules.length - 1, 1); |
||||
|
} |
||||
|
return rules; |
||||
|
}); |
||||
|
|
||||
|
const hideIfComputed = computed(() => { |
||||
|
return props.hideIf(); |
||||
|
}); |
||||
|
const requiredIfComputed = computed(() => { |
||||
|
return props.requiredIf(); |
||||
|
}); |
||||
|
const readonlyIfComputed = computed(() => { |
||||
|
return props.readonlyIf(); |
||||
|
}); |
||||
|
const disableIfComputed = computed(() => { |
||||
|
return props.disableIf(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,15 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-icon v-if="value" :name="IconEnum.是状态" color="green" size="sm"> </q-icon> |
||||
|
<q-icon v-else-if="!value && showNoEnable" :name="IconEnum.否状态" color="red" size="sm"> </q-icon> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup> |
||||
|
import { IconEnum } from '@/platform/enums'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
value: { type: Boolean, default: false }, // 值 |
||||
|
showNoEnable: { type: Boolean, default: false }, // 不可用是否显示 |
||||
|
}); |
||||
|
</script> |
File diff suppressed because it is too large
@ -0,0 +1,95 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-markup-table separator="cell" flat bordered wrap-cells v-bind="attrs"> |
||||
|
<tbody> |
||||
|
<template v-for="(trItem, trIndex) in tableComputed" :key="trIndex"> |
||||
|
<tr class="q-tr--no-hover"> |
||||
|
<template v-for="(tdItem, tdIndex) in trItem as any" :key="tdIndex"> |
||||
|
<td :class="labelAlignClassComputed">{{ tdItem.label }}</td> |
||||
|
<td :class="valueAlignClassComputed"> |
||||
|
<template v-if="tdItem.value && typeof tdItem.value === 'object' && tdItem.value.type && tdItem.value._vuecomp_"> |
||||
|
<component :is="tdItem.value.type" v-bind="tdItem.value.props"></component> |
||||
|
</template> |
||||
|
<template v-else> |
||||
|
{{ tdItem.value }} |
||||
|
</template> |
||||
|
</td> |
||||
|
</template> |
||||
|
</tr> |
||||
|
</template> |
||||
|
</tbody> |
||||
|
</q-markup-table> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, useAttrs } from 'vue'; |
||||
|
import { getCssVar } from 'quasar'; |
||||
|
import { Environment } from '@/platform'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const gc = Environment.getConfigure(); |
||||
|
const darkBgColor = getCssVar('dark'); |
||||
|
const bgColor = gc.theme.dark ? darkBgColor : gc.theme?.grid?.headBgColor || '#f5f7fa'; |
||||
|
const props = defineProps({ |
||||
|
columnNum: { type: Number, default: 1 }, |
||||
|
labelAlign: { type: String, default: 'left' }, |
||||
|
valueAlign: { type: String, default: 'left' }, |
||||
|
info: { |
||||
|
type: Array, |
||||
|
default: () => { |
||||
|
return []; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const tableComputed = computed(() => { |
||||
|
const table = <any>[]; |
||||
|
let tmp = <any>[]; |
||||
|
props.info.forEach((item, index) => { |
||||
|
if (tmp.length < props.columnNum) { |
||||
|
tmp.push(item); |
||||
|
} else { |
||||
|
table.push(tmp); |
||||
|
tmp = []; |
||||
|
tmp.push(item); |
||||
|
} |
||||
|
}); |
||||
|
table.push(tmp); |
||||
|
return table; |
||||
|
}); |
||||
|
const labelAlignClassComputed = computed(() => { |
||||
|
let className = ''; |
||||
|
switch (props.labelAlign) { |
||||
|
case 'right': |
||||
|
className = 'text-right'; |
||||
|
break; |
||||
|
case 'center': |
||||
|
className = 'text-center'; |
||||
|
break; |
||||
|
default: |
||||
|
className = 'text-left'; |
||||
|
} |
||||
|
return className; |
||||
|
}); |
||||
|
const valueAlignClassComputed = computed(() => { |
||||
|
let className = ''; |
||||
|
switch (props.valueAlign) { |
||||
|
case 'right': |
||||
|
className = 'text-right'; |
||||
|
break; |
||||
|
case 'center': |
||||
|
className = 'text-center'; |
||||
|
break; |
||||
|
default: |
||||
|
className = 'text-left'; |
||||
|
} |
||||
|
return className; |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.q-table td:nth-child(odd) { |
||||
|
background-color: v-bind(bgColor); |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,57 @@ |
|||||
|
<template> |
||||
|
<q-item clickable :disable="button[0].enableIf ? !button[0].enableIf(gridProp.gridSelected) : false"> |
||||
|
<q-item-section> |
||||
|
<q-item-label><q-icon v-if="button[0].icon" :name="button[0].icon" size="20px"></q-icon> {{ button[0].label }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
<q-item-section side> |
||||
|
<q-icon name="keyboard_arrow_right" /> |
||||
|
</q-item-section> |
||||
|
|
||||
|
<q-menu anchor="top end" self="top start"> |
||||
|
<q-list> |
||||
|
<template v-for="(childrenBtn, index) in button" :key="index"> |
||||
|
<template v-if="index === 0 && !childrenBtn.click"></template> |
||||
|
<q-separator v-else-if="typeof childrenBtn === 'string' && childrenBtn === 'separator'" /> |
||||
|
<ChildrenBtn v-else-if="Array.isArray(childrenBtn) && childrenBtn.length > 0" :button="childrenBtn"></ChildrenBtn> |
||||
|
<template v-else> |
||||
|
<q-item |
||||
|
v-close-popup |
||||
|
clickable |
||||
|
:disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProp.gridSelected) : false" |
||||
|
@click="buttonClick(childrenBtn)" |
||||
|
> |
||||
|
<q-item-section> |
||||
|
<q-item-label><q-icon v-if="childrenBtn.icon" :name="childrenBtn.icon" size="20px"></q-icon> {{ childrenBtn.label }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
</template> |
||||
|
</q-list> |
||||
|
</q-menu> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
const props = defineProps({ |
||||
|
button: { |
||||
|
type: Object, |
||||
|
default: () => { |
||||
|
return []; |
||||
|
}, |
||||
|
}, |
||||
|
gridProp: { |
||||
|
type: Object, |
||||
|
default: () => { |
||||
|
return { |
||||
|
gridSelected: [], |
||||
|
gridRefs: {}, |
||||
|
}; |
||||
|
}, |
||||
|
}, |
||||
|
buttonClick: { |
||||
|
type: Function, |
||||
|
default: () => { |
||||
|
return () => {}; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,284 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div |
||||
|
ref="containerRef" |
||||
|
:class="'flex ' + (align === 'left' ? 'justify-start' : align === 'center' ? 'justify-center' : 'justify-end') + ' gap-x-[' + props.xGap + 'px]'" |
||||
|
> |
||||
|
<!-- buttons --> |
||||
|
<template v-for="(btn, index) in baseActions" :key="'button_' + index"> |
||||
|
<q-separator v-if="typeof btn.data === 'string' && btn.data === 'separator'" vertical class="class-action-item" /> |
||||
|
<q-btn-dropdown |
||||
|
v-else-if="Array.isArray(btn.data) && btn.data.length > 0" |
||||
|
unelevated |
||||
|
outline |
||||
|
v-bind="btn.data[0]" |
||||
|
:split="btn.data[0].click ? true : false" |
||||
|
:disable="btn.data[0].enableIf ? !btn.data[0].enableIf(gridProp.gridSelected) : false" |
||||
|
class="class-action-item" |
||||
|
@click="buttonClick(btn.data[0])" |
||||
|
> |
||||
|
<q-list> |
||||
|
<template v-for="(childrenBtn, childrenIndex) in btn.data" :key="'button_c_' + childrenIndex"> |
||||
|
<template v-if="childrenIndex === 0"></template> |
||||
|
<template v-else> |
||||
|
<q-separator v-if="typeof childrenBtn === 'string' && childrenBtn === 'separator'" /> |
||||
|
<ChildrenBtn |
||||
|
v-else-if="Array.isArray(childrenBtn) && childrenBtn.length > 0" |
||||
|
:button="childrenBtn" |
||||
|
:grid-prop="gridProp" |
||||
|
:button-click="buttonClick" |
||||
|
></ChildrenBtn> |
||||
|
<q-item |
||||
|
v-else |
||||
|
v-close-popup |
||||
|
clickable |
||||
|
:disable="childrenBtn.enableIf ? !childrenBtn.enableIf(gridProp.gridSelected) : false" |
||||
|
@click="buttonClick(childrenBtn)" |
||||
|
> |
||||
|
<q-item-section> |
||||
|
<q-item-label><q-icon v-if="childrenBtn.icon" :name="childrenBtn.icon" size="20px"></q-icon> {{ childrenBtn.label }}</q-item-label> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
</template> |
||||
|
</q-list> |
||||
|
</q-btn-dropdown> |
||||
|
<q-btn |
||||
|
v-else |
||||
|
:disable="btn.data.enableIf ? !btn.data.enableIf(gridProp.gridSelected) : false" |
||||
|
no-wrap |
||||
|
outline |
||||
|
v-bind="btn.data" |
||||
|
class="class-action-item" |
||||
|
@click="buttonClick(btn.data)" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<!-- moreActions --> |
||||
|
<q-btn-dropdown v-if="moreActions && moreActions.length > 0" unelevated outline :label="$t('more')" class="class-action-item"> |
||||
|
<q-list> |
||||
|
<template v-for="(childrenBtn, childrenIndex) in moreActions" :key="'moreAction_' + childrenIndex"> |
||||
|
<q-separator v-if="typeof childrenBtn.data === 'string' && childrenBtn.data === 'separator'" /> |
||||
|
<ChildrenBtn |
||||
|
v-else-if="Array.isArray(childrenBtn.data) && childrenBtn.data.length > 0" |
||||
|
:button="childrenBtn.data" |
||||
|
:grid-prop="gridProp" |
||||
|
:button-click="buttonClick" |
||||
|
></ChildrenBtn> |
||||
|
<q-item |
||||
|
v-else |
||||
|
v-close-popup |
||||
|
clickable |
||||
|
:disable="childrenBtn.data.enableIf ? !childrenBtn.data.enableIf(gridProp.gridSelected) : false" |
||||
|
@click="buttonClick(childrenBtn.data)" |
||||
|
> |
||||
|
<q-item-section> |
||||
|
<q-item-label |
||||
|
><q-icon v-if="childrenBtn.data.icon" :name="childrenBtn.data.icon" size="20px"></q-icon> {{ childrenBtn.data.label }}</q-item-label |
||||
|
> |
||||
|
</q-item-section> |
||||
|
</q-item> |
||||
|
</template> |
||||
|
</q-list> |
||||
|
</q-btn-dropdown> |
||||
|
</div> |
||||
|
<q-resize-observer @resize="onResize" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive, nextTick } from 'vue'; |
||||
|
import { Tools } from '@/platform/utils'; |
||||
|
import ChildrenBtn from './ChildrenBtn.vue'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
xGap: { type: Number, default: 4 }, // 按扭之间x轴间隔像素点 |
||||
|
noIcon: { type: Boolean, default: false }, // 无icon模式 |
||||
|
align: { type: String, default: 'right' }, // 对齐方式 |
||||
|
buttons: { |
||||
|
type: Array, |
||||
|
default: () => { |
||||
|
return []; |
||||
|
}, |
||||
|
}, |
||||
|
gridProp: { |
||||
|
type: Object, |
||||
|
default: () => { |
||||
|
return { |
||||
|
gridSelected: [], |
||||
|
gridRefs: {}, |
||||
|
}; |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
const containerRef = ref(); |
||||
|
|
||||
|
// 将所有按钮根据 name 提取到 JSON 对象中 |
||||
|
const buttonsJson = {}; |
||||
|
const extractButton = (btns: any) => { |
||||
|
for (const btn of btns) { |
||||
|
if (Array.isArray(btn)) { |
||||
|
extractButton(btn); |
||||
|
} else if (typeof btn === 'object') { |
||||
|
buttonsJson[btn.name] = { ...btn }; |
||||
|
if (props.noIcon) { |
||||
|
buttonsJson[btn.name].icon = undefined; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
extractButton(props.buttons); |
||||
|
|
||||
|
// // 将按钮形成父子关系 |
||||
|
// const handleChildren = (parent, children, arr) => { |
||||
|
// for (const item of arr) { |
||||
|
// if (Array.isArray(item)) { |
||||
|
// const other = item.splice(1); |
||||
|
// const children_ = <any>[]; |
||||
|
// handleChildren(item[0].name, children_, other); |
||||
|
// children.push({ parent, children: children_, button: buttonsJson[item[0].name] }); |
||||
|
// } else if (typeof item === 'object') { |
||||
|
// children.push({ parent, children: null, button: buttonsJson[item.name] }); |
||||
|
// } else if (typeof item === 'string' && item === 'separator') { |
||||
|
// // 当最后一个元素是分割符时,不再追加分割符,避免两个按钮之间出现重复的无意义分割符 |
||||
|
// if (children.length > 0 && children[children.length - 1].button !== 'separator') { |
||||
|
// children.push({ parent, children: null, button: 'separator' }); |
||||
|
// } |
||||
|
// } |
||||
|
// } |
||||
|
// }; |
||||
|
// const buttons_ = <any>[]; |
||||
|
// for (const btn of props.buttons) { |
||||
|
// if (Array.isArray(btn)) { |
||||
|
// const other = btn.splice(1); |
||||
|
// const children = <any>[]; |
||||
|
// handleChildren(btn[0].name, children, other); |
||||
|
// buttons_.push({ parent: null, children: children, button: buttonsJson[btn[0].name] }); |
||||
|
// } else if (typeof btn === 'object') { |
||||
|
// buttons_.push({ parent: null, children: null, button: buttonsJson[btn.name] }); |
||||
|
// } else if (typeof btn === 'string' && btn === 'separator') { |
||||
|
// // 当最后一个元素是分割符时,不再追加分割符,避免两个按钮之间出现重复的无意义分割符 |
||||
|
// if (buttons_.length > 0 && buttons_[buttons_.length - 1].button !== 'separator') { |
||||
|
// buttons_.push({ parent: null, children: null, button: 'separator' }); |
||||
|
// } |
||||
|
// } |
||||
|
// } |
||||
|
|
||||
|
const buttons_ = <any>[]; |
||||
|
const handleChildrenSeparator = (arr) => { |
||||
|
const tempArr = []; |
||||
|
for (let i = 0; i < arr.length; i++) { |
||||
|
const btn = arr[i]; |
||||
|
if (i === 0 && typeof btn === 'string' && btn === 'separator') { |
||||
|
// 按钮数组第一个元素为分割符时直接跳过 |
||||
|
continue; |
||||
|
} |
||||
|
if (typeof btn === 'string' && btn === 'separator' && tempArr.length > 0 && tempArr[tempArr.length - 1] === btn) { |
||||
|
// 连续的分割符直接跳过,避免出现重复的无意义分割符 |
||||
|
continue; |
||||
|
} |
||||
|
if (Array.isArray(btn) && btn.length > 0) { |
||||
|
const handleResult = handleChildrenSeparator(btn); |
||||
|
if (handleResult && handleResult.length > 0) { |
||||
|
tempArr.push(handleResult); |
||||
|
} |
||||
|
} else if (typeof btn === 'string' && btn === 'separator') { |
||||
|
tempArr.push(btn); |
||||
|
} else { |
||||
|
tempArr.push(buttonsJson[btn.name]); |
||||
|
} |
||||
|
} |
||||
|
return tempArr; |
||||
|
}; |
||||
|
for (let i = 0; i < props.buttons.length; i++) { |
||||
|
const btn = props.buttons[i]; |
||||
|
if (i === 0 && typeof btn === 'string' && btn === 'separator') { |
||||
|
// 按钮数组第一个元素为分割符时直接跳过 |
||||
|
continue; |
||||
|
} |
||||
|
if (typeof btn === 'string' && btn === 'separator' && buttons_.length > 0 && buttons_[buttons_.length - 1].data === btn) { |
||||
|
// 连续的分割符直接跳过,避免出现重复的无意义分割符 |
||||
|
continue; |
||||
|
} |
||||
|
if (Array.isArray(btn) && btn.length > 0) { |
||||
|
buttons_.push({ data: handleChildrenSeparator(btn) }); |
||||
|
} else if (typeof btn === 'string' && btn === 'separator') { |
||||
|
buttons_.push({ data: btn }); |
||||
|
} else { |
||||
|
buttons_.push({ data: buttonsJson[btn.name] }); |
||||
|
} |
||||
|
} |
||||
|
const baseActions = ref(buttons_); |
||||
|
const moreActions = ref([]); |
||||
|
const isActionWidthInitializedRef = ref(false); |
||||
|
const moreActionWidth = 100; |
||||
|
const onResize = (size) => { |
||||
|
if (Tools.isUndefinedOrNull(containerRef.value)) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!isActionWidthInitializedRef.value) { |
||||
|
const nodes = containerRef.value.getElementsByClassName('class-action-item'); |
||||
|
for (let i = 0; i < buttons_.length; i++) { |
||||
|
buttons_[i].width = nodes[i].clientWidth; |
||||
|
} |
||||
|
isActionWidthInitializedRef.value = true; |
||||
|
} |
||||
|
|
||||
|
const _baseActions = []; |
||||
|
const _moreActions = []; |
||||
|
const length = buttons_.length; |
||||
|
let availableWidth = size.width; |
||||
|
let width = 0; |
||||
|
let index = 0; |
||||
|
|
||||
|
for (; index < length; index++) { |
||||
|
if (width + buttons_[index].width > availableWidth) { |
||||
|
availableWidth -= moreActionWidth; |
||||
|
while (width > availableWidth) { |
||||
|
index--; |
||||
|
width -= buttons_[index].width; |
||||
|
_baseActions.pop(); |
||||
|
} |
||||
|
break; |
||||
|
} else { |
||||
|
_baseActions.push(buttons_[index]); |
||||
|
width += buttons_[index].width; |
||||
|
width += props.xGap; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (; index < length; index++) { |
||||
|
_moreActions.push(buttons_[index]); |
||||
|
} |
||||
|
|
||||
|
baseActions.value = _baseActions; |
||||
|
moreActions.value = _moreActions; |
||||
|
}; |
||||
|
|
||||
|
const buttonClick = async (button) => { |
||||
|
let beforeResult = true; |
||||
|
const context = {}; |
||||
|
if (button.beforeClick) { |
||||
|
beforeResult = await button.beforeClick(props.gridProp.gridSelected, context, props.gridProp.gridRefs); |
||||
|
} |
||||
|
if (beforeResult && button.click) { |
||||
|
await button.click(props.gridProp.gridSelected, context, button._click, props.gridProp.gridRefs); |
||||
|
if (button.afterClick) { |
||||
|
nextTick(() => { |
||||
|
button.afterClick(props.gridProp.gridSelected, context, props.gridProp.gridRefs); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="css"> |
||||
|
.q-btn.disabled { |
||||
|
opacity: 0.7 !important; |
||||
|
color: #a8a8a8; |
||||
|
} |
||||
|
.q-item.disabled { |
||||
|
opacity: 0.6 !important; |
||||
|
color: #a8a8a8; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,58 @@ |
|||||
|
/** |
||||
|
* Form表单元素验证器 |
||||
|
*/ |
||||
|
export class FormValidators { |
||||
|
/** |
||||
|
* 必填项验证 |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static required(msg: string) { |
||||
|
return (val) => { |
||||
|
if (val === null || val === undefined) { |
||||
|
return msg || '必填项未填写'; |
||||
|
} |
||||
|
if (typeof val === 'string') { |
||||
|
return val !== '' || msg || '必填项未填写'; |
||||
|
} else if (Array.isArray(val)) { |
||||
|
return val.length > 0 || msg || '必填项未填写'; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 长度范围验证 |
||||
|
* @param min 最小长度 |
||||
|
* @param max 最大长度 |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static lengthRange(min: number, max: number, msg: string) { |
||||
|
return (val) => { |
||||
|
const tmp = String(val); |
||||
|
if (tmp === null || tmp === '' || (tmp.length >= min && tmp.length <= max)) { |
||||
|
return true; |
||||
|
} else { |
||||
|
return msg || '长度不符合要求(' + min + '-' + max + ')'; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数字最大精度校验 |
||||
|
* @param precision 最大位数 |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static maxPrecision(precision: number, msg: string) { |
||||
|
return (val) => { |
||||
|
const tmp = String(val); |
||||
|
if (val === null || tmp === '' || tmp.indexOf('.') === -1 || tmp.substring(tmp.indexOf('.') + 1).length <= precision) { |
||||
|
return true; |
||||
|
} else if (precision === 0) { |
||||
|
return '只能输入整数'; |
||||
|
} else { |
||||
|
return msg || '最大允许输入的小数位:' + precision; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-form :fields="fields" :cols-num-auto="false" :cols-num="3"></w-form> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
const fields = [ |
||||
|
{ |
||||
|
label: '姓名', |
||||
|
name: 'name', |
||||
|
type: 'text', |
||||
|
required: true, |
||||
|
colspan: 2, |
||||
|
button: { |
||||
|
round: false, |
||||
|
icon: 'home', |
||||
|
label: '选择', |
||||
|
click: () => { |
||||
|
console.info('11111'); |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '年龄', |
||||
|
name: 'age', |
||||
|
type: 'number', |
||||
|
required: true, |
||||
|
}, |
||||
|
]; |
||||
|
</script> |
@ -0,0 +1,4 @@ |
|||||
|
<template> |
||||
|
<div>2222</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"></script> |
@ -0,0 +1,13 @@ |
|||||
|
<template> |
||||
|
<q-input ref="aaaref" :model-value="a" label="dddd"></q-input> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
const aaaref = ref(); |
||||
|
const a = ref(''); |
||||
|
|
||||
|
onMounted(() => { |
||||
|
aaaref.value.focus(); |
||||
|
console.info('aaaref====', aaaref); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,35 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-dialog |
||||
|
ref="dialogRef" |
||||
|
:buttons="[ |
||||
|
{ |
||||
|
label: '测试', |
||||
|
click: aaaaa, |
||||
|
}, |
||||
|
]" |
||||
|
@hide="aaaaa" |
||||
|
> |
||||
|
<q-splitter v-model="aa" style="height: 100%"> |
||||
|
<template #before> 11111 </template> |
||||
|
<template #after> 22222 </template> |
||||
|
</q-splitter> |
||||
|
<template #buttons> <q-btn label="xxx"></q-btn> </template |
||||
|
></w-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive, onMounted } from 'vue'; |
||||
|
|
||||
|
const dialogRef = ref(); |
||||
|
|
||||
|
const aa = ref(50); |
||||
|
const aaaaa = (e) => { |
||||
|
console.info('dddddddddddddd', e); |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
console.info('dialogRef====', dialogRef); |
||||
|
dialogRef.value.show(); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,34 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-btn label="弹出" @click="click"></q-btn> |
||||
|
<w-drawer |
||||
|
ref="drawerRef" |
||||
|
title="xxx" |
||||
|
:maximized="false" |
||||
|
:buttons="[ |
||||
|
{ |
||||
|
label: '测试', |
||||
|
}, |
||||
|
]" |
||||
|
> |
||||
|
1111 |
||||
|
<template #buttons> <q-btn label="xxx"></q-btn> </template> |
||||
|
</w-drawer> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive, onMounted } from 'vue'; |
||||
|
import { IconEnum } from '@/platform/enums'; |
||||
|
|
||||
|
const drawerRef = ref(); |
||||
|
|
||||
|
const aa = ref(50); |
||||
|
const aaaaa = (e) => { |
||||
|
console.info('dddddddddddddd', e); |
||||
|
}; |
||||
|
const click = () => { |
||||
|
drawerRef.value.show(); |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => {}); |
||||
|
</script> |
@ -0,0 +1,152 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-form ref="formRef" :fields="aaaa.fields" :cols-x-gap="8"> </w-form> |
||||
|
<q-btn label="提交" @click="submit"></q-btn> <q-btn label="重置" @click="reset"></q-btn> |
||||
|
<q-btn label="初始化值" @click="setValue"></q-btn> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive } from 'vue'; |
||||
|
import { FormValidators } from '@/platform/components'; |
||||
|
const formRef = ref(); |
||||
|
const aaaa = { |
||||
|
fields: [ |
||||
|
{ |
||||
|
label: '姓名', |
||||
|
name: 'name', |
||||
|
type: 'w-text', |
||||
|
// maxlength: 10, |
||||
|
rules: [FormValidators.lengthRange(5, 10, '22222')], |
||||
|
defaultValue: '123', |
||||
|
colspan: 2, |
||||
|
requiredIf: () => true, |
||||
|
'onUpdate:modelValue': () => {}, |
||||
|
onFocus: () => { |
||||
|
// console.info('33333333'); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '机构', |
||||
|
name: 'org', |
||||
|
type: 'w-text-btn', |
||||
|
requiredIf: () => true, |
||||
|
// buttonPosition: 'prepend', |
||||
|
button: { |
||||
|
icon: 'home', |
||||
|
click: () => { |
||||
|
console.info('点击!!'); |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '年龄', |
||||
|
name: 'age', |
||||
|
type: 'w-number', |
||||
|
defaultValue: 111, |
||||
|
precision: 0, |
||||
|
requiredIf: () => true, |
||||
|
}, |
||||
|
{ |
||||
|
label: '出生日期', |
||||
|
name: 'cs', |
||||
|
type: 'w-date', |
||||
|
requiredIf: () => true, |
||||
|
}, |
||||
|
{ |
||||
|
label: '爱好', |
||||
|
name: 'ah', |
||||
|
type: 'w-text', |
||||
|
requiredIf: () => true, |
||||
|
}, |
||||
|
{ |
||||
|
label: '性别', |
||||
|
name: 'sex', |
||||
|
type: 'w-select', |
||||
|
options: [ |
||||
|
{ |
||||
|
label: '男', |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: '女', |
||||
|
value: 0, |
||||
|
}, |
||||
|
], |
||||
|
requiredIf: () => true, |
||||
|
'onUpdate:modelValue': (value) => { |
||||
|
if (value === 1) { |
||||
|
formRef.value.fieldsMap.get('addr').label = '地址2222'; |
||||
|
} else { |
||||
|
formRef.value.fieldsMap.get('addr').label = '地址3333'; |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '地址', |
||||
|
name: 'addr', |
||||
|
rows: 2, |
||||
|
colspan: 'full', |
||||
|
type: 'w-textarea', |
||||
|
hideIf: () => { |
||||
|
if (formRef.value) { |
||||
|
if (formRef.value.data.sex && formRef.value.data.sex === 1) { |
||||
|
return false; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
requiredIf: () => true, |
||||
|
// readonlyIf: () => { |
||||
|
// return true; |
||||
|
// }, |
||||
|
disableIf: () => { |
||||
|
return false; |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '是否可用1', |
||||
|
name: 'ky1', |
||||
|
colsFirst: true, |
||||
|
colspan: 2, |
||||
|
type: 'w-checkbox', |
||||
|
// disableIf: () => { |
||||
|
// return true; |
||||
|
// }, |
||||
|
}, |
||||
|
{ |
||||
|
label: '是否可用2', |
||||
|
name: 'ky2', |
||||
|
type: 'w-checkbox', |
||||
|
}, |
||||
|
{ |
||||
|
label: '是否可用3', |
||||
|
name: 'ky3', |
||||
|
type: 'w-checkbox', |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const submit = async () => { |
||||
|
aaaa.fields[1].required = false; |
||||
|
const validateResult = await formRef.value.validate(); |
||||
|
console.info('表单验证结果:', validateResult); |
||||
|
console.info('数据:', formRef.value.getData()); |
||||
|
}; |
||||
|
const reset = () => { |
||||
|
formRef.value.reset(); |
||||
|
}; |
||||
|
const setValue = () => { |
||||
|
const data = { |
||||
|
name: '张三', |
||||
|
age: 18, |
||||
|
cs: '2023-12-25', |
||||
|
ah: '唱、跳、篮球', |
||||
|
ky: true, |
||||
|
sex: 1, |
||||
|
addr: '上海市', |
||||
|
}; |
||||
|
formRef.value.setData(data); |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,220 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-grid |
||||
|
:title="testGrid.title" |
||||
|
:row-drag="true" |
||||
|
:row-key="testGrid.rowKey" |
||||
|
:auto-load-data="testGrid.autoLoadData" |
||||
|
:get-data-url="testGrid.tableDataUrl" |
||||
|
:show-sort-no="testGrid.tableShowSortNo" |
||||
|
:columns="testGrid.tableColumns" |
||||
|
:left-column-sticky-number="testGrid.tableLeftColumnStickyNumber" |
||||
|
:column-title-dense="true" |
||||
|
:toolbar="testGrid.toolbar" |
||||
|
:query-form="testGrid.queryForm" |
||||
|
:table-pagination="testGrid.tablePagination" |
||||
|
:add-edit="testGrid.addEdit" |
||||
|
:view="testGrid.view" |
||||
|
@selection="selection" |
||||
|
@row-click="rowClick" |
||||
|
@row-db-click="rowDbClick" |
||||
|
></w-grid> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted, nextTick } from 'vue'; |
||||
|
import { axios, Environment } from '@/platform'; |
||||
|
import EnableIcon from '@/platform/components/grid/EnableIcon.vue'; |
||||
|
import { IconEnum } from '@/platform/enums'; |
||||
|
|
||||
|
const selection = (details) => { |
||||
|
console.info('details====', details); |
||||
|
}; |
||||
|
const rowClick = (evt, row, index) => { |
||||
|
console.info('row====', row); |
||||
|
}; |
||||
|
const rowDbClick = (evt, row, index) => { |
||||
|
console.info('row1====', row); |
||||
|
}; |
||||
|
const testGrid = { |
||||
|
hideBottom: false, |
||||
|
autoLoadData: true, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
title: '用户列表', |
||||
|
rowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('api/system/user'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 10, |
||||
|
}, |
||||
|
toolbar: { |
||||
|
buttons: [ |
||||
|
['query', 'separator', 'moreQuery'], |
||||
|
'reset', |
||||
|
'refresh', |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'custBtn', |
||||
|
extend: 'add', |
||||
|
icon: undefined, |
||||
|
label: '自定义按钮', |
||||
|
enableIf: (selected) => { |
||||
|
if (selected && selected.length > 0) { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
// beforeClick: (selected, context, gridRefs) => { |
||||
|
// console.info('先执行before'); |
||||
|
// context.aaa = '111'; |
||||
|
// }, |
||||
|
click: (selected, context, _click, gridRefs) => { |
||||
|
_click(); |
||||
|
}, |
||||
|
afterClick: (selected, context, gridRefs) => { |
||||
|
gridRefs.addEditFormRef.setFieldValue('userName', '李四'); |
||||
|
}, |
||||
|
}, |
||||
|
[ |
||||
|
{ |
||||
|
name: 'op', |
||||
|
icon: 'difference', |
||||
|
label: '操作', |
||||
|
}, |
||||
|
'add', |
||||
|
'edit', |
||||
|
'clone', |
||||
|
'remove', |
||||
|
'separator', |
||||
|
'view', |
||||
|
'export', |
||||
|
], |
||||
|
'separator', |
||||
|
], |
||||
|
}, |
||||
|
tableShowSortNo: true, |
||||
|
queryForm: { |
||||
|
rowNum: 1, |
||||
|
fields: [ |
||||
|
{ label: '登录名', name: 'loginName', type: 'w-text' }, |
||||
|
{ label: '用户名', name: 'userName', type: 'w-text' }, |
||||
|
{ label: '描述', name: 'description', type: 'w-text' }, |
||||
|
{ label: '是否可用', name: 'enable', type: 'w-select' }, |
||||
|
// { label: '邮箱地址', name: 'email', type: 'w-text' }, |
||||
|
// { label: '电话', name: 'phone', type: 'w-text' }, |
||||
|
// { label: '手机号', name: 'mobile', type: 'w-number' }, |
||||
|
// { label: '最后修改人', name: 'lastModifier', type: 'w-text' }, |
||||
|
// { label: '最后修改时间', name: 'lastModifyDate', type: 'w-date' }, |
||||
|
], |
||||
|
}, |
||||
|
tableColumns: [ |
||||
|
{ |
||||
|
name: 'info', |
||||
|
label: '用户信息', |
||||
|
childrenColumns: [ |
||||
|
{ name: 'loginName', label: '登录名', align: 'right' }, |
||||
|
{ name: 'userName', label: '用户名' }, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
name: 'lxxx', |
||||
|
label: '联系方式', |
||||
|
childrenColumns: [ |
||||
|
{ name: 'email', label: '邮箱地址' }, |
||||
|
{ |
||||
|
name: 'tx', |
||||
|
label: '通讯', |
||||
|
childrenColumns: [ |
||||
|
{ name: 'phone', label: '电话' }, |
||||
|
{ name: 'mobile', label: '手机号' }, |
||||
|
], |
||||
|
}, |
||||
|
{ name: 'qq', label: 'QQ' }, |
||||
|
], |
||||
|
}, |
||||
|
{ name: 'description', label: '描述' }, |
||||
|
{ |
||||
|
name: 'enable', |
||||
|
label: '是否可用', |
||||
|
align: 'center', |
||||
|
format: (val, row) => { |
||||
|
// return { |
||||
|
// _vuecomp_: true, |
||||
|
// type: EnableIcon, |
||||
|
// props: { |
||||
|
// value: val, |
||||
|
// showNoEnable: true, |
||||
|
// }, |
||||
|
// }; |
||||
|
// return { |
||||
|
// _vuecomp_: true, |
||||
|
// type: 'q-chip', |
||||
|
// props: { |
||||
|
// label: val ? '是' : '否', |
||||
|
// icon: val ? IconEnum.是状态 : IconEnum.否状态, |
||||
|
// color: val ? 'green' : 'red', |
||||
|
// }, |
||||
|
// }; |
||||
|
return { |
||||
|
_vuecomp_: true, |
||||
|
type: 'q-icon', |
||||
|
props: { |
||||
|
name: val ? IconEnum.是状态 : IconEnum.否状态, |
||||
|
color: val ? 'green' : 'red', |
||||
|
size: 'sm', |
||||
|
}, |
||||
|
}; |
||||
|
// return { |
||||
|
// _vuecomp_: true, |
||||
|
// type: 'w-text', |
||||
|
// props: { |
||||
|
// name: 'aaa', |
||||
|
// label: '请输入', |
||||
|
// }, |
||||
|
// }; |
||||
|
}, |
||||
|
}, |
||||
|
{ name: 'lastModifier', label: '最后修改人' }, |
||||
|
{ name: 'lastModifyDate', label: '最后修改时间' }, |
||||
|
], |
||||
|
addEdit: { |
||||
|
dialog: {}, |
||||
|
form: { |
||||
|
colsNum: 1, |
||||
|
fields: [ |
||||
|
{ label: '登录名', name: 'loginName', type: 'w-text' }, |
||||
|
{ label: '用户名', name: 'userName', type: 'w-text' }, |
||||
|
{ label: '密码', name: 'password', type: 'w-text' }, |
||||
|
{ label: '是否可用1111', name: 'enable', type: 'w-checkbox' }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
view: { |
||||
|
infoPanel: { |
||||
|
columnNum: 2, |
||||
|
fields: [ |
||||
|
{ name: 'id', label: '主键' }, |
||||
|
{ name: 'loginName', label: '登录名' }, |
||||
|
{ name: 'userName', label: '用户名' }, |
||||
|
{ name: 'description', label: '描述' }, |
||||
|
{ |
||||
|
name: 'enable', |
||||
|
label: '是否可用', |
||||
|
}, |
||||
|
{ name: 'email', label: '邮箱地址' }, |
||||
|
{ name: 'phone', label: '电话' }, |
||||
|
{ name: 'mobile', label: '手机号' }, |
||||
|
{ name: 'lastModifier', label: '最后修改人' }, |
||||
|
{ name: 'lastModifyDate', label: '最后修改时间' }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
// testGridRef.value.replaceRowsFun([{ typeName: '股权投资信息', typeDesc: '股权投资信息', lastModifier: 'admin', lastModifyDate: '2023-12-26' }]); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,308 @@ |
|||||
|
<template> |
||||
|
<q-splitter :model-value="70" class="w-full h-full"> |
||||
|
<template #before> |
||||
|
<w-grid |
||||
|
ref="userGridRef" |
||||
|
:title="userConfigure.tableTitle" |
||||
|
:row-key="userConfigure.tableRowKey" |
||||
|
:auto-load-data="userConfigure.tableInitLoadData" |
||||
|
:get-data-url="userConfigure.tableDataUrl" |
||||
|
:show-sort-no="false" |
||||
|
:columns="userConfigure.tableColumns" |
||||
|
:left-column-sticky-number="userConfigure.tableLeftColumnStickyNumber" |
||||
|
:toolbar="userConfigure.toolbar" |
||||
|
:query-form="userConfigure.queryForm" |
||||
|
:table-pagination="userConfigure.tablePagination" |
||||
|
@row-click="userConfigure.rowClickFun" |
||||
|
></w-grid> |
||||
|
</template> |
||||
|
<template #after> |
||||
|
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0"> |
||||
|
<q-tab name="role" icon="bi-people" :label="$t('role')" /> |
||||
|
<q-tab name="org" icon="bi-diagram-3" :label="$t('org')" /> |
||||
|
</q-tabs> |
||||
|
|
||||
|
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive> |
||||
|
<q-tab-panel name="role" class="p-0"> |
||||
|
<w-grid |
||||
|
ref="roleGridRef" |
||||
|
selection="multiple" |
||||
|
:hide-bottom="false" |
||||
|
:title="roleConfigure.tableTitle" |
||||
|
:row-key="roleConfigure.tableRowKey" |
||||
|
:auto-load-data="roleConfigure.tableInitLoadData" |
||||
|
:get-data-url="roleConfigure.tableDataUrl" |
||||
|
:show-sort-no="false" |
||||
|
:columns="roleConfigure.tableColumns" |
||||
|
:left-column-sticky-number="roleConfigure.tableLeftColumnStickyNumber" |
||||
|
:toolbar="roleConfigure.toolbar" |
||||
|
:table-pagination="roleConfigure.tablePagination" |
||||
|
></w-grid> |
||||
|
</q-tab-panel> |
||||
|
<q-tab-panel name="org"> 11111 </q-tab-panel> |
||||
|
</q-tab-panels> |
||||
|
</template> |
||||
|
</q-splitter> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from '@/platform'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const userGridRef = ref(); |
||||
|
const roleGridRef = ref(); |
||||
|
const orgTreeGridRef = ref(); |
||||
|
|
||||
|
const selectRoleDialog = ref(); |
||||
|
const changePasswordDialog = ref(); |
||||
|
|
||||
|
const selectedTabRef = ref('role'); |
||||
|
|
||||
|
const userConfigure = { |
||||
|
queryForm: { |
||||
|
fields: [ |
||||
|
{ label: t('loginName'), name: 'loginName', type: 'w-text' }, |
||||
|
{ label: t('userName'), name: 'userName', type: 'w-text' }, |
||||
|
{ |
||||
|
label: t('enable'), |
||||
|
name: 'enable', |
||||
|
type: 'w-select', |
||||
|
options: [ |
||||
|
{ value: true, label: '是' }, |
||||
|
{ value: false, label: '否' }, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
label: t('dataComeFrom'), |
||||
|
name: 'dataComeFrom', |
||||
|
type: 'w-select', |
||||
|
options: [ |
||||
|
{ value: 'MANUAL', label: t('io.sc.platform.orm.api.enums.DataComeFrom.MANUAL') }, |
||||
|
{ value: 'AUTO', label: t('io.sc.platform.orm.api.enums.DataComeFrom.AUTO') }, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
hideBottom: false, |
||||
|
tableInitLoadData: true, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: t('system.user.gridTitle'), |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('/api/system/user'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 10, |
||||
|
}, |
||||
|
toolbar: { |
||||
|
buttons: [ |
||||
|
'query', |
||||
|
'reset', |
||||
|
'separator', |
||||
|
'refresh', |
||||
|
'add', |
||||
|
'edit', |
||||
|
'remove', |
||||
|
'separator', |
||||
|
'view', |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'setPassword', |
||||
|
label: t('system.user.action.setPassword'), |
||||
|
icon: 'bi-shield-exclamation', |
||||
|
enableIf: function () {}, |
||||
|
click: function () { |
||||
|
changePasswordDialog.value.show(); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
tableColumns: [ |
||||
|
{ width: 100, name: 'loginName', label: t('loginName') }, |
||||
|
{ width: 100, name: 'userName', label: t('userName') }, |
||||
|
{ width: 100, name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
{ width: 100, name: 'dataComeFrom', label: t('dataComeFrom') }, |
||||
|
{ width: 100, name: 'accountExpired', label: t('accountExpired'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
{ width: 100, name: 'accountLocked', label: t('accountLocked'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
{ width: 120, name: 'credentialsExpired', label: t('credentialsExpired'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
{ width: 110, name: 'lastModifier', label: t('lastModifier') }, |
||||
|
{ width: 115, name: 'lastModifyDate', label: t('lastModifyDate') }, |
||||
|
], |
||||
|
addFormProps: { |
||||
|
dialogInitWidth: '50%', |
||||
|
dialogInitHeight: '90%', |
||||
|
formColsNumber: 1, |
||||
|
formColsAuto: false, |
||||
|
formFields: [ |
||||
|
{ modelName: 'loginName', label: t('loginName'), type: 'text', required: true }, |
||||
|
{ modelName: 'userName', label: t('userName'), type: 'text', required: true }, |
||||
|
{ modelName: 'password', label: t('password'), type: 'password' }, |
||||
|
{ modelName: 'confirmPassword', label: t('confirmPassword'), type: 'password' }, |
||||
|
{ modelName: 'description', label: t('description'), type: 'textarea' }, |
||||
|
{ modelName: 'email', label: t('email'), type: 'text' }, |
||||
|
{ modelName: 'phone', label: t('phone'), type: 'text' }, |
||||
|
{ modelName: 'mobile', label: t('mobile'), type: 'text' }, |
||||
|
{ modelName: 'weixin', label: t('weixin'), type: 'text' }, |
||||
|
{ modelName: 'qq', label: t('qq'), type: 'text' }, |
||||
|
{ modelName: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true }, |
||||
|
{ modelName: 'accountExpired', label: t('accountExpired'), type: 'checkbox' }, |
||||
|
{ modelName: 'accountLocked', label: t('accountLocked'), type: 'checkbox' }, |
||||
|
{ modelName: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox' }, |
||||
|
], |
||||
|
}, |
||||
|
rowClickFun: (evt, row, index) => { |
||||
|
if (roleGridRef.value) { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
} |
||||
|
if (orgTreeGridRef.value) { |
||||
|
axios.get(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id).then((response) => { |
||||
|
orgTreeGridRef.value.setNodes(response.data); |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const roleConfigure = { |
||||
|
queryFormColsNumber: 4, |
||||
|
queryFormColsAuto: false, |
||||
|
queryFormFields: [], |
||||
|
hideBottom: true, |
||||
|
tableInitLoadData: false, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: t('system.role.gridTitle'), |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: '', |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 0, |
||||
|
}, |
||||
|
toolbar: { |
||||
|
buttons: [ |
||||
|
'refresh', |
||||
|
{ |
||||
|
name: 'addRole', |
||||
|
label: t('system.role.action.addRole'), |
||||
|
icon: '', |
||||
|
enable: () => { |
||||
|
if (userGridRef.value) { |
||||
|
return userGridRef.value.getSelectedRows().length > 0; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
click: () => { |
||||
|
selectRoleDialog.value.show({ userGrid: userGridRef, roleGrid: roleGridRef }); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'addAllRole', |
||||
|
label: t('system.role.action.addAllRole'), |
||||
|
icon: '', |
||||
|
enable: () => { |
||||
|
if (userGridRef.value) { |
||||
|
console.log(userGridRef.value.getSelectedRows()); |
||||
|
return userGridRef.value.getSelectedRows().length > 0; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
click: () => { |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/user/addAllRoles'), { |
||||
|
one: userGridRef.value.getSelectedRows()[0].id, |
||||
|
many: [], |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + userGridRef.value.getSelectedRows()[0].id) |
||||
|
.then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'removeRole', |
||||
|
label: t('system.role.action.removeRole'), |
||||
|
icon: '', |
||||
|
enable: () => { |
||||
|
if (userGridRef.value) { |
||||
|
return userGridRef.value.getSelectedRows().length > 0; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
click: () => { |
||||
|
const roleIds = []; |
||||
|
for (const role of roleGridRef.value.getSelectedRows()) { |
||||
|
roleIds.push(role.id); |
||||
|
} |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/user/removeRoles'), { |
||||
|
one: userGridRef.value.getSelectedRows()[0].id, |
||||
|
many: roleIds, |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + userGridRef.value.getSelectedRows()[0].id) |
||||
|
.then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'removeAllRole', |
||||
|
label: t('system.role.action.removeAllRole'), |
||||
|
icon: '', |
||||
|
enable: () => { |
||||
|
if (userGridRef.value) { |
||||
|
return userGridRef.value.getSelectedRows().length > 0; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
click: () => { |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/user/removeAllRoles'), { |
||||
|
one: userGridRef.value.getSelectedRows()[0].id, |
||||
|
many: [], |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + userGridRef.value.getSelectedRows()[0].id) |
||||
|
.then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
tableColumns: [ |
||||
|
{ name: 'code', label: t('code') }, |
||||
|
{ name: 'name', label: t('name') }, |
||||
|
{ name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const orgConfigure = { |
||||
|
actions: [ |
||||
|
{ |
||||
|
name: 'save', |
||||
|
label: '保存', |
||||
|
click: () => { |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/user/updateOrgs'), { |
||||
|
one: userGridRef.value.getSelectedRows()[0].id, |
||||
|
many: orgTreeGridRef.value.getTicked(), |
||||
|
}) |
||||
|
.then((response) => {}); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,15 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-info-panel :column-num="2" label-align="center" value-align="center" :info="infoArray" dense> </w-info-panel> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, reactive } from 'vue'; |
||||
|
|
||||
|
const infoArray = [ |
||||
|
{ label: '姓名', value: '张三' }, |
||||
|
{ label: '年龄', value: 18 }, |
||||
|
{ label: '性别', value: '男' }, |
||||
|
{ label: '爱好', value: '唱跳' }, |
||||
|
]; |
||||
|
</script> |
@ -0,0 +1,154 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-table |
||||
|
title="Treats" |
||||
|
table-style="height: 500px;" |
||||
|
:rows="rows" |
||||
|
:columns="columns" |
||||
|
row-key="name" |
||||
|
:flat="true" |
||||
|
:selection="'single'" |
||||
|
:separator="'cell'" |
||||
|
/> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
|
||||
|
const columns = [ |
||||
|
{ |
||||
|
name: 'name', |
||||
|
required: true, |
||||
|
label: 'Dessert (100g serving)', |
||||
|
align: 'left', |
||||
|
field: (row) => row.name, |
||||
|
format: (val) => `${val}`, |
||||
|
sortable: true, |
||||
|
}, |
||||
|
{ name: 'calories', align: 'center', label: 'Calories', field: 'calories', sortable: true }, |
||||
|
{ name: 'fat', label: 'Fat (g)', field: 'fat', sortable: true }, |
||||
|
{ name: 'carbs', label: 'Carbs (g)', field: 'carbs' }, |
||||
|
{ name: 'protein', label: 'Protein (g)', field: 'protein' }, |
||||
|
{ name: 'sodium', label: 'Sodium (mg)', field: 'sodium' }, |
||||
|
{ name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }, |
||||
|
{ name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }, |
||||
|
]; |
||||
|
|
||||
|
const rows = [ |
||||
|
{ |
||||
|
name: 'Frozen Yogurt', |
||||
|
calories: 159, |
||||
|
fat: 6.0, |
||||
|
carbs: 24, |
||||
|
protein: 4.0, |
||||
|
sodium: 87, |
||||
|
calcium: '14%', |
||||
|
iron: '1%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Ice cream sandwich', |
||||
|
calories: 237, |
||||
|
fat: 9.0, |
||||
|
carbs: 37, |
||||
|
protein: 4.3, |
||||
|
sodium: 129, |
||||
|
calcium: '8%', |
||||
|
iron: '1%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Eclair', |
||||
|
calories: 262, |
||||
|
fat: 16.0, |
||||
|
carbs: 23, |
||||
|
protein: 6.0, |
||||
|
sodium: 337, |
||||
|
calcium: '6%', |
||||
|
iron: '7%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Cupcake', |
||||
|
calories: 305, |
||||
|
fat: 3.7, |
||||
|
carbs: 67, |
||||
|
protein: 4.3, |
||||
|
sodium: 413, |
||||
|
calcium: '3%', |
||||
|
iron: '8%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Gingerbread', |
||||
|
calories: 356, |
||||
|
fat: 16.0, |
||||
|
carbs: 49, |
||||
|
protein: 3.9, |
||||
|
sodium: 327, |
||||
|
calcium: '7%', |
||||
|
iron: '16%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Jelly bean', |
||||
|
calories: 375, |
||||
|
fat: 0.0, |
||||
|
carbs: 94, |
||||
|
protein: 0.0, |
||||
|
sodium: 50, |
||||
|
calcium: '0%', |
||||
|
iron: '0%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Lollipop', |
||||
|
calories: 392, |
||||
|
fat: 0.2, |
||||
|
carbs: 98, |
||||
|
protein: 0, |
||||
|
sodium: 38, |
||||
|
calcium: '0%', |
||||
|
iron: '2%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Honeycomb', |
||||
|
calories: 408, |
||||
|
fat: 3.2, |
||||
|
carbs: 87, |
||||
|
protein: 6.5, |
||||
|
sodium: 562, |
||||
|
calcium: '0%', |
||||
|
iron: '45%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'Donut', |
||||
|
calories: 452, |
||||
|
fat: 25.0, |
||||
|
carbs: 51, |
||||
|
protein: 4.9, |
||||
|
sodium: 326, |
||||
|
calcium: '2%', |
||||
|
iron: '22%', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'KitKat', |
||||
|
calories: 518, |
||||
|
fat: 26.0, |
||||
|
carbs: 65, |
||||
|
protein: 7, |
||||
|
sodium: 54, |
||||
|
calcium: '12%', |
||||
|
iron: '6%', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
const separator = ref('vertical'); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="css"> |
||||
|
:deep(.q-table) { |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
.q-table--vertical-separator td, |
||||
|
.q-table--vertical-separator th, |
||||
|
.q-table--cell-separator td, |
||||
|
.q-table--cell-separator th { |
||||
|
border-bottom-width: 1px !important; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,153 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<div class="flex flex-nowrap"> |
||||
|
<div class="flex-none">这是测试标题</div> |
||||
|
<div class="flex-1"> |
||||
|
<w-toolbar :no-icon="toolbar.noIcon" :align="toolbar.align" :x-gap="toolbar.xGap" :buttons="toolbar.buttons"></w-toolbar> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
|
||||
|
const toolbar = { |
||||
|
xGap: 8, |
||||
|
noIcon: false, |
||||
|
align: 'right', |
||||
|
buttons: [ |
||||
|
[ |
||||
|
{ |
||||
|
name: 'query', |
||||
|
icon: 'search', |
||||
|
label: '查询', |
||||
|
beforeClick: (tableRef, context) => {}, |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('查询'); |
||||
|
}, |
||||
|
afterClick: (tableRef, context) => {}, |
||||
|
}, |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'moreQuery', |
||||
|
icon: 'search', |
||||
|
label: '更多查询', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('更多查询'); |
||||
|
}, |
||||
|
}, |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'reset', |
||||
|
icon: 'autorenew', |
||||
|
label: '重置', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('重置'); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'addnew', |
||||
|
extend: 'add', |
||||
|
icon: 'add', |
||||
|
label: '新增', |
||||
|
beforeClick: (tableRef, context) => {}, |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('新增'); |
||||
|
}, |
||||
|
afterClick: (tableRef, context) => {}, |
||||
|
}, |
||||
|
'separator', |
||||
|
[ |
||||
|
{ |
||||
|
name: 'edit', |
||||
|
icon: 'edit', |
||||
|
label: '编辑', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('编辑'); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'clone', |
||||
|
icon: 'edit', |
||||
|
label: '复制', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('复制'); |
||||
|
}, |
||||
|
}, |
||||
|
'separator', |
||||
|
[ |
||||
|
{ |
||||
|
name: 'editConfig', |
||||
|
icon: 'edit', |
||||
|
label: '修改配置信息', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('修改配置信息'); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'editBasicInfo', |
||||
|
icon: 'edit', |
||||
|
label: '修改基本信息', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('修改基本信息'); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'editVersionInfo', |
||||
|
icon: 'edit', |
||||
|
label: '修改版本信息', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('修改版本信息'); |
||||
|
}, |
||||
|
}, |
||||
|
'separator', |
||||
|
[ |
||||
|
{ |
||||
|
name: 'edit1', |
||||
|
icon: 'edit', |
||||
|
label: '修改详细信息1', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('修改详细信息1'); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'edit2', |
||||
|
icon: 'edit', |
||||
|
label: '修改详细信息2', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('修改详细信息2'); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
], |
||||
|
], |
||||
|
'separator', |
||||
|
{ |
||||
|
name: 'remove', |
||||
|
icon: 'remove', |
||||
|
label: '删除', |
||||
|
click: (tableRef, context, _click) => { |
||||
|
console.info('删除'); |
||||
|
}, |
||||
|
}, |
||||
|
// { icon: 'home', label: '测试1' }, |
||||
|
// { separator: true }, |
||||
|
// { icon: 'home', label: '测试2' }, |
||||
|
// { icon: 'home', label: '测试3' }, |
||||
|
// { icon: 'home', label: '测试4' }, |
||||
|
// { separator: true }, |
||||
|
// { separator: true }, |
||||
|
// { icon: 'home', label: '测试5' }, |
||||
|
// { icon: 'home', label: '测试6' }, |
||||
|
// { icon: 'home', label: '测试7' }, |
||||
|
// { icon: 'home', label: '测试8' }, |
||||
|
// { icon: 'home', label: '测试9' }, |
||||
|
// { icon: 'home', label: '测试10' }, |
||||
|
// { icon: 'home', label: '测试11' }, |
||||
|
// { icon: 'home', label: '测试12' }, |
||||
|
// { icon: 'home', label: '测试13' }, |
||||
|
], |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,30 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-form :fields="fields" :cols-num-auto="false" :cols-num="3"></w-form> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
const fields = [ |
||||
|
{ |
||||
|
label: '姓名', |
||||
|
name: 'name', |
||||
|
type: 'text', |
||||
|
required: true, |
||||
|
colspan: 2, |
||||
|
button: { |
||||
|
round: false, |
||||
|
icon: 'home', |
||||
|
label: '选择', |
||||
|
click: () => { |
||||
|
console.info('11111'); |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '年龄', |
||||
|
name: 'age', |
||||
|
type: 'number', |
||||
|
required: true, |
||||
|
}, |
||||
|
]; |
||||
|
</script> |
@ -0,0 +1,4 @@ |
|||||
|
<template> |
||||
|
<div>2222</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"></script> |
Loading…
Reference in new issue