|
@@ -0,0 +1,429 @@
|
|
|
+<!--<script setup lang="ts">-->
|
|
|
+
|
|
|
+<!--</script>-->
|
|
|
+
|
|
|
+<!--<template>-->
|
|
|
+
|
|
|
+<!--</template>-->
|
|
|
+
|
|
|
+<!--<style scoped lang="scss">-->
|
|
|
+
|
|
|
+<!--</style>-->
|
|
|
+<template>
|
|
|
+ <div class="app-container p-2">
|
|
|
+ <el-row :gutter="20" class="mb8" style="margin-top: 5px">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-upload class="upload-demo" :http-request="handleFileUpload" :before-upload="beforeUpload" :file-list="fileList" accept=".xlsx, .xls">
|
|
|
+ <template #trigger>
|
|
|
+ <el-button size="big" type="primary">选择Excel文件</el-button>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" @click="handleNewTemplate">空白模板</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" @click="handleNewTemplate">重新加载</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" @click="handleSaveTemporarily(1)">暂存</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" @click="handleSave(formRef,2)"> 发布 </el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="danger" @click="handleReturn()"> 返回 </el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-form :model="form" :rules="rules" ref="formRef">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :lg="30" :xs="24" style="margin-top: -10px">
|
|
|
+ <el-row :span="24" :gutter="10">
|
|
|
+ <!-- 联系人姓名 -->
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="联系人姓名:" prop="creator_name" label-width="auto">
|
|
|
+ <el-input v-model="form.creator_name" placeholder="请输入联系人姓名" style="width: 300px"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <!-- 联系电话 -->
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="联 系 电 话:" prop="creator_phone" label-width="auto">
|
|
|
+ <el-input v-model="form.creator_phone" placeholder="请输入联系电话" style="width: 300px"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <!-- 截止时间 -->
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="截 止 时 间 :" prop="end_time">
|
|
|
+ <el-date-picker v-model="form.end_time" value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm" type="datetime" placeholder="选择截止时间" style="width: 300px" @change="handleTimeChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="表           名:" prop="table_name" label-width="auto">
|
|
|
+ <el-input v-model="form.table_name" placeholder="请输入表名" style="width: 300px"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <!-- 选择填报人 -->
|
|
|
+ <el-col :span="16">
|
|
|
+ <el-form-item label="选择填报人:" prop="user_ids" label-width="auto" style="font-weight: bold;">
|
|
|
+ <div>
|
|
|
+ <el-tag
|
|
|
+ v-for="tag in selectedReporter"
|
|
|
+ :key="tag"
|
|
|
+ closable
|
|
|
+ :disable-transitions="false"
|
|
|
+ @close="handleClose(tag)"
|
|
|
+ style="margin-right: 10px"
|
|
|
+ >
|
|
|
+ {{ tag.label }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <el-button @click="showSelect">点击选择</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <!-- <el-col :span="8">-->
|
|
|
+ <!-- <el-button type="primary" @click="handleReport()"> 智能识别 </el-button>-->
|
|
|
+ <!-- </el-col>-->
|
|
|
+ </el-row>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div style="height: 350px">
|
|
|
+ <hot-table v-if="showTable" ref="wrapper" :data="hotData" :settings="hotSettings" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <informantSelect
|
|
|
+ v-model="isShowSelect"
|
|
|
+ :tree-data="treeData"
|
|
|
+ :default-check-data="selectContactSelectData"
|
|
|
+ @confirm="handleContactSelectData" />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted, ref } from 'vue';
|
|
|
+import { ElButton, ElCol, ElDatePicker, ElFormItem, ElInput, ElOption, ElRow, ElSelect, ElTable, ElTableColumn } from 'element-plus';
|
|
|
+import * as XLSX from 'xlsx';
|
|
|
+import { fillingAdd, fillingList } from '@/api/dataFilling/fillingManage';
|
|
|
+import { HotTable } from '@handsontable/vue3';
|
|
|
+import Handsontable from 'handsontable';
|
|
|
+import 'handsontable/languages';
|
|
|
+import 'handsontable/dist/handsontable.full.css';
|
|
|
+import { registerAllModules } from 'handsontable/registry';
|
|
|
+import informantSelect from './informantSelect.vue'
|
|
|
+import { getPhoneList } from '@/api/informationissue/informationissue';
|
|
|
+import { deepClone } from '@/utils';
|
|
|
+import { createWarehousingEntry } from '@/api/comprehensiveGuarantee/materialReserveManagement/InboundManagement';
|
|
|
+import { validatePhone } from '@/utils/validate';
|
|
|
+registerAllModules();
|
|
|
+
|
|
|
+const props = defineProps<{
|
|
|
+ id: string | number;
|
|
|
+}>();
|
|
|
+const fileList = ref([]);
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+const emits = defineEmits(['close','confirm']);
|
|
|
+const formRef = ref('');
|
|
|
+const detailData = ref({
|
|
|
+ title: '表单数据',
|
|
|
+ start: '2024-10-15 17:02:22',
|
|
|
+ end: '2024-10-15 18:00:00'
|
|
|
+});
|
|
|
+const hotData = ref([]);
|
|
|
+const field_names = ref([]);
|
|
|
+const selectedReporter = ref(null);
|
|
|
+const isShowSelect = ref(false);
|
|
|
+let treeData = ref([]);
|
|
|
+
|
|
|
+// 初始化表格数据
|
|
|
+onMounted(() => {
|
|
|
+ fetchTreeData();
|
|
|
+ fetchData();
|
|
|
+});
|
|
|
+
|
|
|
+const showTable = ref(false);
|
|
|
+const handleNewTemplate = () => {
|
|
|
+ showTable.value = true;
|
|
|
+ created();
|
|
|
+};
|
|
|
+
|
|
|
+const form = ref({
|
|
|
+ table_name: "",
|
|
|
+ end_time: "",
|
|
|
+ status: "0",
|
|
|
+ issued_status: "",
|
|
|
+ period_type: "",
|
|
|
+ creator_name: "",
|
|
|
+ creator_phone: "",
|
|
|
+ field_names: [],
|
|
|
+ user_ids: []
|
|
|
+})
|
|
|
+const rules = {
|
|
|
+ table_name: [{ required: true, message: '表名不能为空', trigger: 'blur' }],
|
|
|
+ end_time: [{ required: true, message: '截止时间不能为空', trigger: 'blur' }],
|
|
|
+ creator_name: [{ required: true, message: '联系人姓名不能为空', trigger: 'blur' }],
|
|
|
+ creator_phone: [
|
|
|
+ { required: true, message: '联系电话不能为空', trigger: 'blur' },
|
|
|
+ { validator: validatePhone, message: '请输入正确格式的联系电话', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ user_ids: [{ required: true, message: '请选择填报人', trigger: 'blur' }],
|
|
|
+}
|
|
|
+const handleSaveTemporarily = async (statuCode) => {
|
|
|
+ if (hotData.value && hotData.value[0] && hotData.value[0].length > 0) {
|
|
|
+ const data2 = [];
|
|
|
+ hotData.value[0].forEach((item) => {
|
|
|
+ if (!!item) {
|
|
|
+ data2.push(item);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ form.value.field_names = data2;
|
|
|
+ }
|
|
|
+ form.value.issued_status = statuCode;
|
|
|
+ fillingAdd(form.value).then(() => {
|
|
|
+ proxy.$modal.msgSuccess('暂存成功');
|
|
|
+ emits('close');
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleSave = async (formEl,statuCode) => {
|
|
|
+ if (!formEl) return;
|
|
|
+ await formEl.validate((valid, fields) => {
|
|
|
+ if (valid) {
|
|
|
+ const data2 = [];
|
|
|
+ hotData.value[0].forEach((item) => {
|
|
|
+ if (!!item) {
|
|
|
+ data2.push(item);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ form.value.field_names = data2;
|
|
|
+ form.value.issued_status = statuCode;
|
|
|
+ fillingAdd(form.value).then((res) => {
|
|
|
+ proxy.$modal.msgSuccess('发布成功');
|
|
|
+ emits('close');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ nextTick(() => {
|
|
|
+ let isError = document.getElementsByClassName('is-error');
|
|
|
+ isError[0].scrollIntoView({
|
|
|
+ // 滚动到指定节点
|
|
|
+ // 值有start,center,end,nearest,当前显示在视图区域中间
|
|
|
+ block: 'center',
|
|
|
+ // 值有auto、instant,smooth,缓动动画(当前是慢速的)
|
|
|
+ behavior: 'smooth'
|
|
|
+ });
|
|
|
+ });
|
|
|
+ proxy.$modal.msgError('表单校验失败');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+const handleReturn = () => {
|
|
|
+ emits('close');
|
|
|
+};
|
|
|
+
|
|
|
+const created = () => {
|
|
|
+ let data = [];
|
|
|
+ for (let i = 0; i < 10; i++) {
|
|
|
+ let arr = [];
|
|
|
+ for (let x = 0; x < 10; x++) {
|
|
|
+ arr.push('');
|
|
|
+ }
|
|
|
+ data.push(arr);
|
|
|
+ }
|
|
|
+ showTable.value = false;
|
|
|
+ nextTick(() => {
|
|
|
+ hotData.value = data;
|
|
|
+ showTable.value = true;
|
|
|
+ });
|
|
|
+};
|
|
|
+const hotSettings = reactive({
|
|
|
+ language: 'zh-CN',
|
|
|
+ colHeaders: true,
|
|
|
+ rowHeaders: true,
|
|
|
+ autoColumnSize: true,
|
|
|
+ width: '100%', // auto or 100%
|
|
|
+ height: '100%', // auto or 100%
|
|
|
+ licenseKey: 'non-commercial-and-evaluation', // 隐藏版权文字
|
|
|
+ colWidths: 129, // 默认单元格宽度
|
|
|
+ rowHeights: 28, // 默认单元格高度
|
|
|
+ wordWrap: true, // 单元格文字是否换行展示
|
|
|
+ contextMenu: {
|
|
|
+ // 自定义右键菜单
|
|
|
+ items: {
|
|
|
+ 'row_above': {
|
|
|
+ name: '向上插一行'
|
|
|
+ },
|
|
|
+ 'row_below': {
|
|
|
+ name: '向下插一行'
|
|
|
+ },
|
|
|
+ 'col_left': {
|
|
|
+ name: '向左插一列'
|
|
|
+ },
|
|
|
+ 'col_right': {
|
|
|
+ name: '向右插一列'
|
|
|
+ },
|
|
|
+ 'hsep1': '---------', // 分隔线
|
|
|
+ 'remove_row': {
|
|
|
+ name: '删除当前行'
|
|
|
+ },
|
|
|
+ 'remove_col': {
|
|
|
+ name: '删除当前列'
|
|
|
+ },
|
|
|
+ 'clear_column': {
|
|
|
+ name: '清空当前列'
|
|
|
+ },
|
|
|
+ 'hsep2': '---------', // 必须和上次的变量名不一样
|
|
|
+ 'undo': {
|
|
|
+ name: '撤销'
|
|
|
+ },
|
|
|
+ 'cut': {
|
|
|
+ name: '剪切'
|
|
|
+ },
|
|
|
+ 'copy': {
|
|
|
+ name: '复制'
|
|
|
+ },
|
|
|
+ 'alignment': {
|
|
|
+ name: '对齐'
|
|
|
+ },
|
|
|
+ 'hsep3': '---------',
|
|
|
+ 'commentsAddEdit': {
|
|
|
+ // 必须开启 comments: true
|
|
|
+ name: '添加备注'
|
|
|
+ },
|
|
|
+ 'commentsRemove': {
|
|
|
+ // 必须开启 comments: true
|
|
|
+ name: '删除备注'
|
|
|
+ },
|
|
|
+ 'freeze_column': {
|
|
|
+ // 必须开启 manualColumnFreeze: true
|
|
|
+ name: '固定列'
|
|
|
+ },
|
|
|
+ 'unfreeze_column': {
|
|
|
+ // 必须开启 manualColumnFreeze: true
|
|
|
+ name: '取消固定列'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+const beforeUpload = (file) => {
|
|
|
+ const isExcel = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.type === 'application/vnd.ms-excel';
|
|
|
+ if (!isExcel) {
|
|
|
+ proxy.$modal.msgError('只能上传xlsx/xls文件!');
|
|
|
+ }
|
|
|
+ return isExcel;
|
|
|
+};
|
|
|
+const handleFileUpload = ({ file }) => {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (event) => {
|
|
|
+ showTable.value = false;
|
|
|
+ nextTick(() => {
|
|
|
+ const data = new Uint8Array(event.target.result);
|
|
|
+ const workbook = XLSX.read(data, { type: 'array' });
|
|
|
+ const firstSheetName = workbook.SheetNames[0];
|
|
|
+ const worksheet = workbook.Sheets[firstSheetName];
|
|
|
+ const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
|
|
|
+ hotData.value = jsonData.slice(1); // 假设第一行是标题行,我们跳过它
|
|
|
+ showTable.value = true;
|
|
|
+ });
|
|
|
+ };
|
|
|
+ reader.readAsArrayBuffer(file);
|
|
|
+ fileList.value = [];
|
|
|
+ return { success: true, file }; // 告诉 el-upload 上传成功(尽管实际上没有发送到服务器)
|
|
|
+};
|
|
|
+
|
|
|
+const showSelect = () => {
|
|
|
+ isShowSelect.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+const fetchTreeData = async () => {
|
|
|
+ try {
|
|
|
+ const response = await getPhoneList({});
|
|
|
+ if (response && response.data) {
|
|
|
+ treeData.value = response.data;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Failed to fetch information:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const selectContactSelectData = ref([]);
|
|
|
+const handleContactSelectData = (data) => {
|
|
|
+ console.log('handleContactSelectData:', data);
|
|
|
+ selectContactSelectData.value = data;
|
|
|
+ // data.user_ids = data;
|
|
|
+ selectedReporter.value = data;
|
|
|
+ const data1 = [];
|
|
|
+ selectContactSelectData.value.forEach((item) => {
|
|
|
+ data1.push(item.id);
|
|
|
+ })
|
|
|
+ form.value.user_ids = data1;
|
|
|
+};
|
|
|
+
|
|
|
+const handleClose = (tag: string) => {
|
|
|
+ selectedReporter.value.splice(selectedReporter.value.indexOf(tag), 1)
|
|
|
+}
|
|
|
+
|
|
|
+const fetchData = () => {
|
|
|
+ fillingList(props.id).then((res) => {
|
|
|
+ form.value.creator_name = res.report_info.creator_name;
|
|
|
+ form.value.creator_phone = res.report_info.creator_phone;
|
|
|
+ form.value.end_time = res.report_info.end_time;
|
|
|
+ form.value.table_name = res.report_info.table_name;
|
|
|
+ form.value.user_ids = res.report_info.user_ids;
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
|
+ -webkit-font-smoothing: antialiased;
|
|
|
+ -moz-osx-font-smoothing: grayscale;
|
|
|
+ text-align: center;
|
|
|
+ color: #2c3e50;
|
|
|
+}
|
|
|
+.report-period {
|
|
|
+ margin-top: 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+.editable-span {
|
|
|
+ cursor: pointer;
|
|
|
+ display: inline-block;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+.editable-span[contenteditable='true'] {
|
|
|
+ white-space: normal;
|
|
|
+ outline: none; /* 移除编辑时的焦点边框 */
|
|
|
+}
|
|
|
+.editable-span[contenteditable='true']:empty::before {
|
|
|
+ content: attr(data-placeholder); /* 可选:为空时显示占位符 */
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.editable-header {
|
|
|
+ cursor: pointer;
|
|
|
+ display: inline-block;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+.editable-header[contenteditable='true'] {
|
|
|
+ white-space: normal;
|
|
|
+ outline: none; /* 移除编辑时的焦点边框 */
|
|
|
+}
|
|
|
+.editable-header[contenteditable='true']:empty::before {
|
|
|
+ content: attr(data-placeholder); /* 可选:为空时显示占位符 */
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.upload-demo {
|
|
|
+ display: inline-block;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+.flex {
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+</style>
|