| | |
| | | "tslib": "^2.7.0", |
| | | "uview-plus": "^3.4.62", |
| | | "vue": "3.4.21", |
| | | "vue-i18n": "^9.14.2" |
| | | "vue-i18n": "^9.14.2", |
| | | "@vueup/vue-quill": "^1.2.0" |
| | | }, |
| | | "devDependencies": { |
| | | "@dcloudio/types": "^3.4.14", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | export function getExamineList(data) { |
| | | return request({ |
| | | url: "/meeting/applicationList", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function getRoomEnum() { |
| | | return request({ |
| | | url: "/meeting/roomEnum", |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function saveMeetingApplication(data){ |
| | | return request({ |
| | | url: "/meeting/saveMeetingApplication", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function getMeetingPublish(data){ |
| | | return request({ |
| | | url: "/meeting/meetingPublishList", |
| | | method: "post", |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | export function getMeetingMinutesByMeetingId(id){ |
| | | return request({ |
| | | url: "/meeting/getMeetingMinutesByMeetingId/"+id, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function saveMeetingMinutes(data){ |
| | | return request({ |
| | | url: "/meeting/saveMeetingMinutes", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="editor-container"> |
| | | <div class="editor"> |
| | | <QuillEditor v-model:content="content" |
| | | contentType="html" |
| | | @textChange="(e) => emit('update:modelValue', content)" |
| | | :options="options" |
| | | :style="styles" /> |
| | | </div> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, watch } from "vue"; |
| | | import { QuillEditor } from "@vueup/vue-quill"; |
| | | import "@vueup/vue-quill/dist/vue-quill.snow.css"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | const props = defineProps({ |
| | | /* ç¼è¾å¨çå
容 */ |
| | | modelValue: { |
| | | type: String, |
| | | }, |
| | | /* é«åº¦ */ |
| | | height: { |
| | | type: Number, |
| | | default: null, |
| | | }, |
| | | /* æå°é«åº¦ */ |
| | | minHeight: { |
| | | type: Number, |
| | | default: null, |
| | | }, |
| | | /* åªè¯» */ |
| | | readOnly: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | /* ä¸ä¼ æä»¶å¤§å°éå¶(MB) */ |
| | | fileSize: { |
| | | type: Number, |
| | | default: 5, |
| | | }, |
| | | /* ç±»åï¼base64æ ¼å¼ãurlæ ¼å¼ï¼ */ |
| | | type: { |
| | | type: String, |
| | | default: "url", |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(["update:modelValue"]); |
| | | |
| | | const styles = computed(() => { |
| | | let style = {}; |
| | | if (props.minHeight) { |
| | | style.minHeight = `${props.minHeight}px`; |
| | | } |
| | | if (props.height) { |
| | | style.height = `${props.height}px`; |
| | | } |
| | | return style; |
| | | }); |
| | | |
| | | const content = ref(""); |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | v => { |
| | | if (v !== content.value) { |
| | | content.value = v == undefined ? "<p></p>" : v; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | const options = { |
| | | theme: "snow", |
| | | bounds: document.body, |
| | | debug: "warn", |
| | | modules: { |
| | | // å·¥å
·æ é
ç½® |
| | | toolbar: [ |
| | | [{ align: [] }], // 坹齿¹å¼ |
| | | ["bold", "italic", "underline", "strike"], // å ç² æä½ ä¸å线 å é¤çº¿ |
| | | ["blockquote", "code-block"], // å¼ç¨ 代ç å |
| | | [{ list: "ordered" }, { list: "bullet" }], // æåºãæ åºå表 |
| | | [{ indent: "-1" }, { indent: "+1" }], // ç¼©è¿ |
| | | [{ size: ["small", false, "large", "huge"] }], // åä½å¤§å° |
| | | [{ header: [1, 2, 3, 4, 5, 6, false] }], // æ é¢ |
| | | [{ color: [] }, { background: [] }], // åä½é¢è²ãåä½èæ¯é¢è² |
| | | ["clean"], // æ¸
é¤ææ¬æ ¼å¼ |
| | | ["link", "image", "video"], // 龿¥ãå¾çãè§é¢ |
| | | ], |
| | | }, |
| | | placeholder: "请è¾å
¥å
容", |
| | | readOnly: props.readOnly, |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | | .editor-container { |
| | | width: 100%; |
| | | } |
| | | |
| | | .editor-img-uploader { |
| | | display: none; |
| | | } |
| | | |
| | | .editor { |
| | | width: 100%; |
| | | } |
| | | |
| | | .quill-editor { |
| | | border: 1px solid #e8e8e8; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* Quillç¼è¾å¨æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow) { |
| | | border-bottom: 1px solid #e8e8e8; |
| | | border-radius: 8px 8px 0 0; |
| | | padding: 8px 12px; |
| | | } |
| | | |
| | | :deep(.ql-container.ql-snow) { |
| | | min-height: 300px; |
| | | border-radius: 0 0 8px 8px; |
| | | } |
| | | |
| | | :deep(.ql-editor) { |
| | | min-height: 300px; |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | padding: 12px; |
| | | } |
| | | |
| | | /* ç§»å¨ç«¯éé
*/ |
| | | @media (max-width: 768px) { |
| | | :deep(.ql-toolbar.ql-snow) { |
| | | padding: 6px 8px; |
| | | } |
| | | |
| | | :deep(.ql-editor) { |
| | | font-size: 13px; |
| | | padding: 10px; |
| | | } |
| | | } |
| | | |
| | | /* å¾çæ ·å¼ */ |
| | | :deep(.ql-editor img) { |
| | | max-width: 100%; |
| | | height: auto; |
| | | border-radius: 4px; |
| | | margin: 8px 0; |
| | | } |
| | | |
| | | /* å·¥å
·æ æé®æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow .ql-button) { |
| | | height: 28px; |
| | | width: 28px; |
| | | padding: 4px; |
| | | } |
| | | |
| | | :deep(.ql-toolbar.ql-snow .ql-picker-label) { |
| | | height: 28px; |
| | | padding: 4px 8px; |
| | | } |
| | | |
| | | /* æç¤ºæ¡æ ·å¼ */ |
| | | :deep(.ql-snow .ql-tooltip[data-mode="link"])::before { |
| | | content: "请è¾å
¥é¾æ¥å°å:"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-tooltip.ql-editing a.ql-action)::after { |
| | | border-right: 0px; |
| | | content: "ä¿å"; |
| | | padding-right: 0px; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-tooltip[data-mode="video"])::before { |
| | | content: "请è¾å
¥è§é¢å°å:"; |
| | | } |
| | | |
| | | /* åä½å¤§å°é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item)::before { |
| | | content: "14px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"])::before { |
| | | content: "10px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"])::before { |
| | | content: "18px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"])::before { |
| | | content: "32px"; |
| | | } |
| | | |
| | | /* æ é¢é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item)::before { |
| | | content: "ææ¬"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"])::before { |
| | | content: "æ é¢1"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"])::before { |
| | | content: "æ é¢2"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"])::before { |
| | | content: "æ é¢3"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"])::before { |
| | | content: "æ é¢4"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"])::before { |
| | | content: "æ é¢5"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"])::before { |
| | | content: "æ é¢6"; |
| | | } |
| | | |
| | | /* åä½é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-item)::before { |
| | | content: "æ ååä½"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"])::before { |
| | | content: "衬线åä½"; |
| | | } |
| | | |
| | | :deep( |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"] |
| | | )::before, |
| | | :deep( |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"] |
| | | )::before { |
| | | content: "ç宽åä½"; |
| | | } |
| | | </style> |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetExamine/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®å®¡æ¹", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetExamine/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "审æ¹", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetPublish/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®åå¸", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetPublish/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "åå¸", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetSummary/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®æ»ç»", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetSummary/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "æ»ç»", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/cooperativeOffice/collaborativeApproval/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "å®¡æ¹æµç¨", |
| | |
| | | label: "ä¼è®®ç³è¯·", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®å®¡æ¹", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®åå¸", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®æ»ç»", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/xietongshenpi@2x.png", |
| | | label: "åå审æ¹", |
| | | }, |
| | |
| | | url: "/pages/managementMeetings/meetApplication/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®å®¡æ¹": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetExamine/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®åå¸": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetPublish/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®æ»ç»": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetSummary/index", |
| | | }); |
| | | break; |
| | | case "åå审æ¹": |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/collaborativeApproval/index", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="审æ¹" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <u-button class="reject-btn" |
| | | @click="handleReject">ä¸éè¿</u-button> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">éè¿</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine"; |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const isEdit = ref(false); |
| | | |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | }); |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const submitForm = status => { |
| | | // è°ç¨å端 |
| | | saveMeetingApplication({ id: approvalData.value.id, status: status }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("å®¡æ¹æäº¤æå"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "å®¡æ¹æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("å®¡æ¹æä½å¤±è´¥:", error); |
| | | showToast("å®¡æ¹æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleReject = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®ä¸éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(2); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®å®¡æ¹" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | å®¡æ¹ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getExamineList, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getExamineList({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetExamine/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetExamine/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="åå¸" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®è¯´æ</text> |
| | | <text class="info-value">{{ approvalData.description }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- å叿è§è¾å
¥ --> |
| | | <view v-if="isEdit" |
| | | class="approval-input"> |
| | | <view class="input-header"> |
| | | <text class="input-title">å叿è§</text> |
| | | </view> |
| | | <view class="input-content"> |
| | | <u-textarea v-model="approvalOpinion" |
| | | rows="4" |
| | | placeholder="请è¾å
¥å叿è§" |
| | | maxlength="200" |
| | | count /> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <!-- <u-button class="reject-btn" |
| | | @click="handleReject">ä¸éè¿</u-button> --> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">åå¸</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine"; |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const approvalOpinion = ref(""); |
| | | const isEdit = ref(false); |
| | | |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼é»è®¤å叿è§ä¸ºå½åå®¡æ¹æè§ |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | console.log(approvalData.value, "approvalData.value"); |
| | | }); |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
åå¸"; |
| | | } else if (params == 1) { |
| | | return "å·²åå¸"; |
| | | } else if (params == 2) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const submitForm = status => { |
| | | // æ ¡éªåå¸æè§ |
| | | if (!approvalOpinion.value?.trim()) { |
| | | showToast("请è¾å
¥å叿è§"); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端 |
| | | saveMeetingApplication({ |
| | | id: approvalData.value.id, |
| | | publishStatus: status, |
| | | publishComment: approvalOpinion.value, // æ·»å åå¸æè§ |
| | | }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("å叿å"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "å叿ä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("å叿ä½å¤±è´¥:", error); |
| | | showToast("å叿ä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦åå¸è¯¥ä¼è®®åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleReject = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®ä¸éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(2); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®åå¸" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | åå¸ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getMeetingPublish, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getMeetingPublish({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
åå¸"; |
| | | } else if (params == 1) { |
| | | return "å·²åå¸"; |
| | | } else if (params == 2) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetPublish/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetPublish/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="æ»ç»" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®è¯´æ</text> |
| | | <text class="info-value">{{ approvalData.description }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æäº¤æè§è¾å
¥ --> |
| | | <view v-if="isEdit" |
| | | class="approval-input"> |
| | | <view class="input-header"> |
| | | <text class="input-title">ä¼è®®çºªè¦</text> |
| | | </view> |
| | | <view class="input-content"> |
| | | <Editor v-model:modelValue="minutesContent" |
| | | :height="300" /> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">æäº¤</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | <script setup> |
| | | import { ref, onMounted, nextTick } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { |
| | | saveMeetingMinutes, |
| | | getMeetingMinutesByMeetingId, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import Editor from "@/components/Editor/index.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const isEdit = ref(false); |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼é»è®¤æäº¤æè§ä¸ºå½åå®¡æ¹æè§ |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | getMeetingMinutes(); |
| | | console.log(approvalData.value, "approvalData.value"); |
| | | }); |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
审æ¹"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const minutesContent = ref(""); |
| | | const minutesContentId = ref(""); |
| | | const getMeetingMinutes = () => { |
| | | getMeetingMinutesByMeetingId(approvalData.value.id) |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | |
| | | if (res.data) { |
| | | minutesContent.value = res.data.content; |
| | | minutesContentId.value = res.data.id; |
| | | } else { |
| | | minutesContent.value = `<h2>${approvalData.value.title}ä¼è®®çºªè¦</h2> |
| | | <p><strong>ä¼è®®æ¶é´ï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .meetingTime |
| | | }</p> |
| | | <p><strong>ä¼è®®å°ç¹ï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .location |
| | | }</p> |
| | | <p><strong>主æäººï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .host |
| | | }</p> |
| | | <p><strong>åä¼äººåï¼</strong></p> |
| | | <ol> |
| | | ${approvalData.value.participants |
| | | .map( |
| | | p => |
| | | `<li>${p.name}</li>` |
| | | ) |
| | | .join( |
| | | "" |
| | | )} |
| | | </ol> |
| | | <p><strong>ä¼è®®å
容ï¼</strong></p> |
| | | <ol> |
| | | <li>è®®é¢ä¸ï¼ |
| | | <ul> |
| | | <li>讨论å
容ï¼</li> |
| | | <li>å³è®®äºé¡¹ï¼</li> |
| | | </ul> |
| | | </li> |
| | | <li>è®®é¢äºï¼ |
| | | <ul> |
| | | <li>讨论å
容ï¼</li> |
| | | <li>å³è®®äºé¡¹ï¼</li> |
| | | </ul> |
| | | </li> |
| | | </ol> |
| | | <p><strong>夿³¨ï¼</strong></p>`; |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("è·åä¼è®®çºªè¦å¤±è´¥:", error); |
| | | showToast("è·åä¼è®®çºªè¦å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | const submitForm = status => { |
| | | console.log(minutesContent.value, "坿æ¬"); |
| | | if (!minutesContent.value) { |
| | | ElMessage.warning("请è¾å
¥ä¼è®®çºªè¦å
容"); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端 |
| | | saveMeetingMinutes({ |
| | | id: minutesContentId.value, |
| | | content: minutesContent.value, |
| | | meetingId: approvalData.value.id, |
| | | title: approvalData.value.title, |
| | | }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("æäº¤æå"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "æäº¤æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("æäº¤æä½å¤±è´¥:", error); |
| | | showToast("æäº¤æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦æäº¤è¯¥ä¼è®®æ»ç»åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | /* å·¥å
·æ æé®æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow .ql-button) { |
| | | height: 28px; |
| | | width: 28px; |
| | | padding: 4px; |
| | | } |
| | | :deep(.ql-toolbar.ql-snow .ql-picker-label) { |
| | | height: 28px; |
| | | padding: 4px 8px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®æ»ç»" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | æ·»å çºªè¦ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getMeetingPublish, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getMeetingPublish({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
审æ¹"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetSummary/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetSummary/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |