Merge branch 'dev_new' of http://114.132.189.42:9002/r/product-inventory-APP-before into dev_new
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // å页æ¥è¯¢ |
| | | export function safeTrainingListPage(query) { |
| | | return request({ |
| | | url: "/safeTraining/page", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | |
| | | // æ°å¢å®å
¨å¹è®èæ ¸ |
| | | export function safeTrainingAdd(query) { |
| | | return request({ |
| | | url: '/safeTraining', |
| | | method: 'post', |
| | | data: query |
| | | }) |
| | | } |
| | | |
| | | // ä¿®æ¹å®å
¨å¹è®èæ ¸ |
| | | export function safeTrainingUpdate(query) { |
| | | return request({ |
| | | url: '/safeTraining', |
| | | method: 'put', |
| | | data: query |
| | | }) |
| | | } |
| | | |
| | | // å é¤å®å
¨å¹è®èæ ¸ |
| | | export function safeTrainingDel(ids) { |
| | | return request({ |
| | | url: '/safeTraining/' + ids, |
| | | method: 'delete', |
| | | data: ids |
| | | }) |
| | | } |
| | | |
| | | // å¯¼åº |
| | | export function safeTrainingExport(query) { |
| | | return request({ |
| | | url: '/safeTraining/export', |
| | | method: 'post', |
| | | data: query, |
| | | responseType: 'blob' |
| | | }) |
| | | } |
| | | |
| | | // æ¥è¯¢éä»¶å表 |
| | | export function safeTrainingFileListPage(query) { |
| | | return request({ |
| | | url: "/safeTrainingFile/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ·»å éä»¶ |
| | | export function safeTrainingFileAdd(query) { |
| | | return request({ |
| | | url: '/safeTrainingFile/add', |
| | | method: 'post', |
| | | data: query |
| | | }) |
| | | } |
| | | |
| | | // å é¤éä»¶ |
| | | export function safeTrainingFileDel(ids) { |
| | | return request({ |
| | | url: '/safeTrainingFile/del', |
| | | method: 'delete', |
| | | data: ids |
| | | }) |
| | | } |
| | | |
| | | // ç¾å° |
| | | export function safeTrainingSign(query) { |
| | | return request({ |
| | | url: '/safeTraining/sign', |
| | | method: 'post', |
| | | data: query |
| | | }) |
| | | } |
| | | |
| | | // æ¥è¯¢è¯¦æ
|
| | | export function safeTrainingGet(query) { |
| | | return request({ |
| | | url: '/safeTraining/getSafeTraining', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | | } |
| | | |
| | | // æäº¤ |
| | | export function safeTrainingSave(query) { |
| | | return request({ |
| | | url: '/safeTraining/saveSafeTraining', |
| | | method: 'post', |
| | | data: query |
| | | }) |
| | | } |
| | | |
| | | export function safeTrainingDetailListPage(query) { |
| | | return request({ |
| | | url: "/safeTrainingDetails/page", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // å¯¼åº |
| | | export function safeTrainingDetailExport(query) { |
| | | return request({ |
| | | url: '/safeTrainingDetails/export', |
| | | method: 'post', |
| | | data: query, |
| | | responseType: 'blob' |
| | | }) |
| | | } |
| | |
| | | "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
| | | "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
| | | "<uses-feature android:name=\"android.hardware.camera\"/>", |
| | | "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
| | | "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>", |
| | | "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", |
| | | "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", |
| | | "<uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\"/>", |
| | | "<uses-feature android:name=\"android.hardware.location\"/>", |
| | | "<uses-feature android:name=\"android.hardware.location.gps\"/>", |
| | | "<uses-feature android:name=\"android.hardware.location.network\"/>" |
| | | ] |
| | | }, |
| | | /* iosæå
é
ç½® */ |
| | | "ios" : { |
| | | "dSYMs" : false |
| | | "dSYMs": false, |
| | | "plist": { |
| | | "NSLocationWhenInUseUsageDescription": "éè¦è·åæ¨çä½ç½®ä¿¡æ¯æ¥è®°å½å®¢æ·æè®¿å°ç¹", |
| | | "NSLocationAlwaysAndWhenInUseUsageDescription": "éè¦è·åæ¨çä½ç½®ä¿¡æ¯æ¥è®°å½å®¢æ·æè®¿å°ç¹" |
| | | } |
| | | }, |
| | | /* SDKé
ç½® */ |
| | | "sdkConfigs" : { |
| | |
| | | "navigationBarTitleText": "åºæ¥é¢æ¡è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/index", |
| | | "style": { |
| | | "navigationBarTitleText": "å®å
¨å¹è®èæ ¸", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "å¹è®è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/view", |
| | | "style": { |
| | | "navigationBarTitleText": "å¹è®è¯¦æ
", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/fileList", |
| | | "style": { |
| | | "navigationBarTitleText": "å¹è®éä»¶", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/resultDetail", |
| | | "style": { |
| | | "navigationBarTitleText": "ç»ææç»", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/safeProduction/safetyTrainingAssessment/record", |
| | | "style": { |
| | | "navigationBarTitleText": "å¹è®è®°å½", |
| | | "navigationStyle": "custom" |
| | | } |
| | | } |
| | | ], |
| | | "subPackages": [ |
| | |
| | | }, |
| | | fail: err => { |
| | | uni.hideLoading(); |
| | | showToast("è·åä½ç½®å¤±è´¥ï¼è¯·æ£æ¥å®ä½æé"); |
| | | console.error("è·åä½ç½®å¤±è´¥:", err); |
| | | |
| | | // æ¾ç¤ºé误æç¤ºå¹¶å¼å¯¼ç¨æ·æ£æ¥æé |
| | | showToast("è·åä½ç½®å¤±è´¥ï¼è¯·æ£æ¥å®ä½æé"); |
| | | |
| | | // å¼å¯¼ç¨æ·æ£æ¥æé设置 |
| | | uni.showModal({ |
| | | title: "ä½ç½®æéæç¤º", |
| | | content: |
| | | "è·åä½ç½®å¤±è´¥ï¼å¯è½æ¯å 为ä½ç½®æéæªå¼å¯ï¼è¯·å¨è®¾å¤è®¾ç½®ä¸æ£æ¥å¹¶å¼å¯ä½ç½®æéã", |
| | | confirmText: "ç¥éäº", |
| | | cancelText: "åæ¶", |
| | | success: res => { |
| | | if (res.confirm) { |
| | | // å¯ä»¥å°è¯æå¼è®¾ç½®é¡µé¢ï¼å¦ææ¯æï¼ |
| | | if (uni.openSetting) { |
| | | uni.openSetting({ |
| | | success: settingRes => { |
| | | console.log("è®¾ç½®ç»æ:", settingRes); |
| | | }, |
| | | }); |
| | | } |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | // å¤±è´¥æ¶æ¾ç¤ºéè¯¯ä¿¡æ¯ |
| | | form.value.visitAddress = "ä½ç½®è·å失败"; |
| | | }, |
| | |
| | | icon: "/static/images/icon/guzhangfenxi@2x.png", |
| | | label: "äºæ
䏿¥", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/guzhangfenxi@2x.png", |
| | | label: "å®å
¨å¹è®", |
| | | }, |
| | | ]); |
| | | // åååå
¬åè½æ°æ® |
| | | const collaborationItems = reactive([ |
| | |
| | | url: "/pages/safeProduction/accidentReportingRecord/index", |
| | | }); |
| | | break; |
| | | case "å®å
¨å¹è®": |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/index", |
| | | }); |
| | | break; |
| | | |
| | | default: |
| | | uni.showToast({ |
| | | title: `ç¹å»äº${item.label}`, |
| | |
| | | <view class="topbox"> |
| | | <view class="boxItem"> |
| | | <view class="boxItem-num"> |
| | | {{stats.total}} |
| | | {{stats.total ? stats.total : 0}} |
| | | </view> |
| | | <view class="boxItem-title"> |
| | | æ»ä¼è®®æ° |
| | |
| | | </view> |
| | | <view class="boxItem"> |
| | | <view class="boxItem-num"> |
| | | {{stats.underWay}} |
| | | {{stats.underWay ? stats.underWay : 0}} |
| | | </view> |
| | | <view class="boxItem-title"> |
| | | è¿è¡ä¸ |
| | |
| | | </view> |
| | | <view class="boxItem"> |
| | | <view class="boxItem-num"> |
| | | {{stats.completed}} |
| | | {{stats.completed ? stats.completed : 0}} |
| | | </view> |
| | | <view class="boxItem-title"> |
| | | 已宿 |
| | |
| | | </view> |
| | | <view class="boxItem"> |
| | | <view class="boxItem-num"> |
| | | {{stats.toStart}} |
| | | {{stats.toStart ? stats.toStart : 0}} |
| | | </view> |
| | | <view class="boxItem-title"> |
| | | å³å°å¼å§ |
| | |
| | | <text class="detail-label">åºä»éé¢(å
)</text> |
| | | <text class="detail-value danger">{{ formatAmount(item.payableAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åçæ¥æ</text> |
| | | <text class="detail-value">{{ item.paymentDate }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | const temFutureTickets = ref(0); |
| | | const originalTicketsNum = ref(0); // ä¿ååå§æ¥ç¥¨æ° |
| | | |
| | | // è¡¨åæ ¡éªè§å |
| | | // è¡¨åæ ¡éªè§å - 使ç¨ç®åç required è§å |
| | | const rules = { |
| | | ticketsNum: [{ required: true, message: "请è¾å
¥æ¥ç¥¨æ°", trigger: "blur" }], |
| | | ticketsAmount: [ |
| | |
| | | |
| | | // 表åæäº¤ |
| | | const onSubmit = async () => { |
| | | if (!formRef.value) { |
| | | console.log("表åå¼ç¨ä¸åå¨"); |
| | | // å¨éªè¯åï¼ç¡®ä¿å¿
å¡«åæ®µæå¼ |
| | | if (!form.value.ticketsNum || form.value.ticketsNum === "" || form.value.ticketsNum === null || form.value.ticketsNum === undefined) { |
| | | uni.showToast({ |
| | | title: "请è¾å
¥æ¥ç¥¨æ°", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // å
è°ç¨ validate æ¹æ³ |
| | | const validateResult = formRef.value.validate(); |
| | | |
| | | // 妿 validate è¿å undefined æ nullï¼ç´æ¥æäº¤ |
| | | if (validateResult === undefined || validateResult === null) { |
| | | submitForm(); |
| | | if (!form.value.ticketsAmount || form.value.ticketsAmount === "" || form.value.ticketsAmount === null || form.value.ticketsAmount === undefined) { |
| | | uni.showToast({ |
| | | title: "请è¾å
¥æ¬æ¬¡æ¥ç¥¨éé¢", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 妿è¿å Promiseï¼ä½¿ç¨ await å catch |
| | | if (validateResult && typeof validateResult.then === 'function') { |
| | | const valid = await validateResult.catch(() => false); |
| | | if (valid) { |
| | | // 表åéªè¯éè¿ï¼æäº¤è¡¨å |
| | | // ç¡®ä¿åæ®µæ¯æ°åç±»åï¼å¹¶è½¬æ¢ä¸ºå符串ï¼å 为表åå¯è½éè¦å符串类åï¼ |
| | | const ticketsNum = Number(form.value.ticketsNum); |
| | | const ticketsAmount = Number(form.value.ticketsAmount); |
| | | |
| | | // 妿æ¥ç¥¨æ°ä¸º0ææ¥ç¥¨éé¢ä¸º0ï¼æç¤ºç¨æ· |
| | | if (isNaN(ticketsNum) || ticketsNum <= 0) { |
| | | uni.showToast({ |
| | | title: "æ¥ç¥¨æ°å¿
须大äº0", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (isNaN(ticketsAmount) || ticketsAmount <= 0) { |
| | | uni.showToast({ |
| | | title: "æ¬æ¬¡æ¥ç¥¨éé¢å¿
须大äº0", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // æ´æ°è¡¨åå¼ï¼ç¡®ä¿æ¯ææçæ°åå符串 |
| | | form.value.ticketsNum = ticketsNum.toString(); |
| | | form.value.ticketsAmount = ticketsAmount.toString(); |
| | | |
| | | // æå¨éªè¯éè¿åï¼ç´æ¥æäº¤ï¼è·³è¿è¡¨åéªè¯ï¼é¿å
çæºä¸çéªè¯é®é¢ï¼ |
| | | submitForm(); |
| | | } else { |
| | | // 表åéªè¯å¤±è´¥ |
| | | console.log("表åéªè¯å¤±è´¥"); |
| | | } |
| | | } else { |
| | | // 妿è¿åå¸å°å¼ï¼ç´æ¥å¤æ |
| | | if (validateResult) { |
| | | submitForm(); |
| | | } else { |
| | | console.log("表åéªè¯å¤±è´¥"); |
| | | } |
| | | } |
| | | } catch (error) { |
| | | // 妿 validate æ¹æ³ä¸å卿æåºé误ï¼ç´æ¥æäº¤ |
| | | console.log("表åéªè¯å¤±è´¥", error); |
| | | submitForm(); |
| | | } |
| | | }; |
| | | const purchaseLedgerId = ref(""); |
| | | const productModelId = ref({}); |
| | |
| | | </up-form-item> |
| | | <up-form-item label="éå®ååå·" |
| | | prop="salesContractNo" |
| | | required |
| | | @click="showPicker = true"> |
| | | required> |
| | | <up-input v-model="form.salesContractNo" |
| | | readonly="" |
| | | @click="showPicker = true" |
| | | readonly |
| | | :disabled="isReadOnly" |
| | | @click="!isReadOnly && (showPicker = true)" |
| | | placeholder="ç¹å»éæ©éå®ååå·" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | v-if="!isReadOnly" |
| | | @click="showPicker = true"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="ä¾åºååç§°" |
| | | prop="supplierName" |
| | | required |
| | | @click="showCustomerPicker = true"> |
| | | > |
| | | <up-input v-model="form.supplierName" |
| | | readonly="" |
| | | @click="showCustomerPicker = true" |
| | | readonly |
| | | :disabled="isReadOnly" |
| | | @click="!isReadOnly && (showCustomerPicker = true)" |
| | | placeholder="ç¹å»éæ©ä¾åºå" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | v-if="!isReadOnly" |
| | | @click="showCustomerPicker = true"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | |
| | | prop="projectName" |
| | | required> |
| | | <up-input v-model="form.projectName" |
| | | :disabled="isReadOnly" |
| | | placeholder="请è¾å
¥é¡¹ç®åç§°" /> |
| | | </up-form-item> |
| | | <up-form-item label="仿¬¾æ¹å¼" |
| | | prop="paymentMethod"> |
| | | <up-input v-model="form.paymentMethod" |
| | | :disabled="isReadOnly" |
| | | placeholder="请è¾å
¥ä»æ¬¾æ¹å¼" /> |
| | | </up-form-item> |
| | | <up-form-item label="ç¾è®¢æ¥æ" |
| | |
| | | prop="executionDate"> |
| | | <up-input v-model="form.executionDate" |
| | | placeholder="è¯·éæ©" |
| | | readonly="" /> |
| | | readonly |
| | | :disabled="isReadOnly" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | v-if="!isReadOnly" |
| | | @click="showTimePicker = true"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | |
| | | <text class="approver-name">{{ step.nickName }}</text> |
| | | </view> |
| | | <view class="delete-approver-btn" |
| | | v-if="!isReadOnly" |
| | | @click="removeApprover(stepIndex)">Ã</view> |
| | | </view> |
| | | <view v-else |
| | | class="add-approver-btn" |
| | | v-if="!isReadOnly" |
| | | @click="addApprover(stepIndex)"> |
| | | <view class="add-circle">+</view> |
| | | <text class="add-label">鿩审æ¹äºº</text> |
| | |
| | | <view class="step-line" |
| | | v-if="stepIndex < approverNodes.length - 1"></view> |
| | | <view class="delete-step-btn" |
| | | v-if="approverNodes.length > 1" |
| | | v-if="approverNodes.length > 1 && !isReadOnly" |
| | | @click="removeApprovalStep(stepIndex)">å é¤èç¹</view> |
| | | </view> |
| | | </view> |
| | | <view class="add-step-btn"> |
| | | <view class="add-step-btn" v-if="!isReadOnly"> |
| | | <u-button icon="plus" |
| | | plain |
| | | type="primary" |
| | |
| | | const operationType = ref(""); |
| | | const editData = ref(null); |
| | | const formRef = ref(null); |
| | | // 审æ¹éè¿ï¼approvalStatus === 3ï¼åï¼ç¦æ¢ç¼è¾/å é¤äº§å |
| | | // 审æ¹éè¿ï¼approvalStatus === 3ï¼åï¼æ´åç¦æ¢ç¼è¾ï¼å«äº§åãåºæ¬ä¿¡æ¯ãå®¡æ¹æµç¨ï¼ |
| | | const isApprovalPassed = computed(() => { |
| | | const status = editData.value?.approvalStatus ?? form.value?.approvalStatus; |
| | | return Number(status) === 3; |
| | | }); |
| | | const canEditProducts = computed(() => { |
| | | return operationType.value !== "view" && !isApprovalPassed.value; |
| | | }); |
| | | // æ¯å¦æ´ä½åªè¯»ï¼æ¥çæ¨¡å¼ æ 已审æ¹éè¿ |
| | | const isReadOnly = computed(() => { |
| | | return operationType.value === "view" || isApprovalPassed.value; |
| | | }); |
| | | |
| | | const userStore = useUserStore(); |
| | |
| | | }; |
| | | |
| | | const onSubmit = () => { |
| | | // 审æ¹éè¿çå°è´¦ç¦æ¢åæ¬¡ä¿®æ¹ |
| | | if (isApprovalPassed.value) { |
| | | uni.showToast({ |
| | | title: "已审æ¹éè¿çå°è´¦ä¸å
许修æ¹", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | const hasEmptyApprover = approverNodes.value.some(node => !node.userId); |
| | | if (hasEmptyApprover) { |
| | | uni.showToast({ |
| | |
| | | }; |
| | | |
| | | const addApprover = stepIndex => { |
| | | if (isReadOnly.value) return; |
| | | // 跳转å°èç³»äººéæ©é¡µé¢ |
| | | uni.setStorageSync("stepIndex", stepIndex); |
| | | uni.navigateTo({ |
| | |
| | | }; |
| | | |
| | | const addApprovalStep = () => { |
| | | if (isReadOnly.value) return; |
| | | // æ·»å æ°çå®¡æ¹æ¥éª¤ |
| | | approverNodes.value.push({ userId: null, nickName: null }); |
| | | console.log(approverNodes.value, "approverNodes.value"); |
| | | }; |
| | | |
| | | const removeApprover = stepIndex => { |
| | | if (isReadOnly.value) return; |
| | | // ç§»é¤å®¡æ¹äºº |
| | | approverNodes.value[stepIndex].userId = null; |
| | | approverNodes.value[stepIndex].nickName = null; |
| | | }; |
| | | |
| | | const removeApprovalStep = stepIndex => { |
| | | if (isReadOnly.value) return; |
| | | // ç¡®ä¿è³å°ä¿çä¸ä¸ªå®¡æ¹æ¥éª¤ |
| | | if (approverNodes.value.length > 1) { |
| | | approverNodes.value.splice(stepIndex, 1); |
| | |
| | | <text class="detail-value">{{ item.entryDate }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- ä»
éâ审æ¹éè¿âçå°è´¦å±ç¤ºå é¤æé® --> |
| | | <view |
| | | class="detail-row" |
| | | v-if="item.approvalStatus !== 3" |
| | | style="justify-content: flex-end; margin-top: 8px;" |
| | | > |
| | | <up-button |
| | | type="error" |
| | | size="small" |
| | | plain |
| | | @click.stop="handleDelete(item)" |
| | | > |
| | | å é¤ |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { purchaseListPage } from "@/api/procurementManagement/procurementLedger"; |
| | | import { purchaseListPage, delPurchase } from "@/api/procurementManagement/procurementLedger"; |
| | | const userStore = useUserStore(); |
| | | const approvalStatusText = { |
| | | 1: "å¾
å®¡æ ¸", |
| | |
| | | } |
| | | }; |
| | | |
| | | // å é¤åæ¡éè´å°è´¦ |
| | | const handleDelete = row => { |
| | | if (!row || !row.id) { |
| | | uni.showToast({ |
| | | title: "æ°æ®æè¯¯ï¼æ æ³å é¤", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.showModal({ |
| | | title: "æç¤º", |
| | | content: "éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", |
| | | confirmText: "确认", |
| | | cancelText: "åæ¶", |
| | | success: res => { |
| | | if (res.confirm) { |
| | | delPurchase([row.id]) |
| | | .then(result => { |
| | | // æåï¼code === 200 |
| | | if (result && result.code === 200) { |
| | | uni.showToast({ |
| | | title: "å 餿å", |
| | | icon: "success", |
| | | }); |
| | | getList(); |
| | | return; |
| | | } |
| | | // ä¸å¡å¤±è´¥ï¼ä¼å
å±ç¤ºå端è¿åç msgï¼å¦ CG2026... ä¸å
许å é¤ï¼ |
| | | uni.showToast({ |
| | | title: (result && result.msg) || "å é¤å¤±è´¥", |
| | | icon: "none", |
| | | }); |
| | | }) |
| | | .catch(error => { |
| | | // å¯¹äº request å°è£
è¿åç '500' æå
¶ä» codeï¼é误æç¤ºå·²ç»å¨ request é toast è¿äºï¼è¿éä¸åéå¤è¦ç |
| | | if (error === "500" || typeof error === "number") { |
| | | return; |
| | | } |
| | | // åªæå¨çæ£å¼å¸¸æ¶ï¼æå¨è¿éå
åºæç¤º |
| | | const msg = |
| | | (error && error.msg) || |
| | | (error && error.response && error.response.data && error.response.data.msg) || |
| | | (error && error.message) || |
| | | "å é¤å¤±è´¥"; |
| | | uni.showToast({ |
| | | title: msg, |
| | | icon: "none", |
| | | }); |
| | | }); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | onShow(() => { |
| | | // 页颿¾ç¤ºæ¶å·æ°å表 |
| | | getList(); |
| | |
| | | <view class="unit">å
</view> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="人åæå¤±æ
åµ" |
| | | prop="personLoss" |
| | | border-bottom> |
| | | <u-input v-model="form.personLoss" |
| | | placeholder="请è¾å
¥äººåæå¤±æ
åµ" /> |
| | | </u-form-item> |
| | | <u-form-item label="äºæ
ç´æ¥åå " |
| | | prop="accidentCause" |
| | | border-bottom> |
| | |
| | | accidentGrade: "", |
| | | happenTime: "", |
| | | happenLocation: "", |
| | | personLoss: "", |
| | | createUserName: "", |
| | | createTime: "", |
| | | assetLoss: "", |
| | |
| | | <view class="info-value">{{ accidentInfo.assetLoss || '-' }}<span v-if="accidentInfo.assetLoss">å
</span></view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">人åæå¤±æ
åµï¼</view> |
| | | <view class="info-value">{{ accidentInfo.personLoss || '-' }}</view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-label">䏿¥æ¶é´ï¼</view> |
| | | <view class="info-value">{{ accidentInfo.createTime || '-' }}</view> |
| | | </view> |
| | |
| | | // æäº¤è¡¨å |
| | | const submitForm = async () => { |
| | | // éªè¯è¡¨åå¿
填项 |
| | | if (!formRef.value) return; |
| | | if (!form.value.planCode) { |
| | | showToast("请è¾å
¥åºæ¥é¢æ¡ç¼ç "); |
| | | return; |
| | | } |
| | | |
| | | const valid = await formRef.value.validate(); |
| | | if (!valid) { |
| | | if (!form.value.planName) { |
| | | showToast("请è¾å
¥åºæ¥é¢æ¡åç§°"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.publishTime) { |
| | | showToast("è¯·éæ©åå¸çææ¶é´"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.planType) { |
| | | showToast("è¯·éæ©é¢æ¡ç±»å"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.coreResponsorUserId) { |
| | | showToast("è¯·éæ©æ ¸å¿è´£ä»»äºº"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.applyScope || form.value.applyScope.length === 0) { |
| | | showToast("è¯·éæ©éç¨èå´"); |
| | | return; |
| | | } |
| | | |
| | |
| | | onLoad(() => { |
| | | // ç¼è¾è§ç¨èµè´¨æ¶ï¼ä»æ¬å°åå¨è·åæ°æ® |
| | | const qualification = uni.getStorageSync("safeQualifications"); |
| | | if (qualification) { |
| | | if (qualification.id) { |
| | | form.value = qualification; |
| | | isEdit.value = true; |
| | | |
| | |
| | | import { delCustomer } from "@/api/cooperativeOffice/clientVisit"; |
| | | import { |
| | | qualificationsListPage, |
| | | safeCertificationAdd, |
| | | safeCertificationUpdate, |
| | | safeCertificationDel, |
| | | fileListPage, |
| | | safeCertificationFileAdd, |
| | | safeCertificationFileDel, |
| | | } from "@/api/safeProduction/safeQualifications"; |
| | | |
| | | import useUserStore from "@/store/modules/user"; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="danger-investigation-detail"> |
| | | <PageHeader :title="isEdit ? 'ç¼è¾å¹è®' : 'æ°å¢å¹è®'" |
| | | @back="goBack" /> |
| | | <u-form @submit="handleSubmit" |
| | | ref="formRef" |
| | | label-width="110"> |
| | | <!-- å¹è®ä¿¡æ¯ --> |
| | | <u-cell-group title="å¹è®ä¿¡æ¯"> |
| | | <u-form-item label="课ç¨ç¼å·" |
| | | prop="courseCode" |
| | | border-bottom> |
| | | <u-input v-model="form.courseCode" |
| | | placeholder="ç³»ç»èªå¨çæ" |
| | | readonly /> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®æ¥æ" |
| | | prop="trainingDate" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.trainingDate" |
| | | placeholder="è¯·éæ©å¹è®æ¥æ" |
| | | @click="showTrainingDatePicker" |
| | | readonly /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showTrainingDatePicker"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="å¼å§æ¶é´" |
| | | prop="openingTime" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.openingTime" |
| | | placeholder="è¯·éæ©å¼å§æ¶é´" |
| | | @click="showOpeningTimePicker" |
| | | readonly /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showOpeningTimePicker"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="ç»ææ¶é´" |
| | | prop="endTime" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.endTime" |
| | | placeholder="è¯·éæ©ç»ææ¶é´" |
| | | @click="showEndTimePicker" |
| | | readonly /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showEndTimePicker"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®ç®æ " |
| | | prop="trainingObjectives" |
| | | border-bottom> |
| | | <u-input v-model="form.trainingObjectives" |
| | | placeholder="请è¾å
¥å¹è®ç®æ " /> |
| | | </u-form-item> |
| | | <u-form-item label="åå 对象" |
| | | prop="participants" |
| | | border-bottom> |
| | | <u-input v-model="form.participants" |
| | | placeholder="请è¾å
¥åå 对象" /> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®å
容" |
| | | prop="trainingContent" |
| | | required |
| | | border-bottom> |
| | | <u-textarea v-model="form.trainingContent" |
| | | placeholder="请è¾å
¥å¹è®å
容" |
| | | :maxlength="200" |
| | | count |
| | | :autoHeight="true" /> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®è®²å¸" |
| | | prop="trainingLecturer" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.trainingLecturer" |
| | | placeholder="请è¾å
¥å¹è®è®²å¸" /> |
| | | </u-form-item> |
| | | <u-form-item label="项ç®å¦å" |
| | | prop="projectCredits" |
| | | border-bottom> |
| | | <u-input v-model="form.projectCredits" |
| | | placeholder="请è¾å
¥é¡¹ç®å¦å" |
| | | type="number" /> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®æ¹å¼" |
| | | prop="trainingMode" |
| | | border-bottom> |
| | | <u-input v-model="trainingModeName" |
| | | placeholder="è¯·éæ©å¹è®æ¹å¼" |
| | | @click="showTrainingModeSheet" |
| | | readonly /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="showTrainingModeSheet"></up-icon> |
| | | </template> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®å°ç¹" |
| | | prop="placeTraining" |
| | | border-bottom> |
| | | <u-input v-model="form.placeTraining" |
| | | placeholder="请è¾å
¥å¹è®å°ç¹" /> |
| | | </u-form-item> |
| | | <u-form-item label="课æ¶" |
| | | prop="classHour" |
| | | required |
| | | border-bottom> |
| | | <u-input v-model="form.classHour" |
| | | placeholder="请è¾å
¥è¯¾æ¶" |
| | | type="number" /> |
| | | </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">{{ isEdit ? 'ä¿åä¿®æ¹' : 'æäº¤' }}</u-button> |
| | | </view> |
| | | </u-form> |
| | | <!-- æ¶é´éæ©å¨ --> |
| | | <up-datetime-picker :show="trainingDateVisible" |
| | | mode="date" |
| | | v-model="nowDate" |
| | | @confirm="handleTrainingDateConfirm" |
| | | @cancel="trainingDateVisible = false" |
| | | title="éæ©å¹è®æ¥æ" /> |
| | | <u-datetime-picker :show="openingTimeVisible" |
| | | mode="time" |
| | | @confirm="handleOpeningTimeConfirm" |
| | | @cancel="openingTimeVisible = false" |
| | | title="éæ©å¼å§æ¶é´" /> |
| | | <u-datetime-picker :show="endTimeVisible" |
| | | mode="time" |
| | | @confirm="handleEndTimeConfirm" |
| | | @cancel="endTimeVisible = false" |
| | | title="éæ©ç»ææ¶é´" /> |
| | | <!-- å¹è®æ¹å¼éæ©å¨ --> |
| | | <up-action-sheet :show="trainingModeSheetVisible" |
| | | :actions="trainingModeOptions" |
| | | @select="handleTrainingModeSelect" |
| | | @close="trainingModeSheetVisible = false" |
| | | title="éæ©å¹è®æ¹å¼" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "danger-investigation-detail" }); |
| | | const showToast = message => { |
| | | uni.showToast({ title: message, icon: "none" }); |
| | | }; |
| | | |
| | | import { ref, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | safeTrainingAdd, |
| | | safeTrainingUpdate, |
| | | } from "@/api/safeProduction/safetyTrainingAssessment"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { useDict } from "@/utils/dict"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { safe_training_methods } = useDict("safe_training_methods"); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = ref({ |
| | | courseCode: "", // 课ç¨ç¼å· |
| | | trainingDate: "", // å¹è®æ¥æ |
| | | openingTime: "", // å¼å§æ¶é´ |
| | | endTime: "", // ç»ææ¶é´ |
| | | trainingObjectives: "", // å¹è®ç®æ |
| | | participants: "", // åå 对象 |
| | | trainingContent: "", // å¹è®å
容 |
| | | trainingLecturer: "", // å¹è®è®²å¸ |
| | | projectCredits: "", // 项ç®å¦å |
| | | trainingMode: "", // å¹è®æ¹å¼ |
| | | placeTraining: "", // å¹è®å°ç¹ |
| | | classHour: "", // è¯¾æ¶ |
| | | }); |
| | | |
| | | // 页é¢ç¶æ |
| | | const loading = ref(false); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | |
| | | // å¹è®æ¹å¼éæ©å¨ |
| | | const trainingModeSheetVisible = ref(false); |
| | | const trainingModeName = ref(""); |
| | | const trainingModeOptions = ref([]); |
| | | |
| | | // æ¶é´éæ©å¨ |
| | | const trainingDateVisible = ref(false); |
| | | const openingTimeVisible = ref(false); |
| | | const endTimeVisible = ref(false); |
| | | const nowDate = ref(new Date()); |
| | | |
| | | const showTrainingDatePicker = () => { |
| | | trainingDateVisible.value = true; |
| | | }; |
| | | |
| | | const showOpeningTimePicker = () => { |
| | | openingTimeVisible.value = true; |
| | | }; |
| | | |
| | | const showEndTimePicker = () => { |
| | | endTimeVisible.value = true; |
| | | }; |
| | | |
| | | const handleTrainingDateConfirm = e => { |
| | | form.value.trainingDate = dayjs(e.value).format("YYYY-MM-DD"); |
| | | nowDate.value = e.value; |
| | | trainingDateVisible.value = false; |
| | | }; |
| | | |
| | | const handleOpeningTimeConfirm = e => { |
| | | console.log(e); |
| | | form.value.openingTime = e.value; |
| | | openingTimeVisible.value = false; |
| | | }; |
| | | |
| | | const handleEndTimeConfirm = e => { |
| | | form.value.endTime = e.value; |
| | | endTimeVisible.value = false; |
| | | }; |
| | | |
| | | // æ¾ç¤ºå¹è®æ¹å¼éæ©å¨ |
| | | const showTrainingModeSheet = () => { |
| | | trainingModeSheetVisible.value = true; |
| | | }; |
| | | |
| | | // å¤çå¹è®æ¹å¼éæ© |
| | | const handleTrainingModeSelect = item => { |
| | | form.value.trainingMode = item.value; |
| | | trainingModeName.value = item.name; |
| | | trainingModeSheetVisible.value = false; |
| | | }; |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.removeStorageSync("safetyTraining"); |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = async () => { |
| | | if (!form.value.trainingDate) { |
| | | showToast("è¯·éæ©å¹è®æ¥æ"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.openingTime) { |
| | | showToast("è¯·éæ©å¼å§æ¶é´"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.endTime) { |
| | | showToast("è¯·éæ©ç»ææ¶é´"); |
| | | return; |
| | | } |
| | | if (!form.value.trainingContent) { |
| | | showToast("请è¾å
¥å¹è®å
容"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.trainingLecturer) { |
| | | showToast("请è¾å
¥å¹è®è®²å¸"); |
| | | return; |
| | | } |
| | | |
| | | if (!form.value.classHour) { |
| | | showToast("请è¾å
¥è¯¾æ¶"); |
| | | return; |
| | | } |
| | | if ( |
| | | form.value.projectCredits && |
| | | (isNaN(Number(form.value.projectCredits)) || |
| | | Number(form.value.projectCredits) <= 0) |
| | | ) { |
| | | showToast("å¦åå¿
é¡»æ¯å¤§äº0çæ°å"); |
| | | return; |
| | | } |
| | | form.value.openingTime = form.value.openingTime + ":00"; |
| | | form.value.endTime = form.value.endTime + ":00"; |
| | | |
| | | if ( |
| | | form.value.classHour && |
| | | (isNaN(Number(form.value.classHour)) || Number(form.value.classHour) <= 0) |
| | | ) { |
| | | showToast("课æ¶å¿
é¡»æ¯å¤§äº0çæ°å"); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | loading.value = true; |
| | | |
| | | // 使ç¨å®å
¨æµ
æ·è´ |
| | | const source = |
| | | form.value && typeof form.value === "object" ? form.value : {}; |
| | | const submitData = {}; |
| | | Object.keys(source).forEach(k => { |
| | | submitData[k] = source[k]; |
| | | }); |
| | | |
| | | if (isEdit.value) { |
| | | const { code } = await safeTrainingAdd(submitData); |
| | | if (code === 200) { |
| | | showToast("ä¿®æ¹æå"); |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 500); |
| | | } else { |
| | | loading.value = false; |
| | | showToast("ä¿®æ¹å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | } else { |
| | | const { code } = await safeTrainingAdd(submitData); |
| | | if (code === 200) { |
| | | showToast("æ°å¢æå"); |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 500); |
| | | } else { |
| | | loading.value = false; |
| | | showToast("æ°å¢å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | } |
| | | } catch (e) { |
| | | loading.value = false; |
| | | console.error("æäº¤å¤±è´¥:", e); |
| | | showToast("æäº¤å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }; |
| | | |
| | | onLoad(() => { |
| | | // ç¼è¾å¹è®æ¶ï¼ä»æ¬å°åå¨è·åæ°æ® |
| | | const safetyTraining = uni.getStorageSync("safetyTraining"); |
| | | if (safetyTraining.id) { |
| | | form.value = safetyTraining; |
| | | nowDate.value = dayjs(form.value.trainingDate).toDate(); |
| | | form.value.openingTime = form.value.openingTime |
| | | ? form.value.openingTime.slice(0, 5) |
| | | : ""; |
| | | form.value.endTime = form.value.endTime |
| | | ? form.value.endTime.slice(0, 5) |
| | | : ""; |
| | | isEdit.value = true; |
| | | } else { |
| | | isEdit.value = false; |
| | | // é»è®¤å¹è®æ¥æä¸ºä»å¤© |
| | | form.value.trainingDate = dayjs().format("YYYY-MM-DD"); |
| | | } |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | // åå§åå¹è®æ¹å¼é项 |
| | | if (safe_training_methods && Array.isArray(safe_training_methods.value)) { |
| | | trainingModeOptions.value = |
| | | safe_training_methods.value.map(item => ({ |
| | | value: item.value, |
| | | name: item.label, |
| | | })) || []; |
| | | } else { |
| | | trainingModeOptions.value = []; |
| | | } |
| | | |
| | | // 设置已éå¼çæ¾ç¤ºææ¬ |
| | | if (form.value.trainingMode) { |
| | | const modeItem = trainingModeOptions.value.find( |
| | | item => String(item.value) === String(form.value.trainingMode) |
| | | ); |
| | | trainingModeName.value = modeItem ? modeItem.name : ""; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/static/scss/form-common.scss"; |
| | | |
| | | .danger-investigation-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 100px; |
| | | } |
| | | |
| | | .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; |
| | | } |
| | | |
| | | .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; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="file-list-page"> |
| | | <!-- 页é¢å¤´é¨ --> |
| | | <PageHeader title="é件管ç" |
| | | @back="goBack" /> |
| | | <!-- éä»¶å表 --> |
| | | <view class="file-list-container"> |
| | | <view v-if="fileList.length > 0" |
| | | class="file-list"> |
| | | <view v-for="(file, index) in fileList" |
| | | :key="file.id || index" |
| | | class="file-item"> |
| | | <!-- æä»¶å¾æ --> |
| | | <!-- <view class="file-icon" |
| | | :class="getFileIconClass(file.fileType)"> |
| | | <up-icon :name="getFileIcon(file.fileType)" |
| | | size="24" |
| | | color="#ffffff" /> |
| | | </view> --> |
| | | <!-- æä»¶ä¿¡æ¯ --> |
| | | <view class="file-info"> |
| | | <text class="file-name">{{ file.name }}</text> |
| | | <!-- <text class="file-meta">{{ formatFileSize(file.fileSize) }} · {{ file.uploadTime || file.createTime }}</text> --> |
| | | </view> |
| | | <!-- æä½æé® --> |
| | | <view class="file-actions"> |
| | | <!-- <u-button size="small" |
| | | type="primary" |
| | | plain |
| | | @click="previewFile(file)">é¢è§</u-button> --> |
| | | <u-button size="small" |
| | | type="info" |
| | | plain |
| | | @click="downloadFile(file)">ä¸è½½å¹¶é¢è§</u-button> |
| | | <u-button size="small" |
| | | type="error" |
| | | plain |
| | | @click="confirmDelete(file, index)">å é¤</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- ç©ºç¶æ --> |
| | | <view v-else |
| | | class="empty-state"> |
| | | <up-icon name="document" |
| | | size="64" |
| | | color="#c0c4cc" /> |
| | | <text class="empty-text">ææ éä»¶</text> |
| | | </view> |
| | | </view> |
| | | <!-- <a rel="nofollow" |
| | | id="downloadLink" |
| | | href="#" |
| | | style="display:none;">ä¸è½½ææ¬æä»¶</a> --> |
| | | <!-- ä¸ä¼ æé® --> |
| | | <view class="upload-button" |
| | | @click="chooseFile"> |
| | | <up-icon name="plus" |
| | | size="24" |
| | | color="#ffffff" /> |
| | | <text class="upload-text">ä¸ä¼ éä»¶</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import config from "@/config"; |
| | | import { getToken } from "@/utils/auth"; |
| | | // import { saveAs } from "file-saver"; |
| | | import { |
| | | listRuleFiles, |
| | | delRuleFile, |
| | | } from "@/api/managementMeetings/rulesRegulationsManagement"; |
| | | import { |
| | | safeTrainingFileListPage, |
| | | safeTrainingFileAdd, |
| | | safeTrainingFileDel, |
| | | } from "@/api/safeProduction/safetyTrainingAssessment"; |
| | | import { blobValidate } from "@/utils/ruoyi"; |
| | | |
| | | // éä»¶å表 |
| | | const fileList = ref([]); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // const request = axios.create({ |
| | | // baseURL: "URL.com", |
| | | // adapter: axiosAdapterUniapp, |
| | | // }); |
| | | // è·åæä»¶å¾æ |
| | | const getFileIcon = fileType => { |
| | | const iconMap = { |
| | | doc: "document", |
| | | docx: "document", |
| | | xls: "grid", |
| | | xlsx: "grid", |
| | | pdf: "document", |
| | | ppt: "copy", |
| | | pptx: "copy", |
| | | txt: "document", |
| | | jpg: "image", |
| | | jpeg: "image", |
| | | png: "image", |
| | | gif: "image", |
| | | zip: "folder", |
| | | rar: "folder", |
| | | }; |
| | | return iconMap[fileType.toLowerCase()] || "document"; |
| | | }; |
| | | |
| | | // è·åæä»¶å¾æ æ ·å¼ç±» |
| | | const getFileIconClass = fileType => { |
| | | const colorMap = { |
| | | doc: "blue", |
| | | docx: "blue", |
| | | xls: "green", |
| | | xlsx: "green", |
| | | pdf: "red", |
| | | ppt: "orange", |
| | | pptx: "orange", |
| | | txt: "gray", |
| | | jpg: "purple", |
| | | jpeg: "purple", |
| | | png: "purple", |
| | | gif: "purple", |
| | | zip: "yellow", |
| | | rar: "yellow", |
| | | }; |
| | | return colorMap[fileType.toLowerCase()] || "gray"; |
| | | }; |
| | | |
| | | // æ ¼å¼åæä»¶å¤§å° |
| | | const formatFileSize = bytes => { |
| | | if (bytes === 0) return "0 B"; |
| | | const k = 1024; |
| | | const sizes = ["B", "KB", "MB", "GB"]; |
| | | const i = Math.floor(Math.log(bytes) / Math.log(k)); |
| | | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; |
| | | }; |
| | | |
| | | // éæ©æä»¶ |
| | | const chooseFile = () => { |
| | | uni.chooseImage({ |
| | | count: 9, |
| | | sizeType: ["original", "compressed"], |
| | | sourceType: ["album", "camera"], |
| | | success: res => { |
| | | console.log(res, "éæ©å¾çæå"); |
| | | uploadFiles(res.tempFiles); |
| | | }, |
| | | fail: err => { |
| | | console.error("éæ©å¾ç失败:", err); |
| | | showToast("éæ©æä»¶å¤±è´¥"); |
| | | }, |
| | | }); |
| | | // uni.chooseFile({ |
| | | // count: 9, |
| | | // extension: [ |
| | | // ".doc", |
| | | // ".docx", |
| | | // ".xls", |
| | | // ".xlsx", |
| | | // ".pdf", |
| | | // ".ppt", |
| | | // ".pptx", |
| | | // ".txt", |
| | | // ".jpg", |
| | | // ".jpeg", |
| | | // ".png", |
| | | // ".gif", |
| | | // ".zip", |
| | | // ".rar", |
| | | // ], |
| | | // success: res => { |
| | | // console.log(res, "éæ©æä»¶æå"); |
| | | // uploadFiles(res.tempFiles); |
| | | // }, |
| | | // fail: err => { |
| | | // showToast("éæ©æä»¶å¤±è´¥"); |
| | | // }, |
| | | // }); |
| | | }; |
| | | |
| | | // ä¸ä¼ æä»¶ |
| | | const uploadFiles = tempFiles => { |
| | | console.log(tempFiles, "ä¸ä¼ æä»¶1"); |
| | | tempFiles.forEach((tempFile, index) => { |
| | | // æ¾ç¤ºä¸ä¼ ä¸æç¤º |
| | | uni.showLoading({ |
| | | title: "ä¸ä¼ ä¸...", |
| | | mask: true, |
| | | }); |
| | | console.log(tempFile, "ä¸ä¼ æä»¶2"); |
| | | // 1. ç´æ¥ä½¿ç¨ uni.uploadFile ä¸ä¼ æä»¶ |
| | | uni.uploadFile({ |
| | | url: config.baseUrl + "/file/upload", |
| | | filePath: tempFile.path, |
| | | name: "file", |
| | | header: { |
| | | Authorization: "Bearer " + getToken(), |
| | | }, |
| | | success: uploadRes => { |
| | | uni.hideLoading(); |
| | | console.log(uploadRes, "ä¸ä¼ æä»¶3"); |
| | | |
| | | try { |
| | | const res = JSON.parse(uploadRes.data); |
| | | console.log(res, "ä¸ä¼ æä»¶4"); |
| | | if (res.code === 200) { |
| | | // 2. æåæä»¶ä¿¡æ¯ |
| | | const fileName = tempFile.name |
| | | ? tempFile.name |
| | | : tempFile.path.split("/").pop(); |
| | | // const fileType = fileName.split(".").pop(); |
| | | // 3. æé ä¿åæä»¶ä¿¡æ¯çåæ° |
| | | const saveData = { |
| | | name: fileName, |
| | | safeTrainingId: rulesRegulationsManagementId.value, |
| | | url: res.data.tempPath || "", |
| | | }; |
| | | console.log(saveData, "ä¿åæä»¶ä¿¡æ¯åæ°"); |
| | | // 4. è°ç¨ addRuleFile æ¥å£ä¿åæä»¶ä¿¡æ¯ |
| | | safeTrainingFileAdd(saveData) |
| | | .then(addRes => { |
| | | if (addRes.code === 200) { |
| | | // 5. æ·»å å°æä»¶å表 |
| | | const newFile = { |
| | | ...addRes.data, |
| | | uploadTime: new Date().toLocaleString(), |
| | | }; |
| | | // fileList.value.push(newFile); |
| | | getFileList(); |
| | | showToast("ä¸ä¼ æå"); |
| | | } else { |
| | | showToast("ä¿åæä»¶ä¿¡æ¯å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | console.error("ä¿åæä»¶ä¿¡æ¯å¤±è´¥:", err); |
| | | showToast("ä¿åæä»¶ä¿¡æ¯å¤±è´¥"); |
| | | }); |
| | | } else { |
| | | showToast("æä»¶ä¸ä¼ 失败"); |
| | | } |
| | | } catch (e) { |
| | | console.error("è§£æä¸ä¼ ç»æå¤±è´¥:", e); |
| | | showToast("ä¸ä¼ 失败"); |
| | | } |
| | | }, |
| | | fail: err => { |
| | | uni.hideLoading(); |
| | | console.error("ä¸ä¼ 失败:", err); |
| | | showToast("ä¸ä¼ 失败"); |
| | | }, |
| | | }); |
| | | }); |
| | | }; |
| | | // ä¸è½½æä»¶ |
| | | const downloadFile = file => { |
| | | var url = |
| | | config.baseUrl + |
| | | "/common/download?fileName=" + |
| | | encodeURIComponent(file.url) + |
| | | "&delete=true"; |
| | | console.log(url, "url"); |
| | | |
| | | uni |
| | | .downloadFile({ |
| | | url: url, |
| | | responseType: "blob", |
| | | header: { Authorization: "Bearer " + getToken() }, |
| | | }) |
| | | .then(res => { |
| | | console.log(res, "ä¸è½½æä»¶"); |
| | | let osType = uni.getStorageSync("deviceInfo").osName; |
| | | let filePath = res.tempFilePath; |
| | | if (osType === "ios") { |
| | | uni.openDocument({ |
| | | filePath: filePath, |
| | | showMenu: true, |
| | | success: res => { |
| | | resolve(res); |
| | | }, |
| | | fail: err => { |
| | | console.log("uni.openDocument--fail"); |
| | | reject(err); |
| | | }, |
| | | }); |
| | | } else { |
| | | uni.saveFile({ |
| | | tempFilePath: filePath, |
| | | success: fileRes => { |
| | | uni.showToast({ |
| | | icon: "none", |
| | | mask: true, |
| | | title: |
| | | "æä»¶å·²ä¿åï¼Android/data/uni.UNI720216F/apps/__UNI__720216F/" + |
| | | fileRes.savedFilePath, //ä¿åè·¯å¾ |
| | | duration: 3000, |
| | | }); |
| | | setTimeout(() => { |
| | | //æå¼ææ¡£æ¥ç |
| | | uni.openDocument({ |
| | | filePath: fileRes.savedFilePath, |
| | | success: function (res) { |
| | | resolve(fileRes); |
| | | }, |
| | | }); |
| | | }, 3000); |
| | | }, |
| | | fail: err => { |
| | | console.log("uni.save--fail"); |
| | | reject(err); |
| | | }, |
| | | }); |
| | | } |
| | | // const isBlob = blobValidate(res.data); |
| | | // if (isBlob) { |
| | | // const blob = new Blob([res.data], { type: "text/plain" }); |
| | | // const url = URL.createObjectURL(blob); |
| | | // const downloadLink = document.getElementById("downloadLink"); |
| | | // downloadLink.href = url; |
| | | // downloadLink.download = file.name; |
| | | // downloadLink.click(); |
| | | // showToast("ä¸è½½æå"); |
| | | // } else { |
| | | // showToast("ä¸è½½å¤±è´¥"); |
| | | // } |
| | | }) |
| | | .catch(err => { |
| | | console.error("ä¸è½½å¤±è´¥:", err); |
| | | showToast("ä¸è½½å¤±è´¥"); |
| | | }); |
| | | }; |
| | | |
| | | // 确认å é¤ |
| | | const confirmDelete = (file, index) => { |
| | | uni.showModal({ |
| | | title: "å é¤ç¡®è®¤", |
| | | content: `ç¡®å®è¦å é¤éä»¶ "${file.name}" åï¼`, |
| | | success: res => { |
| | | if (res.confirm) { |
| | | deleteFile(file.id, index); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // å 餿件 |
| | | const deleteFile = (fileId, index) => { |
| | | uni.showLoading({ |
| | | title: "å é¤ä¸...", |
| | | mask: true, |
| | | }); |
| | | |
| | | safeTrainingFileDel([fileId]) |
| | | .then(res => { |
| | | uni.hideLoading(); |
| | | if (res.code === 200) { |
| | | // fileList.value.splice(index, 1); |
| | | getFileList(); |
| | | showToast("å 餿å"); |
| | | } else { |
| | | showToast("å é¤å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | uni.hideLoading(); |
| | | showToast("å é¤å¤±è´¥"); |
| | | }); |
| | | }; |
| | | |
| | | // æ¾ç¤ºæç¤º |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | const rulesRegulationsManagementId = ref(""); |
| | | // 页é¢å è½½æ¶ |
| | | onMounted(() => { |
| | | rulesRegulationsManagementId.value = uni.getStorageSync( |
| | | "safetyTrainingFileId" |
| | | ); |
| | | // ä» API è·åéä»¶å表 |
| | | getFileList(); |
| | | // 仿¬å°åå¨è·å rulesRegulationsManagementId |
| | | }); |
| | | |
| | | // è·åéä»¶å表 |
| | | const getFileList = () => { |
| | | uni.showLoading({ |
| | | title: "å è½½ä¸...", |
| | | mask: true, |
| | | }); |
| | | |
| | | safeTrainingFileListPage({ |
| | | safeTrainingId: rulesRegulationsManagementId.value, |
| | | current: -1, |
| | | size: -1, |
| | | }) |
| | | .then(res => { |
| | | uni.hideLoading(); |
| | | if (res.code === 200) { |
| | | fileList.value = res.data.records || []; |
| | | } else { |
| | | showToast("è·åéä»¶å表失败"); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | uni.hideLoading(); |
| | | showToast("è·åéä»¶å表失败"); |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .file-list-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 100rpx; |
| | | } |
| | | |
| | | .file-list-container { |
| | | padding: 20rpx; |
| | | } |
| | | |
| | | .file-list { |
| | | background: #ffffff; |
| | | border-radius: 8rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .file-item { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | } |
| | | |
| | | .file-icon { |
| | | width: 56rpx; |
| | | height: 56rpx; |
| | | border-radius: 8rpx; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | margin-right: 20rpx; |
| | | |
| | | &.blue { |
| | | background: #409eff; |
| | | } |
| | | |
| | | &.green { |
| | | background: #67c23a; |
| | | } |
| | | |
| | | &.red { |
| | | background: #f56c6c; |
| | | } |
| | | |
| | | &.orange { |
| | | background: #e6a23c; |
| | | } |
| | | |
| | | &.gray { |
| | | background: #909399; |
| | | } |
| | | |
| | | &.purple { |
| | | background: #909399; |
| | | } |
| | | |
| | | &.yellow { |
| | | background: #e6a23c; |
| | | } |
| | | } |
| | | |
| | | .file-info { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .file-name { |
| | | display: block; |
| | | font-size: 16px; |
| | | color: #303133; |
| | | margin-bottom: 8rpx; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .file-meta { |
| | | display: block; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .file-actions { |
| | | display: flex; |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .empty-state { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 100rpx 0; |
| | | background: #ffffff; |
| | | border-radius: 8rpx; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .empty-text { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | .upload-button { |
| | | position: fixed; |
| | | bottom: 40rpx; |
| | | right: 40rpx; |
| | | width: 130rpx; |
| | | height: 130rpx; |
| | | border-radius: 50%; |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .upload-text { |
| | | font-size: 10px; |
| | | color: #ffffff; |
| | | margin-top: 4rpx; |
| | | } |
| | | |
| | | .upload-progress { |
| | | padding: 40rpx 0; |
| | | } |
| | | |
| | | .upload-progress-text { |
| | | display: block; |
| | | text-align: center; |
| | | margin-top: 20rpx; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="sales-accoun"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="å®å
¨å¹è®èæ ¸" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view @click="selectDate" |
| | | class="search-input"> |
| | | <view class="search-text">{{ searchKeyword? searchKeyword : 'è¯·éæ©å¹è®æ¥æ' }}</view> |
| | | </view> |
| | | <view class="filter-button" |
| | | @click="clearDate"> |
| | | <u-icon name="close-circle" |
| | | size="24" |
| | | color="#999"></u-icon> |
| | | </view> |
| | | </view> |
| | | <!-- å¹è®è®°å½æé® --> |
| | | <view class="record-button"> |
| | | <u-button type="info" |
| | | @click="viewTrainingRecord">å¹è®è®°å½</u-button> |
| | | </view> |
| | | </view> |
| | | <!-- æ ç¾é¡µ --> |
| | | <view class="tabs-section"> |
| | | <up-tabs v-model="searchForm.state" |
| | | :list="tabList" |
| | | itemStyle="width: 33%;height: 80rpx;" |
| | | @change="tabhandleQuery"> |
| | | </up-tabs> |
| | | </view> |
| | | <!-- å¹è®è®°å½å表 --> |
| | | <view class="ledger-list" |
| | | v-if="trainingList.length > 0"> |
| | | <view v-for="(item, index) in trainingList" |
| | | :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.courseCode }}</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.courseCode || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®æ¥æ</text> |
| | | <text class="detail-value">{{ item.trainingDate || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¼å§æ¶é´</text> |
| | | <text class="detail-value">{{ item.openingTime || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»ææ¶é´</text> |
| | | <text class="detail-value">{{ item.endTime || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®ç®æ </text> |
| | | <text class="detail-value">{{ item.trainingObjectives || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åå 对象</text> |
| | | <text class="detail-value">{{ item.participants || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®å
容</text> |
| | | <text class="detail-value">{{ item.trainingContent || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®è®²å¸</text> |
| | | <text class="detail-value">{{ item.trainingLecturer || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项ç®å¦å</text> |
| | | <text class="detail-value">{{ item.projectCredits || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®æ¹å¼</text> |
| | | <text class="detail-value">{{ getTrainingModeLabel(item.trainingMode) || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¹è®å°ç¹</text> |
| | | <text class="detail-value">{{ item.placeTraining || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">课æ¶</text> |
| | | <text class="detail-value">{{ item.classHour || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- æé®åºå --> |
| | | <view class="action-buttons"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.state !== 0" |
| | | @click="editVisit(item)"> |
| | | ç¼è¾ |
| | | </u-button> |
| | | <u-button type="info" |
| | | size="small" |
| | | class="action-btn" |
| | | @click="viewFileList(item)"> |
| | | éä»¶ |
| | | </u-button> |
| | | <u-button type="error" |
| | | size="small" |
| | | class="action-btn" |
| | | @click="deleteVisit(item)"> |
| | | å é¤ |
| | | </u-button> |
| | | </view> |
| | | <view class="action-buttons"> |
| | | <u-button type="warning" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.state !== 1" |
| | | @click="signIn(item)"> |
| | | ç¾å° |
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn" |
| | | :disabled="item.state === 0" |
| | | @click="viewResultDetail(item)"> |
| | | ç»ææç» |
| | | </u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ å¹è®è®°å½</text> |
| | | </view> |
| | | <up-datetime-picker :show="trainingDateVisible" |
| | | mode="date" |
| | | @confirm="handleDateConfirm" |
| | | @cancel="handleDateCancel" |
| | | title="éæ©å¹è®æ¥æ" /> |
| | | <!-- æµ®å¨æ°å¢æé® --> |
| | | <view class="fab-button" |
| | | @click="addVisit"> |
| | | <up-icon name="plus" |
| | | size="24" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, reactive } from "vue"; |
| | | |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | safeTrainingListPage, |
| | | safeTrainingDel, |
| | | safeTrainingSign, |
| | | safeTrainingGet, |
| | | } from "@/api/safeProduction/safetyTrainingAssessment"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { useDict } from "@/utils/dict"; |
| | | import dayjs from "dayjs"; |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "safety-training-index" }); |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { safe_training_methods } = useDict("safe_training_methods"); |
| | | |
| | | // æç´¢å
³é®è¯ |
| | | const searchKeyword = ref(""); |
| | | // æ¥æéæ©å¨ç¶æ |
| | | const trainingDateVisible = ref(false); |
| | | |
| | | const tabList = reactive([ |
| | | { name: "æªå¼å§", value: 0 }, |
| | | { name: "è¿è¡ä¸", value: 1 }, |
| | | { name: "å·²ç»æ", value: 2 }, |
| | | ]); |
| | | // æç´¢è¡¨å |
| | | const searchForm = ref({ |
| | | state: 0, // é»è®¤æ¾ç¤ºå·²ç»æ |
| | | trainingDate: "", |
| | | }); |
| | | const tabhandleQuery = val => { |
| | | searchForm.value.state = val.value; |
| | | getList(); |
| | | }; |
| | | const getTrainingModeLabel = mode => { |
| | | if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) { |
| | | return mode || "-"; |
| | | } |
| | | const dictItem = safe_training_methods.value.find( |
| | | item => String(item.value) === String(mode) |
| | | ); |
| | | return dictItem ? dictItem.label : mode || "-"; |
| | | }; |
| | | |
| | | // å¹è®è®°å½æ°æ® |
| | | const trainingList = ref([]); |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | const viewFileList = item => { |
| | | uni.setStorageSync("safetyTrainingFileId", item.id); |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/fileList", |
| | | }); |
| | | }; |
| | | const currentUserId = ref(""); |
| | | // ç¾å°åè½ |
| | | const signIn = item => { |
| | | uni.showModal({ |
| | | title: "æç¤º", |
| | | content: "确认ç¾å°åï¼", |
| | | success: function (res) { |
| | | if (res.confirm) { |
| | | safeTrainingSign({ |
| | | safeTrainingId: item.id, |
| | | userId: currentUserId.value, |
| | | }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | uni.showToast({ title: "ç¾å°æå", icon: "success" }); |
| | | setTimeout(() => {}, 1000); |
| | | } else { |
| | | uni.showToast({ title: res.msg || "ç¾å°å¤±è´¥", icon: "none" }); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ title: "ç¾å°å¤±è´¥ï¼è¯·éè¯", icon: "none" }); |
| | | }); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // æ¥çç»ææç» |
| | | const viewResultDetail = item => { |
| | | uni.setStorageSync("safetyTrainingResultId", item.id); |
| | | uni.setStorageSync("safetyTrainingResultNums", item.nums); |
| | | |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/resultDetail", |
| | | }); |
| | | }; |
| | | |
| | | // æ¥çå¹è®è®°å½ |
| | | const viewTrainingRecord = () => { |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/record", |
| | | }); |
| | | }; |
| | | // æ¸
餿¥æéæ© |
| | | const clearDate = () => { |
| | | searchKeyword.value = ""; |
| | | searchForm.value.trainingDate = ""; |
| | | getList(); |
| | | }; |
| | | // æ¾ç¤ºæ¥æéæ©å¨ |
| | | const selectDate = () => { |
| | | trainingDateVisible.value = true; |
| | | }; |
| | | |
| | | // å¤çæ¥æéæ©ç¡®è®¤ |
| | | const handleDateConfirm = e => { |
| | | searchKeyword.value = dayjs(e.value).format("YYYY-MM-DD"); |
| | | searchForm.value.trainingDate = dayjs(e.value).format("YYYY-MM-DD"); |
| | | trainingDateVisible.value = false; |
| | | getList(); |
| | | }; |
| | | |
| | | // å¤çæ¥æéæ©åæ¶ |
| | | const handleDateCancel = () => { |
| | | trainingDateVisible.value = false; |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const params = { |
| | | current: -1, |
| | | size: -1, |
| | | trainingDate: searchForm.value.trainingDate, |
| | | state: searchForm.value.state, |
| | | }; |
| | | safeTrainingListPage(params) |
| | | .then(res => { |
| | | trainingList.value = res.records || res.data?.records || []; |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | showToast("è·åæ°æ®å¤±è´¥"); |
| | | }); |
| | | }; |
| | | |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ°å¢å¹è® |
| | | const addVisit = () => { |
| | | uni.setStorageSync("safetyTraining", {}); |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/detail", |
| | | }); |
| | | }; |
| | | // ç¼è¾å¹è® |
| | | const editVisit = item => { |
| | | uni.setStorageSync("safetyTraining", item); |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/detail", |
| | | }); |
| | | }; |
| | | // å é¤å¹è® |
| | | const deleteVisit = item => { |
| | | uni.showModal({ |
| | | title: "å é¤ç¡®è®¤", |
| | | content: `ç¡®å®è¦å é¤è¯¥å¹è®è®°å½åï¼`, |
| | | success: res => { |
| | | if (res.confirm) { |
| | | deleteClientVisit(item.id); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | // å é¤å¹è®è®°å½ |
| | | const deleteClientVisit = id => { |
| | | showLoadingToast("å é¤ä¸..."); |
| | | safeTrainingDel([id]) |
| | | .then(() => { |
| | | closeToast(); |
| | | showToast("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | showToast("å é¤å¤±è´¥"); |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.setStorageSync("safetyTraining", item); |
| | | uni.navigateTo({ |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/view", |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | userStore.getInfo().then(res => { |
| | | currentUserId.value = res.user.userId; |
| | | }); |
| | | // currentUserId |
| | | 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; |
| | | } |
| | | |
| | | // å¹è®è®°å½æé® |
| | | .record-button { |
| | | margin-top: 10px; |
| | | text-align: center; |
| | | } |
| | | |
| | | // ç¹å®ç徿 æ ·å¼ |
| | | .document-icon { |
| | | background: #667eea; // ä¿æé¡µé¢ç¹æçèæ¯è² |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .visit-status { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .detail-value { |
| | | word-break: break-all; // ä¿ç页é¢ç¹æçææ¬æ¢è¡æ ·å¼ |
| | | } |
| | | |
| | | // ç¹å®çæµ®å¨æé®æ ·å¼ |
| | | .fab-button { |
| | | background: #667eea; // ä¿æé¡µé¢ç¹æçèæ¯è² |
| | | box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // ä¿æé¡µé¢ç¹æçé´å½±ææ |
| | | } |
| | | .action-buttons { |
| | | gap: 4px; |
| | | } |
| | | .action-buttons { |
| | | padding: 0 0 10rpx 0; |
| | | } |
| | | |
| | | .tabs-section { |
| | | background: #fff; |
| | | margin-bottom: 1rem; |
| | | box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.05); |
| | | } |
| | | .search-text { |
| | | // font-size: 24rpx; |
| | | color: #a6a6a6; |
| | | height: 70rpx; |
| | | line-height: 70rpx; |
| | | margin-left: 20rpx; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="training-record"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <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.searchText" |
| | | @change="searchName" |
| | | clearable /> |
| | | </view> |
| | | <view class="filter-button" |
| | | @click="searchName"> |
| | | <u-icon name="search" |
| | | size="24" |
| | | color="#999"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 人åå¡çå表 --> |
| | | <view class="user-card-list" |
| | | v-if="userList.length > 0"> |
| | | <view v-for="(user, index) in userList" |
| | | :key="index" |
| | | class="user-card"> |
| | | <!-- å¡çå¤´é¨ --> |
| | | <view class="card-header" |
| | | @click="toggleUserCard(index)"> |
| | | <view class="header-left"> |
| | | <text class="user-name">{{ user.nickName }}</text> |
| | | <text class="user-dept">æå±ï¼{{ user.deptNames || '-' }}</text> |
| | | <text class="user-dept">èç³»æ¹å¼ï¼{{ user.phonenumber || '-' }}</text> |
| | | <!-- å¹è®ç»è®¡ä¿¡æ¯ --> |
| | | </view> |
| | | <u-icon :name="expandedUsers[index] ? 'arrow-up' : 'arrow-down'" |
| | | size="20" |
| | | color="#999"></u-icon> |
| | | </view> |
| | | <!-- å¡çå
å®¹ï¼æå é¨åï¼ --> |
| | | <view class="card-content" |
| | | v-if="expandedUsers[index]"> |
| | | <!-- 年份çé --> |
| | | <view class="year-filter-section"> |
| | | <!-- <text class="filter-label">年份çé</text> --> |
| | | <view class="year-options"> |
| | | <u-tag v-for="year in yearOptions" |
| | | :key="year" |
| | | :text="year" |
| | | :type="userYearFilters[user.userId] === year.toString() ? 'primary' : 'info'" |
| | | @click="() => { |
| | | userYearFilters[user.userId] = year.toString(); |
| | | filterUserCourses(user.userId); |
| | | }" |
| | | :class="{ active: userYearFilters[user.userId] === year.toString() }" |
| | | style="margin-right: 8px; margin-bottom: 8px;"></u-tag> |
| | | </view> |
| | | </view> |
| | | <!-- å¹è®è¯¾ç¨å表 --> |
| | | <view class="course-list" |
| | | v-if="userCourses[user.userId] && userCourses[user.userId].length > 0"> |
| | | <view class="user-stats" |
| | | v-if="userStats[user.userId]"> |
| | | <text class="stat-item">å¹è®æ¬¡æ°: {{ userStats[user.userId].total }}</text> |
| | | <text class="stat-item success">åæ ¼: {{ userStats[user.userId].qualified }}</text> |
| | | <text class="stat-item danger">ä¸åæ ¼: {{ userStats[user.userId].unqualified }}</text> |
| | | </view> |
| | | <view v-for="(course, courseIndex) in userCourses[user.userId]" |
| | | :key="courseIndex"> |
| | | <view class="course-item" |
| | | v-if="userYearFilters[user.userId] === 'å
¨é¨' || course.trainingDate.includes(userYearFilters[user.userId])"> |
| | | <view class="course-header"> |
| | | <text class="course-date">{{ course.trainingDate || '-' }}</text> |
| | | <u-tag :type="course.examinationResults === 'åæ ¼' ? 'success' : 'error'"> |
| | | {{ course.examinationResults || '-' }} |
| | | </u-tag> |
| | | </view> |
| | | <view class="course-info"> |
| | | <text class="info-label">å¹è®å
容ï¼</text> |
| | | <text class="info-value">{{ course.trainingContent || '-' }}</text> |
| | | </view> |
| | | <view class="course-info"> |
| | | <text class="info-label">å¹è®è¯¾æ¶ï¼</text> |
| | | <text class="info-value">{{ course.classHour || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- çéåæ æ°æ® --> |
| | | <view v-if="userYearFilters[user.userId] === 'å
¨é¨' ? userCourses[user.userId].length === 0 : userCourses[user.userId].filter(c => c.trainingDate.includes(userYearFilters[user.userId])).length === 0" |
| | | class="empty-course"> |
| | | <text class="empty-text">{{ userYearFilters[user.userId] === 'å
¨é¨' ? 'ææ å¹è®è®°å½' : 'è¯¥å¹´ä»½ææ å¹è®è®°å½' }}</text> |
| | | </view> |
| | | </view> |
| | | <!-- ç©ºç¶æ --> |
| | | <view v-else |
| | | class="empty-course"> |
| | | <text class="empty-text">ææ å¹è®è®°å½</text> |
| | | </view> |
| | | </view> |
| | | <!-- å¯¼åºæé® --> |
| | | <!-- <view class="course-export"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | @click="exportUserRecord(user.userId)">导åºè®°å½</u-button> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="empty-state"> |
| | | <up-icon name="people" |
| | | size="64" |
| | | color="#c0c4cc"></up-icon> |
| | | <text class="empty-text">ææ äººåæ°æ®</text> |
| | | </view> |
| | | <!-- ç©ºç¶æ --> |
| | | <!-- å¹´ä»½éæ©å¨ --> |
| | | <up-datetime-picker :show="yearPickerVisible" |
| | | mode="year" |
| | | @confirm="handleYearConfirm" |
| | | @cancel="yearPickerVisible = false" |
| | | title="鿩年份" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, reactive } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { safeTrainingDetailListPage } from "@/api/safeProduction/safetyTrainingAssessment"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import config from "@/config"; |
| | | |
| | | // 页é¢ç¶æ |
| | | const userList = ref([]); |
| | | const userCourses = ref({}); // å卿¯ä¸ªç¨æ·çå¹è®è¯¾ç¨ |
| | | const userStats = ref({}); // å卿¯ä¸ªç¨æ·çå¹è®ç»è®¡ä¿¡æ¯ |
| | | const expandedUsers = ref([]); // æ§å¶ç¨æ·å¡çå±å¼ç¶æ |
| | | const loading = ref(false); |
| | | const courseLoading = ref({}); // æ§å¶æ¯ä¸ªç¨æ·ç课ç¨å è½½ç¶æ |
| | | const userYearFilters = ref({}); // å卿¯ä¸ªç¨æ·ç年份ç鿡件 |
| | | const yearOptions = ref([]); // 年份é项ï¼ä»å¹´åè¿å»ä¸å¹´ï¼ |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = reactive({ |
| | | searchText: "", |
| | | invoiceDate: "", |
| | | }); |
| | | |
| | | // 年份鿩å¨ç¶æ |
| | | const yearPickerVisible = ref(false); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // çæå¹´ä»½é项 |
| | | const generateYearOptions = () => { |
| | | const currentYear = new Date().getFullYear(); |
| | | const options = []; |
| | | // æ·»å "å
¨é¨"é项 |
| | | options.push("å
¨é¨"); |
| | | for (let i = 0; i < 4; i++) { |
| | | options.push(currentYear - i); |
| | | } |
| | | yearOptions.value = options; |
| | | }; |
| | | |
| | | // æç´¢äººååç§° |
| | | const searchName = () => { |
| | | getUserList(); |
| | | }; |
| | | |
| | | // æ¾ç¤ºå¹´ä»½éæ©å¨ |
| | | const showYearPicker = () => { |
| | | yearPickerVisible.value = true; |
| | | }; |
| | | |
| | | // å¤çå¹´ä»½éæ©ç¡®è®¤ |
| | | const handleYearConfirm = e => { |
| | | searchForm.invoiceDate = e.value; |
| | | yearPickerVisible.value = false; |
| | | }; |
| | | |
| | | // æå¹´ä»½æç´¢ |
| | | const searchDate = () => { |
| | | // éåææå±å¼çç¨æ·å¡çï¼éæ°å è½½å¹è®è®°å½ |
| | | userList.value.forEach((user, index) => { |
| | | if (expandedUsers.value[index]) { |
| | | getUserCourses(user.userId, index); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // è·å人åå表 |
| | | const getUserList = () => { |
| | | loading.value = true; |
| | | userListNoPage() |
| | | .then(res => { |
| | | loading.value = false; |
| | | if (res.data && res.data.length > 0) { |
| | | let users = res.data; |
| | | // 妿ææç´¢å
³é®è¯ï¼è¿è¡çé |
| | | if (searchForm.searchText) { |
| | | users = users.filter(user => |
| | | user.nickName.includes(searchForm.searchText) |
| | | ); |
| | | } |
| | | userList.value = users; |
| | | // åå§åææå¡ç为æ¶èµ·ç¶æ |
| | | expandedUsers.value = new Array(userList.value.length).fill(false); |
| | | } else { |
| | | userList.value = []; |
| | | expandedUsers.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | loading.value = false; |
| | | uni.showToast({ title: "è·å人åå表失败", icon: "none" }); |
| | | }); |
| | | }; |
| | | |
| | | // åæ¢ç¨æ·å¡çå±å¼ç¶æ |
| | | const toggleUserCard = index => { |
| | | const user = userList.value[index]; |
| | | expandedUsers.value[index] = !expandedUsers.value[index]; |
| | | |
| | | // 妿å±å¼å¡çï¼å è½½å¹è®è®°å½ |
| | | if (expandedUsers.value[index]) { |
| | | // åå§å年份çéæ¡ä»¶ä¸º"å
¨é¨" |
| | | userYearFilters.value[user.userId] = "å
¨é¨"; |
| | | getUserCourses(user.userId, index); |
| | | } |
| | | }; |
| | | |
| | | // çéç¨æ·å¹è®è¯¾ç¨ |
| | | const filterUserCourses = userId => { |
| | | if (!userYearFilters.value[userId]) return; |
| | | console.log("userYearFilters", userYearFilters.value); |
| | | const year = userYearFilters.value[userId]; |
| | | const allCourses = userCourses.value[userId] || []; |
| | | |
| | | // çéæå®å¹´ä»½çå¹è®è®°å½ |
| | | let filteredCourses = allCourses; |
| | | if (year !== "å
¨é¨") { |
| | | filteredCourses = allCourses.filter( |
| | | course => course.trainingDate && course.trainingDate.includes(year) |
| | | ); |
| | | } |
| | | console.log("filteredCourses", filteredCourses); |
| | | |
| | | // æ´æ°ç»è®¡ä¿¡æ¯ |
| | | const total = filteredCourses.length; |
| | | const qualified = filteredCourses.filter( |
| | | course => course.examinationResults === "åæ ¼" |
| | | ).length; |
| | | const unqualified = filteredCourses.filter( |
| | | course => course.examinationResults === "ä¸åæ ¼" |
| | | ).length; |
| | | userStats.value[userId] = { |
| | | total, |
| | | qualified, |
| | | unqualified, |
| | | }; |
| | | }; |
| | | |
| | | // è·åç¨æ·å¹è®è¯¾ç¨ |
| | | const getUserCourses = (userId, index) => { |
| | | courseLoading.value[userId] = true; |
| | | |
| | | const params = { |
| | | userId, |
| | | // 妿æå¹´ä»½çéï¼æ·»å 年份忰 |
| | | // è¿ééè¦æ ¹æ®å端æ¥å£çå®é
åæ°åè¿è¡è°æ´ |
| | | }; |
| | | |
| | | safeTrainingDetailListPage(params) |
| | | .then(res => { |
| | | courseLoading.value[userId] = false; |
| | | if (res.data && res.data.records) { |
| | | let courses = res.data.records; |
| | | // 妿æå¹´ä»½çéï¼è¿è¡çé |
| | | if (searchForm.invoiceDate) { |
| | | const year = searchForm.invoiceDate.substring(0, 4); |
| | | courses = courses.filter( |
| | | course => course.trainingDate && course.trainingDate.includes(year) |
| | | ); |
| | | } |
| | | userCourses.value[userId] = courses; |
| | | |
| | | // 计ç®å¹è®ç»è®¡ä¿¡æ¯ |
| | | const total = courses.length; |
| | | const qualified = courses.filter( |
| | | course => course.examinationResults === "åæ ¼" |
| | | ).length; |
| | | const unqualified = courses.filter( |
| | | course => course.examinationResults === "ä¸åæ ¼" |
| | | ).length; |
| | | |
| | | userStats.value[userId] = { |
| | | total, |
| | | qualified, |
| | | unqualified, |
| | | }; |
| | | } else { |
| | | userCourses.value[userId] = []; |
| | | userStats.value[userId] = { |
| | | total: 0, |
| | | qualified: 0, |
| | | unqualified: 0, |
| | | }; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | courseLoading.value[userId] = false; |
| | | uni.showToast({ title: "è·åå¹è®è®°å½å¤±è´¥", icon: "none" }); |
| | | }); |
| | | }; |
| | | |
| | | // 页é¢å è½½ |
| | | onMounted(() => { |
| | | // çæå¹´ä»½é项 |
| | | generateYearOptions(); |
| | | getUserList(); |
| | | }); |
| | | |
| | | // 页颿¾ç¤ºæ¶å·æ° |
| | | onShow(() => { |
| | | // å¯ä»¥å¨è¿éæ·»å å·æ°é»è¾ |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | .training-record { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 20px; |
| | | } |
| | | |
| | | // å¹´ä»½éæ©å¨ |
| | | .year-picker { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 10px 15px; |
| | | background: #f8f9fa; |
| | | border-radius: 4px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .picker-text { |
| | | font-size: 14px; |
| | | color: #333; |
| | | } |
| | | |
| | | // 人åå¡çå表 |
| | | .user-card-list { |
| | | padding: 10px; |
| | | } |
| | | |
| | | // 人åå¡ç |
| | | .user-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | margin-bottom: 12px; |
| | | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); |
| | | overflow: hidden; |
| | | border: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | // å¡çå¤´é¨ |
| | | .card-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 16px; |
| | | background: #f5f7fa; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .header-left { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .user-name { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .user-dept { |
| | | font-size: 14px; |
| | | color: #666; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | // å¹è®ç»è®¡ä¿¡æ¯ |
| | | .user-stats { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .stat-item { |
| | | font-size: 12px; |
| | | color: #555; |
| | | padding: 5px 10px; |
| | | background: #f0f2f5; |
| | | border-radius: 4px; |
| | | border: 1px solid #e0e0e0; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .stat-item.success { |
| | | background: #e6f7ff; |
| | | color: #1890ff; |
| | | border-color: #91d5ff; |
| | | } |
| | | |
| | | .stat-item.danger { |
| | | background: #fff1f0; |
| | | color: #ff4d4f; |
| | | border-color: #ffccc7; |
| | | } |
| | | |
| | | // 年份çéåºå |
| | | .year-filter-section { |
| | | margin-bottom: 16px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | .filter-label { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-bottom: 8px; |
| | | display: block; |
| | | } |
| | | |
| | | .year-options { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | // å¡çå
容 |
| | | .card-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | // å¹è®è¯¾ç¨å表 |
| | | .course-list { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | // 课ç¨é¡¹ |
| | | .course-item { |
| | | background: #fafafa; |
| | | border-radius: 6px; |
| | | padding: 14px; |
| | | margin-bottom: 12px; |
| | | border: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | // 课ç¨å¤´é¨ |
| | | .course-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 12px; |
| | | padding-bottom: 8px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .course-date { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | // 课ç¨ä¿¡æ¯ |
| | | .course-info { |
| | | display: flex; |
| | | margin-bottom: 8px; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | // 课ç¨å¯¼åºæé® |
| | | .course-export { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | // ç©ºç¶æ |
| | | .empty-state { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 60px 0; |
| | | } |
| | | |
| | | .empty-course { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 30px 0; |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .empty-text { |
| | | font-size: 14px; |
| | | color: #999; |
| | | margin-top: 16px; |
| | | } |
| | | :deep(.u-tag--info) { |
| | | background-color: #c1c3c8; |
| | | border-width: 1px; |
| | | border-color: #c1c3c8; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="result-detail"> |
| | | <!-- 页é¢å¤´é¨ --> |
| | | <PageHeader title="ç»ææç»" |
| | | @back="goBack" /> |
| | | <!-- å
容åºå --> |
| | | <view class="content"> |
| | | <!-- 课ç¨è¯¦æ
--> |
| | | <view class="section"> |
| | | <view class="section-title">课ç¨è¯¦æ
</view> |
| | | <view class="info-list"> |
| | | <view class="info-item"> |
| | | <text class="info-label">课ç¨ç¼å·</text> |
| | | <text class="info-value">{{ currentTraining.courseCode || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®å
容</text> |
| | | <text class="info-value">{{ currentTraining.trainingContent || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">ç¶æ</text> |
| | | <text class="info-value"> |
| | | <u-tag :type="currentTraining.state === 0 ? 'success' : (currentTraining.state === 1 ? 'warning' : 'info')"> |
| | | {{ currentTraining.state === 0 ? 'æªå¼å§' : (currentTraining.state === 1 ? 'è¿è¡ä¸' : 'å·²ç»æ') }} |
| | | </u-tag> |
| | | </text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®è®²å¸</text> |
| | | <text class="info-value">{{ currentTraining.trainingLecturer || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®å¼å§æ¶é´</text> |
| | | <text class="info-value">{{ currentTraining.trainingDate + ' ' + currentTraining.openingTime || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®ç»ææ¶é´</text> |
| | | <text class="info-value">{{ currentTraining.trainingDate + ' ' + currentTraining.endTime || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®ç®æ </text> |
| | | <text class="info-value">{{ currentTraining.trainingObjectives || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">åå 对象</text> |
| | | <text class="info-value">{{ currentTraining.participants || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®æ¹å¼</text> |
| | | <text class="info-value">{{ getTrainingModeLabel(currentTraining.trainingMode) || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®å°ç¹</text> |
| | | <text class="info-value">{{ currentTraining.placeTraining || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">课æ¶</text> |
| | | <text class="info-value">{{ currentTraining.classHour || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">课ç¨å¦å</text> |
| | | <text class="info-value">{{ currentTraining.projectCredits || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">æ¥å人æ°</text> |
| | | <text class="info-value">{{ currentTraining.nums || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 课ç¨è¯ä»· --> |
| | | <view class="section"> |
| | | <view class="section-title">课ç¨è¯ä»·</view> |
| | | <u-form ref="formRef" |
| | | label-width="90" |
| | | :model="endform"> |
| | | <u-form-item label="è¯ä»·äºº"> |
| | | <u-input v-model="endform.assessmentUserName" |
| | | disabled |
| | | placeholder="è¯·éæ©è¯ä»·äºº" /> |
| | | </u-form-item> |
| | | <u-form-item label="è¯ä»·æ¶é´"> |
| | | <u-input v-model="endform.assessmentDate" |
| | | disabled |
| | | placeholder="è¯·éæ©è¯ä»·æ¶é´" /> |
| | | </u-form-item> |
| | | <u-form-item label="èæ ¸æ¹å¼"> |
| | | <u-input v-model="endform.assessmentMethod" |
| | | placeholder="请è¾å
¥èæ ¸æ¹å¼" /> |
| | | </u-form-item> |
| | | <u-form-item label="综åè¯ä»·"> |
| | | <u-input v-model="endform.comprehensiveAssessment" |
| | | placeholder="请è¾å
¥æ¬æ¬¡è¯¾ç¨ç»¼åè¯ä»·" /> |
| | | </u-form-item> |
| | | <u-form-item label="å¹è®æè¦"> |
| | | <u-textarea v-model="endform.trainingAbstract" |
| | | :rows="4" |
| | | placeholder="请è¾å
¥å¹è®æè¦" /> |
| | | </u-form-item> |
| | | </u-form> |
| | | </view> |
| | | <!-- èæ ¸å表 --> |
| | | <view class="section"> |
| | | <view class="section-title">èæ ¸å表</view> |
| | | <view class="assessment-list"> |
| | | <view v-for="(item, index) in endform.safeTrainingDetailsDtoList" |
| | | :key="index" |
| | | class="assessment-item"> |
| | | <view class="assessment-info"> |
| | | <view class="info-row"> |
| | | <text class="label">å§åï¼</text> |
| | | <text class="value">{{ item.nickName || '-' }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="label">çµè¯å·ç ï¼</text> |
| | | <text class="value">{{ item.phonenumber || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | <view class="assessment-result"> |
| | | <text class="result-label">èæ ¸ç»æï¼</text> |
| | | <u-radio-group v-model="endform.safeTrainingDetailsDtoList[index].examinationResults" |
| | | :key="index" |
| | | size="default"> |
| | | <u-radio label="åæ ¼" |
| | | name="åæ ¼"></u-radio> |
| | | <u-radio label="ä¸åæ ¼" |
| | | name="ä¸åæ ¼"></u-radio> |
| | | </u-radio-group> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æäº¤æé® --> |
| | | <view class="submit-btn"> |
| | | <u-button type="primary" |
| | | @click="submitForm" |
| | | :loading="loading">æäº¤</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { useDict } from "@/utils/dict"; |
| | | import dayjs from "dayjs"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | safeTrainingGet, |
| | | safeTrainingSave, |
| | | } from "@/api/safeProduction/safetyTrainingAssessment"; |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { safe_training_methods } = useDict("safe_training_methods"); |
| | | |
| | | // 页é¢ç¶æ |
| | | const loading = ref(false); |
| | | const currentTraining = ref({}); |
| | | const endform = ref({ |
| | | assessmentUserId: "", |
| | | assessmentUserName: "", |
| | | assessmentMethod: "", |
| | | assessmentDate: "", |
| | | comprehensiveAssessment: "", |
| | | trainingAbstract: "", |
| | | safeTrainingFileList: [], |
| | | safeTrainingDetailsDtoList: [], |
| | | }); |
| | | |
| | | // è·åå¹è®æ¹å¼æ ç¾ |
| | | const getTrainingModeLabel = val => { |
| | | if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) { |
| | | return val; |
| | | } |
| | | const item = safe_training_methods.value.find( |
| | | i => String(i.value) === String(val) |
| | | ); |
| | | return item ? item.label : val; |
| | | }; |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | // éªè¯èæ ¸ç»æ |
| | | for (let i = 0; i < endform.value.safeTrainingDetailsDtoList.length; i++) { |
| | | const item = endform.value.safeTrainingDetailsDtoList[i]; |
| | | if (!item.examinationResults) { |
| | | uni.showToast({ |
| | | title: `è¯·éæ©${item.nickName}çèæ ¸ç»æ`, |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | loading.value = true; |
| | | safeTrainingSave(endform.value) |
| | | .then(res => { |
| | | loading.value = false; |
| | | if (res.code === 200) { |
| | | uni.showToast({ title: "æäº¤æå", icon: "success" }); |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 500); |
| | | } else { |
| | | uni.showToast({ title: res.msg || "æäº¤å¤±è´¥", icon: "none" }); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | loading.value = false; |
| | | uni.showToast({ title: "æäº¤å¤±è´¥ï¼è¯·éè¯", icon: "none" }); |
| | | }); |
| | | }; |
| | | |
| | | // 页é¢å è½½ |
| | | onLoad(() => { |
| | | const trainingId = uni.getStorageSync("safetyTrainingResultId"); |
| | | const trainingNums = uni.getStorageSync("safetyTrainingResultNums"); |
| | | |
| | | if (trainingId) { |
| | | getTrainingDetail(trainingId, trainingNums); |
| | | } |
| | | }); |
| | | const userStore = useUserStore(); |
| | | const getuserInfo = () => { |
| | | const userInfo = { |
| | | id: "", |
| | | nickName: "", |
| | | }; |
| | | userStore.getInfo().then(res => { |
| | | userInfo.id = res.user.userId; |
| | | userInfo.nickName = res.user.nickName; |
| | | endform.value.assessmentUserName = res.user.nickName; |
| | | endform.value.assessmentUserId = res.user.userId; |
| | | }); |
| | | return userInfo; |
| | | }; |
| | | |
| | | // è·åå¹è®è¯¦æ
|
| | | const getTrainingDetail = (id, trainingNums) => { |
| | | loading.value = true; |
| | | safeTrainingGet({ id }) |
| | | .then(res => { |
| | | loading.value = false; |
| | | if (res.code === 200) { |
| | | currentTraining.value = res.data; |
| | | currentTraining.value.nums = trainingNums; |
| | | |
| | | endform.value = { ...res.data }; |
| | | // 设置é»è®¤å¼ |
| | | if (!endform.value.assessmentUserId) { |
| | | getuserInfo(); |
| | | } |
| | | |
| | | endform.value.assessmentDate = endform.value.assessmentDate |
| | | ? dayjs(endform.value.assessmentDate).format("YYYY-MM-DD") |
| | | : dayjs().format("YYYY-MM-DD"); |
| | | endform.value.safeTrainingDetailsDtoList = |
| | | endform.value.safeTrainingDetailsDtoList || []; |
| | | } else { |
| | | uni.showToast({ title: "è·å详æ
失败", icon: "none" }); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | loading.value = false; |
| | | uni.showToast({ title: "è·å详æ
失败", icon: "none" }); |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .result-detail { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .section { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 16px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | margin-bottom: 16px; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .info-item:last-child { |
| | | border-bottom: none; |
| | | padding-bottom: 0; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 100px; |
| | | } |
| | | |
| | | .info-value { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #333; |
| | | text-align: right; |
| | | } |
| | | |
| | | .assessment-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .assessment-item { |
| | | background: #f8f9fa; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | border: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | .assessment-info { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .info-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | min-width: 80px; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .assessment-result { |
| | | display: flex; |
| | | align-items: center; |
| | | padding-top: 8px; |
| | | border-top: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | .result-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | min-width: 80px; |
| | | } |
| | | |
| | | .submit-btn { |
| | | margin-top: 24px; |
| | | margin-bottom: 32px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="danger-investigation-view"> |
| | | <PageHeader title="å¹è®è¯¦æ
" |
| | | @back="goBack" /> |
| | | <!-- å
å®¹å®¹å¨ --> |
| | | <view class="detail-content"> |
| | | <!-- å¹è®ä¿¡æ¯ --> |
| | | <view class="info-section"> |
| | | <!-- <view class="section-title">å¹è®ä¿¡æ¯</view> --> |
| | | <view class="info-grid"> |
| | | <view class="info-item"> |
| | | <text class="info-label">课ç¨ç¼å·</text> |
| | | <text class="info-value">{{ form.courseCode || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®æ¥æ</text> |
| | | <text class="info-value">{{ form.trainingDate || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¼å§æ¶é´</text> |
| | | <text class="info-value">{{ form.openingTime || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">ç»ææ¶é´</text> |
| | | <text class="info-value">{{ form.endTime || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®ç®æ </text> |
| | | <text class="info-value">{{ form.trainingObjectives || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">åå 对象</text> |
| | | <text class="info-value">{{ form.participants || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®å
容</text> |
| | | <text class="info-value">{{ form.trainingContent || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®è®²å¸</text> |
| | | <text class="info-value">{{ form.trainingLecturer || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">项ç®å¦å</text> |
| | | <text class="info-value">{{ form.projectCredits || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®æ¹å¼</text> |
| | | <text class="info-value">{{ getTrainingModeLabel(form.trainingMode) || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">å¹è®å°ç¹</text> |
| | | <text class="info-value">{{ form.placeTraining || '-' }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">课æ¶</text> |
| | | <text class="info-value">{{ form.classHour || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { useDict } from "@/utils/dict"; |
| | | // æ¿æ¢ toast æ¹æ³ |
| | | defineOptions({ name: "safety-training-view" }); |
| | | const showToast = message => { |
| | | uni.showToast({ title: message, icon: "none" }); |
| | | }; |
| | | |
| | | // è·ååå
¸æ°æ® |
| | | const { safe_training_methods } = useDict("safe_training_methods"); |
| | | |
| | | // è·åå¹è®æ¹å¼æ ç¾ |
| | | const getTrainingModeLabel = val => { |
| | | if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) { |
| | | return val; |
| | | } |
| | | const item = safe_training_methods.value.find( |
| | | i => String(i.value) === String(val) |
| | | ); |
| | | return item ? item.label : val; |
| | | }; |
| | | |
| | | // å¹è®ä¿¡æ¯ |
| | | const form = ref({}); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | onLoad(() => { |
| | | // 仿¬å°åå¨è·åå¹è®ä¿¡æ¯ |
| | | const safetyTraining = uni.getStorageSync("safetyTraining"); |
| | | if (safetyTraining) { |
| | | form.value = safetyTraining; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .danger-investigation-view { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 2rem; |
| | | } |
| | | |
| | | .detail-content { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .info-section { |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | padding: 24px; |
| | | margin-bottom: 24px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .section-title { |
| | | padding: 1rem; |
| | | font-size: 1rem; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | background: #f5f5f5; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 1rem; |
| | | } |
| | | .info-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20px; |
| | | } |
| | | .info-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | .info-item:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #303133; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .description-content { |
| | | padding: 1rem; |
| | | font-size: 0.875rem; |
| | | color: #303133; |
| | | line-height: 1.5; |
| | | } |
| | | </style> |
| | |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°/ååå·æç´¢" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°/éå®ååå·æç´¢" |
| | | v-model="searchForm.searchText" |
| | | @change="handleQuery" |
| | | clearable /> |
| | |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·åç§°</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项ç®</text> |
| | |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¸å¡å</text> |
| | | <text class="detail-value">{{ item.salesman }}</text> |
| | | </view> |
| | |
| | | <text class="info-value">{{ form.salesContractNo }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">客æ·ååå·</text> |
| | | <text class="info-value highlight">{{ form.customerContractNo }}</text> |
| | | </view> |
| | | <view class="info-item"> |
| | | <text class="info-label">客æ·åç§°</text> |
| | | <text class="info-value">{{ form.customerName }}</text> |
| | | </view> |
| | |
| | | const form = ref({ |
| | | id: '', |
| | | salesContractNo: '', |
| | | customerContractNo: '', |
| | | customerId: '', |
| | | customerName: '', |
| | | projectName: '', |
| | |
| | | const searchForm = ref({ |
| | | customerName: "", |
| | | status: true, |
| | | customerContractNo: "", |
| | | projectName: "", |
| | | }); |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·åç§°</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | |
| | | <text class="detail-label">åºæ¶éé¢(å
)</text> |
| | | <text class="detail-value danger">{{ formatAmount(item.unReceiptPaymentAmount) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åçæ¥æ</text> |
| | | <text class="detail-value">{{ item.receiptPaymentDate }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="detail-buttons"> |
| | | <u-button class="detail-button" |
| | | size="small" |
| | | type="primary" |
| | | @click="openOut(item)"> |
| | | åè´§ç¶æ |
| | | </u-button> |
| | | <u-button class="detail-button" |
| | | size="small" |
| | | type="error" |
| | | plain |
| | | @click.stop="handleDelete(item)"> |
| | | å é¤ |
| | | </u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import { ledgerListPage } from "@/api/salesManagement/salesLedger"; |
| | | import { |
| | | ledgerListPage, |
| | | delLedger, |
| | | productList, |
| | | } from "@/api/salesManagement/salesLedger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | const userStore = useUserStore(); |
| | |
| | | |
| | | // éå®å°è´¦æ°æ® |
| | | const ledgerList = ref([]); |
| | | |
| | | // 夿æ¯å¦åå¨å·²åè´§/åè´§å®æç产å |
| | | const hasShippedProducts = products => { |
| | | if (!products || products.length === 0) return false; |
| | | return products.some(p => { |
| | | const statusStr = (p.shippingStatus ?? "").toString(); |
| | | // å
å«âåè´§âææåè´§æ¥æ/车çå·è§ä¸ºå·²åè´§ |
| | | return ( |
| | | statusStr.includes("åè´§") || |
| | | !!p.shippingDate || |
| | | !!p.shippingCarNumber |
| | | ); |
| | | }); |
| | | }; |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | |
| | | uni.setStorageSync("outData", JSON.stringify(item)); |
| | | uni.navigateTo({ |
| | | url: "/pages/sales/salesAccount/out", |
| | | }); |
| | | }; |
| | | |
| | | // å é¤åæ¡éå®å°è´¦ |
| | | const handleDelete = async row => { |
| | | if (!row || !row.id) return; |
| | | |
| | | // è·å产åå表ï¼ç¨äºå¤ææ¯å¦å·²åè´§ |
| | | let products = row.children && row.children.length > 0 ? row.children : null; |
| | | if (!products) { |
| | | try { |
| | | const res = await productList({ salesLedgerId: row.id, type: 1 }); |
| | | products = res.data || res.records || []; |
| | | } catch (e) { |
| | | products = []; |
| | | } |
| | | } |
| | | |
| | | if (hasShippedProducts(products)) { |
| | | uni.showToast({ |
| | | title: "å·²åè´§/åè´§å®æçéå®è®¢åä¸è½å é¤", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.showModal({ |
| | | title: "å é¤ç¡®è®¤", |
| | | content: "éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", |
| | | success: async res => { |
| | | if (res.confirm) { |
| | | try { |
| | | showLoadingToast("å¤çä¸..."); |
| | | await delLedger([row.id]); |
| | | closeToast(); |
| | | uni.showToast({ |
| | | title: "å 餿å", |
| | | icon: "success", |
| | | }); |
| | | getList(); |
| | | } catch (e) { |
| | | closeToast(); |
| | | uni.showToast({ |
| | | title: "å é¤å¤±è´¥ï¼è¯·éè¯", |
| | | icon: "none", |
| | | }); |
| | | } |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | // å¤çå°è´¦ä¿¡æ¯æä½ï¼æ¥ç/ç¼è¾/æ°å¢ï¼ |
| | |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/styles/sales-common.scss"; |
| | | .detail-buttons { |
| | | display: flex; |
| | | gap: 10px; |
| | | justify-content: space-between; |
| | | } |
| | | </style> |