import { computed, ref } from "vue";
import {
getEquipNameToDeptMap,
getDeptByEquipName,
clearequipCache
} from "@/service/api/"; // 根据实际路径调整
/**
* 设备部门映射钩子
* 提供设备名称到部门的映射关系操作
*/
export function useEquipequip() {
// 加载状态
const loading = ref(false);
// 错误信息
const error = ref<Error | null>(null);
// 设备名称到部门的映射
const nameToequipMap = ref<Record<string, string>>({});
// 设备选项列表(新增)
const equipOptions = ref<{ label: string; value: string }[]>([]);
// 搜索查询(新增)
const equipSearchQuery = ref("");
// 计算过滤后的设备选项(新增)
const filteredequipOptions = computed(() => {
if (!equipSearchQuery.value) return equipOptions.value;
const query = equipSearchQuery.value.toLowerCase();
return equipOptions.value.filter(option =>
option.label.toLowerCase().includes(query)
);
});
// 处理设备搜索(新增)
const handleequipSearch = (query: string) => {
equipSearchQuery.value = query;
};
/**
* 加载设备映射关系
* @param forceRefresh 是否强制刷新缓存
*/
const loadEquipMap = async (forceRefresh: boolean = false) => {
try {
loading.value = true;
error.value = null;
nameToequipMap.value = await getEquipNameToDeptMap(forceRefresh);
// 生成设备选项列表(新增)
equipOptions.value = Object.keys(nameToequipMap.value).map(name => ({
label: name,
value: name
}));
} catch (err) {
console.error('加载设备映射失败:', err);
error.value = err as Error;
} finally {
loading.value = false;
}
};
/**
* 根据设备名称获取部门
* @param equipName 设备名称
* @returns 对应的部门值
*/
const getequip = async (equipName: string): Promise<string | undefined> => {
// 如果本地已有映射,直接使用
if (nameToequipMap.value[equipName]) {
return nameToequipMap.value[equipName];
}
// 否则从API获取
try {
loading.value = true;
return await getDeptByEquipName(equipName);
} catch (err) {
console.error('获取设备部门失败:', err);
error.value = err as Error;
return undefined;
} finally {
loading.value = false;
}
};
/**
* 刷新设备映射缓存
*/
const refreshCache = () => {
clearequipCache();
loadEquipMap(true);
};
// 返回钩子方法和状态
return {
loading,
error,
nameToequipMap,
equipOptions, // 新增
filteredequipOptions, // 新增
equipSearchQuery, // 新增
loadEquipMap,
getequip,
refreshCache,
handleequipSearch // 新增
};
}
根据这个hook修改下面代码,实现编辑和克隆时,带出已有信息,并在设备选择与部门自动填充功能
<script setup lang="ts">
import { computed, reactive, ref, watch } from "vue";
import { useFormRules, useNaiveForm } from "@/hooks/common/form";
import { fetchAddInterlock, fetchUpdateInterlock, } from "@/service/api";
import { $t } from "@/locales";
import {
lockTypesOptions,
logLevelTypeOptions,
moduleTypesOptions,
} from "@/constants/business";
import { translateOptions } from "@/utils/common";
import { NSelect } from "naive-ui";
import { useEquipequip } from "@/hooks/common/useEquipment";
defineOptions({
name: "LedgerOperateDrawer",
});
interface Props {
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
rowData?: Api.InterLock.Ledger | null;
}
const props = defineProps<Props>();
interface Emits {
(e: "submitted"): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>("visible", {
default: false,
});
// 设备搜索查询
const equipSearchQuery = ref("");
const { formRef, validate, restoreValidation } = useNaiveForm();
const { defaultRequiredRule } = useFormRules();
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: $t("common.add"),
edit: $t("common.edit"),
clone: $t("common.clone"),
};
return titles[props.operateType];
});
const model: Api.InterLock.LedgerUpdateParams = reactive(createDefaultModel());
function createDefaultModel(): Api.InterLock.LedgerAddParams {
return {
alarmName: "",
lockType: "sinterlock",
moduleName: "",
moduleType: "",
product: "",
deptName: "",
trigger: "",
channelNumber: "",
triggerWay: "",
alarmDesc: "",
alarmLevel: "INFO",
alarmDetail: "",
alarmAction: "",
alarmChannel: "",
alarmActionDesc: "",
condition: "",
desc: "",
};
}
type RuleKey = Extract<
keyof Api.InterLock.LedgerUpdateParams,
| "alarmName"
| "lockType"
| "moduleName"
| "moduleType"
| "product"
>;
const rules = ref<Record<RuleKey, App.Global.FormRule>>({
alarmName: defaultRequiredRule,
lockType: defaultRequiredRule,
moduleName: defaultRequiredRule,
moduleType: defaultRequiredRule,
product: defaultRequiredRule,
});
// 设备选择变化处理
const handleProductChange = async (productName: string) => {
if (productName) {
// 获取设备对应的部门
const dept = await getDept(productName);
model.deptName = dept || "";
} else {
model.deptName = "";
}
};
function handleInitModel() {
Object.assign(model, createDefaultModel());
const operateTypes = ["edit", "clone"];
if (operateTypes.includes(props.operateType) && props.rowData) {
Object.assign(model, props.rowData);
// 编辑模式:如果已有设备名称,自动填充部门
if (props.rowData.product) {
// 使用异步方式获取部门(确保设备列表已加载)
setTimeout(async () => {
const dept = await getDept(props.rowData!.product);
model.deptName = dept || "";
}, 100);
}
}
}
function closeDrawer() {
visible.value = false;
}
async function handleSubmit() {
await validate();
// request
// 提交前确保部门信息已设置
if (model.product && !model.deptName) {
const dept = await getDept(model.product);
model.deptName = dept || "";
}
if (props.operateType === "add" || props.operateType === "clone") {
const { error } = await fetchAddInterlock(model);
if (!error) {
window.$message?.success($t("common.addSuccess"));
}
} else if (props.operateType === "edit") {
const { error } = await fetchUpdateInterlock(model);
if (!error) {
window.$message?.success($t("common.updateSuccess"));
}
}
closeDrawer();
emit("submitted");
}
watch(visible, () => {
if (visible.value) {
handleInitModel();
restoreValidation();
}
});
</script>
<template>
<NDrawer v-model:show="visible" display-directive="show" :width="360">
<NDrawerContent :title="title" :native-scrollbar="false" closable>
<NForm ref="formRef" :model="model" :rules="rules">
<NFormItem
:label="$t('page.interlock.ledger.alarmName')"
path="alarmName"
>
<NInput
v-model:value="model.alarmName"
:placeholder="$t('page.interlock.ledger.form.alarmName')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.lockType')"
path="lockType"
>
<NSelect
v-model:value="model.lockType"
:options="translateOptions(lockTypesOptions)"
size="small"
class="w-120px"
/>
</NFormItem>
<NFormItem :label="$t('page.interlock.ledger.product')" path="product">
<!-- <NInput
v-model:value="model.product"
:placeholder="$t('page.interlock.ledger.form.product')"
/> -->
<NSelect
v-model:value="model.product"
filterable
clearable
:placeholder="$t('page.interlock.ledger.form.product')"
:options="filteredequipOptions"
:loading="Loading"
:remote="true"
@update:value="handleProductChange"
@search="handleequipSearch"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.moduleName')"
path="moduleName"
>
<NInput
v-model:value="model.moduleName"
:placeholder="$t('page.interlock.ledger.form.moduleName')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.moduleType')"
path="moduleType"
>
<NSelect
v-model:value="model.moduleType"
:options="translateOptions(moduleTypesOptions)"
size="small"
class="w-120px"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.deptName')"
path="deptName"
>
<NInput
v-model:value="model.deptName"
:placeholder="$t('page.interlock.ledger.form.deptName')"
/>
</NFormItem>
<NFormItem :label="$t('page.interlock.ledger.trigger')" path="trigger">
<NInput
v-model:value="model.trigger"
:placeholder="$t('page.interlock.ledger.form.trigger')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.triggerWay')"
path="triggerWay"
>
<NInput
v-model:value="model.triggerWay"
:placeholder="$t('page.interlock.ledger.form.triggerWay')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.alarmDesc')"
path="alarmDesc"
>
<NInput
v-model:value="model.alarmDesc"
:placeholder="$t('page.interlock.ledger.form.alarmDesc')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.alarmLevel')"
path="alarmLevel"
>
<NSelect
v-model:value="model.alarmLevel"
:options="translateOptions(logLevelTypeOptions)"
size="small"
class="w-120px"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.alarmAction')"
path="alarmAction"
>
<NInput
v-model:value="model.alarmAction"
:placeholder="$t('page.interlock.ledger.form.alarmAction')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.alarmChannel')"
path="alarmChannel"
>
<NInput
v-model:value="model.alarmChannel"
:placeholder="$t('page.interlock.ledger.form.alarmChannel')"
/>
</NFormItem>
<NFormItem
:label="$t('page.interlock.ledger.channelNumber')"
path="channelNumber"
>
<NInput
v-model:value="model.channelNumber"
:placeholder="$t('page.interlock.ledger.form.channelNumber')"
/>
</NFormItem>
<NFormItem :label="$t('page.interlock.ledger.alarmActionDesc')">
<NInput
v-model:value="model.alarmActionDesc"
:placeholder="$t('page.interlock.ledger.form.alarmActionDesc')"
/>
</NFormItem>
<NFormItem :label="$t('page.interlock.ledger.condition')">
<NInput
v-model:value="model.condition"
:placeholder="$t('page.interlock.ledger.form.condition')"
/>
</NFormItem>
<NFormItem :label="$t('page.interlock.ledger.desc')">
<NInput
v-model:value="model.desc"
:placeholder="$t('page.interlock.ledger.form.desc')"
/>
</NFormItem>
</NForm>
<template #footer>
<NSpace :size="16">
<NButton @click="closeDrawer">{{ $t("common.cancel") }}</NButton>
<NButton type="primary" @click="handleSubmit">{{
$t("common.confirm")
}}</NButton>
</NSpace>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped></style>