You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

666 lines
36 KiB

8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
2 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
2 months ago
8 months ago
  1. <template>
  2. <div class="customer-css">
  3. <!-- 查询条件 -->
  4. <el-form :inline="true" label-position="top" class="pi-search-form">
  5. <el-form-item label="任务单号">
  6. <el-input v-model="searchData.requestNo" style="width:140px" @keyup.enter.native="getList" />
  7. </el-form-item>
  8. <el-form-item>
  9. <span style="cursor: pointer" slot="label" @click="getBaseList(501)"><a href="#">供应商编码</a></span>
  10. <el-input v-model="searchData.supplierNo" style="width: 130px"></el-input>
  11. </el-form-item>
  12. <el-form-item label="供应商名称">
  13. <el-input v-model="searchData.supplierName" style="width:200px" @keyup.enter.native="getList" />
  14. </el-form-item>
  15. <el-form-item label="创建者">
  16. <el-input v-model="searchData.createBy" style="width:140px" @keyup.enter.native="getList" />
  17. </el-form-item>
  18. <el-form-item label="预计完成时间">
  19. <el-date-picker v-model="searchData.wantedCompleteDateStart" type="date" placeholder="Start Date"
  20. value-format="yyyy-MM-dd"
  21. style="width:140px" />
  22. -
  23. <el-date-picker v-model="searchData.wantedCompleteDateEnd" type="date" placeholder="End Date"
  24. value-format="yyyy-MM-dd"
  25. style="width:140px" />
  26. </el-form-item>
  27. <el-form-item label="创建日期">
  28. <el-date-picker v-model="searchData.createDateStart" type="date" placeholder="Start Date"
  29. value-format="yyyy-MM-dd HH:mm:ss"
  30. style="width:140px" />
  31. -
  32. <el-date-picker v-model="searchData.createDateEnd" type="date" placeholder="End Date"
  33. value-format="yyyy-MM-dd HH:mm:ss"
  34. style="width:140px" />
  35. </el-form-item>
  36. <el-form-item label="状态">
  37. <el-select v-model="searchData.statusList" multiple collapse-tags clearable style="width:150px"
  38. placeholder="All">
  39. <el-option
  40. v-for="item in taskStatusOptions"
  41. :key="item.value"
  42. :label="item.label"
  43. :value="item.value" />
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item label=" ">
  47. <el-button type="primary" class="customer-bun-min" @click="getList">查询</el-button>
  48. <el-button type="primary" class="customer-bun-min" @click="openCreateDialog">新增</el-button>
  49. </el-form-item>
  50. </el-form>
  51. <!-- Evaluate Request 列表 -->
  52. <el-table :data="dataList" :height="requestTableHeight - 100" border highlight-current-row v-loading="loading"
  53. @row-click="rowClick" ref="mainTable" style="width:100%;margin-bottom:8px">
  54. <el-table-column prop="requestNo" label="任务单号" min-width="140" header-align="center" align="left" />
  55. <el-table-column prop="supplierNo" label="供应商编号" width="120" header-align="center" align="left" />
  56. <el-table-column prop="supplierName" label="供应商名称" min-width="200" header-align="center" align="left" show-overflow-tooltip />
  57. <el-table-column prop="wantedCompleteDate" label="预计完成时间" width="160" header-align="center" align="center" />
  58. <el-table-column prop="status" label="状态" width="110" header-align="center" align="center" />
  59. <el-table-column prop="createBy" label="创建者" min-width="90" header-align="center" align="left" />
  60. <el-table-column prop="createDate" label="创建时间" width="140" header-align="center" align="center" />
  61. <el-table-column fixed="right" label="操作" width="160" header-align="center" align="center">
  62. <template slot-scope="scope">
  63. <template v-if="!isCompleted(scope.row)">
  64. <a class="customer-a" @click.stop="openEditDialog(scope.row)">编辑</a>
  65. <span style="color:#dcdfe6;margin:0 2px">|</span>
  66. <a class="customer-a" @click.stop="removeRequest(scope.row)">删除</a>
  67. </template>
  68. </template>
  69. </el-table-column>
  70. </el-table>
  71. <el-pagination style="margin-top:0" @size-change="sizeChangeHandle" @current-change="currentChangeHandle"
  72. :current-page="pageIndex" :page-sizes="[20,50,100,200,500]" :page-size="pageSize" :total="totalPage"
  73. layout="total, sizes, prev, pager, next, jumper" />
  74. <!-- 指标 & 进度 查看 -->
  75. <el-row :gutter="10" style="margin-top:12px">
  76. <el-col :span="16">
  77. <div class="sub-panel-header">
  78. <span style="font-size:16px">考核单</span>
  79. </div>
  80. <el-table :data="indicatorList" size="mini" border :height="indicatorTableHeight" highlight-current-row
  81. ref="indicatorTable" @row-click="selectIndicatorRow" v-loading="indicatorLoading">
  82. <el-table-column prop="indicatorCode" label="指标编码" min-width="120" header-align="center" align="left" show-overflow-tooltip />
  83. <el-table-column prop="indicatorDesc" label="指标描述" min-width="220" header-align="center" align="left" show-overflow-tooltip />
  84. <el-table-column prop="category" label="指标分类" width="110" header-align="center" align="center" />
  85. <el-table-column prop="ownerRole" label="负责部门" width="110" header-align="center" align="center" />
  86. <el-table-column prop="maxScore" label="最高分" width="110" header-align="center" align="right">
  87. </el-table-column>
  88. <el-table-column prop="score" label="分数" width="90" header-align="center" align="right" />
  89. </el-table>
  90. </el-col>
  91. <el-col :span="8">
  92. <div class="sub-panel-header">
  93. <span style="font-size:16px">进度 <span v-if="viewIndicatorCode"></span></span>
  94. </div>
  95. <el-table :data="progressList" size="mini" border :height="indicatorTableHeight" v-loading="progressLoading">
  96. <el-table-column prop="departmentName" label="部门" min-width="90" header-align="center"
  97. align="left" />
  98. <el-table-column prop="owner" label="负责人" min-width="80" header-align="center" align="left" />
  99. <el-table-column prop="userDisplay" label="负责人名称" min-width="90" header-align="center" align="left" />
  100. <el-table-column prop="completedFlag" label="已完成" width="60" header-align="center" align="center">
  101. </el-table-column>
  102. <el-table-column prop="completedDate" label="完成时间" min-width="140" header-align="center"
  103. align="center" />
  104. </el-table>
  105. </el-col>
  106. </el-row>
  107. <!-- 调整供应商等级 -->
  108. <el-dialog title="调整供应商等级" :visible.sync="adjustVisible" width="420px" :close-on-click-modal="false" v-drag>
  109. <el-form label-position="top" size="small">
  110. <el-form-item label="任务单号">
  111. <el-input v-model="currentRequest.requestNo" disabled />
  112. </el-form-item>
  113. <el-form-item label="供应商名称">
  114. <el-input v-model="currentRequest.supplierName" disabled />
  115. </el-form-item>
  116. <el-form-item label="新等级" :required="true">
  117. <el-select v-model="adjustForm.newLevel" placeholder="Select" style="width:180px">
  118. <el-option v-for="l in supplierLevelOptions" :key="l.value" :label="l.label" :value="l.value" />
  119. </el-select>
  120. </el-form-item>
  121. <el-form-item label="备注">
  122. <el-input type="textarea" v-model="adjustForm.remark" :rows="3" maxlength="300" />
  123. </el-form-item>
  124. </el-form>
  125. <span slot="footer" class="dialog-footer">
  126. <el-button type="primary" :loading="adjustLoading" @click="submitAdjust">确认</el-button>
  127. <el-button @click="adjustVisible=false">取消</el-button>
  128. </span>
  129. </el-dialog>
  130. <!-- 新建 / 编辑 绩效请求弹窗 -->
  131. <el-dialog :title="isEdit ? '编辑绩效评估考核' : '新增绩效评估考核'" :visible.sync="createDialogVisible" :width="isEdit ? '760px' : '940px'" top="4vh"
  132. :close-on-click-modal="false" v-drag>
  133. <el-form :inline="true" label-position="top" size="mini" class="create-top-form">
  134. <el-form-item :required="true">
  135. <span slot="label" @click="getBaseList(2014)"><a href="#">模板编号</a></span>
  136. <!-- 允许编辑模式下修改模板号: 去掉 :disabled="isEdit" -->
  137. <el-input v-model="createForm.templateNo" style="width:150px" @blur="autoFetchTemplateInfo" />
  138. </el-form-item>
  139. <el-form-item label="模板描述">
  140. <el-input v-model="createForm.templateDesc" style="width:260px" disabled />
  141. </el-form-item>
  142. <el-form-item label="预计完成时间" :required="true">
  143. <el-date-picker v-model="createForm.wantedCompleteDate" type="date" value-format="yyyy-MM-dd" style="width:160px" />
  144. </el-form-item>
  145. <el-form-item label=" " style="margin-top:-2px" v-if="!isEdit">
  146. <el-button size="small" type="primary" :disabled="!createForm.templateNo" @click="openTemplateIndicatorDialog">指标信息</el-button>
  147. </el-form-item>
  148. <el-form-item v-if="isEdit" label="任务单号">
  149. <el-input v-model="createForm.requestNo" disabled style="width:150px" />
  150. </el-form-item>
  151. <el-form-item label=" " style="margin-top:-2px" v-if="isEdit">
  152. <el-button size="small" type="primary" :disabled="!createForm.templateNo" @click="openTemplateIndicatorDialog">指标信息</el-button>
  153. </el-form-item>
  154. </el-form>
  155. <el-row :gutter="10" style="margin-top:5px">
  156. <el-col :span="12" v-if="!isEdit">
  157. <!-- Supplier List (only new) -->
  158. <div class="sub-panel-header supplier-panel-header">
  159. <span class="sub-panel-title">供应商清单</span>
  160. <div class="supplier-header-filters">
  161. <el-input
  162. v-model="supplierQuery.supplierNo"
  163. size="mini"
  164. placeholder="供应商编码"
  165. clearable
  166. style="width:100px"
  167. @keyup.enter.native="loadSuppliers"
  168. />
  169. <el-input
  170. v-model="supplierQuery.supplierName"
  171. size="mini"
  172. placeholder="供应商名称"
  173. clearable
  174. style="width:200px"
  175. @keyup.enter.native="loadSuppliers"
  176. />
  177. <el-button size="mini" type="primary" @click="loadSuppliers">查询</el-button>
  178. </div>
  179. </div>
  180. <el-table ref="createSupplierTable" :data="supplierList" size="mini" border height="380" v-loading="supplierLoading" @selection-change="supplierSelectionChange">
  181. <el-table-column type="selection" width="40" header-align="center" align="center" />
  182. <el-table-column prop="supplierNo" label="供应商编码" width="120" header-align="center" align="left" />
  183. <el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip />
  184. </el-table>
  185. </el-col>
  186. <el-col :span="12" v-if="!isEdit">
  187. <!-- Specify Owner (new) -->
  188. <div class="sub-panel-header">
  189. <span style="font-size:14px">指定负责人</span>
  190. </div>
  191. <el-table :data="departmentList" :key="'dept-new'" size="mini" border height="380" v-loading="deptLoading">
  192. <el-table-column prop="departmentNo" label="部门编号" min-width="60" header-align="center" align="left" />
  193. <el-table-column prop="departmentName" label="部门名称" min-width="80" header-align="center" align="left" />
  194. <el-table-column prop="owner" label="负责人" min-width="80" header-align="center" align="left" show-overflow-tooltip>
  195. <template slot-scope="scope">
  196. <span v-if="scope.row.owner">{{ scope.row.owner }}</span>
  197. <span v-else style="color:#999">(未选择)</span>
  198. </template>
  199. </el-table-column>
  200. <el-table-column prop="ownerDisplay" label="负责人姓名" min-width="120" header-align="center" align="left" show-overflow-tooltip>
  201. <template slot-scope="scope">
  202. <span v-if="scope.row.ownerDisplay">{{ scope.row.ownerDisplay }}</span>
  203. <span v-else style="color:#999">-</span>
  204. </template>
  205. </el-table-column>
  206. <el-table-column label="操作" fixed="right" width="90" header-align="center" align="center">
  207. <template slot-scope="scope">
  208. <a class="customer-a" @click="openOwnerSelect(scope.row)">查询</a>
  209. <a v-if="scope.row.owner" class="customer-a" style="margin-left:4px" @click="clearOwner(scope.row)">清除</a>
  210. </template>
  211. </el-table-column>
  212. </el-table>
  213. </el-col>
  214. <el-col :span="24" v-if="isEdit">
  215. <!-- Owner only (edit) -->
  216. <div class="sub-panel-header">
  217. <span style="font-size:14px">指定负责人</span>
  218. </div>
  219. <el-table :data="departmentList" :key="'dept-edit'" size="mini" border height="380" v-loading="deptLoading">
  220. <el-table-column prop="departmentNo" label="部门编号" min-width="100" header-align="center" align="left" />
  221. <el-table-column prop="departmentName" label="部门名称" min-width="200" header-align="center" align="left" />
  222. <el-table-column prop="owner" label="负责人" min-width="120" header-align="center" align="left" show-overflow-tooltip>
  223. <template slot-scope="scope">
  224. <span v-if="scope.row.owner">{{ scope.row.owner }}</span>
  225. <span v-else style="color:#999">(未选择)</span>
  226. </template>
  227. </el-table-column>
  228. <el-table-column prop="ownerDisplay" label="负责人姓名" min-width="140" header-align="center" align="left" show-overflow-tooltip>
  229. <template slot-scope="scope">
  230. <span v-if="scope.row.ownerDisplay">{{ scope.row.ownerDisplay }}</span>
  231. <span v-else style="color:#999">-</span>
  232. </template>
  233. </el-table-column>
  234. <el-table-column label="操作" width="110" header-align="center" align="center">
  235. <template slot-scope="scope">
  236. <a class="customer-a" @click="openOwnerSelect(scope.row)">查询</a>
  237. <a v-if="scope.row.owner" class="customer-a" style="margin-left:4px" @click="clearOwner(scope.row)">清除</a>
  238. </template>
  239. </el-table-column>
  240. </el-table>
  241. </el-col>
  242. </el-row>
  243. <span slot="footer" class="dialog-footer">
  244. <el-button type="primary" :loading="createSaving" @click="saveCreate">保存</el-button>
  245. <el-button @click="createDialogVisible=false">关闭</el-button>
  246. </span>
  247. </el-dialog>
  248. <!-- 模板指标弹窗 -->
  249. <el-dialog title="指标信息" :visible.sync="templateIndicatorDialogVisible" width="760px" top="8vh" :close-on-click-modal="false" v-drag>
  250. <div style="margin-bottom:6px;font-size:12px;color:#666">Template: {{createForm.templateNo}} - {{createForm.templateDesc}}</div>
  251. <el-table :data="templateIndicatorList" size="mini" border height="420" v-loading="templateIndicatorLoading">
  252. <el-table-column prop="indicatorCode" label="指标编号" min-width="140" header-align="center" align="left" />
  253. <el-table-column prop="indicatorDesc" label="指标描述" min-width="240" header-align="center" align="left" show-overflow-tooltip />
  254. <el-table-column prop="category" label="指标分类" width="120" header-align="center" align="center" />
  255. <el-table-column prop="ownerRole" label="负责部门" width="120" header-align="center" align="center" />
  256. </el-table>
  257. <span slot="footer" class="dialog-footer"><el-button @click="templateIndicatorDialogVisible=false">关闭</el-button></span>
  258. </el-dialog>
  259. <!-- Owner 选择弹窗 -->
  260. <el-dialog title="Select Owner" :visible.sync="ownerDialogVisible" width="600px" top="10vh" :close-on-click-modal="false" v-drag>
  261. <div style="margin-bottom:4px;font-size:12px;color:#555">Department: {{ currentDeptRow.departmentName }}</div>
  262. <el-table :data="ownerUserList" size="mini" border height="360" highlight-current-row v-loading="ownerLoading" @row-dblclick="confirmOwner">
  263. <el-table-column prop="username" label="用户名称" width="160" header-align="center" align="left" />
  264. <el-table-column prop="userDisplay" label="用户显示名" min-width="260" header-align="center" align="left" show-overflow-tooltip />
  265. </el-table>
  266. <span slot="footer" class="dialog-footer"><el-button @click="ownerDialogVisible=false">关闭</el-button></span>
  267. </el-dialog>
  268. <Chooselist ref="baseList" @getBaseData="getBaseData"></Chooselist>
  269. </div>
  270. </template>
  271. <script>
  272. import {
  273. adjustSupplierLevel,
  274. deleteEvaluateRequest,
  275. getEvaluateRequestIndicatorProgress,
  276. getEvaluateRequestIndicators,
  277. searchEvaluateRequestList,
  278. updateEvaluateRequest
  279. } from '@/api/supplierPerformance/myPerformanceEvaluateRequest.js'
  280. import {
  281. fetchDepartmentList,
  282. fetchOwnerUserList,
  283. fetchSupplierList,
  284. fetchTemplateInfo,
  285. saveEvaluateRequest
  286. } from '@/api/supplierPerformance/performanceEvaluateRequestBuild.js'
  287. import Chooselist from '@/views/modules/common/Chooselist_eam'
  288. import {getTemplateIndicators} from "../../../api/supplierPerformance/performanceIndicatorTemplate";
  289. import {
  290. PERF_TASK_STATUS_OPTIONS,
  291. PERF_TASK_STATUS_DEFAULT
  292. } from './supplierPerformanceStatusOptions.js'
  293. export default {
  294. components: {
  295. Chooselist,
  296. },
  297. name: 'MyPerformanceEvaluateRequest',
  298. data() {
  299. return {
  300. height: 500,
  301. loading: false,
  302. dataList: [],
  303. pageIndex: 1,
  304. pageSize: 20,
  305. totalPage: 0,
  306. taskStatusOptions: PERF_TASK_STATUS_OPTIONS,
  307. searchData: {
  308. site: this.$store.state.user.site,
  309. username: this.$store.state.user.name,
  310. requestNo: '',
  311. supplierNo: '',
  312. supplierName: '',
  313. createBy: '',
  314. wantedCompleteDateStart: '',
  315. wantedCompleteDateEnd: '',
  316. createDateStart: '',
  317. createDateEnd: '',
  318. statusList: []
  319. },
  320. currentRequest: {},
  321. indicatorList: [],
  322. indicatorLoading: false,
  323. viewIndicatorCode: '',
  324. // progress
  325. progressList: [],
  326. progressLoading: false,
  327. // 调整等级
  328. adjustVisible: false,
  329. adjustLoading: false,
  330. adjustForm: { newLevel: '', remark: '' },
  331. supplierLevelOptions: [ {label:'A',value:'A'},{label:'B',value:'B'},{label:'C',value:'C'},{label:'D',value:'D'} ],
  332. // 新建弹窗相关
  333. createDialogVisible: false,
  334. createForm: { templateNo:'', templateDesc:'', wantedCompleteDate:'' },
  335. createSaving: false,
  336. templateIndicatorDialogVisible: false,
  337. templateIndicatorList: [],
  338. templateIndicatorLoading: false,
  339. supplierQuery: { supplierNo: '', supplierName: '' },
  340. supplierList: [],
  341. supplierSelected: [],
  342. supplierLoading: false,
  343. departmentList: [],
  344. deptLoading: false,
  345. ownerDialogVisible: false,
  346. ownerUserList: [],
  347. ownerLoading: false,
  348. ownerQuery: { keyword:'' },
  349. currentDeptRow: {},
  350. isEdit: false,
  351. }
  352. },
  353. computed: {
  354. requestTableHeight() { return this.height - 360 < 260 ? 260 : this.height - 360 },
  355. indicatorTableHeight() { return 300 }
  356. },
  357. mounted() {
  358. this.calcHeight();
  359. window.addEventListener('resize', this.calcHeight)
  360. this.getList()
  361. },
  362. beforeDestroy() { window.removeEventListener('resize', this.calcHeight) },
  363. methods: {
  364. // 获取基础数据列表S
  365. getBaseList (val,type) {
  366. this.tagNo = val
  367. this.$nextTick(() => {
  368. let strVal = ''
  369. let conSql = ''
  370. if (val === 2014 ) {
  371. strVal = this.createForm.templateNo
  372. conSql = " and site = '" + this.$store.state.user.site + "'"
  373. } else if (val === 501) {
  374. strVal = this.searchData.supplierNo || ''
  375. conSql = " and site = '" + this.$store.state.user.site + "'"
  376. }
  377. this.$refs.baseList.init(val, strVal,conSql)
  378. })
  379. },
  380. /* 列表方法的回调 */
  381. getBaseData (val) {
  382. console.log('Chooselist返回的数据:', val, 'tagNo:', this.tagNo)
  383. if (this.tagNo === 2014) {
  384. this.createForm.templateId = val.id
  385. this.createForm.templateNo = val.template_no
  386. this.createForm.templateDesc = val.template_desc
  387. this.loadDepartments()
  388. } else if (this.tagNo === 501) {
  389. // 供应商编码字段 - SQL返回: SupplierID, SupplierName
  390. const supplierNoVal = val.SupplierID || val.supplierID || val.supplierId || ''
  391. this.searchData.supplierNo = supplierNoVal
  392. console.log('供应商编码赋值:', supplierNoVal)
  393. }
  394. },
  395. calcHeight() { this.$nextTick(()=> { this.height = window.innerHeight - 40 }) },
  396. getList() {
  397. this.loading = true
  398. if (this.searchData.statusList.length === 0) this.searchData.statusList = [...PERF_TASK_STATUS_DEFAULT]
  399. const params = { ...this.searchData, statusList: this.searchData.statusList, page: this.pageIndex, limit: this.pageSize,selectType: 1 }
  400. searchEvaluateRequestList(params).then(({data}) => {
  401. if (data && (data.code === 0 || data.code === '0')) {
  402. if (data.page) {
  403. this.dataList = data.page.list || []
  404. this.pageIndex = data.page.currPage || params.page
  405. this.pageSize = data.page.pageSize || params.limit
  406. this.totalPage = data.page.totalCount || 0
  407. if (this.dataList.length > 0) { this.$nextTick(()=> { this.$refs.mainTable.setCurrentRow(this.dataList[0]); this.rowClick(this.dataList[0]) }) }
  408. } else {
  409. this.dataList = data.rows || []
  410. this.totalPage = data.total || this.dataList.length
  411. }
  412. } else { this.dataList=[]; this.totalPage=0 }
  413. }).catch(()=> { this.dataList=[]; this.totalPage=0 })
  414. .finally(()=> { this.loading=false })
  415. },
  416. sizeChangeHandle(v) { this.pageSize=v; this.pageIndex=1; this.getList() },
  417. currentChangeHandle(v) { this.pageIndex=v; this.getList() },
  418. rowClick(row) { this.currentRequest = row; this.loadIndicators() },
  419. loadIndicators() {
  420. if (!this.currentRequest.requestNo) { this.indicatorList=[]; return }
  421. this.indicatorLoading = true
  422. const p = { requestId: this.currentRequest.id, requestNo: this.currentRequest.requestNo, site: this.$store.state.user.site }
  423. getEvaluateRequestIndicators(p).then(({data}) => {
  424. if (data && (data.code === 0 || data.code === '0')) {
  425. this.indicatorList = data.list
  426. this.$nextTick(()=> { if (this.indicatorList.length>0) { this.$refs.indicatorTable.setCurrentRow(this.indicatorList[0]); this.selectIndicatorRow(this.indicatorList[0]) } else { this.viewIndicatorCode=''; this.progressList=[] } })
  427. } else { this.indicatorList=[] }
  428. }).catch(()=> { this.indicatorList=[] })
  429. .finally(()=> { this.indicatorLoading=false })
  430. },
  431. selectIndicatorRow(row) { this.viewIndicatorCode = row.indicatorCode; this.loadProgress() },
  432. loadProgress() {
  433. if (!this.viewIndicatorCode || !this.currentRequest.requestNo) { this.progressList=[]; return }
  434. this.progressLoading = true
  435. const p = { requestId: this.currentRequest.id, requestNo: this.currentRequest.requestNo, site: this.$store.state.user.site }
  436. getEvaluateRequestIndicatorProgress(p).then(({data}) => {
  437. if (data && (data.code === 0 || data.code === '0')) {
  438. this.progressList = data.list
  439. } else { this.progressList=[] }
  440. }).catch(()=> { this.progressList=[] })
  441. .finally(()=> { this.progressLoading=false })
  442. },
  443. openAdjustDialog(row) { this.currentRequest = row; this.adjustForm = { newLevel:'', remark:'' }; this.adjustVisible=true },
  444. submitAdjust() {
  445. if (!this.adjustForm.newLevel) { this.$message.warning('请选择等级'); return }
  446. this.adjustLoading = true
  447. const payload = { requestId: this.currentRequest.id, requestNo: this.currentRequest.requestNo, supplierCode: this.currentRequest.supplierCode, newLevel: this.adjustForm.newLevel, remark: this.adjustForm.remark, site: this.$store.state.user.site, user: this.$store.state.user.name }
  448. adjustSupplierLevel(payload).then(({data}) => {
  449. if (data && (data.code===0 || data.code==='0')) { this.$message.success('调整成功'); this.adjustVisible=false; this.getList() } else { this.$message.error((data&&data.msg)||'调整失败') }
  450. }).catch(e=> this.$message.error('调整失败: '+ e.message))
  451. .finally(()=> { this.adjustLoading=false })
  452. },
  453. openEditDialog(row) {
  454. this.isEdit = true
  455. this.createSaving = false
  456. this.currentRequest = row
  457. this.createForm = {
  458. templateNo: row.templateNo,
  459. templateDesc: row.templateDesc,
  460. wantedCompleteDate: row.wantedCompleteDate,
  461. id: row.id,
  462. requestNo: row.requestNo,
  463. templateId: row.templateId,
  464. _originalTemplateNo: row.templateNo // 记录原模板号用于校验
  465. }
  466. this.createDialogVisible = true
  467. this.deptLoading = true
  468. this.loadDepartments()
  469. // 载入指标用于后续 score 校验
  470. this.loadIndicators()
  471. },
  472. reloadEditOwners() { if (!this.isEdit || !this.createForm.id) return; this.openEditDialog({ templateNo:this.createForm.templateNo, wantedCompleteDate:this.createForm.wantedCompleteDate, id:this.createForm.id, requestNo:this.createForm.requestNo }) },
  473. removeRequest(row) {
  474. const site = this.$store.state.user.site
  475. // 先获取该请求的指标,若存在已评分(score>0)则禁止删除
  476. getEvaluateRequestIndicators({ requestId: row.id, requestNo: row.requestNo, site }).then(({data}) => {
  477. let indicators = []
  478. if (data && (data.code === 0 || data.code === '0')) {
  479. indicators = data.list || data.rows || data.obj || []
  480. }
  481. const hasScored = indicators.some(i => Number(i.score) > 0)
  482. if (hasScored) {
  483. this.$message.error('该考核任务存在已评分指标,禁止删除')
  484. return
  485. }
  486. this.$confirm('确认删除该考核任务: ' + row.requestNo + ' ?', '提示', { type: 'warning' }).then(() => {
  487. deleteEvaluateRequest({ id: row.id, site }).then(({data: delData}) => {
  488. if (delData && (delData.code === 0 || delData.code === '0')) { this.$message.success('删除成功'); this.getList() }
  489. else { this.$message.error((delData && delData.msg) || '删除失败') }
  490. }).catch(e => this.$message.error('删除失败: ' + e.message))
  491. }).catch(()=>{})
  492. }).catch(e => {
  493. this.$message.error('校验失败: ' + e.message)
  494. })
  495. },
  496. saveCreate() {
  497. if (!this.validateCreate()) return
  498. this.createSaving = true
  499. const site = this.$store.state.user.site
  500. if (this.isEdit) {
  501. const payload = {
  502. site,
  503. id: this.createForm.id,
  504. requestNo: this.createForm.requestNo,
  505. templateNo: this.createForm.templateNo,
  506. wantedCompleteDate: this.createForm.wantedCompleteDate,
  507. detailList: this.departmentList.map(d=> ({ department: d.departmentNo || d.department || d.departmentName, owner: d.owner })),
  508. updateBy: this.$store.state.user.name
  509. }
  510. updateEvaluateRequest(payload).then(({data})=> {
  511. if (data && (data.code===0||data.code==='0')) { this.$message.success('更新成功'); this.createDialogVisible=false; this.isEdit=false; this.getList() }
  512. else { this.$message.error((data&&data.msg)||'更新失败') }
  513. }).catch(e=> this.$message.error('更新失败: '+ e.message))
  514. .finally(()=> { this.createSaving=false })
  515. } else {
  516. const payload = {
  517. site,
  518. templateNo: this.createForm.templateNo,
  519. wantedCompleteDate: this.createForm.wantedCompleteDate,
  520. headerList: this.supplierSelected.map(s=> ({ supplierNo:s.supplierNo, supplierName:s.supplierName })),
  521. detailList: this.departmentList.map(d=> ({ department: d.departmentNo || d.department || d.departmentName, owner: d.owner })),
  522. createBy: this.$store.state.user.name
  523. }
  524. saveEvaluateRequest(payload).then(({data})=> {
  525. if (data && (data.code===0||data.code==='0')) { this.$message.success('保存成功'); this.createDialogVisible=false; this.getList() } else { this.$message.error((data&&data.msg)||'保存失败') }
  526. }).catch(e=> this.$message.error('保存失败: '+ e.message))
  527. .finally(()=> { this.createSaving=false })
  528. }
  529. },
  530. openCreateDialog() {
  531. this.isEdit = false
  532. this.resetCreateForm();
  533. this.createDialogVisible = true;
  534. this.supplierList = [];
  535. this.departmentList = [];
  536. },
  537. resetCreateForm() {
  538. this.createForm = { templateNo:'', templateDesc:'', wantedCompleteDate:'' };
  539. this.templateIndicatorList = [];
  540. this.supplierSelected = [];
  541. this.supplierQuery = { supplierNo: '', supplierName: '' };
  542. this.supplierList = [];
  543. if (this.$refs.createSupplierTable) this.$refs.createSupplierTable.clearSelection();
  544. this.departmentList.forEach(d=>{ d.owner=''; });
  545. },
  546. autoFetchTemplateInfo() { if (!this.createForm.templateNo) return; this.fetchTemplateDesc(); },
  547. fetchTemplateDesc() {
  548. fetchTemplateInfo({ templateNo: this.createForm.templateNo, site: this.$store.state.user.site }).then(({data})=> {
  549. if (data && (data.code===0||data.code==='0')) { const obj=data.obj||{}; this.createForm.templateDesc = obj.templateDesc || obj.templateDescCn || '' } else { this.createForm.templateDesc='' }
  550. }).catch(()=> { this.createForm.templateDesc='' })
  551. },
  552. openTemplateIndicatorDialog() { if (!this.createForm.templateNo) { this.$message.warning('请输入 Template No');
  553. return } this.templateIndicatorDialogVisible=true; this.loadTemplateIndicators(); },
  554. loadTemplateIndicators() {
  555. this.templateIndicatorLoading = true;
  556. getTemplateIndicators({ templateId: this.createForm.templateId, site: this.$store.state.user.site }).then(({data})=> {
  557. if (data && (data.code===0||data.code==='0')) { this.templateIndicatorList = data.rows || data.obj || [] } else { this.templateIndicatorList=[] }
  558. }).catch(()=> { this.templateIndicatorList=[] }).finally(()=> { this.templateIndicatorLoading=false })
  559. },
  560. loadSuppliers() {
  561. this.supplierLoading = true;
  562. fetchSupplierList({
  563. site: this.$store.state.user.site,
  564. supplierNo: this.supplierQuery.supplierNo,
  565. supplierName: this.supplierQuery.supplierName
  566. }).then(({data})=> {
  567. if (data && (data.code===0||data.code==='0')) {
  568. this.supplierList = (data.page ? data.page.list : (data.rows || data.obj || [])) || []
  569. } else {
  570. this.supplierList = []
  571. }
  572. }).catch(()=> { this.supplierList=[] }).finally(()=> { this.supplierLoading=false })
  573. },
  574. supplierSelectionChange(val) { this.supplierSelected = val },
  575. loadDepartments() {
  576. this.deptLoading = true;
  577. fetchDepartmentList({ templateId: this.createForm.templateId, requestNo: this.createForm.requestNo ? this.createForm.requestNo : '',
  578. site: this.$store.state.user.site
  579. }).then(({data})=> {
  580. if (data && (data.code === 0 || data.code === '0')) {
  581. // 统一使用 owner 字段
  582. this.departmentList = data.rows || data.obj || []
  583. // 加载所有用户列表,用于匹配 ownerDisplay
  584. this.loadAllUsersForDisplay()
  585. } else { this.departmentList = [] }
  586. }).catch(()=> { this.departmentList=[] }).finally(()=> { this.deptLoading=false })
  587. },
  588. // 加载所有用户用于匹配显示名称
  589. loadAllUsersForDisplay() {
  590. // 使用和 loadOwners 相同的调用方式,传入一个空对象或第一个部门
  591. const queryParam = this.departmentList.length > 0 ? this.departmentList[0] : {}
  592. fetchOwnerUserList(queryParam).then(({data})=> {
  593. if (data && (data.code===0||data.code==='0')) {
  594. const userList = (data.page? data.page.list : (data.rows||data.obj||[])) || []
  595. // 为每个有 owner 的部门匹配 userDisplay
  596. this.departmentList.forEach(dept => {
  597. if (dept.owner) {
  598. const matchedUser = userList.find(u => u.username === dept.owner || u.userName === dept.owner)
  599. if (matchedUser) {
  600. this.$set(dept, 'ownerDisplay', matchedUser.userDisplay || matchedUser.user_display || '')
  601. }
  602. }
  603. })
  604. }
  605. }).catch(()=> {
  606. // 静默失败,不影响其他数据显示
  607. })
  608. },
  609. openOwnerSelect(row) { this.currentDeptRow = row; this.ownerDialogVisible = true; this.ownerQuery.keyword=''; this.loadOwners(); },
  610. loadOwners() {
  611. this.ownerLoading = true;
  612. fetchOwnerUserList(this.currentDeptRow).then(({data})=> {
  613. if (data && (data.code===0||data.code==='0')) { this.ownerUserList = (data.page? data.page.list : (data.rows||data.obj||[])) || [] } else { this.ownerUserList=[] }
  614. }).catch(()=> { this.ownerUserList=[] }).finally(()=> { this.ownerLoading=false })
  615. },
  616. confirmOwner(row) {
  617. if (!this.currentDeptRow || !row) return;
  618. const uname = row.username || row.userName || row.user_id || ''
  619. if (!uname) { this.$message.warning('该行缺少 username无法选择'); return }
  620. // 保存 username 到 owner 字段(用于提交)
  621. this.$set(this.currentDeptRow, 'owner', uname)
  622. // 保存 userDisplay 到 ownerDisplay 字段(仅用于显示)
  623. this.$set(this.currentDeptRow, 'ownerDisplay', row.userDisplay || row.user_display || '')
  624. this.ownerDialogVisible = false
  625. },
  626. clearOwner(row) { row.owner = '' },
  627. validateCreate() {
  628. if (this.createForm.templateNo) this.createForm.templateNo = this.createForm.templateNo.trim()
  629. if (!this.createForm.templateNo) { this.$message.warning('Template No 不能为空'); return false }
  630. if (!this.createForm.wantedCompleteDate) { this.$message.warning('Wanted Complete Date 不能为空'); return false }
  631. if (!this.isEdit && this.supplierSelected.length === 0) { this.$message.warning('请至少选择一个供应商'); return false }
  632. const hasAnyOwner = this.departmentList.some(d => (d.owner && d.owner.toString().trim() !== ''))
  633. if (!hasAnyOwner) { this.$message.warning('所有部门 Owner 均为空,请至少为一个部门选择 Owner'); return false }
  634. // 编辑时模板变更且存在已评分指标(score>0)禁止保存
  635. if (this.isEdit && this.createForm._originalTemplateNo && this.createForm.templateNo !== this.createForm._originalTemplateNo) {
  636. const hasScored = (this.indicatorList || []).some(i => Number(i.score) > 0)
  637. if (hasScored) { this.$message.error('存在已评分指标 ,禁止修改模板'); return false }
  638. }
  639. return true
  640. },
  641. isCompleted(row) { if (!row) return false; const v = (row.status||'').toString().toUpperCase(); return v==='COMPLETED' || v==='已完成'.toUpperCase(); },
  642. }
  643. }
  644. </script>
  645. <style scoped>
  646. .pi-search-form { margin-top:0; }
  647. .sub-panel-header { display:flex; align-items:center; justify-content:space-between; font-weight:600; padding:4px 6px; background:#f5f7fa; border:1px solid #ebeef5; border-bottom:none; }
  648. .supplier-panel-header { min-height: 32px; padding: 2px 6px; }
  649. .sub-panel-title { font-size:14px; white-space:nowrap; flex-shrink:0; }
  650. .supplier-header-filters { display:flex; align-items:center; gap:4px; margin-left:8px; flex:1; justify-content:flex-end; }
  651. .supplier-header-filters /deep/ .el-input__inner { height:24px; line-height:24px; font-size:12px; }
  652. .supplier-header-filters ::v-deep .el-input__inner { height:24px; line-height:24px; font-size:12px; }
  653. .supplier-header-filters /deep/ .el-button--mini { padding:4px 8px; font-size:12px; }
  654. .supplier-header-filters ::v-deep .el-button--mini { padding:4px 8px; font-size:12px; }
  655. .create-top-form { margin-top:-6px; }
  656. </style>