170 lines
5.0 KiB
Vue
170 lines
5.0 KiB
Vue
<!--
|
||
功能:承载资源详情页中的审核、流转、归属调整和菜单分配等短业务操作。
|
||
版本:v1.0.0
|
||
-->
|
||
<template>
|
||
<a-modal
|
||
:visible="visible"
|
||
:title="action?.name"
|
||
:width="680"
|
||
:ok-loading="submitting"
|
||
:ok-button-props="{ status: action?.danger ? 'danger' : 'normal' }"
|
||
@cancel="close"
|
||
@ok="submit"
|
||
>
|
||
<a-alert v-if="action?.danger" class="action-alert" type="error" show-icon>
|
||
这是高风险操作,可能改变业务状态且无法直接撤销。请确认目标记录和填写内容准确。
|
||
</a-alert>
|
||
<a-alert v-if="isOwnershipAction" class="action-alert" type="warning" show-icon>
|
||
智能气阀只能有一个当前归属。选择新归属前请清空原归属,操作会写入审计记录。
|
||
</a-alert>
|
||
<a-form :model="form" layout="vertical">
|
||
<ResourceFieldForm
|
||
v-model="form"
|
||
:fields="action?.fields ?? []"
|
||
:required-keys="requiredKeys"
|
||
:relation-options="relations.options"
|
||
:relation-loading="relations.loading"
|
||
@search-relation="searchRelation"
|
||
/>
|
||
</a-form>
|
||
</a-modal>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { Message } from '@arco-design/web-vue';
|
||
import { computed, reactive, ref, watch } from 'vue';
|
||
import { buildResourcePayload, isMissingField } from '@/api/resource-form';
|
||
import { resourceApi } from '@/api/resource';
|
||
import { platformApi } from '@/api/platform';
|
||
import type { DetailAction, ResourceField } from '@/api/resources';
|
||
import type { ResourceRow } from '@/api/resource-page-rules';
|
||
import ResourceFieldForm from './ResourceFieldForm.vue';
|
||
import { useResourceRelations } from './use-resource-relations';
|
||
|
||
const props = defineProps<{
|
||
visible: boolean;
|
||
action?: DetailAction;
|
||
identity: string;
|
||
record: ResourceRow;
|
||
}>();
|
||
const emit = defineEmits<{
|
||
'update:visible': [value: boolean];
|
||
completed: [];
|
||
}>();
|
||
const form = reactive<Record<string, any>>({});
|
||
const submitting = ref(false);
|
||
const relations = useResourceRelations();
|
||
const requiredKeys = computed(() =>
|
||
(props.action?.fields ?? [])
|
||
.filter((field) => field.required)
|
||
.map((field) => field.key),
|
||
);
|
||
const isOwnershipAction = computed(
|
||
() => props.action?.resource === '/product_info/:identity',
|
||
);
|
||
const ownershipKeys = [
|
||
'warehouse_identity',
|
||
'gas_basic_identity',
|
||
'delivery_basic_identity',
|
||
'user_account_identity',
|
||
];
|
||
|
||
/** 业务动作字段不启用记录页联动,只沿用普通关联搜索。 */
|
||
function searchRelation(field: ResourceField, keyword: string) {
|
||
relations.searchField(field, keyword);
|
||
}
|
||
|
||
watch(
|
||
() => [props.visible, props.action?.name] as const,
|
||
async ([visible]) => {
|
||
if (!visible || !props.action) return;
|
||
for (const field of props.action.fields ?? []) {
|
||
form[field.key] = isOwnershipAction.value
|
||
? props.record[field.key]
|
||
: undefined;
|
||
}
|
||
await relations.preload(props.action.fields ?? []);
|
||
if (props.action.resource.includes('/menu')) {
|
||
try {
|
||
const [menus, assigned] = await Promise.all([
|
||
platformApi.listMenu(),
|
||
platformApi.listRoleMenuIdentities(props.identity),
|
||
]);
|
||
relations.options['/platform_menu'] = menus.list;
|
||
form.menu_identities = assigned.menu_identities;
|
||
} catch (error) {
|
||
Message.error((error as Error).message);
|
||
close();
|
||
}
|
||
}
|
||
},
|
||
);
|
||
|
||
function close() {
|
||
emit('update:visible', false);
|
||
}
|
||
|
||
async function submit() {
|
||
const action = props.action;
|
||
if (!action) return;
|
||
if (
|
||
(action.fields ?? []).some(
|
||
(field) => field.required && isMissingField(form[field.key]),
|
||
)
|
||
) {
|
||
Message.warning('请填写必填字段');
|
||
return;
|
||
}
|
||
const invalidPassword = (action.fields ?? []).find(
|
||
(field) =>
|
||
field.type === 'password' &&
|
||
!isMissingField(form[field.key]) &&
|
||
String(form[field.key]).length < 6,
|
||
);
|
||
if (invalidPassword) {
|
||
Message.warning(`${invalidPassword.label}长度不能少于 6 位`);
|
||
return;
|
||
}
|
||
if (isOwnershipAction.value) {
|
||
const selected = ownershipKeys.filter((key) => !isMissingField(form[key]));
|
||
if (selected.length > 1) {
|
||
Message.warning('智能气阀只能选择一个当前归属');
|
||
return;
|
||
}
|
||
}
|
||
submitting.value = true;
|
||
try {
|
||
const payload = buildResourcePayload(action.fields ?? [], form, 'create');
|
||
if (isOwnershipAction.value) {
|
||
for (const key of ownershipKeys) payload[key] = String(form[key] ?? '');
|
||
}
|
||
if (action.resource.includes('/menu')) {
|
||
await platformApi.replaceRoleMenus(
|
||
props.identity,
|
||
payload.menu_identities as string[],
|
||
);
|
||
} else {
|
||
await resourceApi.action(
|
||
action.resource.replace(':identity', props.identity),
|
||
action.method ?? 'POST',
|
||
payload,
|
||
);
|
||
}
|
||
Message.success('操作成功');
|
||
close();
|
||
emit('completed');
|
||
} catch (error) {
|
||
Message.error((error as Error).message);
|
||
} finally {
|
||
submitting.value = false;
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.action-alert {
|
||
margin-bottom: 16px;
|
||
}
|
||
</style>
|