fabulous_front/src/components/PatrolSetting/AddTemplateDialog.vue

373 lines
12 KiB
Vue

<template>
<el-dialog
:model-value="visible"
title="新增樣板"
modal-penetrable
style="max-width: 800px; width: 90%"
@close="onClose"
>
<!-- 通用對話框 -->
<VerificationSettingDialog
v-model:visible="dialogVisibility.verification"
@add="(item) => addItem('verification', item)"
/>
<InspectionItemDialog
v-model:visible="dialogVisibility.inspection"
@add="(item) => addItem('inspection', item)"
/>
<CheckItemsDialog
v-model:visible="dialogVisibility.checkItems"
@add="(item) => addItem('checkItems', item)"
/>
<el-form :model="form">
<el-divider content-position="left">樣板資訊</el-divider>
<el-row :gutter="20">
<el-col :xs="24" :sm="12">
<el-form-item label="電廠">
<el-select v-model="form.factory" placeholder="請選擇電廠">
<el-option label="四磺子坪" value="四磺子坪" />
<el-option label="硫磺子坪" value="硫磺子坪" />
<el-option label="大清水" value="大清水" />
<el-option label="小清水" value="小清水" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12">
<el-form-item label="模板">
<el-select v-model="form.template" placeholder="請選擇模板類型">
<el-option label="巡檢表" value="1" />
<el-option label="點檢表" value="2" />
<el-option label="高壓特每日自動檢查表" value="3" />
<el-option label="高壓特每月自動檢查表" value="4" />
<el-option label="一班作業安全許可申請表" value="5" />
<el-option label="侷限作業安全許可申請表" value="6" />
<el-option label="動火作業安全許可申請表" value="7" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12">
<el-form-item label="母版">
<el-select v-model="form.isParent" placeholder="請選擇">
<el-option label="是" value="是" />
<el-option label="否" value="否" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24">
<el-form-item label="樣板名稱">
<el-input
v-model="form.templateName"
placeholder="請輸入樣板名稱"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24">
<el-form-item label="備註">
<el-input
v-model="form.remark"
placeholder="請輸入備註"
type="textarea"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 動態渲染樣板內容欄位 -->
<template v-if="activeSchema">
<template v-for="section in activeSchema.sections" :key="section.title">
<el-divider content-position="left">{{ section.title }}</el-divider>
<el-row :gutter="20">
<el-col
v-for="field in section.fields"
:key="field.key"
:xs="24"
:sm="field.span"
>
<el-form-item :label="field.label">
<!-- 下拉選單 -->
<el-select
v-if="field.type === 'select'"
v-model="form[field.key]"
:placeholder="`請選擇${field.label}`"
>
<el-option
v-for="option in field.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
<!-- 多行文本 -->
<el-input
v-else-if="field.type === 'textarea'"
v-model="form[field.key]"
type="textarea"
:rows="3"
:placeholder="`請輸入${field.label}`"
/>
<!-- 一般文本輸入 -->
<el-input
v-else
v-model="dynamicFields[field.key]"
:placeholder="`請輸入${field.label}`"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 動態渲染表格 -->
<template v-for="table in activeSchema.tables" :key="table.key">
<el-row :align="'middle'" justify="space-between">
<h3>{{ table.title }}</h3>
<el-button
type="primary"
size="small"
@click="openDialog(table.dialogType)"
>
{{ table.addButtonText }}
</el-button>
</el-row>
<!-- 使用分頁表格或一般表格 -->
<PaginatedTable
v-if="table.usePagination"
:data="dynamicTableData[table.key] || []"
:page-sizes="[5, 10]"
row-key="index"
>
<el-table-column
v-for="column in table.columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
/>
<el-table-column label="功能" width="140" fixed="right">
<template #default="scope">
<el-button size="small" type="primary" plain>修改</el-button>
<el-button
size="small"
type="danger"
plain
@click="deleteItem(table.key, scope.$index)"
>
刪除
</el-button>
</template>
</el-table-column>
</PaginatedTable>
<el-table
v-else
:data="dynamicTableData[table.key] || []"
:border="true"
>
<el-table-column
v-for="column in table.columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
/>
<el-table-column
label="功能"
min-width="80"
width="140"
fixed="right"
>
<template #default="scope">
<el-button size="small" type="primary" plain>修改</el-button>
<el-button
size="small"
type="danger"
plain
@click="deleteItem(table.key, scope.$index)"
>
刪除
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<!-- 動態渲染驗證區塊 -->
<template v-if="activeSchema.verification?.enabled">
<el-divider content-position="left">樣板查證</el-divider>
<el-row :align="'middle'" justify="space-between">
<h3>{{ activeSchema.verification.title }}</h3>
<el-button
type="primary"
size="small"
@click="openDialog(activeSchema.verification.dialogType)"
>
{{ activeSchema.verification.addButtonText }}
</el-button>
</el-row>
<el-table :data="dynamicTableData.verification || []" :border="true">
<el-table-column
v-for="column in activeSchema.verification.columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
/>
<el-table-column
label="功能"
min-width="80"
width="140"
fixed="right"
>
<template #default="scope">
<el-button size="small" type="primary" plain>修改</el-button>
<el-button
size="small"
type="danger"
plain
@click="deleteItem('verification', scope.$index)"
>
刪除
</el-button>
</template>
</el-table-column>
</el-table>
</template>
</template>
</el-form>
<template #footer>
<el-button @click="onClose">取消</el-button>
<el-button type="primary" @click="onConfirm">確定</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch, reactive } from "vue";
import PaginatedTable from "../Common/PaginatedTable.vue";
import VerificationSettingDialog from "./VerificationSettingDialog.vue";
import InspectionItemDialog from "./InspectionItemDialog.vue";
import CheckItemsDialog from "./CheckItemsDialog.vue";
import {
getTemplateSchema,
initializeTableData,
initializeFieldData,
} from "../../constants/templateSchemas.js";
const props = defineProps({
visible: { type: Boolean, default: false },
form: { type: Object, required: true },
});
const emit = defineEmits(["update:visible", "confirm", "close"]);
// 當前模板的 schema
const activeSchema = computed(() => {
const schema = getTemplateSchema(props.form.template);
if (!schema) return null;
// 過濾只顯示於樣板的內容
return {
...schema,
sections: schema.sections?.filter(s => s.showInTemplate !== false) || [],
tables: schema.tables?.filter(t => t.showInTemplate !== false) || [],
verification: schema.verification, // 查證始終顯示
};
});
// 動態欄位資料
const dynamicFields = reactive({});
// 動態表格資料
const dynamicTableData = reactive({});
// 對話框顯示狀態
const dialogVisibility = reactive({
dutyLog: false,
handover: false,
inspection: false,
verification: false,
checkItems: false,
});
// 監聽模板類型變化,重新初始化資料
watch(
() => props.form.template,
(newTemplate) => {
if (!newTemplate) return;
const schema = getTemplateSchema(newTemplate);
if (!schema) return;
// 重置動態欄位
Object.keys(dynamicFields).forEach((key) => delete dynamicFields[key]);
Object.assign(dynamicFields, initializeFieldData(schema));
// 重置動態表格
Object.keys(dynamicTableData).forEach(
(key) => delete dynamicTableData[key]
);
Object.assign(dynamicTableData, initializeTableData(schema));
}
);
// 打開對話框
function openDialog(dialogType) {
if (dialogType === "dutyLog") {
dialogVisibility.dutyLog = true;
} else if (dialogType === "handover") {
dialogVisibility.handover = true;
} else if (dialogType === "inspection") {
dialogVisibility.inspection = true;
} else if (dialogType === "verification") {
dialogVisibility.verification = true;
} else if (dialogType === "checkItems") {
dialogVisibility.checkItems = true;
}
// 其他 dialogType 可以根據需要擴展
}
// 通用新增項目方法
function addItem(tableKey, item) {
if (!dynamicTableData[tableKey]) {
dynamicTableData[tableKey] = [];
}
const arr = dynamicTableData[tableKey];
arr.push({ index: arr.length + 1, ...item });
}
// 刪除項目
function deleteItem(tableKey, index) {
if (dynamicTableData[tableKey]) {
dynamicTableData[tableKey].splice(index, 1);
// 重新計算項次
dynamicTableData[tableKey].forEach((item, idx) => {
item.index = idx + 1;
});
}
}
function onClose() {
emit("update:visible", false);
emit("close");
}
function onConfirm() {
// 可以在這裡整合 dynamicFields 和 dynamicTableData 到 form
const templateData = {
...props.form,
fields: dynamicFields,
tables: dynamicTableData,
};
emit("confirm", templateData);
}
</script>
<style scoped>
.el-divider--horizontal {
margin-top: 30px;
margin-bottom: 20px;
}
</style>