audit.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <template>
  2. <view class="content">
  3. <uni-calendar
  4. class="uni-calendar--hook"
  5. :selected="info.selected"
  6. :showMonth="false"
  7. @change="change"
  8. />
  9. <uni-collapse ref="collapse">
  10. <uni-collapse-item
  11. v-for="collapse in collapseList"
  12. :key="collapse.name"
  13. :title="collapse.name"
  14. >
  15. <view class="content">
  16. <template v-for="(item, index) in collapse.children">
  17. <uni-card :key="index" :title="allType[item.type_id] && allType[item.type_id].name">
  18. <view class="uni-body">
  19. <view class="detail-item">
  20. <view class="detail-label">提交人</view>
  21. <view class="detail-value">
  22. {{ item.User.CName }}
  23. </view>
  24. </view>
  25. <view class="detail-item">
  26. <view class="detail-label">审核状态</view>
  27. <view
  28. class="detail-value"
  29. :style="{ color: stateColor[item.audit_state] }"
  30. >
  31. {{ auditState[item.audit_state] }}
  32. </view>
  33. </view>
  34. <view class="detail-item" v-if="item.audit_state == 3">
  35. <view class="detail-label">拒绝原因</view>
  36. <view class="detail-value">
  37. {{ item.audit_desc }}
  38. </view>
  39. </view>
  40. <view class="detail-item">
  41. <view class="detail-label">工时</view>
  42. <view class="detail-value">
  43. {{ item.workload }}
  44. </view>
  45. </view>
  46. </view>
  47. <view
  48. v-if="item.audit_state == 1"
  49. slot="actions"
  50. class="card-actions"
  51. >
  52. <view class="card-actions-item" @click="onHandleAudit(item)">
  53. <text class="card-actions-item-text">通过</text>
  54. </view>
  55. <view class="card-actions-item" @click="onHandleReject(item)">
  56. <text class="card-actions-item-text">拒绝</text>
  57. </view>
  58. </view>
  59. </uni-card>
  60. </template>
  61. </view>
  62. </uni-collapse-item>
  63. </uni-collapse>
  64. <uni-popup ref="inputDialog" type="dialog">
  65. <uni-popup-dialog
  66. ref="inputClose"
  67. mode="input"
  68. title="拒绝原因"
  69. :value="auditDesc"
  70. @confirm="dialogInputConfirm"
  71. ></uni-popup-dialog>
  72. </uni-popup>
  73. <uni-popup ref="auditDialog" type="dialog">
  74. <uni-popup-dialog
  75. type="info"
  76. title="提示"
  77. content="是否确认通过审批"
  78. @confirm="auditConfirm"
  79. ></uni-popup-dialog>
  80. </uni-popup>
  81. </view>
  82. </template>
  83. <script>
  84. import {
  85. queryAuthWorkHours,
  86. addWorkHours,
  87. queryProject,
  88. authWorkload,
  89. } from "@/services/workload";
  90. import moment from "moment";
  91. import { mapState } from "vuex";
  92. export default {
  93. data() {
  94. return {
  95. auditDesc: "",
  96. info: {
  97. lunar: true,
  98. range: true,
  99. insert: false,
  100. selected: [],
  101. },
  102. currentItem: {},
  103. projectList: [],
  104. currentList: [],
  105. stateColor: {
  106. 1: "#1890ff",
  107. 2: "#a0d911",
  108. 3: "#f5222d",
  109. },
  110. auditState: {
  111. 0: "未提审",
  112. 1: "待审核",
  113. 2: "已通过",
  114. 3: "已拒绝",
  115. },
  116. day: moment().format("YYYY-MM-DD"),
  117. };
  118. },
  119. onReady() {
  120. this.init();
  121. },
  122. computed: {
  123. ...mapState(["allType", "typeList"]),
  124. collapseList() {
  125. const projectList = this.projectList;
  126. let data = {};
  127. this.currentList.forEach((item) => {
  128. let pid = item.project_id;
  129. let name = "";
  130. if (!data[pid]) {
  131. if (pid == "0") name = "其他";
  132. else {
  133. let find = projectList.find((p) => p.ID == pid);
  134. if (!find) return;
  135. name = find.Name;
  136. }
  137. data[pid] = {
  138. id: pid,
  139. name,
  140. children: [],
  141. };
  142. }
  143. data[pid].children.push(item);
  144. });
  145. let allList = Object.values(data);
  146. // 将id为0的项 放置到数组最后
  147. let index = allList.findIndex((item) => item.id == "0");
  148. if (index != -1) {
  149. var temp = allList.splice(index, 1);
  150. allList.push(temp[0]);
  151. }
  152. // allList.forEach((item) => {
  153. // // 根据type进行分类
  154. // const { list, audit } = this.getTableInfo(item.list);
  155. // item.list = list;
  156. // item.audit = audit;
  157. // });
  158. return allList;
  159. },
  160. },
  161. methods: {
  162. async init() {
  163. await this.$store.dispatch("getType");
  164. this.projectList = await queryProject();
  165. await this.queryAuthWorkHours();
  166. },
  167. change(e) {
  168. this.day = e.fulldate;
  169. this.currentList = e.extraInfo.list || [];
  170. },
  171. getProject(id) {
  172. let p = this.projectList.find((p) => p.ID == id);
  173. if (!p) return "";
  174. return p.Name;
  175. },
  176. onHandleReject(item) {
  177. this.currentItem = item;
  178. this.$refs.inputDialog.open();
  179. },
  180. onHandleAudit(item) {
  181. this.currentItem = item;
  182. this.$refs.auditDialog.open();
  183. },
  184. async dialogInputConfirm(desc) {
  185. let item = this.currentItem;
  186. let params = [
  187. {
  188. id: item.id,
  189. ts: item.ts,
  190. user_id: item.User.ID,
  191. workload: item.workload,
  192. status: 3,
  193. desc: desc || "",
  194. },
  195. ];
  196. // 保存
  197. await authWorkload(params);
  198. await this.queryAuthWorkHours();
  199. },
  200. async auditConfirm() {
  201. let item = this.currentItem;
  202. let params = [
  203. {
  204. id: item.id,
  205. status: 2,
  206. desc: "",
  207. },
  208. ];
  209. await authWorkload(params);
  210. this.queryAuthWorkHours();
  211. this.$refs.auditDialog.close();
  212. },
  213. async queryAuthWorkHours() {
  214. const user = uni.getStorageSync("user");
  215. const data = await queryAuthWorkHours({
  216. user_id: user.ID,
  217. audit_state: 1,
  218. });
  219. let selected = [];
  220. Object.keys(data).map((day) => {
  221. let list = data[day];
  222. let total = 0;
  223. let canEdit = false;
  224. list.forEach((item) => {
  225. if (item.audit_state == 1) {
  226. total += item.workload;
  227. canEdit = true;
  228. }
  229. });
  230. selected.push({
  231. date: day,
  232. info: total > 0 ? `${total} 小时` : "",
  233. list: list,
  234. color: canEdit ? "#e43d33" : "",
  235. });
  236. if (this.day == day) {
  237. this.currentList = list;
  238. }
  239. });
  240. this.info.selected = selected;
  241. },
  242. async onSubmit(values) {
  243. let params = [
  244. {
  245. type_id: Number(values.subTypeId),
  246. comment: "",
  247. data: [
  248. {
  249. project_id: Number(values.projectId),
  250. workload: 0,
  251. day: this.day,
  252. },
  253. ],
  254. },
  255. ];
  256. // 新增
  257. await addWorkHours(params);
  258. this.queryAuthWorkHours();
  259. },
  260. showModal() {
  261. this.$refs.addModal.open();
  262. },
  263. getTableInfo(list) {
  264. let data = {},
  265. audit = [];
  266. const allType = this.allType;
  267. list.forEach((item) => {
  268. let pid = allType[item.type_id].parent_id;
  269. if (!pid) return;
  270. if (!data[pid]) data[pid] = [];
  271. data[pid].push(item);
  272. // 判断是否处于待审批状态
  273. if (item.audit_state == 1) {
  274. // 保存可审批的项
  275. audit.push(item);
  276. }
  277. });
  278. let newList = Object.keys(data).map((pid) => ({
  279. zIndex: 0,
  280. id: pid,
  281. type_id: allType[pid].id,
  282. children: data[pid],
  283. }));
  284. return {
  285. list: newList,
  286. audit,
  287. };
  288. },
  289. },
  290. };
  291. </script>
  292. <style lang="scss" scoped>
  293. .content {
  294. padding: 30rpx;
  295. padding-top: 0;
  296. }
  297. .button {
  298. margin-right: 20rpx;
  299. }
  300. .card-actions {
  301. display: flex;
  302. flex-direction: row;
  303. justify-content: space-around;
  304. align-items: center;
  305. height: 45px;
  306. border-top: 1px #eee solid;
  307. }
  308. .detail-item {
  309. margin: 12rpx 0;
  310. display: flex;
  311. justify-content: space-between;
  312. align-items: flex-start;
  313. .detail-value {
  314. max-width: 60%;
  315. text-align: right;
  316. }
  317. }
  318. </style>