| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | // è·åä¼è®®ä½¿ç¨å表 |
| | | export function getMeetingUseList(data){ |
| | | return request({ |
| | | url: "/meeting/meetingUseList", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿åä¼è®®ç³è¯· |
| | | export function saveMeetingApplication(data){ |
| | | return request({ |
| | | url: "/meeting/saveMeetingApplication", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function getRoomEnum() { |
| | | return request({ |
| | | url: "/meeting/roomEnum", |
| | | method: "get", |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // ä¼è®®ç®¡ç |
| | | import request from "@/utils/request"; |
| | | |
| | | export function getMeetingRoomList(data) { |
| | | return request({ |
| | | url: "/meeting/roomList", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function saveRoom(data) { |
| | | return request({ |
| | | url: "/meeting/saveRoom", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | export function delRoom(id) { |
| | | return request({ |
| | | url: "/meeting/delRoom/"+id, |
| | | method: "delete", |
| | | }); |
| | | } |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/cooperativeOffice/collaborativeApproval/index", |
| | | "path": "pages/managementMeetings/meetingSettings/index", |
| | | "style": { |
| | | "navigationBarTitleText": "审æ¹ç®¡ç", |
| | | "navigationBarTitleText": "ä¼è®®è®¾ç½®", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetingSettings/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®å®¤è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetingList/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®å表", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetApplication/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®ç³è¯·", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="审æ¹ç®¡ç" @back="goBack" /> |
| | | |
| | | <PageHeader :title="pageTitle" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input |
| | | class="search-text" |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥æµç¨ç¼å·" |
| | | v-model="searchForm.approveId" |
| | | clearable |
| | | /> |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" @click="getList"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | <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-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> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.approveId }}</text> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | |
| | | <text class="detail-label">ç³è¯·æ¥æ</text> |
| | | <text class="detail-value">{{ item.approveTime }}</text> |
| | | </view> |
| | | |
| | | <!-- approveType=2 请åç¸å
³å段 --> |
| | | <template v-if="item.approveType === 2"> |
| | | <view class="detail-row"> |
| | |
| | | <text class="detail-value">{{ item.endDate || '-' }}</text> |
| | | </view> |
| | | </template> |
| | | |
| | | <!-- approveType=3 åºå·®ç¸å
³å段 --> |
| | | <view v-if="item.approveType === 3" class="detail-row"> |
| | | <view v-if="item.approveType === 3" |
| | | class="detail-row"> |
| | | <text class="detail-label">åºå·®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location || '-' }}</text> |
| | | </view> |
| | | |
| | | <!-- approveType=4 æ¥éç¸å
³å段 --> |
| | | <view v-if="item.approveType === 4" class="detail-row"> |
| | | <view v-if="item.approveType === 4" |
| | | class="detail-row"> |
| | | <text class="detail-label">æ¥ééé¢</text> |
| | | <text class="detail-value highlightYellow">{{ item.price ? `Â¥${item.price}` : '-' }}</text> |
| | | </view> |
| | | |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»ææ¥æ</text> |
| | | <text class="detail-value">{{ item.approveOverTime }}</text> |
| | |
| | | </view> |
| | | <view class="detail-row"> |
| | | <view class="actions"> |
| | | <u-button |
| | | type="primary" |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn edit" |
| | | :disabled="item.approveStatus == 2 || item.approveStatus == 1 || item.approveStatus == 4" |
| | | @click="handleItemClick(item)" |
| | | > |
| | | @click="handleItemClick(item)"> |
| | | ç¼è¾ |
| | | </u-button> |
| | | <u-button |
| | | type="success" |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.approveUserCurrentId == null || item.approveStatus == 2 || item.approveStatus == 3 || item.approveStatus == 4 || item.approveUserCurrentId !== userStore.id" |
| | | @click="approve(item)" |
| | | > |
| | | @click="approve(item)"> |
| | | å®¡æ ¸ |
| | | </u-button> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else class="no-data"> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ å®¡æ¹æ°æ®</text> |
| | | </view> |
| | | <!-- æµ®å¨æä½æé® --> |
| | | <view class="fab-button" @click="handleAdd"> |
| | | <up-icon name="plus" size="24" color="#ffffff"></up-icon> |
| | | <view class="fab-button" |
| | | @click="handleAdd"> |
| | | <up-icon name="plus" |
| | | size="24" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { |
| | | ref, |
| | | toRefs, |
| | | reactive |
| | | } from "vue"; |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import {approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess"; |
| | | import {onShow} from "@dcloudio/uni-app"; |
| | |
| | | const props = defineProps({ |
| | | approveType: { |
| | | type: Number, |
| | | default: 0 |
| | | } |
| | | default: 0, |
| | | }, |
| | | }); |
| | | |
| | | const userStore = useUserStore() |
| | | // æ å° approveType å°å¯¹åºç页颿 é¢ |
| | | const getPageTitle = type => { |
| | | const titleMap = { |
| | | 1: "å
¬åºç®¡ç", |
| | | 2: "请å管ç", |
| | | 3: "åºå·®ç®¡ç", |
| | | 4: "æ¥é管ç", |
| | | 5: "éè´ç®¡ç", |
| | | 6: "æ¥ä»·ç®¡ç", |
| | | 7: "åºåºç®¡ç", |
| | | }; |
| | | return titleMap[type] || "审æ¹ç®¡ç"; |
| | | }; |
| | | |
| | | const pageTitle = getPageTitle(props.approveType); |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast('å è½½ä¸...') |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | approveProcessListPage({ |
| | | ...page,approveType: props.approveType,...searchForm.value |
| | | ...page, |
| | | approveType: props.approveType, |
| | | ...searchForm.value, |
| | | }) |
| | | .then((res) => { |
| | | .then(res => { |
| | | ledgerList.value = res.data.records; |
| | | closeToast() |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast() |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = (message) => { |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true |
| | | mask: true, |
| | | }); |
| | | }; |
| | | |
| | |
| | | const showFilterOptions = () => { |
| | | uni.showActionSheet({ |
| | | itemList: ["ææ¥æçé", "æç¶æçé", "æéé¢çé"], |
| | | success: (res) => { |
| | | success: res => { |
| | | console.log("éæ©äºçéé项:", res.tapIndex); |
| | | }, |
| | | }); |
| | | }; |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = (params) => { |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params == 1) { |
| | |
| | | } else if (params == 4) { |
| | | return "已鿰æäº¤"; |
| | | } else { |
| | | return 'ä¸éè¿'; |
| | | return "ä¸éè¿"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = (type) => { |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "warning"; |
| | | } else if (type == 1) { |
| | |
| | | }; |
| | | |
| | | // ç¹å»å表项 |
| | | const handleItemClick = (item) => { |
| | | const handleItemClick = item => { |
| | | // ä½¿ç¨æ¬å°åå¨ä¼ éæ°æ® |
| | | uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item)); |
| | | uni.setStorageSync('operationType', 'edit'); |
| | | uni.setStorageSync('approveId', item.approveId); |
| | | uni.setStorageSync('approveType', props.approveType); |
| | | uni.setStorageSync("invoiceLedgerEditRow", JSON.stringify(item)); |
| | | uni.setStorageSync("operationType", "edit"); |
| | | uni.setStorageSync("approveId", item.approveId); |
| | | uni.setStorageSync("approveType", props.approveType); |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/collaborativeApproval/detail", |
| | | }); |
| | |
| | | |
| | | // æ·»å æ°è®°å½ |
| | | const handleAdd = () => { |
| | | uni.setStorageSync('operationType', 'add'); |
| | | uni.setStorageSync('approveType', props.approveType); |
| | | uni.setStorageSync("operationType", "add"); |
| | | uni.setStorageSync("approveType", props.approveType); |
| | | uni.navigateTo({ |
| | | url: `/pages/cooperativeOffice/collaborativeApproval/detail?approveType=${props.approveType}`, |
| | | }); |
| | | }; |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = (item) => { |
| | | uni.setStorageSync('approveId', item.approveId); |
| | | uni.setStorageSync('approveType', props.approveType); |
| | | const approve = item => { |
| | | uni.setStorageSync("approveId", item.approveId); |
| | | uni.setStorageSync("approveType", props.approveType); |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/collaborativeApproval/approve?approveType=" + props.approveType |
| | | }) |
| | | } |
| | | url: |
| | | "/pages/cooperativeOffice/collaborativeApproval/approve?approveType=" + |
| | | props.approveType, |
| | | }); |
| | | }; |
| | | |
| | | onShow(() => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | |
| | | </style> |
| | |
| | | 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/cooperativeOffice/collaborativeApproval/index7", |
| | | }); |
| | | break; |
| | | case "ä¼è®®è®¾ç½®": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetingSettings/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®å表": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetingList/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®ç³è¯·": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetApplication/index", |
| | | }); |
| | | break; |
| | | case "åå审æ¹": |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/collaborativeApproval/index", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view style="background-color: #fff;" |
| | | class="client-visit-detail"> |
| | | <PageHeader title="ä¼è®®ç³è¯·" |
| | | @back="goBack" /> |
| | | <view> |
| | | <view v-for="item in applicationTypes" |
| | | :key="item.value" |
| | | class="application-type-item" |
| | | :class="{ active: meetingForm.applicationType === item.value }" |
| | | @click="selectApplicationType(item)"> |
| | | <view class="application-type-info"> |
| | | <view class="application-type-name">{{ item.name }}</view> |
| | | <view class="application-type-desc">{{ item.desc }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <u-form ref="formRef" |
| | | label-width="90"> |
| | | <!-- 客æ·ä¿¡æ¯ --> |
| | | <u-cell-group title="ä¼è®®ç³è¯·"> |
| | | <u-form-item label="ä¼è®®ä¸»é¢" |
| | | prop="title" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.title" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" /> |
| | | </u-form-item> |
| | | <u-form-item label="ä¼è®®å®¤" |
| | | prop="roomId" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.roomName" |
| | | placeholder="è¯·éæ©ä¼è®®å®¤" |
| | | readonly |
| | | @click="showRoomPicker = true" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showRoomPicker = true"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="主æäºº" |
| | | prop="host" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.host" |
| | | placeholder="请è¾å
¥ä¸»æäººå§å" /> |
| | | </u-form-item> |
| | | <u-form-item label="ä¼è®®æ¥æ" |
| | | prop="meetingDate" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.meetingDate" |
| | | placeholder="è¯·éæ©ä¼è®®æ¥æ" |
| | | readonly |
| | | @click="showDatePicker = true" /> |
| | | <template #right> |
| | | <up-icon name="calendar" |
| | | @click="showDatePicker = true"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="å¼å§æ¶é´" |
| | | prop="startTime" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.startTime" |
| | | placeholder="è¯·éæ©å¼å§æ¶é´" |
| | | readonly |
| | | @click="showStartTimePicker = true" /> |
| | | <template #right> |
| | | <up-icon name="clock" |
| | | @click="showStartTimePicker = true"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="ç»ææ¶é´" |
| | | prop="endTime" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.endTime" |
| | | placeholder="è¯·éæ©ç»ææ¶é´" |
| | | readonly |
| | | @click="showEndTimePicker = true" /> |
| | | <template #right> |
| | | <up-icon name="clock" |
| | | @click="showEndTimePicker = true"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="åä¼äººå" |
| | | prop="participants" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.participantsNames" |
| | | placeholder="è¯·éæ©åä¼äººå" |
| | | readonly |
| | | @click="showEquipmentSheet = true" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="openParticipantPicker"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="ä¼è®®è¯´æ" |
| | | prop="description" |
| | | border-bottom> |
| | | <u-input v-model="meetingForm.description" |
| | | placeholder="请è¾å
¥ä¼è®®è¯´æ" /> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <!-- æäº¤æé® --> |
| | | </u-form> |
| | | <view class="footer-btns"> |
| | | <u-button class="cancel-btn" |
| | | @click="resetForm">éç½®</u-button> |
| | | <u-button class="save-btn" |
| | | @click="handleSubmit">ä¿å</u-button> |
| | | </view> |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <up-datetime-picker v-model="meetingForm.meetingDate" |
| | | mode="date" |
| | | :show="showDatePicker" |
| | | @confirm="onDateSelect" |
| | | @cancel="showDatePicker = false" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | :min-date="minDate" /> |
| | | <!-- å¼å§æ¶é´éæ©å¨ --> |
| | | <up-action-sheet :show="showStartTimePicker" |
| | | :actions="timeOptions" |
| | | @select="onStartTimeSelect" |
| | | @close="showStartTimePicker = false" /> |
| | | <!-- ç»ææ¶é´éæ©å¨ --> |
| | | <up-action-sheet :show="showEndTimePicker" |
| | | :actions="timeOptions" |
| | | @select="onEndTimeSelect" |
| | | @close="showEndTimePicker = false" /> |
| | | <!-- ä¼è®®å®¤éæ©å¨ --> |
| | | <up-action-sheet :show="showRoomPicker" |
| | | :actions="meetingRooms" |
| | | @select="onRoomSelect" |
| | | @close="showRoomPicker = false" /> |
| | | <u-popup :show="showEquipmentSheet" |
| | | mode="bottom" |
| | | @close="showEquipmentSheet = false" |
| | | height="200px"> |
| | | <view class="popup-content"> |
| | | <view class="popup-body"> |
| | | <u-checkbox-group v-model="meetingForm.participants" |
| | | @change="handleParticipantChange" |
| | | icon-placement="right" |
| | | placement="row"> |
| | | <view style="width:100%;padding:10px;margin-top:20px;"> |
| | | <u-checkbox v-for="option in employees" |
| | | :key="option.id" |
| | | :name="option.id" |
| | | :label="`${option.staffName} (${option.postJob})`" |
| | | class="checkbox-item"></u-checkbox> |
| | | </view> |
| | | </u-checkbox-group> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "meeting-settings-detail" }); |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | saveMeetingApplication, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meeting"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const meetingForm = reactive({ |
| | | title: "", |
| | | type: "", |
| | | roomId: "", |
| | | roomName: "", |
| | | host: "", |
| | | meetingDate: "", |
| | | startTime: "", |
| | | endTime: "", |
| | | participants: [], |
| | | description: "", |
| | | participantsNames: [], |
| | | applicationType: "department", |
| | | }); |
| | | // ç³è¯·ç±»åé项 |
| | | const applicationTypes = ref([ |
| | | { |
| | | value: "approval", |
| | | name: "å®¡æ¹æµç¨ä¼è®®", |
| | | desc: "éè¦ç»è¿å¤çº§å®¡æ¹çä¼è®®ç³è¯·", |
| | | // icon: Document, |
| | | }, |
| | | { |
| | | value: "department", |
| | | name: "é¨é¨çº§ä¼è®®", |
| | | desc: "é¨é¨å
é¨ä¼è®®ç³è¯·æµç¨", |
| | | // icon: Promotion, |
| | | }, |
| | | { |
| | | value: "notification", |
| | | name: "ä¼è®®éç¥", |
| | | desc: "æ é审æ¹ç´æ¥åå¸çä¼è®®éç¥", |
| | | // icon: Bell, |
| | | }, |
| | | ]); |
| | | // 页é¢ç¶æ |
| | | const loading = ref(false); |
| | | const formRef = ref(null); |
| | | const showDatePicker = ref(false); |
| | | const showStartTimePicker = ref(false); |
| | | const showEndTimePicker = ref(false); |
| | | const showRoomPicker = ref(false); |
| | | |
| | | // æå°æ¥æï¼ä»å¤©ï¼ |
| | | const minDate = computed(() => { |
| | | return dayjs().format("YYYY-MM-DD"); |
| | | }); |
| | | |
| | | // éæ©ç³è¯·ç±»å |
| | | const selectApplicationType = item => { |
| | | meetingForm.applicationType = item.value; |
| | | }; |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | const showEquipmentSheet = ref(false); |
| | | const openParticipantPicker = () => { |
| | | showEquipmentSheet.value = true; |
| | | }; |
| | | |
| | | // é置表å |
| | | const resetForm = () => { |
| | | meetingForm.title = ""; |
| | | meetingForm.type = ""; |
| | | meetingForm.roomId = ""; |
| | | meetingForm.roomName = ""; |
| | | meetingForm.host = ""; |
| | | meetingForm.meetingDate = ""; |
| | | meetingForm.startTime = ""; |
| | | meetingForm.endTime = ""; |
| | | meetingForm.participants = []; |
| | | meetingForm.participantsNames = []; |
| | | meetingForm.description = ""; |
| | | meetingForm.applicationType = "department"; |
| | | }; |
| | | const handleParticipantChange = val => { |
| | | console.log("val", val); |
| | | |
| | | meetingForm.participants = val; |
| | | meetingForm.participantsNames = employees.value |
| | | .filter(employee => val.includes(employee.id)) |
| | | .map(employee => employee.staffName); |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = async () => { |
| | | console.log("meetingForm", meetingForm); |
| | | if (!meetingForm.title) { |
| | | showToast("请è¾å
¥ä¼è®®ä¸»é¢"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.roomId) { |
| | | showToast("è¯·éæ©ä¼è®®å®¤"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.host) { |
| | | showToast("请è¾å
¥ä¸»æäºº"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.meetingDate) { |
| | | showToast("è¯·éæ©ä¼è®®æ¥æ"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.startTime) { |
| | | showToast("è¯·éæ©å¼å§æ¶é´"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.endTime) { |
| | | showToast("è¯·éæ©ç»ææ¶é´"); |
| | | return; |
| | | } |
| | | |
| | | if (!meetingForm.participants) { |
| | | showToast("è¯·éæ©åä¼äººå"); |
| | | return; |
| | | } |
| | | |
| | | // éªè¯å¼å§æ¶é´å¿
é¡»å°äºç»ææ¶é´ |
| | | if (meetingForm.startTime >= meetingForm.endTime) { |
| | | showToast("å¼å§æ¶é´å¿
é¡»å°äºç»ææ¶é´"); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | loading.value = true; |
| | | |
| | | let formData = { ...meetingForm }; |
| | | formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00`; |
| | | formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00`; |
| | | formData.participants = JSON.stringify(meetingForm.participants); |
| | | |
| | | console.log(formData); |
| | | |
| | | // è°ç¨å®é
çAPI |
| | | const res = await saveMeetingApplication(formData); |
| | | |
| | | if (res.code === 200) { |
| | | showToast("ä¿åæå"); |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 500); |
| | | } else { |
| | | showToast(res.message || "ä¿å失败ï¼è¯·éè¯"); |
| | | } |
| | | } catch (e) { |
| | | console.error("ä¿å失败:", e); |
| | | showToast("ä¿å失败ï¼è¯·éè¯"); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | // æ¥æéæ©å¨ç¡®è®¤åè° |
| | | const onDateSelect = action => { |
| | | console.log(action.value); |
| | | |
| | | if (action.value) { |
| | | meetingForm.meetingDate = dayjs(action.value).format("YYYY-MM-DD"); |
| | | } else { |
| | | meetingForm.meetingDate = dayjs().format("YYYY-MM-DD"); |
| | | } |
| | | |
| | | showDatePicker.value = false; |
| | | }; |
| | | const onStartTimeSelect = action => { |
| | | meetingForm.startTime = action.value; |
| | | showStartTimePicker.value = false; |
| | | }; |
| | | const onEndTimeSelect = action => { |
| | | meetingForm.endTime = action.value; |
| | | showEndTimePicker.value = false; |
| | | }; |
| | | |
| | | // ä¼è®®å®¤éæ©åè° |
| | | const onRoomSelect = action => { |
| | | meetingForm.roomId = action.id; |
| | | meetingForm.roomName = action.name; |
| | | showRoomPicker.value = false; |
| | | }; |
| | | // æ¶é´é项ï¼ä»¥åå°æ¶ä¸ºé´éï¼ |
| | | const timeOptions = ref([]); |
| | | |
| | | // åå§åæ¶é´é项 |
| | | const initTimeOptions = () => { |
| | | const options = []; |
| | | for (let hour = 8; hour <= 18; hour++) { |
| | | // æ¯ä¸ªå°æ¶æ·»å 两个éé¡¹ï¼æ´ç¹ååç¹ |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, "0")}:00`, |
| | | name: `${hour.toString().padStart(2, "0")}:00`, |
| | | }); |
| | | |
| | | if (hour < 18) { |
| | | // 18:00ä¹å没æåç¹é项 |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, "0")}:30`, |
| | | name: `${hour.toString().padStart(2, "0")}:30`, |
| | | }); |
| | | } |
| | | } |
| | | timeOptions.value = options; |
| | | }; |
| | | // ä¼è®®å®¤å表 |
| | | const employees = ref([]); |
| | | const meetingRooms = ref([]); |
| | | const getMeetingRooms = async () => { |
| | | try { |
| | | const res = await getRoomEnum(); |
| | | if (res.code === 200) { |
| | | meetingRooms.value = res.data || []; |
| | | } else { |
| | | showToast(res.message || "è·åä¼è®®å®¤å表失败"); |
| | | } |
| | | } catch (e) { |
| | | console.error("è·åä¼è®®å®¤å表失败:", e); |
| | | showToast("è·åä¼è®®å®¤å表失败ï¼è¯·éè¯"); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initPageData(); |
| | | initTimeOptions(); |
| | | getMeetingRooms(); |
| | | getStaffOnJob().then(res => { |
| | | employees.value = res.data.sort((a, b) => |
| | | a.postJob.localeCompare(b.postJob) |
| | | ); |
| | | }); |
| | | }); |
| | | |
| | | const initPageData = () => { |
| | | // åå§åæ°æ® |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/static/scss/form-common.scss"; |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #ffffff; |
| | | width: 6.375rem; |
| | | background: #c7c9cc; |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .save-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #ffffff; |
| | | width: 14rem; |
| | | background: linear-gradient(140deg, #00baff 0%, #006cfb 100%); |
| | | box-shadow: 0 0.25rem 0.625rem 0 rgba(3, 88, 185, 0.2); |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | .application-type-item { |
| | | width: 94%; |
| | | margin-left: 3%; |
| | | // height: 120rpx; |
| | | background-color: #f1f1f1; |
| | | border-radius: 10rpx; |
| | | margin-top: 20rpx; |
| | | padding: 20rpx; |
| | | box-shadow: 0 2rpx 12rpx 0 rgba(246, 244, 244, 0.1); |
| | | transition: box-shadow 0.3s ease; |
| | | } |
| | | .application-type-item.active { |
| | | box-shadow: 0 4rpx 16rpx 0 rgba(0, 0, 0, 0.15); |
| | | background-color: #fff; |
| | | border: 1rpx solid #0078a3; |
| | | } |
| | | |
| | | .application-type-name { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #000000; |
| | | } |
| | | .application-type-item.active .application-type-name { |
| | | color: #0078a3; |
| | | } |
| | | .application-type-desc { |
| | | font-weight: 400; |
| | | font-size: 0.875rem; |
| | | margin-top: 0.5rem; |
| | | color: #757575; |
| | | } |
| | | .application-type-item.active .application-type-desc { |
| | | color: #0078a3; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="meeting-list"> |
| | | <PageHeader title="ä¼è®®å表" |
| | | @back="goBack" /> |
| | | <!-- æ¥è¯¢è¡¨å --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="æ¥è¯¢æ¥æ" |
| | | @click.stop="showDatePicker" |
| | | v-model="queryForm.meetingDate" |
| | | clearable /> |
| | | </view> |
| | | <view class="filter-button" |
| | | @click="clearDate"> |
| | | <u-icon name="close-circle-fill" |
| | | size="24" |
| | | color="#999"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <up-datetime-picker v-model="datePickerValue" |
| | | mode="date" |
| | | :show="showDatePickerDialog" |
| | | @confirm="handleDateConfirm" |
| | | @cancel="showDatePickerDialog = false" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" /> |
| | | <!-- ä¼è®®å®¤ä½¿ç¨æ
åµ --> |
| | | <view class="table-container"> |
| | | <scroll-view scroll-x="true" |
| | | style="width: 100%;"> |
| | | <view class="time-table"> |
| | | <!-- 表头 --> |
| | | <view class="table-header"> |
| | | <view class="header-cell room-header">ä¼è®®å®¤</view> |
| | | <view v-for="timeSlot in timeSlots" |
| | | :key="timeSlot.value" |
| | | class="header-cell time-header"> |
| | | {{ timeSlot.label }} |
| | | </view> |
| | | </view> |
| | | <!-- è¡¨æ ¼å
容 --> |
| | | <view class="table-body"> |
| | | <view v-for="room in roomUsage" |
| | | :key="room.id" |
| | | class="table-row"> |
| | | <view class="cell room-cell">{{ room.name }}</view> |
| | | <view class="cells-container"> |
| | | <template v-for="(cell, index) in generateMeetingCells(room)" |
| | | :key="index"> |
| | | <view class="cell content-cell" |
| | | :class="[cell.type, `status-${cell.meeting?.status || '0'}`]" |
| | | :style="{ width: `${cell.span * 120}rpx` }" |
| | | @click="viewMeetingDetails(cell)"> |
| | | <view v-if="cell.type === 'meeting'" |
| | | class="meeting-content"> |
| | | <view class="meeting-title">{{ cell.meeting.title }}</view> |
| | | <view class="meeting-time">{{ cell.startTime }}-{{ cell.endTime }}</view> |
| | | </view> |
| | | <view v-else |
| | | class="free-content"> |
| | | ç©ºé² |
| | | </view> |
| | | </view> |
| | | </template> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | <!-- ä¼è®®è¯¦æ
å¯¹è¯æ¡ --> |
| | | <u-popup :show="detailDialogVisible" |
| | | mode="center" |
| | | customStyle="width: 80%;" |
| | | :round="10"> |
| | | <view class="dialog-content"> |
| | | <view class="dialog-header"> |
| | | <text class="dialog-title">ä¼è®®è¯¦æ
</text> |
| | | <up-icon name="close" |
| | | @click="detailDialogVisible = false" |
| | | class="close-icon"></up-icon> |
| | | </view> |
| | | <view v-if="currentMeeting" |
| | | class="dialog-body"> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="detail-value">{{ currentMeeting.title }}</text> |
| | | </view> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">ä¼è®®å®¤</text> |
| | | <text class="detail-value">{{ currentMeeting.room }}</text> |
| | | </view> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value">{{ currentMeeting.time }}</text> |
| | | </view> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">主æäºº</text> |
| | | <text class="detail-value">{{ currentMeeting.host }}</text> |
| | | </view> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ currentMeeting.participants }}人</text> |
| | | </view> |
| | | <view class="detail-item"> |
| | | <text class="detail-label">ä¼è®®è¯´æ</text> |
| | | <text class="detail-value">{{ currentMeeting.description }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="dialog-footer"> |
| | | <u-button @click="detailDialogVisible = false">å
³é</u-button> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { getMeetingUseList } from "@/api/managementMeetings/meeting.js"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | // æ¥è¯¢è¡¨å |
| | | const queryForm = reactive({ |
| | | meetingDate: dayjs().format("YYYY-MM-DD"), |
| | | }); |
| | | |
| | | const loading = ref(false); |
| | | const timeSlots = ref([]); |
| | | const roomUsage = ref([]); |
| | | const currentMeeting = ref(null); |
| | | const detailDialogVisible = ref(false); |
| | | const showDatePickerDialog = ref(false); |
| | | const datePickerValue = ref(Date.now()); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // æ¸
ç©ºæ¥æ |
| | | const clearDate = () => { |
| | | datePickerValue.value = Date.now(); |
| | | queryForm.meetingDate = dayjs().format("YYYY-MM-DD"); |
| | | getList(); |
| | | }; |
| | | |
| | | // æ¾ç¤ºæ¥æéæ©å¨ |
| | | const showDatePicker = () => { |
| | | if (queryForm.meetingDate) { |
| | | datePickerValue.value = new Date(queryForm.meetingDate).getTime(); |
| | | } else { |
| | | datePickerValue.value = Date.now(); |
| | | } |
| | | console.log(datePickerValue.value, "datePickerValue.value"); |
| | | showDatePickerDialog.value = true; |
| | | }; |
| | | |
| | | // å¤çæ¥æéæ©ç¡®è®¤ |
| | | const handleDateConfirm = value => { |
| | | // dayjs().format("YYYY-MM-DD") |
| | | console.log(value, "value"); |
| | | |
| | | queryForm.meetingDate = dayjs(value.value).format("YYYY-MM-DD"); |
| | | showDatePickerDialog.value = false; |
| | | getList(); |
| | | }; |
| | | |
| | | // è·ååè¡¨æ°æ® |
| | | const getList = () => { |
| | | handleSearch(); |
| | | }; |
| | | |
| | | // åå§åæ¶é´æ§½ï¼ä»¥åå°æ¶ä¸ºé´éï¼ä»8:00å°18:00ï¼ |
| | | const initTimeSlots = () => { |
| | | const slots = []; |
| | | for (let hour = 8; hour < 18; hour++) { |
| | | // æ¯ä¸ªå°æ¶æ·»å 两个æ¶é´æ®µï¼æ´ç¹ååç¹ |
| | | slots.push({ |
| | | label: `${hour.toString().padStart(2, "0")}:00`, |
| | | value: `${hour.toString().padStart(2, "0")}:00`, |
| | | }); |
| | | |
| | | if (hour < 17) { |
| | | // å°17:30ä¸ºæ¢ |
| | | slots.push({ |
| | | label: `${hour.toString().padStart(2, "0")}:30`, |
| | | value: `${hour.toString().padStart(2, "0")}:30`, |
| | | }); |
| | | } |
| | | } |
| | | timeSlots.value = slots; |
| | | console.log(timeSlots.value, "timeSlots.value"); |
| | | }; |
| | | |
| | | // çæä¼è®®å®¤çæ¶é´åå
æ ¼ |
| | | const generateMeetingCells = room => { |
| | | const cells = []; |
| | | const meetings = room.meetings || []; |
| | | const occupiedSlots = new Set(); |
| | | |
| | | // å¤çæ¯ä¸ªä¼è®® |
| | | for (const meeting of meetings) { |
| | | const startIdx = timeSlots.value.findIndex( |
| | | slot => slot.value === meeting.startTime |
| | | ); |
| | | let endIdx = timeSlots.value.findIndex( |
| | | slot => slot.value === meeting.endTime |
| | | ); |
| | | if (endIdx === -1) { |
| | | endIdx = timeSlots.value.length; |
| | | } |
| | | |
| | | if (startIdx !== -1) { |
| | | // æ 记被å ç¨çæ¶é´æ®µ |
| | | for (let i = startIdx; i < endIdx; i++) { |
| | | if (timeSlots.value[i]) { |
| | | occupiedSlots.add(timeSlots.value[i].value); |
| | | } |
| | | } |
| | | |
| | | // å建ä¼è®®åå
æ ¼ |
| | | cells.push({ |
| | | type: "meeting", |
| | | meeting: meeting, |
| | | span: endIdx - startIdx, |
| | | startTime: meeting.startTime, |
| | | endTime: meeting.endTime, |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // å¤çç©ºé²æ¶é´æ®µ |
| | | for (let i = 0; i < timeSlots.value.length; i++) { |
| | | const slot = timeSlots.value[i]; |
| | | if (!occupiedSlots.has(slot.value)) { |
| | | // æ¥æ¾è¿ç»çç©ºé²æ¶é´æ®µ |
| | | let span = 1; |
| | | while ( |
| | | i + span < timeSlots.value.length && |
| | | !occupiedSlots.has(timeSlots.value[i + span].value) |
| | | ) { |
| | | occupiedSlots.add(timeSlots.value[i + span].value); |
| | | span++; |
| | | } |
| | | |
| | | cells.push({ |
| | | type: "free", |
| | | span: span, |
| | | time: slot.value, |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // ææ¶é´æåº |
| | | cells.sort((a, b) => { |
| | | const timeA = a.startTime || a.time; |
| | | const timeB = b.startTime || b.time; |
| | | return ( |
| | | timeSlots.value.findIndex(s => s.value === timeA) - |
| | | timeSlots.value.findIndex(s => s.value === timeB) |
| | | ); |
| | | }); |
| | | |
| | | return cells; |
| | | }; |
| | | |
| | | // æ¥çä¼è®®è¯¦æ
|
| | | const viewMeetingDetails = cell => { |
| | | console.log(cell, "cell"); |
| | | |
| | | if (cell && cell.type === "meeting") { |
| | | currentMeeting.value = cell.meeting; |
| | | detailDialogVisible.value = true; |
| | | } else { |
| | | uni.showToast({ |
| | | title: "该æ¶é´æ®µä¼è®®å®¤ç©ºé²", |
| | | icon: "info", |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | // æ¥è¯¢æé®æä½ |
| | | const handleSearch = async () => { |
| | | loading.value = true; |
| | | try { |
| | | const resp = await getMeetingUseList({ ...queryForm }); |
| | | roomUsage.value = resp.data; |
| | | } catch (error) { |
| | | uni.showToast({ |
| | | title: "è·åæ°æ®å¤±è´¥", |
| | | icon: "error", |
| | | }); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // éç½®æç´¢è¡¨å |
| | | const resetSearch = () => { |
| | | queryForm.meetingDate = dayjs().format("YYYY-MM-DD"); |
| | | }; |
| | | |
| | | // 页é¢å è½½æ¶è·åæ°æ® |
| | | onMounted(() => { |
| | | // åå§åæ¶é´æ§½ |
| | | initTimeSlots(); |
| | | |
| | | // é»è®¤æ¥è¯¢ä»å¤©çæ°æ® |
| | | handleSearch(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | .meeting-list { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding: 16rpx; |
| | | } |
| | | |
| | | .search-section { |
| | | background: #fff; |
| | | padding: 16rpx; |
| | | border-radius: 8rpx; |
| | | margin-bottom: 16rpx; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | } |
| | | |
| | | .filter-button { |
| | | padding: 12rpx 16rpx; |
| | | background: #f5f7fa; |
| | | border-radius: 4rpx; |
| | | } |
| | | |
| | | .form-buttons { |
| | | display: flex; |
| | | gap: 12rpx; |
| | | margin-top: 16rpx; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .table-container { |
| | | margin-top: 16rpx; |
| | | overflow-x: auto; |
| | | } |
| | | |
| | | .time-table { |
| | | width: 100%; |
| | | } |
| | | |
| | | .table-header { |
| | | display: flex; |
| | | border: 1rpx solid #e4e7ed; |
| | | background: #f5f7fa; |
| | | } |
| | | |
| | | .header-cell { |
| | | padding: 12rpx 8rpx; |
| | | text-align: center; |
| | | font-weight: bold; |
| | | border-right: 1rpx solid #e4e7ed; |
| | | } |
| | | |
| | | .room-header { |
| | | width: 120rpx; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .time-header { |
| | | width: 120rpx; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .table-body { |
| | | border: 1rpx solid #e4e7ed; |
| | | border-top: none; |
| | | } |
| | | |
| | | .table-row { |
| | | display: flex; |
| | | border-top: 1rpx solid #e4e7ed; |
| | | } |
| | | |
| | | .table-row:first-child { |
| | | border-top: none; |
| | | } |
| | | |
| | | .cell { |
| | | padding: 16rpx 8rpx; |
| | | text-align: center; |
| | | border-right: 1rpx solid #e4e7ed; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | word-break: break-word; |
| | | line-height: 1.2; |
| | | } |
| | | |
| | | .room-cell { |
| | | width: 120rpx; |
| | | font-weight: bold; |
| | | flex-shrink: 0; |
| | | background: #f9fafc; |
| | | } |
| | | |
| | | .cells-container { |
| | | display: flex; |
| | | } |
| | | |
| | | .content-cell { |
| | | min-height: 120rpx; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .content-cell:active { |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .free { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .meeting { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .status-1 { |
| | | background-color: #fef0f0; |
| | | color: #d14646; |
| | | } |
| | | |
| | | .status-0 { |
| | | background-color: #ecf5ff; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .meeting-content { |
| | | width: 100%; |
| | | } |
| | | |
| | | .meeting-title { |
| | | font-weight: bold; |
| | | margin-bottom: 8rpx; |
| | | font-size: 24rpx; |
| | | } |
| | | |
| | | .meeting-time { |
| | | font-size: 20rpx; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .free-content { |
| | | color: #909399; |
| | | } |
| | | |
| | | /* å¯¹è¯æ¡æ ·å¼ */ |
| | | .dialog-content { |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .dialog-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24rpx; |
| | | padding-bottom: 16rpx; |
| | | border-bottom: 1rpx solid #e4e7ed; |
| | | } |
| | | |
| | | .dialog-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | .close-icon { |
| | | font-size: 32rpx; |
| | | color: #909399; |
| | | } |
| | | |
| | | .dialog-body { |
| | | margin-bottom: 24rpx; |
| | | } |
| | | |
| | | .detail-item { |
| | | display: flex; |
| | | margin-bottom: 16rpx; |
| | | padding: 8rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .detail-label { |
| | | width: 140rpx; |
| | | font-weight: bold; |
| | | color: #606266; |
| | | } |
| | | |
| | | .detail-value { |
| | | flex: 1; |
| | | color: #303133; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | display: flex; |
| | | justify-content: center; |
| | | margin-top: 16rpx; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="client-visit-detail"> |
| | | <PageHeader title="ä¼è®®å®¤è¯¦æ
" |
| | | @back="goBack" /> |
| | | <u-form ref="formRef" |
| | | label-width="90"> |
| | | <!-- 客æ·ä¿¡æ¯ --> |
| | | <u-cell-group title="ä¼è®®å®¤ä¿¡æ¯"> |
| | | <u-form-item label="ä¼è®®å®¤åç§°" |
| | | prop="name" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.name" |
| | | placeholder="请è¾å
¥ä¼è®®å®¤åç§°" /> |
| | | </u-form-item> |
| | | <u-form-item label="ä½ç½®" |
| | | required |
| | | prop="location" |
| | | border-bottom> |
| | | <u-input v-model="form.location" |
| | | placeholder="请è¾å
¥ä½ç½®" /> |
| | | </u-form-item> |
| | | <u-form-item label="容纳人æ°" |
| | | required |
| | | prop="capacity" |
| | | border-bottom> |
| | | <u-input v-model="form.capacity" |
| | | placeholder="请è¾å
¥å®¹çº³äººæ°" /> |
| | | </u-form-item> |
| | | <u-form-item label="设å¤é
ç½®" |
| | | prop="equipment" |
| | | border-bottom> |
| | | <u-input v-model="form.equipment" |
| | | readonly |
| | | placeholder="è¯·éæ©è®¾å¤é
ç½®" |
| | | @click="showEquipmentSheet = true" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="openEquipmentSheet"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="ç¶æ" |
| | | prop="status" |
| | | border-bottom> |
| | | <u-input v-model="statusname" |
| | | readonly |
| | | placeholder="è¯·éæ©ç¶æ" |
| | | @click="showStatusSheet = true" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showStatusSheet = true"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="夿³¨" |
| | | prop="remark" |
| | | border-bottom> |
| | | <u-input v-model="form.remark" |
| | | placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </u-form-item> |
| | | </u-cell-group> |
| | | <!-- æäº¤æé® --> |
| | | <view class="footer-btns"> |
| | | <u-button class="cancel-btn" |
| | | @click="goBack">åæ¶</u-button> |
| | | <u-button class="sign-btn" |
| | | type="primary" |
| | | @click="handleSubmit" |
| | | :loading="loading">ä¿å</u-button> |
| | | </view> |
| | | </u-form> |
| | | <!-- 设å¤é
ç½®éæ©å¨ --> |
| | | <u-popup :show="showEquipmentSheet" |
| | | mode="bottom" |
| | | @close="showEquipmentSheet = false" |
| | | height="200px"> |
| | | <view class="popup-content"> |
| | | <view class="popup-body"> |
| | | <u-checkbox-group v-model="form.equipment" |
| | | @change="handleEquipmentChange" |
| | | icon-placement="right" |
| | | placement="row"> |
| | | <view style="width:100%;padding:10px;margin-top:20px;"> |
| | | <u-checkbox v-for="option in equipmentOptions" |
| | | :key="option.value" |
| | | :name="option.value" |
| | | :label="option.name" |
| | | class="checkbox-item"></u-checkbox> |
| | | </view> |
| | | </u-checkbox-group> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | | <!-- ç¶æéæ©å¨ --> |
| | | <up-action-sheet :show="showStatusSheet" |
| | | :actions="statusOptions" |
| | | @select="onStatusSelect" |
| | | @close="showStatusSheet = false" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "meeting-settings-detail" }); |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | |
| | | import { ref, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { saveRoom } from "@/api/managementMeetings/meetingSettings"; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | name: "", |
| | | location: "", |
| | | capacity: "", |
| | | equipment: [], |
| | | status: "", |
| | | remark: "", |
| | | }); |
| | | const equipmentOptions = ref([ |
| | | { value: "æå½±ä»ª", name: "æå½±ä»ª" }, |
| | | { value: "çµè§", name: "çµè§" }, |
| | | { value: "é³å", name: "é³å" }, |
| | | { value: "çµè¯", name: "çµè¯" }, |
| | | { value: "è§é¢ä¼è®®ç³»ç»", name: "è§é¢ä¼è®®ç³»ç»" }, |
| | | { value: "ç½æ¿", name: "ç½æ¿" }, |
| | | { value: "ååæ¿", name: "ååæ¿" }, |
| | | { value: "æ 线ç½ç»", name: "æ 线ç½ç»" }, |
| | | ]); |
| | | const statusOptions = ref([ |
| | | { value: "1", name: "å¯ç¨" }, |
| | | { value: "0", name: "ç¦ç¨" }, |
| | | ]); |
| | | //// 页é¢ç¶æ |
| | | const loading = ref(false); |
| | | const formRef = ref(null); |
| | | const showEquipmentSheet = ref(false); |
| | | const showStatusSheet = ref(false); |
| | | const openEquipmentSheet = () => { |
| | | showEquipmentSheet.value = true; |
| | | }; |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | const statusname = ref(""); |
| | | // ç¶æéæ© |
| | | const onStatusSelect = action => { |
| | | form.value.status = action.value; |
| | | statusname.value = action.name; |
| | | showStatusSheet.value = false; |
| | | }; |
| | | // 设å¤é
ç½®éæ© |
| | | const handleEquipmentChange = val => { |
| | | form.value.equipment = val; |
| | | console.log("form.value.equipment", form.value.equipment); |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = async () => { |
| | | if (!form.value.name) { |
| | | showToast("请è¾å
¥ä¼è®®å®¤åç§°"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.location) { |
| | | showToast("请è¾å
¥ä½ç½®"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.capacity) { |
| | | showToast("请è¾å
¥å®¹çº³äººæ°"); |
| | | return; |
| | | } |
| | | try { |
| | | loading.value = true; |
| | | form.value.equipment = form.value.equipment.join(","); |
| | | form.value.status = Number(form.value.status); |
| | | form.value.capacity = Number(form.value.capacity); |
| | | // 使ç¨å®å
¨æµ
æ·è´ï¼é¿å
对象å±å¼å¨æäºè¿è¡æ¶æé |
| | | console.log("form.value", form.value); |
| | | saveRoom(form.value).then(res => { |
| | | if (res.code !== 200) { |
| | | showToast("ä¿å失败ï¼è¯·éè¯"); |
| | | return; |
| | | } |
| | | loading.value = false; |
| | | showToast("ä¿åæå"); |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 500); |
| | | }); |
| | | } catch (e) { |
| | | loading.value = false; |
| | | console.error("ä¿å失败:", e); |
| | | showToast("ä¿å失败ï¼è¯·éè¯"); |
| | | } |
| | | }; |
| | | |
| | | // åå§å页颿°æ® |
| | | const initPageData = () => { |
| | | // 仿¬å°åå¨ä¸è·åä¼è®® room æ°æ® |
| | | const meetingRoom = uni.getStorageSync("meetingRoom"); |
| | | if (meetingRoom) { |
| | | form.value = JSON.parse(JSON.stringify(meetingRoom)); |
| | | if (meetingRoom.equipment) { |
| | | if (Array.isArray(meetingRoom.equipment)) { |
| | | form.value.equipment = meetingRoom.equipment; |
| | | } else { |
| | | form.value.equipment = meetingRoom.equipment.split(","); |
| | | } |
| | | } |
| | | statusname.value = meetingRoom.status === 1 ? "å¯ç¨" : "ç¦ç¨"; |
| | | |
| | | // æ¸
餿¬å°åå¨ä¸çæ°æ®ï¼é¿å
䏿¬¡æå¼æ¶ä»ç¶æ¾ç¤º |
| | | uni.removeStorageSync("meetingRoom"); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initPageData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/static/scss/form-common.scss"; |
| | | .client-visit { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 5rem; |
| | | } |
| | | |
| | | .footer-btns { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 0.75rem 0; |
| | | box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | font-weight: 400; |
| | | font-size: 1rem; |
| | | color: #666; |
| | | background: #f5f5f5; |
| | | border: 1px solid #ddd; |
| | | width: 45%; |
| | | height: 2.5rem; |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .sign-btn { |
| | | font-weight: 500; |
| | | font-size: 1rem; |
| | | color: #fff; |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | border: none; |
| | | width: 45%; |
| | | height: 2.5rem; |
| | | border-radius: 2.5rem 2.5rem 2.5rem 2.5rem; |
| | | } |
| | | |
| | | .location-icon { |
| | | color: #1989fa; |
| | | font-size: 1.2rem; |
| | | } |
| | | |
| | | .selector-container { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .selector-text { |
| | | font-size: 14px; |
| | | color: #333; |
| | | } |
| | | |
| | | .popup-content { |
| | | padding: 20rpx; |
| | | } |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .popup-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .close-icon { |
| | | font-size: 20px; |
| | | color: #999; |
| | | } |
| | | |
| | | .popup-body { |
| | | max-height: 60vh; |
| | | overflow-y: auto; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .checkbox-item { |
| | | margin-bottom: 15rpx; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .popup-footer { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 15rpx; |
| | | } |
| | | |
| | | .cancel-btn-popup { |
| | | flex: 1; |
| | | border-radius: 8rpx; |
| | | } |
| | | |
| | | .confirm-btn-popup { |
| | | flex: 1; |
| | | border-radius: 8rpx; |
| | | } |
| | | .checkbox-item { |
| | | margin-top: 40rpx; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="sales-accoun"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®è®¾ç½®" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | v-model="name" |
| | | @blur="getList" |
| | | clearable /> |
| | | </view> |
| | | <view class="filter-button" |
| | | @click="getList"> |
| | | <u-icon name="search" |
| | | size="24" |
| | | color="#999"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æè®¿è®°å½å表 --> |
| | | <view class="ledger-list" |
| | | v-if="visitList.length > 0"> |
| | | <view v-for="(item, index) in visitList" |
| | | :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.name || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <!-- <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å®¤åç§°</text> |
| | | <text class="detail-value">{{ item.name || '-' }}</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.capacity || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">设å¤é
ç½®</text> |
| | | <text class="detail-value">{{ item.equipment }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç¶æ</text> |
| | | <text class="detail-value" |
| | | :class="{'status-enabled': item.status == 1, 'status-disabled': item.status == 0}">{{ item.status == 1 ? 'å¯ç¨' : 'ç¦ç¨' }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- æé®åºå --> |
| | | <view class="action-buttons"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | @click="viewDetail(item)"> |
| | | ç¼è¾ |
| | | </u-button> |
| | | <u-button type="error" |
| | | size="small" |
| | | class="action-btn" |
| | | @click="confirmDelete(item)"> |
| | | å é¤ |
| | | </u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ ä¼è®®å®¤è®°å½</text> |
| | | </view> |
| | | <!-- æµ®å¨æ°å¢æé® --> |
| | | <view class="fab-button" |
| | | @click="addVisit"> |
| | | <up-icon name="plus" |
| | | size="24" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getMeetingRoomList, |
| | | delRoom, |
| | | } from "@/api/managementMeetings/meetingSettings"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "client-visit-index" }); |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // æç´¢å
³é®è¯ |
| | | const name = ref(""); |
| | | |
| | | // æè®¿è®°å½æ°æ® |
| | | const visitList = ref([]); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | const confirmDelete = item => { |
| | | uni.showModal({ |
| | | title: "确认å é¤", |
| | | content: `æ¯å¦ç¡®è®¤å é¤ä¼è®®å®¤ ${item.name}ï¼`, |
| | | success: res => { |
| | | if (res.confirm) { |
| | | delRoom(item.id) |
| | | .then(() => { |
| | | showToast("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | showToast("å é¤å¤±è´¥"); |
| | | }); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const params = { |
| | | current: -1, |
| | | size: -1, |
| | | name: name.value, |
| | | }; |
| | | getMeetingRoomList(params) |
| | | .then(res => { |
| | | visitList.value = res.data.records; |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | showToast("è·åæ°æ®å¤±è´¥"); |
| | | }); |
| | | }; |
| | | |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ°å¢æè®¿ - 跳转å°ç»è®°é¡µé¢ |
| | | const addVisit = () => { |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetingSettings/detail", |
| | | }); |
| | | }; |
| | | |
| | | // ç¼è¾ |
| | | const viewDetail = item => { |
| | | uni.setStorageSync("meetingRoom", item); |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetingSettings/detail", |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | onShow(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | // 页é¢ç¹å®çæ ·å¼è¦ç |
| | | .sales-accoun { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | // ç¹å®ç徿 æ ·å¼ |
| | | .document-icon { |
| | | background: #667eea; // ä¿æé¡µé¢ç¹æçèæ¯è² |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .visit-status { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .detail-value { |
| | | word-break: break-all; // ä¿ç页é¢ç¹æçææ¬æ¢è¡æ ·å¼ |
| | | color: #333; // ä¿æé¡µé¢ç¹æçææ¬é¢è² |
| | | } |
| | | |
| | | // ç¶ææ ·å¼ |
| | | .status-enabled { |
| | | color: #28a745; // ä¿æé¡µé¢ç¹æçæåé¢è² |
| | | } |
| | | |
| | | .status-disabled { |
| | | color: #dc3545; // ä¿æé¡µé¢ç¹æçé误é¢è² |
| | | } |
| | | |
| | | // ç¹å®çæµ®å¨æé®æ ·å¼ |
| | | .fab-button { |
| | | background: #667eea; // ä¿æé¡µé¢ç¹æçèæ¯è² |
| | | box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // ä¿æé¡µé¢ç¹æçé´å½±ææ |
| | | } |
| | | </style> |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="client-visit-detail"> |
| | | <PageHeader title="å®¢æ·æè®¿è¯¦æ
" @back="goBack" /> |
| | | |
| | | <!-- å
å®¹å®¹å¨ --> |
| | | <view class="content-container"> |
| | | <!-- 客æ·ä¿¡æ¯ --> |
| | | <view class="section"> |
| | | <view class="section-title">客æ·ä¿¡æ¯</view> |
| | | <view class="info-item"> |
| | | <text class="info-label">客æ·åç§°</text> |
| | | <text class="info-value">{{ form.customerName || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">è系人</text> |
| | | <text class="info-value">{{ form.contact || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">èç³»çµè¯</text> |
| | | <text class="info-value">{{ form.contactPhone || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- æè®¿ä¿¡æ¯ --> |
| | | <view class="section"> |
| | | <view class="section-title">æè®¿ä¿¡æ¯</view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æè®¿ç®ç</text> |
| | | <text class="info-value">{{ form.purposeVisit || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æè®¿æ¶é´</text> |
| | | <text class="info-value">{{ form.purposeDate || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æè®¿å°ç¹</text> |
| | | <text class="info-value multi-line">{{ form.visitAddress || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æè®¿äºº</text> |
| | | <text class="info-value">{{ form.visitingPeople || '-' }}</text> |
| | | </view> |
| | | <view class="info-item" v-if="form.latitude && form.longitude"> |
| | | <text class="info-label">ç»çº¬åº¦</text> |
| | | <text class="info-value">{{ form.latitude }}, {{ form.longitude }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 夿³¨ä¿¡æ¯ --> |
| | | <view class="section"> |
| | | <view class="section-title">夿³¨ä¿¡æ¯</view> |
| | | <view class="info-item remark-item"> |
| | | <text class="info-label">夿³¨</text> |
| | | <text class="info-value multi-line">{{ form.remark }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | const showToast = (message) => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | |
| | | import { ref, onMounted } from 'vue' |
| | | import PageHeader from '@/components/PageHeader.vue' |
| | | import useUserStore from "@/store/modules/user" |
| | | |
| | | const userStore = useUserStore() |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | customerName: '', |
| | | contact: '', |
| | | contactPhone: '', |
| | | visitingPeople: '', |
| | | purposeVisit: '', |
| | | purposeDate: '', |
| | | visitAddress: '', |
| | | latitude: '', |
| | | longitude: '', |
| | | locationAddress: '', |
| | | remark: '' |
| | | }) |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | // è¿åæ¶æ¸
餿¬å°åå¨çID |
| | | uni.removeStorageSync('clientVisit') |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // åå§å页颿°æ® |
| | | const initPageData = () => { |
| | | // 仿¬å°åå¨è·åæè®¿è®°å½è¯¦æ
|
| | | const row = uni.getStorageSync('clientVisit') |
| | | if (row) { |
| | | form.value = { ...row } |
| | | } else { |
| | | showToast('ææ æè®¿è®°å½æ°æ®') |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | initPageData() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import '@/static/scss/form-common.scss'; |
| | | |
| | | .client-visit-detail { |
| | | min-height: 100vh; |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | .content-container { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .section { |
| | | background-color: #ffffff; |
| | | border-radius: 12px; |
| | | margin-bottom: 16px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333333; |
| | | padding: 16px 16px 12px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | padding: 14px 16px; |
| | | border-bottom: 1px solid #f8f8f8; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .info-item:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666666; |
| | | min-width: 80px; |
| | | flex-shrink: 0; |
| | | line-height: 22px; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333333; |
| | | flex: 1; |
| | | line-height: 22px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .multi-line { |
| | | text-align: left; |
| | | word-break: break-all; |
| | | line-height: 1.6; |
| | | } |
| | | |
| | | .remark-item { |
| | | padding-bottom: 16px; |
| | | } |
| | | </style> |