index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <template>
  2. <view class="page">
  3. <view class="content">
  4. <!-- <button class="btn-add" @click="toAdd" type="primary">新增</button> -->
  5. <uni-calendar
  6. class="uni-calendar--hook"
  7. :selected="info.selected"
  8. :showMonth="false"
  9. :date="day"
  10. @change="change"
  11. @monthSwitch="monthSwitch"
  12. >
  13. <text @click="toAdd">新增工时</text>
  14. </uni-calendar>
  15. <!-- <button @click="showModal" type="primary">新增</button> -->
  16. <uni-collapse ref="collapse">
  17. <uni-collapse-item
  18. v-for="collapse in collapseList"
  19. :key="collapse.name"
  20. :title="collapse.name"
  21. >
  22. <uni-card
  23. v-for="(item, index) in collapse.children"
  24. :key="index"
  25. :title="allType[item.type_id] && allType[item.type_id].name"
  26. >
  27. <view class="uni-body">
  28. <view class="detail-item" v-if="item.project_id != '0'">
  29. <view class="detail-label">所属项目</view>
  30. <view class="detail-value">
  31. {{ getProject(item.project_id) }}
  32. </view>
  33. </view>
  34. <view class="detail-item">
  35. <view class="detail-label">审核状态</view>
  36. <view
  37. class="detail-value"
  38. :style="{ color: stateColor[item.audit_state] }"
  39. >
  40. {{ auditState[item.audit_state] }}
  41. </view>
  42. </view>
  43. <view class="detail-item" v-if="item.audit_state == 3">
  44. <view class="detail-label">拒绝原因</view>
  45. <view class="detail-value">
  46. {{ item.audit_desc }}
  47. </view>
  48. </view>
  49. <view class="detail-item">
  50. <view class="detail-label">工时</view>
  51. <view class="detail-value">
  52. {{ item.workload }}
  53. </view>
  54. </view>
  55. </view>
  56. <view
  57. v-if="item.audit_state == 0 || item.audit_state == 3"
  58. slot="actions"
  59. class="card-actions"
  60. >
  61. <view class="card-actions-item" @click="onHandleSave(item)">
  62. <text class="card-actions-item-text">修改工时</text>
  63. </view>
  64. <view class="card-actions-item" @click="onHandleAudit(item, 0)">
  65. <text class="card-actions-item-text">上报审批</text>
  66. </view>
  67. </view>
  68. </uni-card>
  69. </uni-collapse-item>
  70. </uni-collapse>
  71. <uni-popup ref="inputDialog" type="dialog">
  72. <uni-popup-dialog
  73. ref="inputClose"
  74. mode="input"
  75. title="填入工时"
  76. :value="currentItem.workload === 0 ? '' : currentItem.workload"
  77. @confirm="dialogInputConfirm"
  78. ></uni-popup-dialog>
  79. </uni-popup>
  80. <uni-popup ref="auditDialog" type="dialog">
  81. <uni-popup-dialog
  82. type="info"
  83. title="提示"
  84. content="是否确认提交审批"
  85. @confirm="auditConfirm"
  86. ></uni-popup-dialog>
  87. </uni-popup>
  88. <view class="group">
  89. <!-- <button
  90. class="approval"
  91. v-if="permission['func-05-mobile-works-approval']"
  92. @click="onHandleApproval()"
  93. >
  94. 审批工时
  95. </button> -->
  96. <button
  97. v-if="permission['func-05-mobile-works-commit']"
  98. @click="onHandleAudit({}, 2)"
  99. type="primary"
  100. class="commit"
  101. >
  102. 上报本月工时
  103. </button>
  104. <button
  105. v-if="permission['func-05-mobile-works-commit']"
  106. v-show="collapseList.length > 0"
  107. @click="onHandleAudit({}, 1)"
  108. class="commit"
  109. >
  110. 上报今日工时
  111. </button>
  112. </view>
  113. </view>
  114. </view>
  115. </template>
  116. <script>
  117. import {
  118. queryAllWorkType,
  119. queryWorkHours,
  120. addWorkHours,
  121. addAuthWorkHours,
  122. queryProject,
  123. } from "@/services/workload";
  124. import moment from "moment";
  125. import { mapState } from "vuex";
  126. export default {
  127. data() {
  128. return {
  129. info: {
  130. lunar: true,
  131. range: true,
  132. insert: false,
  133. selected: [],
  134. },
  135. currentItem: {},
  136. projectList: [],
  137. currentList: [],
  138. stateColor: {
  139. 1: "#1890ff",
  140. 2: "#a0d911",
  141. 3: "#f5222d",
  142. },
  143. auditState: {
  144. 0: "未提审",
  145. 1: "待审核",
  146. 2: "已通过",
  147. 3: "已拒绝",
  148. },
  149. auditType: 0,
  150. day: moment().format("YYYY-MM-DD"),
  151. monthDate: moment(),
  152. permission: {},
  153. };
  154. },
  155. onLoad() {
  156. this.init();
  157. },
  158. onShow() {
  159. this.queryWorkHours();
  160. },
  161. computed: {
  162. ...mapState(["allType"]),
  163. collapseList() {
  164. const allType = this.allType;
  165. let data = {};
  166. this.currentList.forEach((item) => {
  167. let pid = allType[item.type_id]?.parent_id;
  168. if (!data[pid]) data[pid] = [];
  169. data[pid].push(item);
  170. });
  171. return Object.keys(data).map((pid) => ({
  172. name: allType[pid]?.name,
  173. children: data[pid],
  174. }));
  175. },
  176. },
  177. onNavigationBarButtonTap() {
  178. uni.reLaunch({
  179. url: "/pages/index/index",
  180. });
  181. },
  182. methods: {
  183. async init() {
  184. await this.$store.dispatch("getType");
  185. this.projectList = await queryProject();
  186. this.queryWorkHours();
  187. },
  188. change(e) {
  189. this.day = e.fulldate;
  190. this.currentList = e.extraInfo.list || [];
  191. },
  192. monthSwitch(e) {
  193. this.monthDate = moment(`${e.year}-${e.month}-01`, "YYYY-MM-DD");
  194. this.day = `${e.year}-${e.month < 10 ? "0" + e.month : e.month}-${moment(
  195. this.day
  196. ).format("DD")}`;
  197. this.currentList = [];
  198. this.queryWorkHours();
  199. // this.day = e.fulldate;
  200. // this.currentList = e.extraInfo.list || [];
  201. },
  202. getProject(id) {
  203. let p = this.projectList.find((p) => p.ID == id);
  204. if (!p) return "";
  205. return p.Name;
  206. },
  207. onHandleSave(item) {
  208. this.currentItem = item;
  209. this.$refs.inputDialog.open();
  210. },
  211. onHandleAudit(item, type) {
  212. this.currentItem = item;
  213. this.auditType = type;
  214. this.$refs.auditDialog.open();
  215. },
  216. onHandleApproval() {
  217. uni.navigateTo({
  218. url: "../WorkingHours/audit",
  219. });
  220. },
  221. async dialogInputConfirm(workload) {
  222. let item = this.currentItem;
  223. if (isNaN(workload)) {
  224. uni.showToast({
  225. title: "工时必须输入数字!",
  226. icon: "none",
  227. });
  228. return;
  229. }
  230. let decimal = workload.split(".")[1];
  231. if (decimal && decimal != 5) {
  232. uni.showToast({
  233. title: "工时最小精确到半小时!",
  234. icon: "none",
  235. });
  236. return;
  237. }
  238. let currentWorkload = this.currentList.reduce((total, temp) => {
  239. if (temp.id == item.id) return total;
  240. return total + temp.workload;
  241. }, 0);
  242. if (currentWorkload + Number(workload) > 8) {
  243. uni.showToast({
  244. title: "每日工时不能超过8小时!",
  245. icon: "none",
  246. });
  247. return;
  248. }
  249. let params = [
  250. {
  251. type_id: Number(item.type_id),
  252. comment: "",
  253. parent_type_id: this.allType[item.type_id].parent_id,
  254. data: [
  255. {
  256. id: item.id,
  257. project_id: Number(item.project_id),
  258. workload: Number(workload),
  259. day: item.day,
  260. },
  261. ],
  262. },
  263. ];
  264. // 保存
  265. await addWorkHours(params);
  266. await this.queryWorkHours();
  267. },
  268. async auditConfirm() {
  269. let type = this.auditType;
  270. let params;
  271. const getData = (item) => {
  272. return {
  273. type_id: Number(item.type_id),
  274. data: [
  275. {
  276. id: item.id,
  277. project_id: item.project_id,
  278. workload: item.workload,
  279. day: item.day,
  280. },
  281. ],
  282. };
  283. };
  284. if (type == 0) {
  285. params = [getData(this.currentItem)];
  286. } else if (type == 1) {
  287. let auditList = this.currentList.filter(
  288. (item) => item.audit_state == 0 || item.audit_state == 3
  289. );
  290. if (auditList.length == 0) {
  291. uni.showToast({
  292. title: "本日没有待上报工时!",
  293. icon: "none",
  294. });
  295. return;
  296. }
  297. params = auditList.map((item) => getData(item));
  298. } else {
  299. let auditList = [];
  300. this.info.selected.forEach((s) => {
  301. if (s.list) {
  302. auditList = auditList.concat(
  303. s.list.filter(
  304. (item) => item.audit_state == 0 || item.audit_state == 3
  305. )
  306. );
  307. }
  308. });
  309. if (auditList.length == 0) {
  310. uni.showToast({
  311. title: "本月没有待上报工时!",
  312. icon: "none",
  313. });
  314. return;
  315. }
  316. params = auditList.map((item) => getData(item));
  317. }
  318. await addAuthWorkHours(params);
  319. this.queryWorkHours();
  320. this.$refs.auditDialog.close();
  321. },
  322. async queryWorkHours() {
  323. let date = this.monthDate;
  324. let s_time = date.format("YYYY-MM-01 00:00:00");
  325. let e_time = moment(s_time)
  326. .add("month", 1)
  327. .add("days", -1)
  328. .format("YYYY-MM-DD 23:59:59");
  329. const user = uni.getStorageSync("user");
  330. const data = await queryWorkHours({ user_id: user.ID, s_time, e_time });
  331. let selected = [];
  332. Object.keys(data).map((day) => {
  333. let list = data[day];
  334. let total = 0;
  335. let canEdit = false;
  336. list.forEach((item) => {
  337. total += item.workload;
  338. if (item.audit_state == 3 || item.audit_state == 0) {
  339. canEdit = true;
  340. }
  341. });
  342. selected.push({
  343. date: day,
  344. info: `${total} 小时`,
  345. list: list,
  346. color: canEdit ? "#e43d33" : "",
  347. });
  348. if (this.day == day) {
  349. this.currentList = list;
  350. }
  351. });
  352. this.info.selected = selected;
  353. let permission = {};
  354. user.Permissions?.forEach((item) => {
  355. permission = {
  356. ...permission,
  357. ...item.Menus,
  358. };
  359. });
  360. this.permission = permission;
  361. },
  362. toAdd() {
  363. uni.navigateTo({
  364. url: `./add?day=${this.day}`,
  365. });
  366. },
  367. // async onSubmit(values) {
  368. // let params = [
  369. // {
  370. // type_id: Number(values.subTypeId),
  371. // comment: "",
  372. // data: [
  373. // {
  374. // project_id: Number(values.projectId),
  375. // workload: 0,
  376. // day: this.day,
  377. // },
  378. // ],
  379. // },
  380. // ];
  381. // // 新增
  382. // await addWorkHours(params);
  383. // this.queryWorkHours();
  384. // },
  385. // showModal() {
  386. // this.$refs.addModal.open();
  387. // },
  388. },
  389. };
  390. </script>
  391. <style lang="scss" scoped>
  392. .content {
  393. padding: 30rpx;
  394. padding-top: 0;
  395. padding-bottom: 60px;
  396. }
  397. // .button {
  398. // margin-right: 20rpx;
  399. // }
  400. .card-actions {
  401. display: flex;
  402. flex-direction: row;
  403. justify-content: space-around;
  404. align-items: center;
  405. height: 45px;
  406. border-top: 1px #eee solid;
  407. }
  408. .detail-item {
  409. margin: 12rpx 0;
  410. display: flex;
  411. justify-content: space-between;
  412. align-items: flex-start;
  413. .detail-value {
  414. max-width: 60%;
  415. text-align: right;
  416. }
  417. }
  418. .group {
  419. width: 100%;
  420. display: flex;
  421. position: fixed;
  422. flex-wrap: wrap;
  423. justify-content: flex-start;
  424. bottom: 0;
  425. left: 0;
  426. .approval {
  427. width: 100%;
  428. border-radius: 0;
  429. margin: inherit;
  430. }
  431. .commit {
  432. width: 50%;
  433. border-radius: 0;
  434. margin: inherit;
  435. }
  436. }
  437. ::v-deep {
  438. .uni-calendar-item__weeks-box-item {
  439. width: 90rpx;
  440. }
  441. }
  442. </style>