feat(mes):完成 cal team 【班组】的迁移
parent
858011bfab
commit
2bcd81dc94
|
|
@ -386,6 +386,9 @@ watch(
|
|||
|
||||
// 使用 nextTick 确保在下一个 tick 中处理数据
|
||||
await nextTick();
|
||||
if ((newValue || '') === paramsJson.value) {
|
||||
return;
|
||||
}
|
||||
handleDataDisplay(newValue || '');
|
||||
},
|
||||
{ immediate: true },
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
IotRuleSceneTriggerTypeEnum,
|
||||
isDeviceTrigger,
|
||||
} from '@vben/constants';
|
||||
import { CronUtils } from '@vben/utils';
|
||||
|
||||
import { Form, message } from 'ant-design-vue';
|
||||
|
||||
|
|
@ -158,12 +159,15 @@ function validateTriggers(_rule: any, value: any, callback: any) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER &&
|
||||
!trigger.cronExpression
|
||||
) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式不能为空`));
|
||||
return;
|
||||
if (trigger.type === IotRuleSceneTriggerTypeEnum.TIMER) {
|
||||
if (!trigger.cronExpression) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式不能为空`));
|
||||
return;
|
||||
}
|
||||
if (!CronUtils.validate(trigger.cronExpression)) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式格式不正确`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 递归校验 conditionGroups(嵌套条件组)
|
||||
if (trigger.conditionGroups?.length) {
|
||||
|
|
|
|||
|
|
@ -28,13 +28,11 @@ const childDataTypeOptions = getDataTypeOptions().filter(
|
|||
|
||||
const dataSpecs = useVModel(props, 'modelValue', emits) as Ref<any>;
|
||||
|
||||
/** 元素类型切到 struct 时,初始化 dataSpecsList 占位 */
|
||||
/** 元素类型切换时,清理旧子类型的结构体属性配置 */
|
||||
function handleChange(e: any) {
|
||||
const val = e?.target?.value ?? e;
|
||||
if (val !== IoTDataSpecsDataTypeEnum.STRUCT) {
|
||||
return;
|
||||
}
|
||||
dataSpecs.value.dataSpecsList = [];
|
||||
dataSpecs.value.childDataType = val;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,17 @@ import { IoTDataSpecsDataTypeEnum } from '@vben/constants';
|
|||
import { cloneDeep, isEmpty } from '@vben/utils';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { Button, Divider, Form, Input } from 'ant-design-vue';
|
||||
import { Button, Divider, Form, Input, message } from 'ant-design-vue';
|
||||
|
||||
import { ThingModelFormRules } from '#/api/iot/thingmodel';
|
||||
|
||||
import ThingModelProperty from './property.vue';
|
||||
|
||||
const props = defineProps<{ direction: string; modelValue: any }>();
|
||||
const props = defineProps<{
|
||||
direction: string;
|
||||
existingIdentifiers?: string[];
|
||||
modelValue: any;
|
||||
}>();
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
const thingModelParams = useVModel(props, 'modelValue', emits) as Ref<any[]>;
|
||||
|
||||
|
|
@ -33,6 +37,13 @@ const [Modal, modalApi] = useVbenModal({
|
|||
}
|
||||
// 组装表单
|
||||
const data = formData.value;
|
||||
if (
|
||||
data.identifier &&
|
||||
props.existingIdentifiers?.includes(data.identifier)
|
||||
) {
|
||||
message.warning('输入参数和输出参数标识符不能重复');
|
||||
return;
|
||||
}
|
||||
const item = {
|
||||
identifier: data.identifier,
|
||||
name: data.name,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ watch(
|
|||
(service.value.callType = IoTThingModelServiceCallTypeEnum.ASYNC.value),
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 提取参数标识符列表,用于输入 / 输出参数跨表去重 */
|
||||
function getParamIdentifiers(params?: any[]) {
|
||||
const identifiers: string[] = [];
|
||||
for (const item of params || []) {
|
||||
if (item.identifier) {
|
||||
identifiers.push(item.identifier);
|
||||
}
|
||||
}
|
||||
return identifiers;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -51,12 +62,14 @@ watch(
|
|||
<ThingModelInputOutputParam
|
||||
v-model="service.inputParams"
|
||||
:direction="IoTThingModelParamDirectionEnum.INPUT"
|
||||
:existing-identifiers="getParamIdentifiers(service.outputParams)"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="输出参数">
|
||||
<ThingModelInputOutputParam
|
||||
v-model="service.outputParams"
|
||||
:direction="IoTThingModelParamDirectionEnum.OUTPUT"
|
||||
:existing-identifiers="getParamIdentifiers(service.inputParams)"
|
||||
/>
|
||||
</Form.Item>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getTeamPage } from '#/api/mes/cal/team';
|
||||
|
||||
import { useTeamSelectGridColumns, useTeamSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{ selected: [rows: MesCalTeamApi.Team[]] }>();
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(true); // 是否多选
|
||||
const selectedRows = ref<MesCalTeamApi.Team[]>([]); // 已选班组列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选班组编号列表
|
||||
|
||||
/** 处理勾选变化 */
|
||||
function handleCheckboxChange({ records }: { records: MesCalTeamApi.Team[] }) {
|
||||
selectedRows.value = records;
|
||||
}
|
||||
|
||||
/** 处理全选变化 */
|
||||
function handleCheckboxAll({ records }: { records: MesCalTeamApi.Team[] }) {
|
||||
selectedRows.value = records;
|
||||
}
|
||||
|
||||
/** 双击行:多选切换勾选,单选直接确认 */
|
||||
function handleCellDblclick({ row }: { row: MesCalTeamApi.Team }) {
|
||||
if (multiple.value) {
|
||||
const records = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
const checked = records.some((item) => item.id === row.id);
|
||||
gridApi.grid.setCheckboxRow(row, !checked);
|
||||
selectedRows.value = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选班组 */
|
||||
function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesCalTeamApi.Team[];
|
||||
for (const row of rows) {
|
||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
||||
gridApi.grid.setCheckboxRow(row, true);
|
||||
}
|
||||
}
|
||||
selectedRows.value = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useTeamSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useTeamSelectGridColumns(),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) =>
|
||||
await getTeamPage({ pageNo: page.currentPage, pageSize: page.pageSize, ...formValues }),
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamApi.Team>,
|
||||
gridEvents: {
|
||||
checkboxAll: handleCheckboxAll,
|
||||
checkboxChange: handleCheckboxChange,
|
||||
cellDblclick: handleCellDblclick,
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
}
|
||||
|
||||
/** 打开班组选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭班组选择弹窗 */
|
||||
async function closeModal() {
|
||||
open.value = false;
|
||||
await resetQueryState();
|
||||
}
|
||||
|
||||
/** 确认选择班组 */
|
||||
function handleConfirm() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? selectedRows.value : [selectedRows.value[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model:open="open"
|
||||
title="班组选择"
|
||||
width="720px"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleConfirm"
|
||||
@cancel="closeModal"
|
||||
>
|
||||
<Grid table-title="班组列表" />
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<script lang="ts" setup>
|
||||
import type { SelectValue } from 'ant-design-vue/es/select';
|
||||
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { Button, Select } from 'ant-design-vue';
|
||||
|
||||
import { getTeamList } from '#/api/mes/cal/team';
|
||||
|
||||
import CalTeamSelectDialog from './cal-team-select-dialog.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
allowClear?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
allowClear: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择班组',
|
||||
},
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
change: [row?: MesCalTeamApi.Team];
|
||||
'update:modelValue': [value?: number];
|
||||
}>();
|
||||
const teamList = ref<MesCalTeamApi.Team[]>([]); // 班组选项
|
||||
const dialogRef = ref<InstanceType<typeof CalTeamSelectDialog>>(); // 班组选择弹窗
|
||||
|
||||
/** 加载班组选项 */
|
||||
async function loadTeamList() {
|
||||
teamList.value = await getTeamList();
|
||||
}
|
||||
|
||||
/** 处理下拉选择变化 */
|
||||
function handleChange(value: SelectValue) {
|
||||
const teamId = typeof value === 'number' ? value : undefined;
|
||||
emit('update:modelValue', teamId);
|
||||
emit(
|
||||
'change',
|
||||
teamList.value.find((item) => item.id === teamId),
|
||||
);
|
||||
}
|
||||
|
||||
/** 打开班组选择弹窗 */
|
||||
function openDialog() {
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
dialogRef.value?.open(props.modelValue ? [props.modelValue] : [], { multiple: false });
|
||||
}
|
||||
|
||||
/** 处理弹窗选择 */
|
||||
function handleSelected(rows: MesCalTeamApi.Team[]) {
|
||||
const row = rows[0];
|
||||
emit('update:modelValue', row?.id);
|
||||
emit('change', row);
|
||||
}
|
||||
|
||||
onMounted(loadTeamList);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full gap-2">
|
||||
<Select
|
||||
:allow-clear="allowClear"
|
||||
:disabled="disabled"
|
||||
:field-names="{ label: 'name', value: 'id' }"
|
||||
:options="teamList"
|
||||
:placeholder="placeholder"
|
||||
:value="modelValue"
|
||||
class="flex-1"
|
||||
option-filter-prop="name"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<Button :disabled="disabled" @click="openDialog">选择</Button>
|
||||
<CalTeamSelectDialog ref="dialogRef" :multiple="false" @selected="handleSelected" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as CalTeamSelectDialog } from './cal-team-select-dialog.vue';
|
||||
export { default as CalTeamSelect } from './cal-team-select.vue';
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { h } from 'vue';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { z } from '#/adapter/form';
|
||||
import { generateAutoCode } from '#/api/mes/md/autocode/record';
|
||||
import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants';
|
||||
|
||||
/** 新增/修改班组的表单 */
|
||||
export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxLength: 64,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
rules: z.string().min(1, '班组编码不能为空').max(64),
|
||||
suffix: () =>
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
type: 'default',
|
||||
onClick: async () => {
|
||||
try {
|
||||
const code = await generateAutoCode(MesAutoCodeRuleCode.CAL_TEAM_CODE);
|
||||
await formApi?.setFieldValue('code', code);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
{ default: () => '生成' },
|
||||
),
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxLength: 100,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
rules: z.string().min(1, '班组名称不能为空').max(100),
|
||||
},
|
||||
{
|
||||
fieldName: 'calendarType',
|
||||
label: '班组类型',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
options: getDictOptions(DICT_TYPE.MES_CAL_CALENDAR_TYPE, 'number'),
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
formItemClass: 'col-span-3',
|
||||
componentProps: {
|
||||
maxLength: 250,
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'calendarType',
|
||||
label: '班组类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.MES_CAL_CALENDAR_TYPE, 'number'),
|
||||
placeholder: '请选择班组类型',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的字段 */
|
||||
export function useGridColumns(): VxeTableGridOptions<MesCalTeamApi.Team>['columns'] {
|
||||
return [
|
||||
{
|
||||
field: 'code',
|
||||
title: '班组编码',
|
||||
minWidth: 150,
|
||||
slots: {
|
||||
default: 'code',
|
||||
},
|
||||
},
|
||||
{ field: 'name', title: '班组名称', minWidth: 150 },
|
||||
{
|
||||
field: 'calendarType',
|
||||
title: '班组类型',
|
||||
width: 140,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_CAL_CALENDAR_TYPE },
|
||||
},
|
||||
},
|
||||
{ field: 'remark', title: '备注', minWidth: 180 },
|
||||
{ field: 'createTime', title: '创建时间', width: 180, formatter: 'formatDateTime' },
|
||||
{
|
||||
title: '操作',
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'actions',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 班组选择弹窗搜索表单 */
|
||||
export function useTeamSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 班组选择弹窗字段 */
|
||||
export function useTeamSelectGridColumns(): VxeTableGridOptions<MesCalTeamApi.Team>['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 50 },
|
||||
{ field: 'code', title: '班组编码', minWidth: 140 },
|
||||
{ field: 'name', title: '班组名称', minWidth: 140 },
|
||||
{ field: 'remark', title: '备注', minWidth: 160 },
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteTeam, exportTeam, getTeamPage } from '#/api/mes/cal/team';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 创建班组 */
|
||||
function handleCreate() {
|
||||
formModalApi.setData({ type: 'create' }).open();
|
||||
}
|
||||
|
||||
/** 查看班组 */
|
||||
function handleDetail(row: MesCalTeamApi.Team) {
|
||||
formModalApi.setData({ id: row.id, type: 'detail' }).open();
|
||||
}
|
||||
|
||||
/** 编辑班组 */
|
||||
function handleEdit(row: MesCalTeamApi.Team) {
|
||||
formModalApi.setData({ id: row.id, type: 'update' }).open();
|
||||
}
|
||||
|
||||
/** 删除班组 */
|
||||
async function handleDelete(row: MesCalTeamApi.Team) {
|
||||
const hideLoading = message.loading({
|
||||
content: $t('ui.actionMessage.deleting', [row.name]),
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteTeam(row.id!);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/** 导出班组 */
|
||||
async function handleExport() {
|
||||
const data = await exportTeam(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '班组.xls', source: data });
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useGridColumns(),
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getTeamPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamApi.Team>,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<Grid table-title="班组列表">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('ui.actionTitle.create', ['班组']),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['mes:cal-team:create'],
|
||||
onClick: handleCreate,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.export'),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.DOWNLOAD,
|
||||
auth: ['mes:cal-team:export'],
|
||||
onClick: handleExport,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<template #code="{ row }">
|
||||
<Button type="link" @click="handleDetail(row)">{{ row.code }}</Button>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('common.edit'),
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.EDIT,
|
||||
auth: ['mes:cal-team:update'],
|
||||
onClick: handleEdit.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: $t('common.delete'),
|
||||
type: 'link',
|
||||
danger: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['mes:cal-team:delete'],
|
||||
popConfirm: {
|
||||
title: $t('ui.actionMessage.deleteConfirm', [row.name]),
|
||||
confirm: handleDelete.bind(null, row),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message, Tabs } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { createTeam, getTeam, updateTeam } from '#/api/mes/cal/team';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useFormSchema } from '../data';
|
||||
import MemberList from './member-list.vue';
|
||||
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formMode = ref<'create' | 'detail' | 'update'>('create'); // 表单模式
|
||||
const subTabsName = ref('member'); // 当前资源页签
|
||||
const formData = ref<MesCalTeamApi.Team>();
|
||||
const isDetail = computed(() => formMode.value === 'detail'); // 是否查看模式
|
||||
const getTitle = computed(() => {
|
||||
if (formMode.value === 'detail') {
|
||||
return $t('ui.actionTitle.view', ['班组']);
|
||||
}
|
||||
return formMode.value === 'update'
|
||||
? $t('ui.actionTitle.edit', ['班组'])
|
||||
: $t('ui.actionTitle.create', ['班组']);
|
||||
});
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-1',
|
||||
labelWidth: 100,
|
||||
},
|
||||
wrapperClass: 'grid-cols-3',
|
||||
layout: 'horizontal',
|
||||
schema: [],
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
/** 表单 schema 需要 formApi 引用,所以通过 setState 设置 schema */
|
||||
formApi.setState({ schema: useFormSchema(formApi) });
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (isDetail.value) {
|
||||
await modalApi.close();
|
||||
return;
|
||||
}
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 提交表单
|
||||
const data = (await formApi.getValues()) as MesCalTeamApi.Team;
|
||||
try {
|
||||
if (formMode.value === 'create') {
|
||||
const id = await createTeam(data);
|
||||
formData.value = { ...data, id: id as number };
|
||||
await formApi.setFieldValue('id', id);
|
||||
formMode.value = 'update';
|
||||
} else {
|
||||
await updateTeam(data);
|
||||
formData.value = { ...formData.value, ...data };
|
||||
}
|
||||
emit('success');
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = undefined;
|
||||
return;
|
||||
}
|
||||
await formApi.resetForm();
|
||||
subTabsName.value = 'member';
|
||||
const data = modalApi.getData<{ id?: number; type?: 'create' | 'detail' | 'update' }>();
|
||||
formMode.value = data?.type || 'create';
|
||||
formApi.setDisabled(formMode.value === 'detail');
|
||||
modalApi.setState({ showConfirmButton: formMode.value !== 'detail' });
|
||||
if (!data?.id) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
formData.value = await getTeam(data.id);
|
||||
await formApi.setValues(formData.value);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle" class="w-4/5">
|
||||
<Form class="mx-4" />
|
||||
<Tabs
|
||||
v-if="formMode !== 'create' && formData?.id"
|
||||
v-model:active-key="subTabsName"
|
||||
class="mx-4 mt-4"
|
||||
>
|
||||
<Tabs.TabPane key="member" tab="班组成员">
|
||||
<MemberList :form-type="formMode" :team-id="formData.id" />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamMemberApi } from '#/api/mes/cal/team/member';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
createTeamMember,
|
||||
deleteTeamMember,
|
||||
getTeamMemberListByTeam,
|
||||
} from '#/api/mes/cal/team/member';
|
||||
import { getSimpleUserList } from '#/api/system/user';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const props = withDefaults(defineProps<{ formType?: string; teamId: number }>(), {
|
||||
formType: 'update',
|
||||
});
|
||||
const isEditable = computed(() => ['create', 'update'].includes(props.formType)); // 是否可编辑
|
||||
const formOpen = ref(false); // 成员表单是否打开
|
||||
const formLoading = ref(false); // 成员表单提交中
|
||||
const list = ref<MesCalTeamMemberApi.TeamMember[]>([]); // 成员列表
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-2',
|
||||
labelWidth: 80,
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
fieldName: 'teamId',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'userId',
|
||||
label: '用户',
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
api: getSimpleUserList,
|
||||
labelField: 'nickname',
|
||||
placeholder: '请选择用户',
|
||||
showSearch: true,
|
||||
valueField: 'id',
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
gridOptions: {
|
||||
autoResize: true,
|
||||
border: true,
|
||||
columns: [
|
||||
{ field: 'userId', title: '用户编号', width: 100 },
|
||||
{ field: 'nickname', title: '用户昵称', minWidth: 120 },
|
||||
{ field: 'telephone', title: '手机号', minWidth: 120 },
|
||||
{ field: 'remark', title: '备注', minWidth: 160 },
|
||||
{
|
||||
title: '操作',
|
||||
width: 90,
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'actions',
|
||||
},
|
||||
visible: isEditable.value,
|
||||
},
|
||||
],
|
||||
data: list.value,
|
||||
minHeight: 240,
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
keyField: 'id',
|
||||
},
|
||||
showOverflow: true,
|
||||
toolbarConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamMemberApi.TeamMember>,
|
||||
});
|
||||
|
||||
/** 加载成员列表 */
|
||||
async function getList() {
|
||||
gridApi.setLoading(true);
|
||||
try {
|
||||
list.value = await getTeamMemberListByTeam(props.teamId);
|
||||
gridApi.setGridOptions({ data: list.value });
|
||||
} finally {
|
||||
gridApi.setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开成员表单 */
|
||||
async function openForm() {
|
||||
formOpen.value = true;
|
||||
await formApi.resetForm();
|
||||
await formApi.setValues({ teamId: props.teamId });
|
||||
}
|
||||
|
||||
/** 提交成员表单 */
|
||||
async function submitForm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesCalTeamMemberApi.TeamMember;
|
||||
await createTeamMember(data);
|
||||
formOpen.value = false;
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
await getList();
|
||||
} finally {
|
||||
formLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除成员 */
|
||||
async function handleDelete(id: number) {
|
||||
await deleteTeamMember(id);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', ['成员']));
|
||||
await getList();
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.teamId,
|
||||
(value) => {
|
||||
if (value) {
|
||||
getList();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isEditable" class="mb-3 flex items-center justify-start">
|
||||
<TableAction :actions="[{ label: '添加成员', type: 'primary', onClick: openForm }]" />
|
||||
</div>
|
||||
<Grid class="w-full">
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '删除',
|
||||
type: 'link',
|
||||
danger: true,
|
||||
popConfirm: {
|
||||
title: '确认删除该成员吗?',
|
||||
confirm: handleDelete.bind(null, row.id!),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
|
||||
<Modal
|
||||
v-model:open="formOpen"
|
||||
title="添加成员"
|
||||
width="520px"
|
||||
:confirm-loading="formLoading"
|
||||
@ok="submitForm"
|
||||
>
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -386,6 +386,9 @@ watch(
|
|||
|
||||
// 使用 nextTick 确保在下一个 tick 中处理数据
|
||||
await nextTick();
|
||||
if ((newValue || '') === paramsJson.value) {
|
||||
return;
|
||||
}
|
||||
handleDataDisplay(newValue || '');
|
||||
},
|
||||
{ immediate: true },
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
IotRuleSceneTriggerTypeEnum,
|
||||
isDeviceTrigger,
|
||||
} from '@vben/constants';
|
||||
import { CronUtils } from '@vben/utils';
|
||||
|
||||
import { ElForm, ElMessage } from 'element-plus';
|
||||
|
||||
|
|
@ -158,12 +159,15 @@ function validateTriggers(_rule: any, value: any, callback: any) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER &&
|
||||
!trigger.cronExpression
|
||||
) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式不能为空`));
|
||||
return;
|
||||
if (trigger.type === IotRuleSceneTriggerTypeEnum.TIMER) {
|
||||
if (!trigger.cronExpression) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式不能为空`));
|
||||
return;
|
||||
}
|
||||
if (!CronUtils.validate(trigger.cronExpression)) {
|
||||
callback(new Error(`触发器 ${i + 1}:CRON 表达式格式不正确`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 递归校验 conditionGroups(嵌套条件组)
|
||||
if (trigger.conditionGroups?.length) {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ const childDataTypeOptions = getDataTypeOptions().filter(
|
|||
|
||||
const dataSpecs = useVModel(props, 'modelValue', emits) as Ref<any>;
|
||||
|
||||
/** 元素类型切到 struct 时,初始化 dataSpecsList 占位 */
|
||||
/** 元素类型切换时,清理旧子类型的结构体属性配置 */
|
||||
function handleChange(val: any) {
|
||||
if (val !== IoTDataSpecsDataTypeEnum.STRUCT) {
|
||||
return;
|
||||
}
|
||||
dataSpecs.value.dataSpecsList = [];
|
||||
dataSpecs.value.childDataType = val;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,18 @@ import {
|
|||
ElForm,
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElMessage,
|
||||
} from 'element-plus';
|
||||
|
||||
import { ThingModelFormRules } from '#/api/iot/thingmodel';
|
||||
|
||||
import ThingModelProperty from './property.vue';
|
||||
|
||||
const props = defineProps<{ direction: string; modelValue: any }>();
|
||||
const props = defineProps<{
|
||||
direction: string;
|
||||
existingIdentifiers?: string[];
|
||||
modelValue: any;
|
||||
}>();
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
const thingModelParams = useVModel(props, 'modelValue', emits) as Ref<any[]>;
|
||||
|
||||
|
|
@ -39,6 +44,13 @@ const [Modal, modalApi] = useVbenModal({
|
|||
}
|
||||
// 组装表单
|
||||
const data = formData.value;
|
||||
if (
|
||||
data.identifier &&
|
||||
props.existingIdentifiers?.includes(data.identifier)
|
||||
) {
|
||||
ElMessage.warning('输入参数和输出参数标识符不能重复');
|
||||
return;
|
||||
}
|
||||
const item = {
|
||||
identifier: data.identifier,
|
||||
name: data.name,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ watch(
|
|||
(service.value.callType = IoTThingModelServiceCallTypeEnum.ASYNC.value),
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 提取参数标识符列表,用于输入 / 输出参数跨表去重 */
|
||||
function getParamIdentifiers(params?: any[]) {
|
||||
const identifiers: string[] = [];
|
||||
for (const item of params || []) {
|
||||
if (item.identifier) {
|
||||
identifiers.push(item.identifier);
|
||||
}
|
||||
}
|
||||
return identifiers;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -51,12 +62,14 @@ watch(
|
|||
<ThingModelInputOutputParam
|
||||
v-model="service.inputParams"
|
||||
:direction="IoTThingModelParamDirectionEnum.INPUT"
|
||||
:existing-identifiers="getParamIdentifiers(service.outputParams)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="输出参数">
|
||||
<ThingModelInputOutputParam
|
||||
v-model="service.outputParams"
|
||||
:direction="IoTThingModelParamDirectionEnum.OUTPUT"
|
||||
:existing-identifiers="getParamIdentifiers(service.inputParams)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { ElButton, ElDialog, ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getTeamPage } from '#/api/mes/cal/team';
|
||||
|
||||
import { useTeamSelectGridColumns, useTeamSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{ selected: [rows: MesCalTeamApi.Team[]] }>();
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(true); // 是否多选
|
||||
const selectedRows = ref<MesCalTeamApi.Team[]>([]); // 已选班组列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选班组编号列表
|
||||
|
||||
/** 处理勾选变化 */
|
||||
function handleCheckboxChange({ records }: { records: MesCalTeamApi.Team[] }) {
|
||||
selectedRows.value = records;
|
||||
}
|
||||
|
||||
/** 处理全选变化 */
|
||||
function handleCheckboxAll({ records }: { records: MesCalTeamApi.Team[] }) {
|
||||
selectedRows.value = records;
|
||||
}
|
||||
|
||||
/** 双击行:多选切换勾选,单选直接确认 */
|
||||
function handleCellDblclick({ row }: { row: MesCalTeamApi.Team }) {
|
||||
if (multiple.value) {
|
||||
const records = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
const checked = records.some((item) => item.id === row.id);
|
||||
gridApi.grid.setCheckboxRow(row, !checked);
|
||||
selectedRows.value = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选班组 */
|
||||
function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesCalTeamApi.Team[];
|
||||
for (const row of rows) {
|
||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
||||
gridApi.grid.setCheckboxRow(row, true);
|
||||
}
|
||||
}
|
||||
selectedRows.value = gridApi.grid.getCheckboxRecords() as MesCalTeamApi.Team[];
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useTeamSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useTeamSelectGridColumns(),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) =>
|
||||
await getTeamPage({ pageNo: page.currentPage, pageSize: page.pageSize, ...formValues }),
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamApi.Team>,
|
||||
gridEvents: {
|
||||
checkboxAll: handleCheckboxAll,
|
||||
checkboxChange: handleCheckboxChange,
|
||||
cellDblclick: handleCellDblclick,
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
}
|
||||
|
||||
/** 打开班组选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭班组选择弹窗 */
|
||||
async function closeModal() {
|
||||
open.value = false;
|
||||
await resetQueryState();
|
||||
}
|
||||
|
||||
/** 确认选择班组 */
|
||||
function handleConfirm() {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? selectedRows.value : [selectedRows.value[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDialog v-model="open" title="班组选择" width="720px" destroy-on-close @close="closeModal">
|
||||
<Grid table-title="班组列表" />
|
||||
<template #footer>
|
||||
<ElButton @click="closeModal">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirm">确定</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { ElButton, ElOption, ElSelect } from 'element-plus';
|
||||
|
||||
import { getTeamList } from '#/api/mes/cal/team';
|
||||
|
||||
import CalTeamSelectDialog from './cal-team-select-dialog.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
clearable?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
clearable: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择班组',
|
||||
},
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
change: [row?: MesCalTeamApi.Team];
|
||||
'update:modelValue': [value?: number];
|
||||
}>();
|
||||
const teamList = ref<MesCalTeamApi.Team[]>([]); // 班组选项
|
||||
const dialogRef = ref<InstanceType<typeof CalTeamSelectDialog>>(); // 班组选择弹窗
|
||||
|
||||
/** 加载班组选项 */
|
||||
async function loadTeamList() {
|
||||
teamList.value = await getTeamList();
|
||||
}
|
||||
|
||||
/** 处理下拉选择变化 */
|
||||
function handleChange(value: number | string | undefined) {
|
||||
const teamId = typeof value === 'number' ? value : undefined;
|
||||
emit('update:modelValue', teamId);
|
||||
emit(
|
||||
'change',
|
||||
teamList.value.find((item) => item.id === teamId),
|
||||
);
|
||||
}
|
||||
|
||||
/** 打开班组选择弹窗 */
|
||||
function openDialog() {
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
dialogRef.value?.open(props.modelValue ? [props.modelValue] : [], { multiple: false });
|
||||
}
|
||||
|
||||
/** 处理弹窗选择 */
|
||||
function handleSelected(rows: MesCalTeamApi.Team[]) {
|
||||
const row = rows[0];
|
||||
emit('update:modelValue', row?.id);
|
||||
emit('change', row);
|
||||
}
|
||||
|
||||
onMounted(loadTeamList);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full gap-2">
|
||||
<ElSelect
|
||||
:clearable="clearable"
|
||||
:disabled="disabled"
|
||||
:model-value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
class="flex-1"
|
||||
@change="handleChange"
|
||||
>
|
||||
<ElOption v-for="item in teamList" :key="item.id" :label="item.name" :value="item.id!" />
|
||||
</ElSelect>
|
||||
<ElButton :disabled="disabled" @click="openDialog">选择</ElButton>
|
||||
<CalTeamSelectDialog ref="dialogRef" :multiple="false" @selected="handleSelected" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as CalTeamSelectDialog } from './cal-team-select-dialog.vue';
|
||||
export { default as CalTeamSelect } from './cal-team-select.vue';
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { h } from 'vue';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { ElButton } from 'element-plus';
|
||||
|
||||
import { z } from '#/adapter/form';
|
||||
import { generateAutoCode } from '#/api/mes/md/autocode/record';
|
||||
import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants';
|
||||
|
||||
/** 新增/修改班组的表单 */
|
||||
export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxLength: 64,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
rules: z.string().min(1, '班组编码不能为空').max(64),
|
||||
suffix: () =>
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: 'default',
|
||||
onClick: async () => {
|
||||
try {
|
||||
const code = await generateAutoCode(MesAutoCodeRuleCode.CAL_TEAM_CODE);
|
||||
await formApi?.setFieldValue('code', code);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
{ default: () => '生成' },
|
||||
),
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxLength: 100,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
rules: z.string().min(1, '班组名称不能为空').max(100),
|
||||
},
|
||||
{
|
||||
fieldName: 'calendarType',
|
||||
label: '班组类型',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: getDictOptions(DICT_TYPE.MES_CAL_CALENDAR_TYPE, 'number'),
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
formItemClass: 'col-span-3',
|
||||
componentProps: {
|
||||
maxLength: 250,
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'calendarType',
|
||||
label: '班组类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
options: getDictOptions(DICT_TYPE.MES_CAL_CALENDAR_TYPE, 'number'),
|
||||
placeholder: '请选择班组类型',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的字段 */
|
||||
export function useGridColumns(): VxeTableGridOptions<MesCalTeamApi.Team>['columns'] {
|
||||
return [
|
||||
{
|
||||
field: 'code',
|
||||
title: '班组编码',
|
||||
minWidth: 150,
|
||||
slots: {
|
||||
default: 'code',
|
||||
},
|
||||
},
|
||||
{ field: 'name', title: '班组名称', minWidth: 150 },
|
||||
{
|
||||
field: 'calendarType',
|
||||
title: '班组类型',
|
||||
width: 140,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_CAL_CALENDAR_TYPE },
|
||||
},
|
||||
},
|
||||
{ field: 'remark', title: '备注', minWidth: 180 },
|
||||
{ field: 'createTime', title: '创建时间', width: 180, formatter: 'formatDateTime' },
|
||||
{
|
||||
title: '操作',
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'actions',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 班组选择弹窗搜索表单 */
|
||||
export function useTeamSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '班组编码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入班组编码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '班组名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入班组名称',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 班组选择弹窗字段 */
|
||||
export function useTeamSelectGridColumns(): VxeTableGridOptions<MesCalTeamApi.Team>['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 50 },
|
||||
{ field: 'code', title: '班组编码', minWidth: 140 },
|
||||
{ field: 'name', title: '班组名称', minWidth: 140 },
|
||||
{ field: 'remark', title: '备注', minWidth: 160 },
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||
|
||||
import { ElButton, ElLoading, ElMessage } from 'element-plus';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { deleteTeam, exportTeam, getTeamPage } from '#/api/mes/cal/team';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
/** 刷新表格 */
|
||||
function handleRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 创建班组 */
|
||||
function handleCreate() {
|
||||
formModalApi.setData({ type: 'create' }).open();
|
||||
}
|
||||
|
||||
/** 查看班组 */
|
||||
function handleDetail(row: MesCalTeamApi.Team) {
|
||||
formModalApi.setData({ id: row.id, type: 'detail' }).open();
|
||||
}
|
||||
|
||||
/** 编辑班组 */
|
||||
function handleEdit(row: MesCalTeamApi.Team) {
|
||||
formModalApi.setData({ id: row.id, type: 'update' }).open();
|
||||
}
|
||||
|
||||
/** 删除班组 */
|
||||
async function handleDelete(row: MesCalTeamApi.Team) {
|
||||
const hideLoading = ElLoading.service({ text: $t('ui.actionMessage.deleting', [row.name]) });
|
||||
try {
|
||||
await deleteTeam(row.id!);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
handleRefresh();
|
||||
} finally {
|
||||
hideLoading.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** 导出班组 */
|
||||
async function handleExport() {
|
||||
const data = await exportTeam(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '班组.xls', source: data });
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useGridColumns(),
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getTeamPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamApi.Team>,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<Grid table-title="班组列表">
|
||||
<template #toolbar-tools>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('ui.actionTitle.create', ['班组']),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.ADD,
|
||||
auth: ['mes:cal-team:create'],
|
||||
onClick: handleCreate,
|
||||
},
|
||||
{
|
||||
label: $t('ui.actionTitle.export'),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.DOWNLOAD,
|
||||
auth: ['mes:cal-team:export'],
|
||||
onClick: handleExport,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<template #code="{ row }">
|
||||
<ElButton link type="primary" @click="handleDetail(row)">{{ row.code }}</ElButton>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('common.edit'),
|
||||
type: 'primary',
|
||||
link: true,
|
||||
icon: ACTION_ICON.EDIT,
|
||||
auth: ['mes:cal-team:update'],
|
||||
onClick: handleEdit.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: $t('common.delete'),
|
||||
type: 'danger',
|
||||
link: true,
|
||||
icon: ACTION_ICON.DELETE,
|
||||
auth: ['mes:cal-team:delete'],
|
||||
popConfirm: {
|
||||
title: $t('ui.actionMessage.deleteConfirm', [row.name]),
|
||||
confirm: handleDelete.bind(null, row),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesCalTeamApi } from '#/api/mes/cal/team';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { ElMessage, ElTabPane, ElTabs } from 'element-plus';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { createTeam, getTeam, updateTeam } from '#/api/mes/cal/team';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useFormSchema } from '../data';
|
||||
import MemberList from './member-list.vue';
|
||||
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formMode = ref<'create' | 'detail' | 'update'>('create'); // 表单模式
|
||||
const subTabsName = ref('member'); // 当前资源页签
|
||||
const formData = ref<MesCalTeamApi.Team>();
|
||||
const isDetail = computed(() => formMode.value === 'detail'); // 是否查看模式
|
||||
const getTitle = computed(() => {
|
||||
if (formMode.value === 'detail') {
|
||||
return $t('ui.actionTitle.view', ['班组']);
|
||||
}
|
||||
return formMode.value === 'update'
|
||||
? $t('ui.actionTitle.edit', ['班组'])
|
||||
: $t('ui.actionTitle.create', ['班组']);
|
||||
});
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-1',
|
||||
labelWidth: 100,
|
||||
},
|
||||
wrapperClass: 'grid-cols-3',
|
||||
layout: 'horizontal',
|
||||
schema: [],
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
/** 表单 schema 需要 formApi 引用,所以通过 setState 设置 schema */
|
||||
formApi.setState({ schema: useFormSchema(formApi) });
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (isDetail.value) {
|
||||
await modalApi.close();
|
||||
return;
|
||||
}
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 提交表单
|
||||
const data = (await formApi.getValues()) as MesCalTeamApi.Team;
|
||||
try {
|
||||
if (formMode.value === 'create') {
|
||||
const id = await createTeam(data);
|
||||
formData.value = { ...data, id: id as number };
|
||||
await formApi.setFieldValue('id', id);
|
||||
formMode.value = 'update';
|
||||
} else {
|
||||
await updateTeam(data);
|
||||
formData.value = { ...formData.value, ...data };
|
||||
}
|
||||
emit('success');
|
||||
ElMessage.success($t('ui.actionMessage.operationSuccess'));
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = undefined;
|
||||
return;
|
||||
}
|
||||
await formApi.resetForm();
|
||||
subTabsName.value = 'member';
|
||||
const data = modalApi.getData<{ id?: number; type?: 'create' | 'detail' | 'update' }>();
|
||||
formMode.value = data?.type || 'create';
|
||||
formApi.setDisabled(formMode.value === 'detail');
|
||||
modalApi.setState({ showConfirmButton: formMode.value !== 'detail' });
|
||||
if (!data?.id) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
formData.value = await getTeam(data.id);
|
||||
await formApi.setValues(formData.value);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle" class="w-4/5">
|
||||
<Form class="mx-4" />
|
||||
<ElTabs v-if="formMode !== 'create' && formData?.id" v-model="subTabsName" class="mx-4 mt-4">
|
||||
<ElTabPane label="班组成员" name="member">
|
||||
<MemberList :form-type="formMode" :team-id="formData.id" />
|
||||
</ElTabPane>
|
||||
</ElTabs>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesCalTeamMemberApi } from '#/api/mes/cal/team/member';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { ElButton, ElDialog, ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
createTeamMember,
|
||||
deleteTeamMember,
|
||||
getTeamMemberListByTeam,
|
||||
} from '#/api/mes/cal/team/member';
|
||||
import { getSimpleUserList } from '#/api/system/user';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const props = withDefaults(defineProps<{ formType?: string; teamId: number }>(), {
|
||||
formType: 'update',
|
||||
});
|
||||
const isEditable = computed(() => ['create', 'update'].includes(props.formType)); // 是否可编辑
|
||||
const formOpen = ref(false); // 成员表单是否打开
|
||||
const formLoading = ref(false); // 成员表单提交中
|
||||
const list = ref<MesCalTeamMemberApi.TeamMember[]>([]); // 成员列表
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-2',
|
||||
labelWidth: 80,
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
fieldName: 'teamId',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'userId',
|
||||
label: '用户',
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
api: getSimpleUserList,
|
||||
labelField: 'nickname',
|
||||
placeholder: '请选择用户',
|
||||
showSearch: true,
|
||||
valueField: 'id',
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
gridOptions: {
|
||||
autoResize: true,
|
||||
border: true,
|
||||
columns: [
|
||||
{ field: 'userId', title: '用户编号', width: 100 },
|
||||
{ field: 'nickname', title: '用户昵称', minWidth: 120 },
|
||||
{ field: 'telephone', title: '手机号', minWidth: 120 },
|
||||
{ field: 'remark', title: '备注', minWidth: 160 },
|
||||
{
|
||||
title: '操作',
|
||||
width: 90,
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'actions',
|
||||
},
|
||||
visible: isEditable.value,
|
||||
},
|
||||
],
|
||||
data: list.value,
|
||||
minHeight: 240,
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
keyField: 'id',
|
||||
},
|
||||
showOverflow: true,
|
||||
toolbarConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
} as VxeTableGridOptions<MesCalTeamMemberApi.TeamMember>,
|
||||
});
|
||||
|
||||
/** 加载成员列表 */
|
||||
async function getList() {
|
||||
gridApi.setLoading(true);
|
||||
try {
|
||||
list.value = await getTeamMemberListByTeam(props.teamId);
|
||||
gridApi.setGridOptions({ data: list.value });
|
||||
} finally {
|
||||
gridApi.setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开成员表单 */
|
||||
async function openForm() {
|
||||
formOpen.value = true;
|
||||
await formApi.resetForm();
|
||||
await formApi.setValues({ teamId: props.teamId });
|
||||
}
|
||||
|
||||
/** 提交成员表单 */
|
||||
async function submitForm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesCalTeamMemberApi.TeamMember;
|
||||
await createTeamMember(data);
|
||||
formOpen.value = false;
|
||||
ElMessage.success($t('ui.actionMessage.operationSuccess'));
|
||||
await getList();
|
||||
} finally {
|
||||
formLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除成员 */
|
||||
async function handleDelete(id: number) {
|
||||
await deleteTeamMember(id);
|
||||
ElMessage.success($t('ui.actionMessage.deleteSuccess', ['成员']));
|
||||
await getList();
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.teamId,
|
||||
(value) => {
|
||||
if (value) {
|
||||
getList();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isEditable" class="mb-3 flex items-center justify-start">
|
||||
<TableAction :actions="[{ label: '添加成员', type: 'primary', onClick: openForm }]" />
|
||||
</div>
|
||||
<Grid class="w-full">
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '删除',
|
||||
type: 'danger',
|
||||
link: true,
|
||||
popConfirm: {
|
||||
title: '确认删除该成员吗?',
|
||||
confirm: handleDelete.bind(null, row.id!),
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
|
||||
<ElDialog v-model="formOpen" title="添加成员" width="520px">
|
||||
<Form class="mx-4" />
|
||||
<template #footer>
|
||||
<ElButton @click="formOpen = false">取消</ElButton>
|
||||
<ElButton type="primary" :loading="formLoading" @click="submitForm">确定</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
Loading…
Reference in New Issue