weeklyCustomization.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <template>
  2. <div class='weeklyCustomization'>
  3. <div class="title">
  4. <el-button @click="getCurrentWeek(-7)" size="small">&lt;&lt;</el-button>
  5. <el-button @click="getCurrentWeek(0)" size="small">本周</el-button>
  6. <el-button @click="getCurrentWeek(7)" size="small">&gt;&gt;</el-button>
  7. </div>
  8. <div class="weekcen flexColumn" v-loading="submitLoading">
  9. <div class="flexColumnAuto flex1">
  10. <el-table :data="weekTableData" border style="width: 100%;" height="0" :span-method="arraySpanMethod">
  11. <el-table-column prop="dateTime" label="日期" width="180">
  12. <template slot-scope="scope">
  13. <span>{{ scope.row.dateTime }}</span>
  14. (<span>{{ scope.row.weekDayTxt }}</span>)
  15. </template>
  16. </el-table-column>
  17. <el-table-column label="项目" width="220">
  18. <template slot-scope="scope">
  19. <el-select v-model="scope.row.projectId" size="small" placeholder="请选择项目" clearable
  20. @change="changeProject(scope.row.projectId, scope.$index)" :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill">
  21. <el-option v-for="item in projectList" :key="item.id" :label="item.projectName"
  22. :value="item.id">
  23. </el-option>
  24. </el-select>
  25. </template>
  26. </el-table-column>
  27. <el-table-column label="分组" width="180">
  28. <template slot-scope="scope">
  29. <el-select v-model="scope.row.groupId" size="small" placeholder="请选择分组"
  30. @change="changeGroup(scope.row.groupId, scope.row.taskGroups, scope.$index)"
  31. :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill">
  32. <el-option v-for="item in scope.row.taskGroups" :key="item.id" :label="item.name"
  33. :value="item.id">
  34. </el-option>
  35. </el-select>
  36. </template>
  37. </el-table-column>
  38. <el-table-column prop="content" label="工作内容" width="300">
  39. <template slot-scope="scope">
  40. <el-input size="small" type="textarea" :rows="2" v-model="scope.row.content"
  41. :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill" resize="none"></el-input>
  42. </template>
  43. </el-table-column>
  44. <el-table-column prop="workingTime" label="时间(小时)" width="160">
  45. <template slot-scope="scope">
  46. <el-input-number size="small" v-model="scope.row.workingTime" :min="0" :max="12" :step="0.5"
  47. :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill"></el-input-number>
  48. </template>
  49. </el-table-column>
  50. <el-table-column prop="projectAuditorId" label="审批人" width="160">
  51. <template slot-scope="scope">
  52. <!-- <span v-if="user.userNameNeedTranslate != '1'">{{ scope.row.projectAuditorName }}</span>
  53. <span v-if="user.userNameNeedTranslate == '1'"><ww-open-data type='userName'
  54. :openid='scope.row.projectAuditorName'></ww-open-data></span> -->
  55. <span v-if="user.userNameNeedTranslate != '1'">{{ auditorNameFun(scope.row) }}</span>
  56. <span v-if="user.userNameNeedTranslate == '1'"><ww-open-data type='userName'
  57. :openid='scope.row.projectAuditorName'></ww-open-data></span>
  58. </template>
  59. </el-table-column>
  60. <el-table-column prop="state" label="状态" width="140" fixed="right">
  61. <template slot-scope="scope">
  62. <div class="controls">
  63. <el-tag v-if="scope.row.state == 0" type="warning">待审</el-tag>
  64. <el-tag v-if="scope.row.state == 1" type="success">通过</el-tag>
  65. <el-tag v-if="scope.row.state == 2" type="danger">拒绝</el-tag>
  66. <span v-if="scope.row.state != 1 && scope.row.canFill">
  67. <el-link type="primary" :underline="false" class="el-icon-circle-plus-outline"
  68. @click="insertRow(scope.$index)"></el-link>
  69. <el-link type="primary" :underline="false" class="el-icon-delete"
  70. @click="deleteRow(scope.$index)" v-if="!scope.row.isDelete"></el-link>
  71. </span>
  72. </div>
  73. </template>
  74. </el-table-column>
  75. </el-table>
  76. </div>
  77. <div class="weeklyCustomization_btn">
  78. <el-button @click="handleClose()">取 消</el-button>
  79. <el-button @click="submitWeekData(1)">暂 存</el-button>
  80. <el-button type="primary" @click="submitWeekData(0)">提 交</el-button>
  81. </div>
  82. </div>
  83. </div>
  84. </template>
  85. <script>
  86. import cloneDeep from 'lodash/cloneDeep'; // 深拷贝
  87. export default {
  88. name: '',
  89. components: {},
  90. props: {
  91. weekParentData: {
  92. type: Object,
  93. default: () => {
  94. return {}
  95. }
  96. },
  97. },
  98. data() {
  99. return {
  100. weekTableData: [],
  101. projectList: [],
  102. nowTime: this.dayjs().format('YYYY-MM-DD'),
  103. submitLoading: false,
  104. permissions: JSON.parse(sessionStorage.getItem("permissions")),
  105. user: JSON.parse(sessionStorage.getItem("user")),
  106. }
  107. },
  108. computed: {},
  109. watch: {},
  110. created() { },
  111. mounted() {
  112. this.$set(this, 'weekTableData', [])
  113. this.getCurrentWeek(0)
  114. this.getProjectList()
  115. },
  116. methods: {
  117. // 提交与暂存
  118. submitWeekData(draft) { // draft 暂存(1)提交(0)
  119. const newWeekData = cloneDeep(this.weekTableData)
  120. let strArr = this.judgmentData(newWeekData)
  121. const { allday } = this.user.timeType // 系统设置的每日工作时间
  122. if (strArr.length > 0) {
  123. this.$message({
  124. message: `【${strArr.join('、')}】填写工时合计非 ${allday} 小时`,
  125. type: "error"
  126. });
  127. return
  128. }
  129. let formData = new FormData();
  130. formData.append("draft", draft);
  131. let fixation = {
  132. id: -1,
  133. projectId: '',
  134. subProjectId: 0,
  135. taskId: 0,
  136. reportTimeType: 1,
  137. workingTime: 0,
  138. multiWorktime: 0,
  139. content: '',
  140. isOvertime: 0,
  141. // professionProgress: [],
  142. groupId: '',
  143. stage: '',
  144. createDate: '',
  145. projectAuditorId: '',
  146. basecostId: 0,
  147. degreeId: -1,
  148. customData: 0,
  149. customText: '-',
  150. }
  151. const arr = newWeekData
  152. .filter(data => data.projectId)
  153. .map(data => ({
  154. ...fixation,
  155. projectId: data.projectId,
  156. createDate: data.dateTime,
  157. content: data.content ? data.content : '',
  158. projectAuditorId: data.projectAuditorId,
  159. workingTime: data.workingTime,
  160. groupId: data.groupId,
  161. id: data.id || -1,
  162. }));
  163. arr.forEach(item => {
  164. Object.entries(item).forEach(([key, value]) => {
  165. formData.append(key, value);
  166. });
  167. });
  168. this.submitLoading = true
  169. this.http.uploadFile(this.port.report.editPort, formData,
  170. res => {
  171. this.submitLoading = false
  172. if (res.code == "ok") {
  173. this.$message({
  174. message: `${draft ? '暂存成功' : '提交成功'}`,
  175. type: "success"
  176. });
  177. this.$emit('weekClose')
  178. this.$emit('weekSubmit')
  179. } else {
  180. this.$message({
  181. message: `${draft ? '暂存失败:' : '提交失败:'}` + res.msg,
  182. type: "error"
  183. });
  184. }
  185. },
  186. error => {
  187. this.submitLoading = false
  188. this.$message({
  189. message: error,
  190. type: "error"
  191. });
  192. });
  193. },
  194. // 判断是否小于系统设置的每日工作时间
  195. judgmentData(data) {
  196. const { allday } = this.user.timeType // 系统设置的每日工作时间
  197. console.log(allday, '<======= 填写日报时长allday')
  198. const result = [];
  199. data.forEach((item) => {
  200. const date = item.dateTime;
  201. const index = result.findIndex((arr) => arr[0].dateTime === date);
  202. if (index === -1) {
  203. result.push([item]);
  204. } else {
  205. result[index].push(item);
  206. }
  207. });
  208. const strArr = result
  209. .filter((arr) => arr[0].projectId)
  210. .filter(
  211. (arr) => arr.reduce((sum, item) => sum + (+item.workingTime || 0), 0) != allday
  212. )
  213. .map((arr) => arr[0].dateTime);
  214. return strArr
  215. },
  216. // 项目切换事件
  217. changeProject(projectId, index) {
  218. this.$set(this.weekTableData[index], 'projectAuditorId', '')
  219. this.$set(this.weekTableData[index], 'projectAuditorName', '')
  220. this.$set(this.weekTableData[index], 'groupId', '')
  221. if (projectId) {
  222. this.getProjectGroup(projectId, index)
  223. }
  224. },
  225. // 分组切换事件
  226. changeGroup(groupId, groupList, index) {
  227. let newArr = groupList.filter(item => item.id == groupId)
  228. if (!newArr[0].inchargerId) {
  229. this.$message({
  230. message: `【${newArr[0].name}】分组未设置审批人,请联系该项目管理人员`,
  231. type: "error"
  232. });
  233. return
  234. }
  235. this.$set(this.weekTableData[index], 'projectAuditorId', newArr[0].inchargerId)
  236. this.$set(this.weekTableData[index], 'projectAuditorName', newArr[0].inchargerName)
  237. },
  238. // 获取周数据
  239. async getCurrentWeek(time) {
  240. if (!time) {
  241. this.nowTime = this.dayjs().format('YYYY-MM-DD')
  242. } else {
  243. this.nowTime = this.dayjs(this.nowTime).add(time, 'day').format('YYYY-MM-DD')
  244. }
  245. let { data } = await this.getData('/report/getWeeklyFillReportData', { targetDate: this.nowTime })
  246. const { dateList, projectList, sumTimeList, cardTimeList } = data;
  247. const weekTableData = dateList.flatMap(date => {
  248. const { weekDayTxt, date: dateTime, reportList, canFill } = date;
  249. const reports = reportList.map(report => ({ ...report, weekDayTxt, dateTime, canFill}));
  250. return reports.length > 0 ? reports : [{ weekDayTxt, dateTime, canFill}];
  251. });
  252. let sumSet = new Set();
  253. weekTableData.forEach(obj => {
  254. obj.isDelete = sumSet.has(obj.dateTime) ? false : true;
  255. sumSet.add(obj.dateTime);
  256. });
  257. this.weekTableData = weekTableData;
  258. console.log(weekTableData, '<========== weekTableData')
  259. },
  260. // 获取项目列表
  261. async getProjectList() {
  262. let { data } = await this.getData('/project/getProjectList', { forReport: 1 })
  263. this.projectList = data
  264. },
  265. // 获取项目下的分组
  266. async getProjectGroup(projectId, index) {
  267. const { isSubstitude } = this.weekParentData;
  268. let { data } = await this.getData('/task-group/listProjectGroupAndAuditor', { projectId, isSubstitude: isSubstitude ? 1 : 0 })
  269. if (data.length == 0) {
  270. this.$message({
  271. message: '分组未设置,请联系该项目管理人员',
  272. type: "error"
  273. });
  274. } else if (data.length == 1) {
  275. this.$set(this.weekTableData[index], 'groupId', data[0].id)
  276. this.$set(this.weekTableData[index], 'projectAuditorId', data[0].inchargerId)
  277. this.$set(this.weekTableData[index], 'projectAuditorName', data[0].inchargerName)
  278. if (!data[0].inchargerId) {
  279. this.$message({
  280. message: `【${data[0].name}】分组未设置审批人,请联系该项目管理人员`,
  281. type: "error"
  282. });
  283. }
  284. }
  285. this.$set(this.weekTableData[index], 'taskGroups', data)
  286. },
  287. // 插入一行
  288. insertRow(index) {
  289. this.weekTableData.splice(index + 1, 0, {
  290. dateTime: this.weekTableData[index].dateTime,
  291. weekDayTxt: this.weekTableData[index].weekDayTxt,
  292. content: '',
  293. workingTime: 0,
  294. projectId: '',
  295. projectAuditorId: '',
  296. projectAuditorName: '',
  297. groupId: '',
  298. groupList: [],
  299. approverList: [],
  300. canFill: 1,
  301. isDelete: false
  302. })
  303. },
  304. // 删除一行
  305. deleteRow(index) {
  306. this.weekTableData.splice(index, 1)
  307. },
  308. // 合并单元格
  309. arraySpanMethod({ row, column, rowIndex, columnIndex }) {
  310. let spanOneArr = [], concatOne = 0;
  311. this.weekTableData.map((item, index) => {
  312. if (index === 0) {
  313. spanOneArr.push(1);
  314. } else {
  315. if (item.dateTime === this.weekTableData[index - 1].dateTime) {
  316. spanOneArr[concatOne] += 1;
  317. spanOneArr.push(0);
  318. } else {
  319. spanOneArr.push(1);
  320. concatOne = index;
  321. };
  322. }
  323. });
  324. if (columnIndex === 0) {
  325. const _row = spanOneArr[rowIndex];
  326. const _col = _row > 0 ? 1 : 0;
  327. return {
  328. rowspan: _row,
  329. colspan: _col
  330. }
  331. }
  332. },
  333. // 回显审批人名字
  334. auditorNameFun(item) {
  335. const { groupId, taskGroups } = item;
  336. if (groupId) {
  337. const newArr = taskGroups.filter(v => v.id === groupId);
  338. return newArr.length > 0 ? newArr[0].inchargerName : '';
  339. }
  340. return '';
  341. },
  342. // post 方法请求二次封装
  343. async getData(url, param) {
  344. return new Promise((resolve, reject) => {
  345. this.http.post(url, param,
  346. res => {
  347. resolve(res)
  348. },
  349. error => {
  350. this.$message({
  351. message: error,
  352. type: "error"
  353. });
  354. reject(error)
  355. }
  356. )
  357. });
  358. },
  359. // 关闭弹窗
  360. handleClose() {
  361. this.$emit('weekClose')
  362. },
  363. },
  364. }
  365. </script>
  366. <style scoped lang='scss'>
  367. .flexColumn {
  368. display: flex;
  369. flex-direction: column;
  370. }
  371. .flexColumnAuto {
  372. display: flex;
  373. flex-direction: column;
  374. overflow: auto;
  375. }
  376. .flex1 {
  377. flex: 1;
  378. overflow-y: auto;
  379. }
  380. .weeklyCustomization {
  381. width: 100%;
  382. height: 100%;
  383. .title {
  384. position: absolute;
  385. top: 16px;
  386. left: 140px;
  387. }
  388. .weekcen {
  389. width: 100%;
  390. height: 100%;
  391. }
  392. .weeklyCustomization_btn {
  393. display: flex;
  394. justify-content: flex-end;
  395. padding-top: 10px;
  396. }
  397. .controls {
  398. display: flex;
  399. justify-content: space-between;
  400. align-items: center;
  401. width: 100%;
  402. .el-link {
  403. font-size: 18px;
  404. margin-right: 5px;
  405. }
  406. }
  407. }
  408. </style>