Task.vue 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. <template>
  2. <div class="create-container" v-loading="loading">
  3. <div class="title h1" v-if="!isModifyMode">任务</div>
  4. <div class="create-body">
  5. <div class="title h2" v-if="!isModifyMode">基本信息</div>
  6. <el-row :gutter="20">
  7. <el-col :span="15">
  8. <el-form :model="task" :rules="rules" ref="task" label-width="120px" class="demo-task"
  9. style="margin:0 0 0 80px;">
  10. <el-form-item label="任务名称" prop="title" style="width: 700px;">
  11. <el-input size="small" v-if="isModifyMode" v-model="task.title"></el-input>
  12. <span v-if="!isModifyMode">{{ task.title }}</span>
  13. <el-tag v-if="!isModifyMode" :type="task.statusVO&&task.statusVO.style">{{
  14. task.statusVO ?
  15. task.statusVO.text : ''
  16. }}
  17. </el-tag>
  18. </el-form-item>
  19. <el-form-item label="任务描述" prop="description" style="width: 700px;">
  20. <el-input autosize v-if="isModifyMode" type="textarea" v-model="task.description"></el-input>
  21. <span v-if="!isModifyMode">{{ task.description ? task.description : '暂无' }}</span>
  22. </el-form-item>
  23. <el-form-item label="任务报价" prop="quotePrice" style="width: 700px;">
  24. <el-input size="small" type="number" v-if="isModifyMode" v-model="task.quotePrice">
  25. <template slot="append">¥</template>
  26. </el-input>
  27. <span v-if="!isModifyMode">¥{{ task.quotePrice }}</span>
  28. </el-form-item>
  29. <!--<el-form-item type="number" label="任务定价" prop="fixedPrice">-->
  30. <!--<el-input v-if="isModifyMode" v-model="task.fixedPrice">-->
  31. <!--<template slot="append">¥</template>-->
  32. <!--</el-input>-->
  33. <!--<span v-if="!isModifyMode">{{task.fixedPrice}}</span>-->
  34. <!--</el-form-item>-->
  35. <el-form-item label="测试类型" prop="serviceType">
  36. <el-radio-group v-if="isModifyMode" v-model="task.serviceType" @change="handleTestTypeChange">
  37. <span v-for="(item,index) in serviceType" :key="index">
  38. <el-radio :label="item.name" name="serviceType">{{ item.name }}</el-radio>
  39. </span>
  40. </el-radio-group>
  41. <span class="badge" v-if="!isModifyMode">{{ task.serviceType }}</span>
  42. </el-form-item>
  43. <el-form-item label="协同模式" prop="endPoint.collaborativeType" style="width:700px;" v-if="currType.type==1">
  44. <el-radio-group v-model="task.endPoint.collaborativeType" v-if="isModifyMode" @change="$forceUpdate()">
  45. <el-radio :label="0">协同</el-radio>
  46. <el-radio :label="1">非协同</el-radio>
  47. </el-radio-group>
  48. <span v-if="!isModifyMode">{{ task.endPoint.collaborativeType ? '非协同' : '协同' }}</span>
  49. </el-form-item>
  50. <el-form-item label="任务可见性" prop="resource">
  51. <div v-if="!isModifyMode">
  52. <!--<div v-if="task.resource=='1'">{{updateLocation(task.location)}}</div>-->
  53. <div v-if="task.resource==0">定向</div>
  54. <div v-if="task.resource==2">{{ resourceType[task.resource] }}</div>
  55. </div>
  56. <el-tabs
  57. :tab-position="tabPosition"
  58. v-model="task.resource"
  59. v-if="isModifyMode"
  60. >
  61. <el-tab-pane v-if="currType.type==0" :label="resourceType[0]" name="0">
  62. <el-radio-group v-model="task.institution" @change="handleTestTypeChange">
  63. <el-radio v-for="(item,index) in institutionArray" :label="item.userId" name="type" :key="index">
  64. {{item.name}}
  65. </el-radio>
  66. </el-radio-group>
  67. </el-tab-pane>
  68. <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
  69. </el-tabs>
  70. </el-form-item>
  71. <el-form-item v-if="!isModifyMode && task.resource==0 && showBD" label="接包人员/机构" prop="agencyName" style="width: 700px;">
  72. <span>{{task.agencyName}}</span>
  73. </el-form-item>
  74. <el-form-item label="领取人数" prop="contactPhone" v-if="isModifyMode&&task.resource !== '0' && currType.type===0">
  75. <el-input-number v-model="task.participantCount" :min="1" :max="1000" label="领取人数"></el-input-number>
  76. </el-form-item>
  77. <el-form-item label="领取人数" prop="contactPhone"
  78. v-if="isModifyMode&&task.resource !== '0' && currType.type===1">
  79. <el-input-number v-model="task.participantCount" :min="2" :max="1000" label="领取人数"></el-input-number>
  80. </el-form-item>
  81. <el-form-item label="领取人数" prop="quotePrice" v-if="!isModifyMode">
  82. {{ task.acceptedCount }}/{{ task.participantCount }}
  83. </el-form-item>
  84. <el-form-item label="需求文档" prop="doc">
  85. <el-upload
  86. style="width: 400px"
  87. v-if="isModifyMode"
  88. drag
  89. class="upload-demo"
  90. action=""
  91. :on-remove="handleRemove"
  92. :before-remove="beforeRemove"
  93. :limit="1"
  94. :on-exceed="handleExceed"
  95. :http-request="uploadRequireDoc"
  96. :file-list="task.doc"
  97. >
  98. <i class="el-icon-upload"></i>
  99. <div class="el-upload__text">
  100. 将文件拖到此处,或
  101. <em>点击上传</em>
  102. </div>
  103. </el-upload>
  104. <span>
  105. <span v-if="task.requireDocUrl == null || task.requireDocUrl == ''">
  106. <i class="el-icon-document"></i>暂无文件
  107. </span>
  108. <span v-if="task.requireDocUrl != null && task.requireDocUrl != ''">
  109. <a :href="task.requireDocUrl"><el-link :underline="false" type="primary"><i
  110. class="el-icon-document"></i>下载文档</el-link></a>
  111. </span>
  112. </span>
  113. </el-form-item>
  114. <el-form-item label="测试大纲" prop="threePageUrl" class="three-page-upload" v-if="currType.type==1">
  115. <el-upload
  116. style="width: 400px"
  117. v-if="isModifyMode"
  118. drag
  119. class="upload-demo"
  120. action=""
  121. :on-remove="handleRemove"
  122. :before-remove="beforeRemove"
  123. :limit="1"
  124. :on-exceed="handleExceed"
  125. :http-request="uploadThreePage"
  126. :file-list="task.threePageList"
  127. >
  128. <i class="el-icon-upload"></i>
  129. <div class="el-upload__text">
  130. 将文件拖到此处,或
  131. <em>点击上传</em>
  132. </div>
  133. </el-upload>
  134. <span>
  135. <span v-if="task.endPoint.threePageUrl == null || task.endPoint.threePageUrl == ''">
  136. <i class="el-icon-document"></i>暂无文件
  137. </span>
  138. <span v-if="task.endPoint.threePageUrl != null && task.endPoint.threePageUrl != ''">
  139. <a :href="task.endPoint.threePageUrl"><el-link :underline="false" type="primary"><i
  140. class="el-icon-document"></i>下载文档</el-link></a>
  141. </span>
  142. <span v-if="isModifyMode"> <a href="http://mooctest-site.oss-cn-shanghai.aliyuncs.com/excel-template.xlsx">&nbsp;&nbsp;&nbsp;<i class="el-icon-document"></i>示例下载</a></span>
  143. </span>
  144. </el-form-item>
  145. <el-form-item v-if="!isModifyMode && task.resource==2 && needAcceptedPWD && showBD" label="任务接收码" prop="agencyName" style="width: 700px;">
  146. <span>{{task.acceptedPassword}}</span>
  147. </el-form-item>
  148. <el-form-item label="任务截止时间" prop="datetime">
  149. <div class="block" v-if="isModifyMode">
  150. <el-date-picker
  151. size="small"
  152. v-model="task.datetime"
  153. type="datetime"
  154. placeholder="选择截止时间"
  155. align="right"
  156. :picker-options="pickerOptions"
  157. ></el-date-picker>
  158. </div>
  159. <span v-if="!isModifyMode">{{ dateFormat(new Date(task.datetime), 'yyyy-MM-dd HH:mm:ss') }}</span>
  160. </el-form-item>
  161. <el-form-item v-if="isModifyMode">
  162. <div class="btn btn-small btn-info" @click="updateTask()">确认修改</div>
  163. <!--<div class="btn btn-small" @click="resetForm()">重置</div>-->
  164. <div class="btn btn-small" @click="cancelMode()">取消</div>
  165. </el-form-item>
  166. <el-form-item v-if="!isModifyMode">
  167. <el-button size="mini" @click="toProject()">项目详情</el-button>
  168. <el-popover
  169. placement="top-start"r
  170. title="确认拒绝?"
  171. width="200"
  172. trigger="hover"
  173. content="拒绝后不可再接收此任务,且该任务对您不可见">
  174. <el-button v-if="taskOperationControl.reject" type="danger" size="mini" slot="reference"
  175. @click="rejectTask()">拒绝任务
  176. </el-button>
  177. </el-popover>
  178. <el-popover
  179. placement="top-start"
  180. title="确认接收?"
  181. width="200"
  182. trigger="hover"
  183. content="接收任务后请认真完成!">
  184. <el-button v-if="taskOperationControl.receive" type="primary" size="mini" slot="reference"
  185. @click="showTaskCodeModal = !showTaskCodeModal">接收任务
  186. </el-button>
  187. </el-popover>
  188. <el-button v-if="taskOperationControl.update" type="primary" size="mini" @click="modifyForm()">修改任务
  189. </el-button>
  190. <el-button v-if="taskOperationControl.writeReport" type="primary" size="mini" @click="gotoWriteReport()">
  191. 填写报告
  192. </el-button>
  193. <el-button v-if="featureTaskRecommend && taskOperationControl.taskRecommend" type="primary" size="mini"
  194. @click="recommendTask()">任务推荐
  195. </el-button>
  196. <el-button v-if="taskOperationControl.exportTask" type="primary" size="mini" @click="toExportTask()">导出任务</el-button>
  197. <el-button v-if="taskOperationControl.uploadReport" type="primary" size="mini" @click="toCreateReport()">
  198. 上传报告
  199. </el-button>
  200. <el-button v-if="taskOperationControl.forkTask" type="primary" size="mini"
  201. @click="showTaskForkModal = !showTaskForkModal">
  202. fork任务
  203. </el-button>
  204. <el-button v-if="taskOperationControl.taskDemonstrate" type="success" size="mini"
  205. @click="gotoDataboard()">
  206. 任务面板
  207. </el-button>
  208. <el-popover
  209. placement="top-start"
  210. title="确认提交?"
  211. width="200"
  212. trigger="hover"
  213. content="提交任务后不可更改,等待区域管理员验收">
  214. <el-button v-if="taskOperationControl.finish" type="primary" size="mini" slot="reference"
  215. @click="submitTaskRequest()">提交任务
  216. </el-button>
  217. </el-popover>
  218. <el-popover
  219. placement="top-start"
  220. title="确认结束?"
  221. width="200"
  222. trigger="hover"
  223. content="测评机构已提交结束申请,请确认是否结束该任务">
  224. <el-button v-if="taskOperationControl.confirmFinish" type="success" size="mini" slot="reference"
  225. @click="endTask()">结束任务
  226. </el-button>
  227. </el-popover>
  228. </el-form-item>
  229. </el-form>
  230. </el-col>
  231. <el-col :span="9">
  232. <TaskCloud :info="wordCloud" v-if="wordCloud.length"></TaskCloud>
  233. </el-col>
  234. </el-row>
  235. </div>
  236. <div class="create-body" v-if="!isModifyMode">
  237. <div class="title h2">用户报告列表</div>
  238. <el-collapse accordion style="margin: 0 30px">
  239. <el-collapse-item v-for="(item,index) in acceptedUserList" :key="item.id">
  240. <template slot="title">
  241. <el-row style="width: 100%;font-size: 16px">
  242. <el-col :span="6">{{ item.userVO.userName }}</el-col>
  243. <el-col :span="6">{{ item.userVO.email }}</el-col>
  244. <el-col :span="6">
  245. <el-tag type="success" v-if="item.crowdReportVOS">已提交报告</el-tag>
  246. <el-tag type="info" v-if="!item.crowdReportVOS">未提交报告</el-tag>
  247. </el-col>
  248. <el-col :span="6">
  249. <el-tag type="success" v-if="item.isCommitted">已提交任务</el-tag>
  250. <el-tag type="info" v-if="!item.isCommitted">未提交任务</el-tag>
  251. </el-col>
  252. </el-row>
  253. </template>
  254. <report-list v-bind:reports="item.crowdReportVOS" v-bind:taskId="taskId" v-bind:projectId="projectId"/>
  255. </el-collapse-item>
  256. </el-collapse>
  257. <!-- <report-list v-if="isAgency" v-bind:reports="reportList" v-bind:taskId="taskId" v-bind:projectId="projectId"/>-->
  258. <!-- <report-list v-bind:reports="reportList" v-bind:taskId="taskId" v-bind:projectId="projectId"/>-->
  259. </div>
  260. <el-dialog title="请输入任务接收码" :visible.sync="showTaskCodeModal">
  261. <el-input v-model="taskValidCode" autocomplete="off" placeholder="请输入任务接收码"></el-input>
  262. <div slot="footer" class="dialog-footer">
  263. <el-button @click="showTaskCodeModal = false;taskValidCode = ''">取 消</el-button>
  264. <el-button type="primary" @click="handleTaskCodeValid()">确 定</el-button>
  265. </div>
  266. </el-dialog>
  267. <el-dialog title="Fork任务?" :visible.sync="showTaskForkModal">
  268. <div>确定基于该任务Fork新任务?</div>
  269. <div slot="footer" class="dialog-footer">
  270. <el-button @click="showTaskForkModal = false;">取 消</el-button>
  271. <el-button type="primary" @click="handleForkTask()">确 定</el-button>
  272. </div>
  273. </el-dialog>
  274. </div>
  275. </template>
  276. <script>
  277. import ResourceType from '@/constants/enum/resource-type.js'
  278. import provincecity from '@/components/commons/ProvinceCity'
  279. import ReportList from '@/components/report/ReportList'
  280. import TaskCloud from '@/components/task/TaskCloud'
  281. import Http from '@/js/http.js'
  282. import Apis from '@/js/api.js'
  283. import {CONFIG} from "../../config";
  284. import {notify} from '@/constants/index'
  285. import {
  286. ensureEndTask,
  287. exportTask,
  288. getAllAgencies,
  289. getAllAgencyAndTestUser,
  290. getAllServiceTypes,
  291. getFormalTimeFromDate,
  292. getProvinceCodeByProvinceName,
  293. getProvinceNameByProvinceCode,
  294. getTask,
  295. receiveTaskRequest,
  296. rejectTask,
  297. storageGet,
  298. submitTaskRequest,
  299. updateTask,
  300. getTaskWordCloud,
  301. getTaskWordCloudByDescription,
  302. refreshToken
  303. } from '@/js/index'
  304. import {AxiosInstance as axios} from "axios";
  305. export default {
  306. name: 'Task',
  307. components: {
  308. provincecity,
  309. ReportList,
  310. TaskCloud
  311. },
  312. data() {
  313. return {
  314. showTaskCodeModal: false,
  315. showTaskForkModal: false,
  316. taskValidCode:'',
  317. featureTaskRecommend: CONFIG.feature_task_recommend,
  318. taskRecommendUrl: CONFIG.task_recommend_url,
  319. needAcceptedPWD: CONFIG.feature_task_acceptedPWD,
  320. currType: {},
  321. user: {},
  322. serviceName: '',
  323. showBD: true,
  324. rolesPermissions: {},
  325. loading: false,
  326. isModifyMode: false,
  327. institutionArray: [],
  328. tabPosition: 'top',
  329. resourceType: ResourceType,
  330. serviceType: [],
  331. taskId: '',
  332. projectId: '',
  333. taskOperationControl: {
  334. confirmFinish: false,
  335. finish: false,
  336. receive: false,
  337. update: false,
  338. uploadReport: false,
  339. writeReport: false,
  340. taskDemonstrate: false,
  341. taskRecommend: false,
  342. exportTask: false,
  343. forkTask: false,
  344. },
  345. crowdReportUrl: '',
  346. exportTaskUrl: '',
  347. wordCloud: [],
  348. task: {
  349. agencyId: '',
  350. agencyName: '',
  351. acceptedPassword: '',
  352. status: '',
  353. name: '',
  354. desc: '',
  355. serviceType: '',
  356. resource: '',
  357. location: {},
  358. institution: 0,
  359. datetime: '',
  360. quotePrice: '',
  361. fixedPrice: '',
  362. doc: [],
  363. requireDocUrl: '',
  364. participantCount: 1,
  365. exportUrl: '',
  366. title: '',
  367. description: '',
  368. endPoint: {
  369. collaborativeType:0,
  370. token: '',
  371. threePageUrl:''
  372. },
  373. writeReportUrl:'',
  374. threePageList: []
  375. },
  376. reportList: [],
  377. pickerOptions: {
  378. shortcuts: [
  379. {
  380. text: '今天',
  381. onClick(picker) {
  382. picker.$emit('pick', new Date())
  383. }
  384. },
  385. {
  386. text: '昨天',
  387. onClick(picker) {
  388. const date = new Date()
  389. date.setTime(date.getTime() - 3600 * 1000 * 24)
  390. picker.$emit('pick', date)
  391. }
  392. },
  393. {
  394. text: '一周前',
  395. onClick(picker) {
  396. const date = new Date()
  397. date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
  398. picker.$emit('pick', date)
  399. }
  400. }
  401. ]
  402. },
  403. rules: {
  404. title: [
  405. {required: true, message: '请输入任务名称', trigger: 'blur'},
  406. {min: 5, max: 50, message: '任务名称长度在 5 到 50 个字符', trigger: 'blur'}
  407. ],
  408. serviceType: [
  409. {required: true, message: '测试类型不可为空', trigger: 'change'},
  410. ],
  411. description: [{required: true, message: '请填写描述', trigger: 'blur'}],
  412. //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
  413. quotePrice: [
  414. {required: true, message: '预算不可为空', trigger: 'blur'},
  415. {
  416. validator: (rule, value, callback) => {
  417. if (value < 0) {
  418. callback(new Error('请输入不小于0的数'))
  419. } else {
  420. callback()
  421. }
  422. }, trigger: 'blur'
  423. },
  424. ],
  425. 'endPoint.threePageUrl': [
  426. {
  427. validator: (rule, value, callback) => {
  428. if (this.currType === 1 && this.task.endPoint.threePageUrl === '') {
  429. callback(new Error('请上传测试大纲'))
  430. } else {
  431. callback()
  432. }
  433. }, trigger: 'change'
  434. },
  435. ],
  436. resource: [
  437. {required: true},
  438. {
  439. validator: (rule, value, callback) => {
  440. if (value == 0 && this.task.institution == 0) {
  441. callback(new Error('定向发布至少要选择一个测评机构'))
  442. } else {
  443. callback()
  444. }
  445. }, trigger: 'change'
  446. },
  447. ],
  448. endPoint: [
  449. {
  450. validator: (rule, value, callback) => {
  451. if (this.currType.type === 1 && this.task.endPoint.serverCode === '') {
  452. callback(new Error('请填写对应得服务序列号'))
  453. } else {
  454. callback()
  455. }
  456. }, trigger: ['change', 'blur']
  457. },
  458. ],
  459. datetime: [{required: true, message: '截止时间不可为空', trigger: 'blur'}],
  460. },
  461. acceptedUserList: [],
  462. shortLink: '',
  463. editShortLink: false,
  464. }
  465. },
  466. watch: {
  467. institutionArray(val) {
  468. this.institutionArray = val
  469. },
  470. serviceType(val) {
  471. this.serviceType = val
  472. },
  473. deep: true
  474. },
  475. mounted() {
  476. this.$nextTick(() => {
  477. this.init()
  478. })
  479. },
  480. methods: {
  481. handleTaskCodeValid(){
  482. let str1 = this.projectId;
  483. let str2 = this.task.code;
  484. let str = str1.substring(str1.length-2) + str2.substring(str2.length-2);
  485. if(str === this.taskValidCode){
  486. //接收码正确,可以正确接收任务
  487. this.receiveTask();
  488. this.showTaskCodeModal = false;
  489. }else{
  490. // 提示接收码错误
  491. notify('error', '接收码错误')
  492. }
  493. },
  494. handleForkTask(){
  495. //跳转到taskFork
  496. this.$router.push({
  497. name: 'TaskCreate',
  498. params: this.task
  499. })
  500. this.showTaskForkModal = false;
  501. },
  502. //跳转到任务对应的数据面板
  503. gotoDataboard() {
  504. window.open(this.task.endPoint.token)
  505. },
  506. //根据短链接获取生成databoard
  507. getTaskDataBoard() {
  508. this.showLoading()
  509. Http.put(`/api/project/${this.projectId}/task/${this.taskId}/addToken`, {"token": this.shortLink}).then((res) => {
  510. this.taskOperationControl = res.taskOperationControl;
  511. this.task.endPoint = res.crowdTaskVO.endPointVO;
  512. this.shortLink = res.crowdTaskVO.endPointVO.token;
  513. if (this.shortLink != '') {
  514. this.editShortLink = false;
  515. }
  516. this.hideLoading()
  517. })
  518. },
  519. getServiceByCode(code) {
  520. let serviceName = this.serviceType.filter((item) => {
  521. return item.code === code;
  522. });
  523. return serviceName && serviceName[0] && serviceName[0]['name']
  524. },
  525. handleTestTypeChange(val) {
  526. let type = this.serviceType.filter((item) => {
  527. return item.name === val;
  528. });
  529. // console.log(type,val)
  530. this.currType = type[0] ? type[0] : {};
  531. if (this.currType.type === 0) {
  532. this.$refs.task.clearValidate('endPoint');
  533. } else {
  534. this.task.resource = '2';
  535. this.task.endPoint.collaborativeType = 0;
  536. }
  537. },
  538. init() {
  539. console.log(CONFIG)
  540. this.taskId = this.$route.params.taskId
  541. this.projectId = this.$route.params.projectId
  542. this.setUserInfo()
  543. this.setServiceType()
  544. //this.loadData(this.projectId, this.taskId)
  545. this.getTaskDetail()
  546. this.getWordCloud()
  547. // this.setInstitutions()
  548. },
  549. //北斗测试报告填写跳转
  550. gotoWriteReport() {
  551. //重开一个界面去进行报告填写
  552. window.open(this.task.writeReportUrl, '_blank');
  553. //更换token
  554. refreshToken(this.projectId,this.taskId,this.refreshSuccess);
  555. },
  556. refreshSuccess(res) {
  557. this.task.writeReportUrl = res.data;
  558. },
  559. //跳转至项目详情页面
  560. toProject() {
  561. this.$router.push({
  562. name: 'Project',
  563. params: {projectId: this.projectId}
  564. })
  565. },
  566. //切换至可编辑页面
  567. modifyForm() {
  568. // this.task.serviceType = '
  569. this.setServiceType()
  570. this.setInstitutions();
  571. this.isModifyMode = true
  572. },
  573. //切换至不可编辑页面
  574. cancelMode() {
  575. this.isModifyMode = false
  576. },
  577. //重置表单
  578. resetForm() {
  579. this.task.name = ''
  580. this.task.desc = ''
  581. this.task.quotePrice = ''
  582. this.task.fixedPrice = ''
  583. this.task.type = ''
  584. this.task.resource = '2' //如果是广场不用管Location和institution ,定向看institution,区域看location
  585. this.task.location = {provinceCode: '', cityCode: ''}
  586. this.task.institution = 0
  587. this.task.datetime = ''
  588. this.task.participantCount = 1
  589. // this.task.endPointVO.caseId = ''
  590. // this.task.endPointVO.examId = ''
  591. },
  592. //显示页面加载画面
  593. showLoading() {
  594. this.loading = true
  595. },
  596. //隐藏页面加载画面
  597. hideLoading() {
  598. this.loading = false
  599. },
  600. //加载用户信息
  601. setUserInfo() {
  602. this.user = storageGet('user')
  603. this.rolesPermissions = storageGet('rolesPermissions')
  604. if (storageGet('rolesPermissions').isRegionManager || storageGet('rolesPermissions').isSystemAdministrator) {
  605. this.showBD = true;
  606. } else {
  607. this.showBD = false;
  608. }
  609. },
  610. //加载任务的测试类型
  611. setServiceType() {
  612. getAllServiceTypes().then((res) => {
  613. this.serviceType = res
  614. }).catch((error) => {
  615. notify('error', '加载测试类型失败')
  616. })
  617. },
  618. //加载所有的测评机构
  619. setInstitutions() {
  620. getAllAgencyAndTestUser().then((res) => {
  621. this.institutionArray = res
  622. }).catch((error) => {
  623. notify('error', '获取机构列表失败')
  624. })
  625. },
  626. //获取任务详情
  627. getTaskDetail() {
  628. this.showLoading()
  629. getTask(this.projectId, this.taskId, this.getTaskDetailSuccess, this.getTaskDetailFail)
  630. },
  631. //获取词云
  632. getWordCloud() {
  633. getTaskWordCloud(this.projectId, this.taskId, this.getTaskCloudSuccess, this.getTaskCloudFail)
  634. },
  635. //获取词云
  636. getWordCloudByDescription() {
  637. getTaskWordCloudByDescription(this.projectId, this.taskId, this.task.description, this.getTaskCloudSuccess, this.getTaskCloudFail)
  638. },
  639. getTaskCloudSuccess(words) {
  640. this.wordCloud = words.data;
  641. },
  642. getTaskCloudFail(err) {
  643. notify('error', err)
  644. },
  645. //获取任务详情成功时回调函数
  646. getTaskDetailSuccess(res) {
  647. this.hideLoading()
  648. // console.log(res)
  649. this.task = res.crowdTaskVO
  650. this.taskId = res.crowdTaskVO.id
  651. this.projectId = res.crowdTaskVO.projectId
  652. this.task.code = res.crowdTaskVO.code
  653. this.task.title = res.crowdTaskVO.title
  654. this.task.description = res.crowdTaskVO.description
  655. this.task.serviceType = res.crowdTaskVO.serviceType
  656. this.task.resource = res.crowdTaskVO.resource.toString()
  657. this.task.location = getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
  658. this.task.institution = res.crowdTaskVO.institution
  659. this.task.datetime = new Date(res.crowdTaskVO.datetime)
  660. this.task.quotePrice = res.crowdTaskVO.quotePrice
  661. this.task.agencyName = res.crowdTaskVO.agencyName
  662. this.task.acceptedPassword = res.crowdTaskVO.acceptedPassword
  663. this.task.acceptedCount = res.crowdTaskVO.acceptedCount
  664. this.task.participantCount = res.crowdTaskVO.participantCount
  665. this.task.fixedPrice = res.crowdTaskVO.fixedPrice
  666. this.task.doc = []
  667. this.task.requireDocUrl = res.crowdTaskVO.requirementFile
  668. this.task.agencyId = res.crowdTaskVO.agencyId
  669. this.task.exportUrl = res.crowdTaskVO.exportUrl
  670. this.task.status = res.crowdTaskVO.status
  671. this.task.statusVO = res.crowdTaskVO.statusVO
  672. this.task.writeReportUrl = res.crowdTaskVO.writeReportUrl
  673. this.task.endPoint = res.crowdTaskVO.endPointVO ? res.crowdTaskVO.endPointVO : {}
  674. this.taskOperationControl = res.taskOperationControl;
  675. this.acceptedUserList = res.acceptedUserList;
  676. this.crowdReportUrl = res.crowdTaskVO.writeReportUrl;
  677. this.handleFormatReport(this.acceptedUserList);
  678. this.handleTestTypeChange(res.crowdTaskVO.serviceType);
  679. this.handleTestTypeChange(res.crowdTaskVO.serviceType);
  680. // this.serviceName = this.getServiceByCode(res.crowdTaskVO.serviceType);
  681. if (res.crowdTaskVO.endPointVO) {
  682. if (res.crowdTaskVO.endPointVO.token) {
  683. this.shortLink = res.crowdTaskVO.endPointVO.token;
  684. this.editShortLink = false
  685. } else {
  686. this.editShortLink = true
  687. }
  688. }
  689. // this.wordCloud = res.wordCloudList;
  690. // console.log(res.crowdTaskVO.endPointVO.token)
  691. // console.log(this.isModifyMode)
  692. },
  693. //获取任务详情失败时回调函数
  694. getTaskDetailFail(error) {
  695. this.hideLoading()
  696. notify('error', '获取任务详情失败:' + error.data)
  697. },
  698. //处理显示报告
  699. handleFormatReport(acceptedUserList) {
  700. acceptedUserList.map((user) => {
  701. user.crowdReportVOS && user.crowdReportVOS.map((report) => {
  702. report.userName = user.userVO.userName;
  703. this.reportList.push(report);
  704. })
  705. })
  706. },
  707. dateFormat(date, format) {
  708. date = new Date(date)
  709. let o = {
  710. 'M+': date.getMonth() + 1, //month
  711. 'd+': date.getDate(), //day
  712. 'H+': date.getHours(), //hour+8小时
  713. 'm+': date.getMinutes(), //minute
  714. 's+': date.getSeconds(), //second
  715. 'q+': Math.floor((date.getMonth() + 3) / 3), //quarter
  716. 'S': date.getMilliseconds() //millisecond
  717. }
  718. if (/(y+)/.test(format)) {
  719. format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
  720. }
  721. for (let k in o)
  722. if (new RegExp('(' + k + ')').test(format))
  723. format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
  724. return format;
  725. },
  726. //更新任务信息
  727. updateTask() {
  728. this.$refs['task'].validate(valid => {
  729. if (valid) {
  730. this.showLoading()
  731. const newTask = {
  732. name: this.task.title,
  733. desc: this.task.description,
  734. type: this.serviceType.filter(type => type.name === this.task.serviceType)[0].code,
  735. resource: this.task.resource,
  736. location: this.task.location == null ? {} : getProvinceNameByProvinceCode(this.task.location.provinceCode, this.task.location.cityCode),
  737. institution: this.task.institution ? this.task.institution : null,
  738. datetime: this.task.datetime,
  739. quotePrice: this.task.quotePrice,
  740. fixedPrice: this.task.fixedPrice,
  741. requirementFile: this.task.requireDocUrl,
  742. participantCount: this.task.participantCount,
  743. endPoint: this.task.endPoint
  744. }
  745. //console.log(newTask)
  746. updateTask(this.projectId, this.taskId, newTask, this.updateTaskSuccess, this.updateTaskFail)
  747. } else {
  748. notify('error', '表单填写有误!')
  749. return false
  750. }
  751. })
  752. },
  753. //更新任务信息成功时回调函数
  754. updateTaskSuccess(res) {
  755. this.cancelMode()
  756. this.task = res.crowdTaskVO
  757. this.taskOperationControl = res.taskOperationControl
  758. this.taskId = res.crowdTaskVO.id
  759. this.projectId = res.crowdTaskVO.projectId
  760. this.task.projectId = res.crowdTaskVO.projectId
  761. this.task.title = res.crowdTaskVO.title
  762. this.task.description = res.crowdTaskVO.description
  763. this.task.serviceType = res.crowdTaskVO.serviceType
  764. this.task.resource = res.crowdTaskVO.resource.toString()
  765. this.task.location = res.crowdTaskVO.location == null ? {
  766. provinceCode: 3200,
  767. cityCode: 3201
  768. } : getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
  769. this.task.institution = res.crowdTaskVO.institution
  770. this.task.datetime = new Date(res.crowdTaskVO.datetime)
  771. this.task.quotePrice = res.crowdTaskVO.quotePrice
  772. this.task.fixedPrice = res.crowdTaskVO.fixedPrice
  773. // this.task.endPointVO = res.crowdTaskVO.endPointVO
  774. this.task.doc = []
  775. this.task.requireDocUrl = res.crowdTaskVO.requirementFile
  776. this.task.participantCount = res.crowdTaskVO.participantCount
  777. this.task.endPoint = res.crowdTaskVO.endPointVO ? res.crowdTaskVO.endPointVO : {
  778. serverCode: '',
  779. }
  780. this.task.createTime = res.crowdTaskVO.createTime,
  781. this.reportList = res.crowdReportVOList
  782. this.crowdReportUrl = res.crowdTaskVO.writeReportUrl;
  783. this.acceptedUserList = res.acceptedUserList
  784. this.handleTestTypeChange(res.crowdTaskVO.serviceType);
  785. this.serviceName = this.getServiceByCode(res.crowdTaskVO.serviceType)
  786. this.getWordCloudByDescription()
  787. this.hideLoading()
  788. notify('success', '修改成功')
  789. },
  790. //更新任务信息失败时回调函数
  791. updateTaskFail(error) {
  792. notify('error', '修改失败:' + error.data)
  793. this.hideLoading()
  794. },
  795. //上传任务需求文档
  796. uploadRequireDoc(param) {
  797. const formData = new FormData()
  798. let config = {
  799. //添加请求头
  800. headers: {'Content-Type': 'multipart/form-data'},
  801. }
  802. formData.append('file', param.file)
  803. Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  804. notify('success', '上传成功')
  805. // console.log(res)
  806. this.task.requireDocUrl = res.data
  807. }).catch((error) => {
  808. // notify('error', '上传失败:' + error.data)
  809. this.uploadRequireDocFail(error)
  810. })
  811. },
  812. //上传测试大纲
  813. uploadThreePage(param) {
  814. const formData = new FormData()
  815. let config = {
  816. //添加请求头
  817. headers: {'Content-Type': 'multipart/form-data'},
  818. }
  819. formData.append('file', param.file)
  820. Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  821. notify('success', '上传成功')
  822. this.task.endPoint.threePageUrl = res.data
  823. console.log("this.task.endPoint.threePageUrl " + this.task.endPoint.threePageUrl)
  824. }).catch((error) => {
  825. // notify('error', '上传失败:' + error.data)
  826. this.uploadRequireDocFail(error)
  827. })
  828. },
  829. //上传任务需求文档失败时回调函数
  830. uploadRequireDocFail(error) {
  831. this.hideLoading()
  832. // notify('error', '任务需求文档上传失败:' + error.data)
  833. },
  834. //文档上传前响应函数
  835. //移除文档前的响应函数
  836. beforeRemove(file, fileList) {
  837. //return this.$confirm(`确定移除 ${file.name}?`)
  838. },
  839. //移除文档时的响应函数
  840. handleRemove(file, fileList) {
  841. console.log(file, fileList)
  842. },
  843. //需求文档添加进来时的响应函数
  844. handleExceed(files, fileList) {
  845. this.$message.warning(
  846. `当前限制选择 1 个文件,本次选择了 ${
  847. files.length
  848. } 个文件,共选择了 ${files.length + fileList.length} 个文件`
  849. )
  850. },
  851. //接收任务
  852. receiveTask() {
  853. this.$confirm('确认接收任务?', '提示', {
  854. confirmButtonText: '确认接收',
  855. cancelButtonText: '取消',
  856. type: 'success'
  857. }).then(() => {
  858. this.showLoading()
  859. receiveTaskRequest(this.projectId, this.taskId, this.user.userVO.id, this.receiveTaskSuccess, this.receiveTaskFail)
  860. }).catch(() => {
  861. })
  862. },
  863. //接收任务成功时的回调函数
  864. receiveTaskSuccess(res) {
  865. this.hideLoading()
  866. // this.getTaskDetail();
  867. notify('success', '接收任务成功')
  868. this.getTaskDetailSuccess(res);
  869. // console.log(res)
  870. // this.taskOperationControl = res.taskOperationControl
  871. // this.task.status = res.crowdTaskVO.status
  872. // this.task.institution = res.crowdTaskVO.institution
  873. // this.task = res.crowdTaskVO
  874. },
  875. //接收任务失败时的回调函数
  876. receiveTaskFail(error) {
  877. this.hideLoading()
  878. notify('error', '接收任务失败:' + error.data)
  879. },
  880. // 任务推荐
  881. recommendTask() {
  882. let task = {
  883. "title": this.task.title,
  884. "description": this.task.description,
  885. "participantCount": this.task.participantCount,
  886. "quotePrice": this.task.quotePrice,
  887. "requirementFile": this.task.requireDocUrl,
  888. "serviceType": this.task.serviceType,
  889. "createTime": this.task.createTime,
  890. "datetime": this.task.datetime
  891. };
  892. Http.post('/recommendationtest/query', task).then((res) => {
  893. window.open(this.taskRecommendUrl, "_blank");
  894. })
  895. },
  896. //拒绝任务
  897. rejectTask() {
  898. this.$confirm('确认拒绝任务?拒绝后将不能再接收该任务', '提示', {
  899. confirmButtonText: '确认拒绝',
  900. cancelButtonText: '取消',
  901. type: 'success'
  902. }).then(() => {
  903. this.showLoading()
  904. rejectTask(this.projectId, this.taskId, this.rejectTaskSuccess, this.rejectTaskFail)
  905. }).catch(() => {
  906. })
  907. },
  908. //拒绝任务成功时的回调函数
  909. rejectTaskSuccess(res) {
  910. this.hideLoading()
  911. this.$router.push({
  912. name: 'Mine'
  913. })
  914. notify('success', '拒绝任务成功,已为您自动跳转到个人中心')
  915. },
  916. //拒绝任务失败时的回调函数
  917. rejectTaskFail(error) {
  918. this.hideLoading()
  919. notify('error', '拒绝任务失败:' + error.data)
  920. },
  921. //提交结束任务申请
  922. submitTaskRequest() {
  923. this.$confirm('确认提交任务?提交后将不能再修改', '提示', {
  924. confirmButtonText: '确认提交',
  925. cancelButtonText: '取消',
  926. type: 'success'
  927. }).then(() => {
  928. this.showLoading()
  929. submitTaskRequest(this.projectId, this.taskId, this.submitTaskRequestSuccess, this.submitTaskRequestFail)
  930. }).catch(() => {
  931. })
  932. },
  933. //提交结束任务申请成功时的回调函数
  934. submitTaskRequestSuccess(res) {
  935. this.hideLoading()
  936. // this.task = res.crowdTaskVO
  937. // this.taskOperationControl = res.taskOperationControl
  938. // this.task.status = res.crowdTaskVO.status
  939. // this.task.institution = res.crowdTaskVO.institution
  940. notify('success', '提交任务成功,等待区域管理员审核')
  941. this.getTaskDetailSuccess(res);
  942. // this.getTaskDetail();
  943. },
  944. //提交结束任务申请失败时的回调函数
  945. submitTaskRequestFail(error) {
  946. this.hideLoading()
  947. notify('error', '提交任务失败:' + error.data)
  948. },
  949. //结束任务
  950. endTask() {
  951. this.$confirm('确认结束任务?', '提示', {
  952. confirmButtonText: '确认结束',
  953. cancelButtonText: '取消',
  954. type: 'success'
  955. }).then(() => {
  956. // this.getTaskDetail()
  957. this.showLoading()
  958. ensureEndTask(this.projectId, this.taskId, this.endTaskSuccess, this.endTaskFail)
  959. }).catch(() => {
  960. })
  961. },
  962. //结束任务成功时的回调函数
  963. endTaskSuccess(res) {
  964. // this.taskOperationControl = res.taskOperationControl
  965. // this.task.status = res.crowdTaskVO.status
  966. // this.task.institution = res.crowdTaskVO.institution
  967. notify('success', '结束任务成功!')
  968. this.getTaskDetailSuccess(res);
  969. this.hideLoading()
  970. // this.getTaskDetail();
  971. },
  972. //结束任务失败时的回调函数
  973. endTaskFail(error) {
  974. this.hideLoading()
  975. notify('error', '结束任务失败:' + error.data)
  976. },
  977. // 导出任务
  978. toExportTask() {
  979. exportTask(this.projectId, this.taskId, this.exportTaskSuccess, this.exportTaskFail);
  980. },
  981. // 导出任务成功时的回调函数
  982. exportTaskSuccess(res) {
  983. this.hideLoading()
  984. console.log(res.data)
  985. this.exportTaskUrl = res.data;
  986. window.open(this.exportTaskUrl, "_self");
  987. notify('success', '任务导出成功!')
  988. },
  989. // 导出任务失败时的回调函数
  990. exportTaskFail(error) {
  991. this.hideLoading()
  992. notify('error', '导出任务失败:' + error.data)
  993. },
  994. //跳转到创建项目报告页面
  995. toCreateReport() {
  996. this.$router.push({
  997. name: 'TaskReportCreate',
  998. params: {
  999. scope: 1,
  1000. dependencyCode: this.taskId,
  1001. projectId: this.projectId,
  1002. taskId: this.taskId,
  1003. }
  1004. })
  1005. },
  1006. reformDate(date) {
  1007. return getFormalTimeFromDate(date)
  1008. }
  1009. },
  1010. }
  1011. //回收站
  1012. //
  1013. // updateLocation (location) {
  1014. // console.log(location)
  1015. // const loactionName = getProvinceNameByProvinceCode(location.provinceCode, location.cityCode)
  1016. // // var provinceName = ''
  1017. // // var cityName = ''
  1018. // // for (var item of provinceCityJSON.provinces) {
  1019. // // if (item.code === location.provinceCode) {
  1020. // // provinceName = item.name
  1021. // // for (var city of item.cities) {
  1022. // // if (city.code === location.cityCode) {
  1023. // // cityName = city.name
  1024. // // break
  1025. // // }
  1026. // // }
  1027. // // }
  1028. // // }
  1029. // return loactionName.provinceCode + ' / ' + loactionName.cityCode
  1030. // },
  1031. //
  1032. // locationChange (provinceId, cityId) {
  1033. // if (provinceId || cityId) {
  1034. // this.task.location = {provinceCode: provinceId, cityCode: cityId}
  1035. // }
  1036. // },
  1037. // submitForm (formName) {
  1038. // this.$refs[formName].validate(valid => {
  1039. // if (valid) {
  1040. // this.isModifyMode = false
  1041. //
  1042. // } else {
  1043. // console.log('error submit!!')
  1044. // return false
  1045. // }
  1046. // })
  1047. // },
  1048. </script>
  1049. <style lang="less" scoped>
  1050. .el-radio {
  1051. margin: 10px 20px 10px 0;
  1052. }
  1053. .el-form-item /deep/ .el-tabs__content {
  1054. /*max-height: 120px !important;*/
  1055. overflow: auto;
  1056. }
  1057. .el-collapse-item__content {
  1058. padding-bottom: 0 !important;
  1059. }
  1060. </style>
  1061. <style lang="scss">
  1062. .three-page-upload {
  1063. label {
  1064. &:before{
  1065. content:'* ';
  1066. color:red
  1067. }
  1068. }
  1069. }
  1070. </style>