|
|
@@ -1,67 +1,1012 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
+ <!-- 按钮区 -->
|
|
|
+ <header class="cf-header">
|
|
|
+ <el-button type="primary" @click="onADD">新增</el-button>
|
|
|
+ <el-button type="primary" :disabled="selectionRows.length === 0" @click="onDel">删除</el-button>
|
|
|
+ </header>
|
|
|
+
|
|
|
<el-container>
|
|
|
- <el-aside width="200px">
|
|
|
+ <el-aside width="260px">
|
|
|
<div class="JKWTree-tree">
|
|
|
- <h3> 客户反馈与投诉记录</h3>
|
|
|
- <el-tree :data="treeData" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
|
|
|
+ <h3>客户反馈与投诉记录</h3>
|
|
|
+ <el-tree
|
|
|
+ :data="treeData"
|
|
|
+ :props="defaultProps"
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ :expand-on-click-node="false"
|
|
|
+ node-key="label"
|
|
|
+ default-expand-all
|
|
|
+ ></el-tree>
|
|
|
</div>
|
|
|
</el-aside>
|
|
|
<el-container>
|
|
|
-
|
|
|
<el-main>
|
|
|
+ <el-table
|
|
|
+ ref="multipleTable"
|
|
|
+ style="width: 100%; height: 45vh"
|
|
|
+ tooltip-effect="dark"
|
|
|
+ :row-style="{ height: '25px' }"
|
|
|
+ :header-cell-style="{ padding: '0px' }"
|
|
|
+ :cell-style="{ padding: '0px' }"
|
|
|
+ :header-row-style="{ height: '22px' }"
|
|
|
+ :data="tableData"
|
|
|
+ border
|
|
|
+ row-key="UniqID"
|
|
|
+ size="small"
|
|
|
+ highlight-current-row="true"
|
|
|
+ @row-click="tableRowClick"
|
|
|
+ @row-dblclick="onEdit"
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="45" align="center" />
|
|
|
+ <el-table-column sortable align="center" label="客诉单号" prop="客诉单号" width="120" />
|
|
|
+ <el-table-column sortable align="center" label="客诉日期" prop="客诉日期" width="120" />
|
|
|
+ <el-table-column sortable align="center" label="客诉方式" prop="客诉方式" width="100" />
|
|
|
+ <el-table-column sortable align="center" label="订单编号" prop="订单编号" width="120" />
|
|
|
+ <el-table-column sortable align="center" label="产品编号" prop="产品编号" width="100" />
|
|
|
+ <el-table-column sortable align="center" label="产品名称" prop="产品名称" width="200" />
|
|
|
+ <el-table-column sortable align="center" label="客户编号" prop="客户编号" width="100" />
|
|
|
+ <el-table-column sortable align="center" label="客户名称" prop="客户名称" width="160" />
|
|
|
+ <el-table-column sortable align="center" label="客诉描述" prop="客诉描述" min-width="260" />
|
|
|
+ <el-table-column sortable align="center" label="缺陷关键字" prop="缺陷关键字" width="120" />
|
|
|
+ <el-table-column sortable align="center" label="客诉性质" prop="客诉性质" width="100" />
|
|
|
+ <el-table-column sortable align="center" label="扣分" prop="扣分" width="70" />
|
|
|
+ <el-table-column sortable align="center" label="主要责任部门" prop="主要责任部门" width="160" />
|
|
|
+ <el-table-column sortable align="center" label="次要责任部门" prop="次要责任部门" width="160" />
|
|
|
+ <!-- <el-table-column sortable align="center" label="负责人A" prop="负责人A" width="130" />
|
|
|
+ <el-table-column sortable align="center" label="负责人B" prop="负责人B" width="130" />
|
|
|
+ <el-table-column sortable align="center" label="关闭状态" prop="关闭状态" width="100" /> -->
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- ============ 下方 Tab:处理环节记录 / 相关整改附件 ============ -->
|
|
|
+ <el-tabs v-model="bottomTab" type="card" style="margin-top: 8px;" @tab-click="onBottomTabClick">
|
|
|
+ <el-tab-pane label="处理环节记录" name="flow">
|
|
|
+ <div style="display: flex; gap: 6px; margin-bottom: 6px;">
|
|
|
+ <el-button size="small" type="primary" @click="onFlowAdd">新增环节</el-button>
|
|
|
+ <el-button size="small" type="danger" :disabled="flowSelection.length === 0" @click="onFlowDel">删除</el-button>
|
|
|
+ <span style="margin-left: auto; color: #909399; font-size: 12px;" v-if="!currentRow">请先在上方选择一条客诉记录</span>
|
|
|
+ </div>
|
|
|
+ <el-table
|
|
|
+ :data="flowList"
|
|
|
+ border
|
|
|
+ size="small"
|
|
|
+ style="height: 200px;"
|
|
|
+ :header-row-style="{ height: '22px' }"
|
|
|
+ :row-style="{ height: '23px' }"
|
|
|
+ @selection-change="(rows) => { flowSelection = rows }"
|
|
|
+ row-key="UniqId"
|
|
|
+ highlight-current-row
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="40" align="center" />
|
|
|
+ <el-table-column type="index" label="序号" width="55" align="center" />
|
|
|
+ <el-table-column label="操作者" prop="操作者" width="120" />
|
|
|
+ <el-table-column label="处理环节" prop="处理环节" width="120" />
|
|
|
+ <el-table-column label="备注说明" prop="备注说明" />
|
|
|
+ <el-table-column label="建档人" prop="sys_id" width="100" />
|
|
|
+ <el-table-column label="建档时间" prop="sys_rq" width="160" />
|
|
|
+ <el-table-column label="修改时间" prop="mod_rq" width="160" />
|
|
|
+ </el-table>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="相关整改附件" name="attachment">
|
|
|
+ <div style="display: flex; gap: 6px; margin-bottom: 6px;">
|
|
|
+ <el-button size="small" type="primary" @click="onAttachmentAdd">新增附件</el-button>
|
|
|
+ <el-button size="small" type="danger" :disabled="attSelection.length === 0" @click="onAttachmentDel">删除</el-button>
|
|
|
+ <span style="margin-left: auto; color: #909399; font-size: 12px;" v-if="!currentRow">请先在上方选择一条客诉记录</span>
|
|
|
+ </div>
|
|
|
+ <el-table
|
|
|
+ :data="attachmentList"
|
|
|
+ border
|
|
|
+ size="small"
|
|
|
+ style="height: 200px;"
|
|
|
+ :header-row-style="{ height: '22px' }"
|
|
|
+ :row-style="{ height: '23px' }"
|
|
|
+ @selection-change="(rows) => { attSelection = rows }"
|
|
|
+ row-key="UniqId"
|
|
|
+ highlight-current-row
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="40" align="center" />
|
|
|
+ <el-table-column type="index" label="序号" width="55" align="center" />
|
|
|
+ <el-table-column label="名称及路径" prop="名称及路径" min-width="200" show-overflow-tooltip />
|
|
|
+ <el-table-column label="修订日期" prop="修订日期" width="160" />
|
|
|
+ <el-table-column label="附件类型" prop="附件类型" width="90" />
|
|
|
+ <el-table-column label="建档人" prop="sys_id" width="100" />
|
|
|
+ <el-table-column label="建档时间" prop="sys_rq" width="160" />
|
|
|
+ <el-table-column label="修改时间" prop="mod_rq" width="160" />
|
|
|
+ </el-table>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
</el-main>
|
|
|
</el-container>
|
|
|
</el-container>
|
|
|
+
|
|
|
+ <!-- ============ 新增/修改 弹窗 ============ -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="formVisible"
|
|
|
+ :title="isEdit ? '修改客诉记录' : '新增客诉记录'"
|
|
|
+ width="800px"
|
|
|
+ destroy-on-close
|
|
|
+ @close="closeForm"
|
|
|
+ @opened="onFormOpened"
|
|
|
+ >
|
|
|
+ <el-form :model="formData" ref="formRef" label-width="95px" size="default">
|
|
|
+ <!-- 第一行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="客诉单号">
|
|
|
+ <el-input
|
|
|
+ id="f_客诉单号"
|
|
|
+ v-model="formData.客诉单号"
|
|
|
+ placeholder="如 / 则留空"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客诉单号')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="10">
|
|
|
+ <el-form-item label="客诉日期">
|
|
|
+ <el-input
|
|
|
+ id="f_客诉日期"
|
|
|
+ v-model="formData.客诉日期"
|
|
|
+ placeholder="回车为当天"
|
|
|
+ readonly
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客诉日期')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label="方式">
|
|
|
+ <el-input
|
|
|
+ id="f_客诉方式"
|
|
|
+ v-model="formData.客诉方式"
|
|
|
+ placeholder="回车选择"
|
|
|
+ readonly
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客诉方式')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第二行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="订单编号">
|
|
|
+ <el-input
|
|
|
+ id="f_订单编号"
|
|
|
+ v-model="formData.订单编号"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_订单编号')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="5">
|
|
|
+ <el-form-item label="产品编号">
|
|
|
+ <el-input
|
|
|
+ id="f_产品编号"
|
|
|
+ v-model="formData.产品编号"
|
|
|
+ placeholder="回车选产品"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_产品编号')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="11">
|
|
|
+ <el-form-item label="产品名称">
|
|
|
+ <el-input
|
|
|
+ id="f_产品名称"
|
|
|
+ v-model="formData.产品名称"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_产品名称')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第三行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="5">
|
|
|
+ <el-form-item label="客户编号">
|
|
|
+ <el-input
|
|
|
+ id="f_客户编号"
|
|
|
+ v-model="formData.客户编号"
|
|
|
+ placeholder="回车选客户"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客户编号')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="11">
|
|
|
+ <el-form-item label="客户名称">
|
|
|
+ <el-input
|
|
|
+ id="f_客户名称"
|
|
|
+ v-model="formData.客户名称"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客户名称')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第四行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="反馈问题">
|
|
|
+ <el-input
|
|
|
+ id="f_客诉描述"
|
|
|
+ v-model="formData.客诉描述"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入反馈问题"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客诉描述')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第五行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="10">
|
|
|
+ <el-form-item label="缺陷关键字">
|
|
|
+ <el-input
|
|
|
+ id="f_缺陷关键字"
|
|
|
+ v-model="formData.缺陷关键字"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_缺陷关键字')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label="性质">
|
|
|
+ <el-input
|
|
|
+ id="f_客诉性质"
|
|
|
+ v-model="formData.客诉性质"
|
|
|
+ placeholder="回车选择"
|
|
|
+ readonly
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_客诉性质')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="扣分">
|
|
|
+ <el-input
|
|
|
+ id="f_扣分"
|
|
|
+ v-model.number="formData.扣分"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_扣分')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第六行 -->
|
|
|
+ <el-row :gutter="15">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="主责部门">
|
|
|
+ <el-input
|
|
|
+ id="f_主要责任部门"
|
|
|
+ v-model="formData.主要责任部门"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_主要责任部门')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="次责部门">
|
|
|
+ <el-input
|
|
|
+ id="f_次要责任部门"
|
|
|
+ v-model="formData.次要责任部门"
|
|
|
+ @keydown="(e) => handleFieldKeydown(e, 'f_次要责任部门')"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="formVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="onSubmit">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 方式 选择小弹窗 ============ -->
|
|
|
+ <el-dialog v-model="wayVisible" title="选择方式" width="300px" @opened="onWayOpened">
|
|
|
+ <div style="display: flex; justify-content: space-around; padding: 20px 0;">
|
|
|
+ <el-button id="way_书面" @click="selectWay('书面')">书面</el-button>
|
|
|
+ <el-button id="way_口头" @click="selectWay('口头')">口头</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 性质 选择小弹窗 ============ -->
|
|
|
+ <el-dialog v-model="natureVisible" title="选择性质" width="300px" @opened="onNatureOpened">
|
|
|
+ <div style="display: flex; justify-content: space-around; padding: 20px 0;">
|
|
|
+ <el-button @click="selectNature('A类')">A类</el-button>
|
|
|
+ <el-button @click="selectNature('B类')">B类</el-button>
|
|
|
+ <el-button @click="selectNature('C类')">C类</el-button>
|
|
|
+ <el-button @click="selectNature('D类')">D类</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 产品编号 选择弹窗 ============ -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="productModal"
|
|
|
+ title="查询产品名称 (输入) 按 Enter 搜索"
|
|
|
+ width="720px"
|
|
|
+ @opened="onProductModalOpened"
|
|
|
+ @close="closeProductModal"
|
|
|
+ @keydown="handleProductModalKeydown"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="productKeyword"
|
|
|
+ placeholder="输入关键字后回车搜索"
|
|
|
+ @keyup.enter="loadProductList"
|
|
|
+ ref="productKeywordInput"
|
|
|
+ />
|
|
|
+ <el-table
|
|
|
+ ref="productTableRef"
|
|
|
+ :data="productList"
|
|
|
+ border
|
|
|
+ style="margin-top: 10px; height: 360px;"
|
|
|
+ highlight-current-row
|
|
|
+ @row-click="pickProduct"
|
|
|
+ @row-dblclick="pickProduct"
|
|
|
+ row-key="产品编号"
|
|
|
+ >
|
|
|
+ <el-table-column prop="产品编号" label="产品编号" width="160" />
|
|
|
+ <el-table-column prop="产品名称" label="产品名称" />
|
|
|
+ </el-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="productModal = false">放弃</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 客户编号 选择弹窗 ============ -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="clientModal"
|
|
|
+ title="查询客户编号 (输入) 按 Enter 搜索"
|
|
|
+ width="620px"
|
|
|
+ @opened="onClientModalOpened"
|
|
|
+ @close="closeClientModal"
|
|
|
+ @keydown="handleClientModalKeydown"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="clientKeyword"
|
|
|
+ placeholder="输入关键字后回车搜索"
|
|
|
+ @keyup.enter="loadClientList"
|
|
|
+ ref="clientKeywordInput"
|
|
|
+ />
|
|
|
+ <el-table
|
|
|
+ ref="clientTableRef"
|
|
|
+ :data="clientList"
|
|
|
+ border
|
|
|
+ style="margin-top: 10px; height: 360px;"
|
|
|
+ highlight-current-row
|
|
|
+ @row-click="pickClient"
|
|
|
+ @row-dblclick="pickClient"
|
|
|
+ row-key="客户编号"
|
|
|
+ >
|
|
|
+ <el-table-column prop="客户编号" label="客户编号" width="160" />
|
|
|
+ <el-table-column prop="客户名称" label="客户名称" />
|
|
|
+ </el-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="clientModal = false">放弃</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 新增处理环节 弹窗 ============ -->
|
|
|
+ <el-dialog v-model="flowFormVisible" title="新增处理环节" width="480px" destroy-on-close>
|
|
|
+ <el-form :model="flowForm" label-width="80px">
|
|
|
+ <el-form-item label="操作者">
|
|
|
+ <el-input v-model="flowForm.操作者" readonly />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="处理环节">
|
|
|
+ <el-select v-model="flowForm.处理环节" placeholder="请选择处理环节" style="width: 100%;">
|
|
|
+ <el-option label="客诉发起" value="客诉发起" />
|
|
|
+ <el-option label="客诉处理中" value="客诉处理中" />
|
|
|
+ <el-option label="处理完毕" value="处理完毕" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注说明">
|
|
|
+ <el-input v-model="flowForm.备注说明" type="textarea" :rows="3" placeholder="请输入备注说明" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="flowFormVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="onFlowSubmit">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- ============ 新增整改附件 弹窗 ============ -->
|
|
|
+ <el-dialog v-model="attFormVisible" title="新增整改附件" width="480px" destroy-on-close>
|
|
|
+ <el-form :model="attForm" label-width="80px">
|
|
|
+ <el-form-item label="名称及路径">
|
|
|
+ <el-input v-model="attForm.名称及路径" placeholder="选择文件后自动填充" readonly />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="附件类型">
|
|
|
+ <el-input v-model="attForm.附件类型" placeholder="如 PDF/DOC/XLSX" readonly />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="选择文件">
|
|
|
+ <input type="file" @change="onAttachmentFileChange" style="width: 100%;" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="attFormVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="onAttachmentSubmit">确定上传</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
+
|
|
|
<script setup>
|
|
|
-import {
|
|
|
- getDepartment,
|
|
|
- getMachineInfo
|
|
|
-} from '@/api/mes/job'
|
|
|
-import {
|
|
|
- createCompany,
|
|
|
- deleteCompany,
|
|
|
- deleteCompanyByIds,
|
|
|
- updateCompany,
|
|
|
- findCompany,
|
|
|
- getCompanyList
|
|
|
-} from '@/api/company'
|
|
|
-// 全量引入格式化工具 请按需保留
|
|
|
-import { getDictFunc, formatDate, formatBoolean, filterDict, ReturnArrImg, onDownloadFile } from '@/utils/format'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import { ref, reactive } from 'vue'
|
|
|
+import { ref, reactive, onMounted, nextTick } from 'vue'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { ClientList, ProductCodeList } from '@/api/yunyin/yunying'
|
|
|
import { useUserStore } from '@/pinia/modules/user'
|
|
|
+import {
|
|
|
+ getCustomerFeedbackTab,
|
|
|
+ getCustomerFeedbackList,
|
|
|
+ addCustomerFeedback,
|
|
|
+ editCustomerFeedback,
|
|
|
+ delCustomerFeedback,
|
|
|
+ getCustomerFeedbackFlowList,
|
|
|
+ addCustomerFeedbackFlow,
|
|
|
+ delCustomerFeedbackFlow,
|
|
|
+ getCustomerFeedbackAttachmentList,
|
|
|
+ addCustomerFeedbackAttachment,
|
|
|
+ delCustomerFeedbackAttachment
|
|
|
+} from '@/api/mes/job'
|
|
|
+
|
|
|
+defineOptions({ name: 'Customerfeedback' })
|
|
|
+
|
|
|
const userStore = useUserStore()
|
|
|
-const sys_id='['+userStore.userInfo.userName+'/'+userStore.userInfo.nickName+']'
|
|
|
-defineOptions({
|
|
|
- name: 'Company'
|
|
|
+const _username = ref('')
|
|
|
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
|
|
|
+
|
|
|
+// =========== 左侧树 ===========
|
|
|
+const treeData = ref([])
|
|
|
+const defaultProps = { children: 'children', label: 'label' }
|
|
|
+
|
|
|
+const getMenuData = async () => {
|
|
|
+ try {
|
|
|
+ const response = await getCustomerFeedbackTab()
|
|
|
+ if (response.code === 0) treeData.value = response.data
|
|
|
+ } catch (error) { console.error(error) }
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 右侧表格 ===========
|
|
|
+const tableData = reactive([])
|
|
|
+const selectionRows = ref([])
|
|
|
+const lastLoadParams = ref({})
|
|
|
+
|
|
|
+const loadList = async (params = {}) => {
|
|
|
+ lastLoadParams.value = params
|
|
|
+ try {
|
|
|
+ const response = await getCustomerFeedbackList(params)
|
|
|
+ if (response.code === 0) {
|
|
|
+ tableData.splice(0, tableData.length, ...(response.data || []))
|
|
|
+ }
|
|
|
+ } catch (error) { console.error(error) }
|
|
|
+}
|
|
|
+
|
|
|
+const handleNodeClick = async (node) => {
|
|
|
+ if (!node.type) return
|
|
|
+ await loadList({ type: node.type, code: node.code || '', name: node.name || '' })
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 当前选中的主表行 ===========
|
|
|
+const currentRow = ref(null)
|
|
|
+
|
|
|
+// =========== 下方 Tab ===========
|
|
|
+const bottomTab = ref('flow')
|
|
|
+const flowList = ref([])
|
|
|
+const attachmentList = ref([])
|
|
|
+const flowSelection = ref([])
|
|
|
+const attSelection = ref([])
|
|
|
+
|
|
|
+const tableRowClick = (row) => {
|
|
|
+ currentRow.value = row
|
|
|
+ if (bottomTab.value === 'flow') {
|
|
|
+ loadFlowList()
|
|
|
+ } else {
|
|
|
+ loadAttachmentList()
|
|
|
+ }
|
|
|
+}
|
|
|
+const handleSelectionChange = (rows) => { selectionRows.value = rows }
|
|
|
+
|
|
|
+const onBottomTabClick = () => {
|
|
|
+ if (!currentRow.value) return
|
|
|
+ if (bottomTab.value === 'flow') {
|
|
|
+ loadFlowList()
|
|
|
+ } else {
|
|
|
+ loadAttachmentList()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const loadFlowList = async () => {
|
|
|
+ if (!currentRow.value) return
|
|
|
+ try {
|
|
|
+ const res = await getCustomerFeedbackFlowList({ RelationID: currentRow.value.UniqID })
|
|
|
+ if (res.code === 0) flowList.value = res.data || []
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+const loadAttachmentList = async () => {
|
|
|
+ if (!currentRow.value) return
|
|
|
+ try {
|
|
|
+ const res = await getCustomerFeedbackAttachmentList({ relationId: currentRow.value.UniqID })
|
|
|
+ if (res.code === 0) attachmentList.value = res.data || []
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 处理环节:新增 / 删除 ===========
|
|
|
+const flowFormVisible = ref(false)
|
|
|
+const flowForm = reactive({ 操作者: '', 处理环节: '', 备注说明: '' })
|
|
|
+
|
|
|
+const onFlowAdd = () => {
|
|
|
+ if (!currentRow.value) { ElMessage.warning('请先选择主表记录'); return }
|
|
|
+ // 操作者默认当前登录人(账号/姓名),无需手填;处理环节从下拉选择
|
|
|
+ Object.assign(flowForm, { 操作者: _username.value, 处理环节: '', 备注说明: '' })
|
|
|
+ flowFormVisible.value = true
|
|
|
+}
|
|
|
+const onFlowSubmit = async () => {
|
|
|
+ if (!flowForm.处理环节) { ElMessage.warning('请选择处理环节'); return }
|
|
|
+ try {
|
|
|
+ const res = await addCustomerFeedbackFlow({
|
|
|
+ RelationID: currentRow.value.UniqID,
|
|
|
+ 操作者: flowForm.操作者,
|
|
|
+ 处理环节: flowForm.处理环节,
|
|
|
+ 备注说明: flowForm.备注说明,
|
|
|
+ sys_id: userStore.userInfo.userName
|
|
|
+ })
|
|
|
+ if (res.code === 0) {
|
|
|
+ ElMessage.success('新增成功')
|
|
|
+ flowFormVisible.value = false
|
|
|
+ await loadFlowList()
|
|
|
+ // 若标记为处理完毕,该客诉应从处理中客诉移除,同步刷新主表与左侧树
|
|
|
+ if (flowForm.处理环节 === '处理完毕') {
|
|
|
+ await loadList(lastLoadParams.value)
|
|
|
+ await getMenuData()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '新增失败')
|
|
|
+ }
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+const onFlowDel = async () => {
|
|
|
+ if (flowSelection.value.length === 0) return
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确定删除选中的 ${flowSelection.value.length} 条环节记录吗?`, '提示', { type: 'warning' })
|
|
|
+ for (const row of flowSelection.value) {
|
|
|
+ await delCustomerFeedbackFlow({ UniqId: row.UniqId })
|
|
|
+ }
|
|
|
+ ElMessage.success('删除成功')
|
|
|
+ await loadFlowList()
|
|
|
+ } catch (_) {}
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 整改附件:新增 / 删除 ===========
|
|
|
+const attFormVisible = ref(false)
|
|
|
+const attForm = reactive({ 名称及路径: '', 附件类型: '', 附件内容: null })
|
|
|
+
|
|
|
+const onAttachmentAdd = () => {
|
|
|
+ if (!currentRow.value) { ElMessage.warning('请先选择主表记录'); return }
|
|
|
+ Object.assign(attForm, { 名称及路径: '', 附件类型: '', 附件内容: null })
|
|
|
+ attFormVisible.value = true
|
|
|
+}
|
|
|
+const onAttachmentFileChange = (event) => {
|
|
|
+ const file = event.target.files[0]
|
|
|
+ if (!file) return
|
|
|
+ attForm.附件内容 = file
|
|
|
+ attForm.名称及路径 = file.name
|
|
|
+ // 根据扩展名推断附件类型
|
|
|
+ const ext = file.name.split('.').pop().toUpperCase()
|
|
|
+ attForm.附件类型 = ext.length <= 5 ? ext : 'FILE'
|
|
|
+}
|
|
|
+const onAttachmentSubmit = async () => {
|
|
|
+ if (!attForm.附件内容) { ElMessage.warning('请选择文件'); return }
|
|
|
+ try {
|
|
|
+ // FileReader 读 base64
|
|
|
+ const dataUrl = await new Promise((resolve, reject) => {
|
|
|
+ const fr = new FileReader()
|
|
|
+ fr.onload = () => resolve(fr.result)
|
|
|
+ fr.onerror = reject
|
|
|
+ fr.readAsDataURL(attForm.附件内容)
|
|
|
+ })
|
|
|
+ const fd = new FormData()
|
|
|
+ fd.append('relationId', currentRow.value.UniqID)
|
|
|
+ fd.append('名称及路径', attForm.名称及路径)
|
|
|
+ fd.append('附件类型', attForm.附件类型)
|
|
|
+ fd.append('附件内容', dataUrl)
|
|
|
+ fd.append('sys_id', userStore.userInfo.userName)
|
|
|
+
|
|
|
+ const res = await addCustomerFeedbackAttachment(fd)
|
|
|
+ if (res.code === 0) {
|
|
|
+ ElMessage.success('上传成功')
|
|
|
+ attFormVisible.value = false
|
|
|
+ await loadAttachmentList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '上传失败')
|
|
|
+ }
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+const onAttachmentDel = async () => {
|
|
|
+ if (attSelection.value.length === 0) return
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确定删除选中的 ${attSelection.value.length} 个附件吗?`, '提示', { type: 'warning' })
|
|
|
+ for (const row of attSelection.value) {
|
|
|
+ await delCustomerFeedbackAttachment({ UniqId: row.UniqId })
|
|
|
+ }
|
|
|
+ ElMessage.success('删除成功')
|
|
|
+ await loadAttachmentList()
|
|
|
+ } catch (_) {}
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await getMenuData()
|
|
|
+ await loadList()
|
|
|
})
|
|
|
|
|
|
+// =========== 表单 字段 顺序 ===========
|
|
|
+// 控制上下左右和回车的跳转
|
|
|
+const fieldOrder = [
|
|
|
+ 'f_客诉单号', 'f_客诉日期', 'f_客诉方式',
|
|
|
+ 'f_订单编号', 'f_产品编号', 'f_产品名称',
|
|
|
+ 'f_客户编号', 'f_客户名称',
|
|
|
+ 'f_客诉描述',
|
|
|
+ 'f_缺陷关键字', 'f_客诉性质', 'f_扣分',
|
|
|
+ 'f_主要责任部门', 'f_次要责任部门'
|
|
|
+]
|
|
|
+
|
|
|
+const focusField = async (id) => {
|
|
|
+ await nextTick()
|
|
|
+ const el = document.getElementById(id)
|
|
|
+ if (el) {
|
|
|
+ el.focus()
|
|
|
+ // 全选文本方便直接输入
|
|
|
+ try { el.select() } catch (_) {}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 表单字段键盘处理
|
|
|
+ * - 回车:若是日期→填当天;若是方式→打开方式弹窗;若是产品编号→产品弹窗;若是客户编号→客户弹窗;若是性质→性质弹窗;否则跳到下一个字段
|
|
|
+ * - 下/右箭头:跳到下一个字段
|
|
|
+ * - 上/左箭头:跳到上一个字段
|
|
|
+ */
|
|
|
+const handleFieldKeydown = (e, currentId) => {
|
|
|
+ // textarea 里上下左右正常操作,不拦截(但 Enter 仍要跳转,除非按住 Shift)
|
|
|
+ const isTextarea = e.target && e.target.tagName === 'TEXTAREA'
|
|
|
+
|
|
|
+ if (e.key === 'Enter') {
|
|
|
+ e.preventDefault()
|
|
|
+ // 特殊字段:弹选择弹窗
|
|
|
+ if (currentId === 'f_客诉日期') {
|
|
|
+ formData.客诉日期 = dayjs().format('YYYY.MM.DD')
|
|
|
+ nextField(currentId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currentId === 'f_客诉方式') {
|
|
|
+ wayVisible.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currentId === 'f_客诉性质') {
|
|
|
+ natureVisible.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currentId === 'f_产品编号') {
|
|
|
+ openProductModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currentId === 'f_客户编号') {
|
|
|
+ openClientModal()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (currentId === 'f_客诉描述' && e.shiftKey) return // Shift+Enter 在 textarea 里换行
|
|
|
+ if (currentId === 'f_客诉描述') return // 普通 Enter 在 textarea 里换行
|
|
|
+ nextField(currentId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isTextarea) return
|
|
|
+
|
|
|
+ if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
|
|
|
+ e.preventDefault()
|
|
|
+ nextField(currentId)
|
|
|
+ } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
|
|
|
+ e.preventDefault()
|
|
|
+ prevField(currentId)
|
|
|
+ } else if (e.key === 'Tab') {
|
|
|
+ // Tab 默认行为即可
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const nextField = (currentId) => {
|
|
|
+ const idx = fieldOrder.indexOf(currentId)
|
|
|
+ if (idx >= 0 && idx < fieldOrder.length - 1) {
|
|
|
+ focusField(fieldOrder[idx + 1])
|
|
|
+ }
|
|
|
+}
|
|
|
+const prevField = (currentId) => {
|
|
|
+ const idx = fieldOrder.indexOf(currentId)
|
|
|
+ if (idx > 0) {
|
|
|
+ focusField(fieldOrder[idx - 1])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 新增/修改 ===========
|
|
|
+const formVisible = ref(false)
|
|
|
+const isEdit = ref(false)
|
|
|
+const formData = reactive(createEmptyForm())
|
|
|
+
|
|
|
+function createEmptyForm() {
|
|
|
+ return {
|
|
|
+ UniqID: null,
|
|
|
+ 客诉单号: '/',
|
|
|
+ 客诉日期: dayjs().format('YYYY.MM.DD'),
|
|
|
+ 客诉方式: '',
|
|
|
+ 订单编号: '',
|
|
|
+ 产品编号: '',
|
|
|
+ 产品名称: '',
|
|
|
+ 客户编号: '',
|
|
|
+ 客户名称: '',
|
|
|
+ 客诉描述: '',
|
|
|
+ 缺陷关键字: '',
|
|
|
+ 客诉性质: '',
|
|
|
+ 扣分: 0,
|
|
|
+ 主要责任部门: '',
|
|
|
+ 次要责任部门: '',
|
|
|
+ // 左侧树按 Sys_id(建档人)分组,新增时默认当前登录人(账号/姓名)
|
|
|
+ Sys_id: _username.value,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onADD = () => {
|
|
|
+ Object.assign(formData, createEmptyForm())
|
|
|
+ isEdit.value = false
|
|
|
+ formVisible.value = true
|
|
|
+}
|
|
|
+const onEdit = (row) => {
|
|
|
+ Object.assign(formData, createEmptyForm(), row)
|
|
|
+ isEdit.value = true
|
|
|
+ formVisible.value = true
|
|
|
+}
|
|
|
+const closeForm = () => { formVisible.value = false }
|
|
|
+
|
|
|
+// 弹窗打开后自动聚焦第一个字段
|
|
|
+const onFormOpened = async () => {
|
|
|
+ await nextTick()
|
|
|
+ focusField('f_客诉单号')
|
|
|
+}
|
|
|
+
|
|
|
+const onDel = async () => {
|
|
|
+ if (selectionRows.value.length === 0) {
|
|
|
+ ElMessage.warning('请选择要删除的记录')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确定删除选中的 ${selectionRows.value.length} 条记录吗?`, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ const ids = selectionRows.value.map(r => r.UniqID)
|
|
|
+ const res = await delCustomerFeedback({ ids })
|
|
|
+ if (res.code === 0) {
|
|
|
+ ElMessage.success('删除成功')
|
|
|
+ await loadList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '删除失败')
|
|
|
+ }
|
|
|
+ } catch (_) {}
|
|
|
+}
|
|
|
+
|
|
|
+const onSubmit = async () => {
|
|
|
+ if (!formData.客诉日期) {
|
|
|
+ formData.客诉日期 = dayjs().format('YYYY.MM.DD')
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const res = isEdit.value
|
|
|
+ ? await editCustomerFeedback(formData)
|
|
|
+ : await addCustomerFeedback(formData)
|
|
|
+ if (res.code === 0) {
|
|
|
+ ElMessage.success(isEdit.value ? '修改成功' : '新增成功')
|
|
|
+ formVisible.value = false
|
|
|
+ await loadList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '操作失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error)
|
|
|
+ ElMessage.error('网络错误')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 方式 选择 ===========
|
|
|
+const wayVisible = ref(false)
|
|
|
+const selectWay = (val) => {
|
|
|
+ formData.客诉方式 = val
|
|
|
+ wayVisible.value = false
|
|
|
+ nextTick(() => focusField('f_订单编号'))
|
|
|
+}
|
|
|
+const onWayOpened = async () => {
|
|
|
+ await nextTick()
|
|
|
+ // 默认聚焦当前值,否则聚焦第一个
|
|
|
+ const cur = formData.客诉方式
|
|
|
+ const target = cur === '口头' ? document.getElementById('way_口头') : document.getElementById('way_书面')
|
|
|
+ if (target) target.focus()
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 性质 选择 ===========
|
|
|
+const natureVisible = ref(false)
|
|
|
+const selectNature = (val) => {
|
|
|
+ formData.客诉性质 = val
|
|
|
+ natureVisible.value = false
|
|
|
+ nextTick(() => focusField('f_扣分'))
|
|
|
+}
|
|
|
+const onNatureOpened = async () => {
|
|
|
+ await nextTick()
|
|
|
+ // 让弹窗能接受键盘
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 产品编号 弹窗 ===========
|
|
|
+const productModal = ref(false)
|
|
|
+const productKeyword = ref('')
|
|
|
+const productList = ref([])
|
|
|
+const productHighlightIndex = ref(-1)
|
|
|
+const productTableRef = ref(null)
|
|
|
+
|
|
|
+const openProductModal = async () => {
|
|
|
+ productKeyword.value = formData.产品编号 || ''
|
|
|
+ productModal.value = true
|
|
|
+}
|
|
|
+const onProductModalOpened = async () => {
|
|
|
+ await loadProductList()
|
|
|
+ await nextTick()
|
|
|
+ // 聚焦搜索框
|
|
|
+ const input = document.querySelector('.product-search-input') || document.activeElement
|
|
|
+ // 让第一个搜索框拿到焦点
|
|
|
+ const inputs = document.querySelectorAll('.el-dialog__body .el-input__inner')
|
|
|
+ if (inputs && inputs.length) inputs[0].focus()
|
|
|
+}
|
|
|
+const closeProductModal = () => {
|
|
|
+ productHighlightIndex.value = -1
|
|
|
+ productList.value = []
|
|
|
+}
|
|
|
+const loadProductList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await ProductCodeList({ cilent: productKeyword.value })
|
|
|
+ productList.value = res.data || []
|
|
|
+ productHighlightIndex.value = productList.value.length > 0 ? 0 : -1
|
|
|
+ await nextTick()
|
|
|
+ if (productTableRef.value && productHighlightIndex.value >= 0) {
|
|
|
+ productTableRef.value.setCurrentRow(productList.value[0])
|
|
|
+ }
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+const pickProduct = (row) => {
|
|
|
+ formData.产品编号 = row.产品编号
|
|
|
+ formData.产品名称 = row.产品名称
|
|
|
+ productModal.value = false
|
|
|
+ nextTick(() => focusField('f_客户编号'))
|
|
|
+}
|
|
|
+const handleProductModalKeydown = (e) => {
|
|
|
+ // 拦截弹窗内部的 方向键 / 回车 / Esc
|
|
|
+ if (e.key === 'Escape') {
|
|
|
+ productModal.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (productList.value.length === 0) return
|
|
|
+
|
|
|
+ if (e.key === 'ArrowDown') {
|
|
|
+ e.preventDefault()
|
|
|
+ productHighlightIndex.value = Math.min(productHighlightIndex.value + 1, productList.value.length - 1)
|
|
|
+ productTableRef.value?.setCurrentRow(productList.value[productHighlightIndex.value])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (e.key === 'ArrowUp') {
|
|
|
+ e.preventDefault()
|
|
|
+ productHighlightIndex.value = Math.max(productHighlightIndex.value - 1, 0)
|
|
|
+ productTableRef.value?.setCurrentRow(productList.value[productHighlightIndex.value])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (e.key === 'Enter') {
|
|
|
+ // 搜索框里的回车已经由 @keyup.enter 处理,只有不在搜索框里时才选行
|
|
|
+ const isInInput = e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA')
|
|
|
+ if (isInInput && e.target.value === productKeyword.value) return // 就是刚刚搜索完
|
|
|
+ if (productHighlightIndex.value >= 0) {
|
|
|
+ e.preventDefault()
|
|
|
+ pickProduct(productList.value[productHighlightIndex.value])
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// =========== 客户编号 弹窗 ===========
|
|
|
+const clientModal = ref(false)
|
|
|
+const clientKeyword = ref('')
|
|
|
+const clientList = ref([])
|
|
|
+const clientHighlightIndex = ref(-1)
|
|
|
+const clientTableRef = ref(null)
|
|
|
+
|
|
|
+const openClientModal = async () => {
|
|
|
+ clientKeyword.value = formData.客户编号 || ''
|
|
|
+ clientModal.value = true
|
|
|
+}
|
|
|
+const onClientModalOpened = async () => {
|
|
|
+ await loadClientList()
|
|
|
+ await nextTick()
|
|
|
+ const inputs = document.querySelectorAll('.el-dialog__body .el-input__inner')
|
|
|
+ if (inputs && inputs.length) inputs[0].focus()
|
|
|
+}
|
|
|
+const closeClientModal = () => {
|
|
|
+ clientHighlightIndex.value = -1
|
|
|
+ clientList.value = []
|
|
|
+}
|
|
|
+const loadClientList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await ClientList({ search: clientKeyword.value })
|
|
|
+ clientList.value = res.data || []
|
|
|
+ clientHighlightIndex.value = clientList.value.length > 0 ? 0 : -1
|
|
|
+ await nextTick()
|
|
|
+ if (clientTableRef.value && clientHighlightIndex.value >= 0) {
|
|
|
+ clientTableRef.value.setCurrentRow(clientList.value[0])
|
|
|
+ }
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
+const pickClient = (row) => {
|
|
|
+ formData.客户编号 = row.客户编号
|
|
|
+ formData.客户名称 = row.客户名称
|
|
|
+ clientModal.value = false
|
|
|
+ nextTick(() => focusField('f_客诉描述'))
|
|
|
+}
|
|
|
+const handleClientModalKeydown = (e) => {
|
|
|
+ if (e.key === 'Escape') {
|
|
|
+ clientModal.value = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (clientList.value.length === 0) return
|
|
|
+
|
|
|
+ if (e.key === 'ArrowDown') {
|
|
|
+ e.preventDefault()
|
|
|
+ clientHighlightIndex.value = Math.min(clientHighlightIndex.value + 1, clientList.value.length - 1)
|
|
|
+ clientTableRef.value?.setCurrentRow(clientList.value[clientHighlightIndex.value])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (e.key === 'ArrowUp') {
|
|
|
+ e.preventDefault()
|
|
|
+ clientHighlightIndex.value = Math.max(clientHighlightIndex.value - 1, 0)
|
|
|
+ clientTableRef.value?.setCurrentRow(clientList.value[clientHighlightIndex.value])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (e.key === 'Enter') {
|
|
|
+ const isInInput = e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA')
|
|
|
+ if (isInInput && e.target.value === clientKeyword.value) return
|
|
|
+ if (clientHighlightIndex.value >= 0) {
|
|
|
+ e.preventDefault()
|
|
|
+ pickClient(clientList.value[clientHighlightIndex.value])
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
-<style>
|
|
|
+<style scoped>
|
|
|
+.cf-header {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
.JKWTree-container {
|
|
|
display: flex;
|
|
|
}
|
|
|
-/* 选中某行时的背景色*/
|
|
|
-.el-table__body tr.current-row>td {
|
|
|
+.el-table__body tr.current-row > td {
|
|
|
background: #ff80ff !important;
|
|
|
}
|
|
|
.JKWTree-tree {
|
|
|
- width: 300px;
|
|
|
+ width: 260px;
|
|
|
background-color: #fff;
|
|
|
padding: 10px;
|
|
|
margin-right: 20px;
|
|
|
+ max-height: 78vh;
|
|
|
+ overflow-y: auto;
|
|
|
}
|
|
|
-
|
|
|
.JKWTree-tree h3 {
|
|
|
font-size: 15px;
|
|
|
font-weight: 700;
|
|
|
margin: 10px 0;
|
|
|
}
|
|
|
-
|
|
|
.JKWTree-content {
|
|
|
flex: 1;
|
|
|
}
|