|
@@ -0,0 +1,443 @@
|
|
|
+<template>
|
|
|
+ <view class="content">
|
|
|
+ <!-- <button class="btn-add" @click="toAdd" type="primary">新增</button> -->
|
|
|
+ <uni-calendar
|
|
|
+ class="uni-calendar--hook"
|
|
|
+ :selected="info.selected"
|
|
|
+ :showMonth="false"
|
|
|
+ :date="day"
|
|
|
+ @change="change"
|
|
|
+ @monthSwitch="monthSwitch"
|
|
|
+ >
|
|
|
+ <text @click="toAdd">新增工时</text>
|
|
|
+ </uni-calendar>
|
|
|
+ <!-- <button @click="showModal" type="primary">新增</button> -->
|
|
|
+ <uni-collapse ref="collapse">
|
|
|
+ <uni-collapse-item
|
|
|
+ v-for="collapse in collapseList"
|
|
|
+ :key="collapse.name"
|
|
|
+ :title="collapse.name"
|
|
|
+ >
|
|
|
+ <view class="content">
|
|
|
+ <uni-card
|
|
|
+ v-for="(item, index) in collapse.children"
|
|
|
+ :key="index"
|
|
|
+ :title="allType[item.type_id] && allType[item.type_id].name"
|
|
|
+ >
|
|
|
+ <view class="uni-body">
|
|
|
+ <view class="detail-item" v-if="item.project_id != '0'">
|
|
|
+ <view class="detail-label">所属项目</view>
|
|
|
+ <view class="detail-value">
|
|
|
+ {{ getProject(item.project_id) }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="detail-item">
|
|
|
+ <view class="detail-label">审核状态</view>
|
|
|
+ <view
|
|
|
+ class="detail-value"
|
|
|
+ :style="{ color: stateColor[item.audit_state] }"
|
|
|
+ >
|
|
|
+ {{ auditState[item.audit_state] }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="detail-item" v-if="item.audit_state == 3">
|
|
|
+ <view class="detail-label">拒绝原因</view>
|
|
|
+ <view class="detail-value">
|
|
|
+ {{ item.audit_desc }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="detail-item">
|
|
|
+ <view class="detail-label">工时</view>
|
|
|
+ <view class="detail-value">
|
|
|
+ {{ item.workload }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ v-if="item.audit_state == 0 || item.audit_state == 3"
|
|
|
+ slot="actions"
|
|
|
+ class="card-actions"
|
|
|
+ >
|
|
|
+ <view class="card-actions-item" @click="onHandleSave(item)">
|
|
|
+ <text class="card-actions-item-text">修改工时</text>
|
|
|
+ </view>
|
|
|
+ <view class="card-actions-item" @click="onHandleAudit(item, 0)">
|
|
|
+ <text class="card-actions-item-text">上报审批</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-card>
|
|
|
+ </view>
|
|
|
+ </uni-collapse-item>
|
|
|
+ </uni-collapse>
|
|
|
+
|
|
|
+ <uni-popup ref="inputDialog" type="dialog">
|
|
|
+ <uni-popup-dialog
|
|
|
+ ref="inputClose"
|
|
|
+ mode="input"
|
|
|
+ title="填入工时"
|
|
|
+ :value="currentItem.workload === 0 ? '' : currentItem.workload"
|
|
|
+ @confirm="dialogInputConfirm"
|
|
|
+ ></uni-popup-dialog>
|
|
|
+ </uni-popup>
|
|
|
+ <uni-popup ref="auditDialog" type="dialog">
|
|
|
+ <uni-popup-dialog
|
|
|
+ type="info"
|
|
|
+ title="提示"
|
|
|
+ content="是否确认提交审批"
|
|
|
+ @confirm="auditConfirm"
|
|
|
+ ></uni-popup-dialog>
|
|
|
+ </uni-popup>
|
|
|
+ <!-- <AddModal
|
|
|
+ ref="addModal"
|
|
|
+ @submit="onSubmit"
|
|
|
+ :projectList="projectList"
|
|
|
+ :typeList="typeList"
|
|
|
+ /> -->
|
|
|
+ <view class="group">
|
|
|
+ <button
|
|
|
+ class="approval"
|
|
|
+ v-if="permission['func-05-mobile-works-approval']"
|
|
|
+ @click="onHandleApproval()"
|
|
|
+ >
|
|
|
+ 审批工时
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ v-if="permission['func-05-mobile-works-commit']"
|
|
|
+ @click="onHandleAudit({}, 2)"
|
|
|
+ type="primary"
|
|
|
+ class="commit"
|
|
|
+ >
|
|
|
+ 上报本月工时
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ v-if="permission['func-05-mobile-works-commit']"
|
|
|
+ v-show="collapseList.length > 0"
|
|
|
+ @click="onHandleAudit({}, 1)"
|
|
|
+ class="commit"
|
|
|
+ >
|
|
|
+ 上报今日工时
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import {
|
|
|
+ queryAllWorkType,
|
|
|
+ queryWorkHours,
|
|
|
+ addWorkHours,
|
|
|
+ addAuthWorkHours,
|
|
|
+ queryProject,
|
|
|
+} from "@/services/workload";
|
|
|
+import AddModal from "./AddModal.vue";
|
|
|
+import moment from "moment";
|
|
|
+import { mapState } from "vuex";
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: { AddModal },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ info: {
|
|
|
+ lunar: true,
|
|
|
+ range: true,
|
|
|
+ insert: false,
|
|
|
+ selected: [],
|
|
|
+ },
|
|
|
+ currentItem: {},
|
|
|
+ projectList: [],
|
|
|
+ currentList: [],
|
|
|
+ stateColor: {
|
|
|
+ 1: "#1890ff",
|
|
|
+ 2: "#a0d911",
|
|
|
+ 3: "#f5222d",
|
|
|
+ },
|
|
|
+ auditState: {
|
|
|
+ 0: "未提审",
|
|
|
+ 1: "待审核",
|
|
|
+ 2: "已通过",
|
|
|
+ 3: "已拒绝",
|
|
|
+ },
|
|
|
+ auditType: 0,
|
|
|
+ day: moment().format("YYYY-MM-DD"),
|
|
|
+ monthDate: moment(),
|
|
|
+ permission: {},
|
|
|
+ };
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ this.init();
|
|
|
+ },
|
|
|
+ onShow() {
|
|
|
+ this.queryWorkHours();
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState(["allType", "typeList"]),
|
|
|
+ collapseList() {
|
|
|
+ const allType = this.allType;
|
|
|
+ let data = {};
|
|
|
+ this.currentList.forEach((item) => {
|
|
|
+ let pid = allType[item.type_id]?.parent_id;
|
|
|
+ if (!data[pid]) data[pid] = [];
|
|
|
+ data[pid].push(item);
|
|
|
+ });
|
|
|
+ return Object.keys(data).map((pid) => ({
|
|
|
+ name: allType[pid]?.name,
|
|
|
+ children: data[pid],
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async init() {
|
|
|
+ await this.$store.dispatch("getType");
|
|
|
+ this.projectList = await queryProject();
|
|
|
+ this.queryWorkHours();
|
|
|
+ },
|
|
|
+ change(e) {
|
|
|
+ this.day = e.fulldate;
|
|
|
+ this.currentList = e.extraInfo.list || [];
|
|
|
+ },
|
|
|
+ monthSwitch(e) {
|
|
|
+ this.monthDate = moment(`${e.year}-${e.month}-01`, "YYYY-MM-DD");
|
|
|
+ this.day = `${e.year}-${e.month < 10 ? "0" + e.month : e.month}-${moment(
|
|
|
+ this.day
|
|
|
+ ).format("DD")}`;
|
|
|
+ this.currentList = [];
|
|
|
+ this.queryWorkHours();
|
|
|
+ // this.day = e.fulldate;
|
|
|
+ // this.currentList = e.extraInfo.list || [];
|
|
|
+ },
|
|
|
+ getProject(id) {
|
|
|
+ let p = this.projectList.find((p) => p.ID == id);
|
|
|
+ if (!p) return "";
|
|
|
+ return p.Name;
|
|
|
+ },
|
|
|
+ onHandleSave(item) {
|
|
|
+ this.currentItem = item;
|
|
|
+ this.$refs.inputDialog.open();
|
|
|
+ },
|
|
|
+ onHandleAudit(item, type) {
|
|
|
+ this.currentItem = item;
|
|
|
+ this.auditType = type;
|
|
|
+ this.$refs.auditDialog.open();
|
|
|
+ },
|
|
|
+ onHandleApproval() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: "../WorkingHours/audit",
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async dialogInputConfirm(workload) {
|
|
|
+ let item = this.currentItem;
|
|
|
+ if (isNaN(workload)) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "工时必须输入数字!",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let decimal = workload.split(".")[1];
|
|
|
+ if (decimal && decimal != 5) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "工时最小精确到半小时!",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let currentWorkload = this.currentList.reduce((total, temp) => {
|
|
|
+ if (temp.id == item.id) return total;
|
|
|
+ return total + temp.workload;
|
|
|
+ }, 0);
|
|
|
+ if (currentWorkload + Number(workload) > 8) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "每日工时不能超过8小时!",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let params = [
|
|
|
+ {
|
|
|
+ type_id: Number(item.type_id),
|
|
|
+ comment: "",
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ id: item.id,
|
|
|
+ project_id: Number(item.project_id),
|
|
|
+ workload: Number(workload),
|
|
|
+ day: item.day,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ // 保存
|
|
|
+ await addWorkHours(params);
|
|
|
+ await this.queryWorkHours();
|
|
|
+ },
|
|
|
+ async auditConfirm() {
|
|
|
+ let type = this.auditType;
|
|
|
+ let params;
|
|
|
+ const getData = (item) => {
|
|
|
+ return {
|
|
|
+ type_id: Number(item.type_id),
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ id: item.id,
|
|
|
+ project_id: item.project_id,
|
|
|
+ workload: item.workload,
|
|
|
+ day: item.day,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ };
|
|
|
+ if (type == 0) {
|
|
|
+ params = [getData(this.currentItem)];
|
|
|
+ } else if (type == 1) {
|
|
|
+ let auditList = this.currentList.filter(
|
|
|
+ (item) => item.audit_state == 0 || item.audit_state == 3
|
|
|
+ );
|
|
|
+ if (auditList.length == 0) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "本日没有待上报工时!",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ params = auditList.map((item) => getData(item));
|
|
|
+ } else {
|
|
|
+ let auditList = [];
|
|
|
+ this.info.selected.forEach((s) => {
|
|
|
+ if (s.list) {
|
|
|
+ auditList = auditList.concat(
|
|
|
+ s.list.filter(
|
|
|
+ (item) => item.audit_state == 0 || item.audit_state == 3
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (auditList.length == 0) {
|
|
|
+ uni.showToast({
|
|
|
+ title: "本月没有待上报工时!",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ params = auditList.map((item) => getData(item));
|
|
|
+ }
|
|
|
+ await addAuthWorkHours(params);
|
|
|
+ this.queryWorkHours();
|
|
|
+ this.$refs.auditDialog.close();
|
|
|
+ },
|
|
|
+ async queryWorkHours() {
|
|
|
+ let date = this.monthDate;
|
|
|
+ let s_time = date.format("YYYY-MM-01 00:00:00");
|
|
|
+ let e_time = moment(s_time)
|
|
|
+ .add("month", 1)
|
|
|
+ .add("days", -1)
|
|
|
+ .format("YYYY-MM-DD 23:59:59");
|
|
|
+ const user = uni.getStorageSync("user");
|
|
|
+ const data = await queryWorkHours({ user_id: user.ID, s_time, e_time });
|
|
|
+ let selected = [];
|
|
|
+ Object.keys(data).map((day) => {
|
|
|
+ let list = data[day];
|
|
|
+ let total = 0;
|
|
|
+ let canEdit = false;
|
|
|
+ list.forEach((item) => {
|
|
|
+ total += item.workload;
|
|
|
+ if (item.audit_state == 3 || item.audit_state == 0) {
|
|
|
+ canEdit = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ selected.push({
|
|
|
+ date: day,
|
|
|
+ info: `${total} 小时`,
|
|
|
+ list: list,
|
|
|
+ color: canEdit ? "#e43d33" : "",
|
|
|
+ });
|
|
|
+ if (this.day == day) {
|
|
|
+ this.currentList = list;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.info.selected = selected;
|
|
|
+ let permission = {};
|
|
|
+ user.Permissions?.forEach((item) => {
|
|
|
+ permission = {
|
|
|
+ ...permission,
|
|
|
+ ...item.Menus,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ this.permission = permission;
|
|
|
+ },
|
|
|
+ toAdd() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: `./add?day=${this.day}`,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // async onSubmit(values) {
|
|
|
+ // let params = [
|
|
|
+ // {
|
|
|
+ // type_id: Number(values.subTypeId),
|
|
|
+ // comment: "",
|
|
|
+ // data: [
|
|
|
+ // {
|
|
|
+ // project_id: Number(values.projectId),
|
|
|
+ // workload: 0,
|
|
|
+ // day: this.day,
|
|
|
+ // },
|
|
|
+ // ],
|
|
|
+ // },
|
|
|
+ // ];
|
|
|
+ // // 新增
|
|
|
+ // await addWorkHours(params);
|
|
|
+ // this.queryWorkHours();
|
|
|
+ // },
|
|
|
+ // showModal() {
|
|
|
+ // this.$refs.addModal.open();
|
|
|
+ // },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.content {
|
|
|
+ padding: 30rpx;
|
|
|
+ padding-top: 0;
|
|
|
+ padding-bottom: 60px;
|
|
|
+}
|
|
|
+// .button {
|
|
|
+// margin-right: 20rpx;
|
|
|
+// }
|
|
|
+.card-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-around;
|
|
|
+ align-items: center;
|
|
|
+ height: 45px;
|
|
|
+ border-top: 1px #eee solid;
|
|
|
+}
|
|
|
+.detail-item {
|
|
|
+ margin: 12rpx 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-start;
|
|
|
+ .detail-value {
|
|
|
+ max-width: 60%;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+}
|
|
|
+.group {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ position: fixed;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ justify-content: flex-start;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ .approval {
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 0;
|
|
|
+ margin: inherit;
|
|
|
+ }
|
|
|
+ .commit {
|
|
|
+ width: 50%;
|
|
|
+ border-radius: 0;
|
|
|
+ margin: inherit;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|