| | |
| | | icon: 'solar:checklist-minimalistic-line-duotone', |
| | | name: 'é®é¢æ´æ¹', |
| | | }, |
| | | { |
| | | path: '/index/inspection/report-manage', |
| | | icon: 'solar:folder-favourite-bookmark-line-duotone', |
| | | name: 'è¯ä¼°æ¥å', |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | |
| | | icon: 'solar:archive-down-minimlistic-line-duotone', |
| | | name: 'ç¯ä¿¡ç 管ç', |
| | | }, |
| | | { |
| | | path: '/index/inspection/report-manage', |
| | | icon: 'solar:folder-favourite-bookmark-line-duotone', |
| | | name: 'è¯ä¼°æ¥å', |
| | | }, |
| | | // { |
| | | // path: '/index/analysis/data-product', |
| | | // icon: 'solar:document-add-line-duotone', |
| | |
| | | methods: { |
| | | initOneWeekAgoTime() { |
| | | // ç»æ¶é´éæ©å¨è®¾ç½®é»è®¤æ¶é´ä¸ºä¸å¨å |
| | | this.time[0] = dayjs().subtract(4, 'week').format('YYYY-MM-DD HH:mm:ss') |
| | | this.time[1] = dayjs().format('YYYY-MM-DD HH:mm:ss') |
| | | // this.time[0] = dayjs().subtract(4, 'week').format('YYYY-MM-DD HH:mm:ss') |
| | | // this.time[1] = dayjs().format('YYYY-MM-DD HH:mm:ss') |
| | | // 2026.3.13 demo ä¸åºå®åå§æ¶é´ |
| | | this.time = ['2023-08-01 00:00:00', '2023-08-31 23:59:59'] |
| | | }, |
| | | |
| | | // å¿«æ·æ¶æ®µéæ© |
| | |
| | | <template>ç¯ä¿¡ç 管ç</template> |
| | | <template> |
| | | <div class="huanxin-code-manage"> |
| | | <!-- é¡¶é¨å®è§çæ¿åº --> |
| | | <el-row :gutter="20" class="dashboard"> |
| | | <el-col :span="8"> |
| | | <el-card shadow="hover" class="dashboard-card green-card" @click="filterByCode('green')"> |
| | | <div class="card-content"> |
| | | <div class="card-title">绿ç åºéºæ°</div> |
| | | <div class="card-value">{{ statistics.greenCount }}</div> |
| | | <div class="card-percentage">{{ statistics.greenPercentage }}%</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-card shadow="hover" class="dashboard-card yellow-card" @click="filterByCode('yellow')"> |
| | | <div class="card-content"> |
| | | <div class="card-title">é»ç åºéºæ°</div> |
| | | <div class="card-value">{{ statistics.yellowCount }}</div> |
| | | <div class="card-percentage">{{ statistics.yellowPercentage }}%</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-card shadow="hover" class="dashboard-card red-card" @click="filterByCode('red')"> |
| | | <div class="card-content"> |
| | | <div class="card-title">红ç åºéºæ°</div> |
| | | <div class="card-value">{{ statistics.redCount }}</div> |
| | | <div class="card-percentage">{{ statistics.redPercentage }}%</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- è¯å模åé
ç½®æé® --> |
| | | <!-- <div class="model-config" v-if="isAdmin"> |
| | | <el-button type="primary" @click="openModelConfig"> |
| | | <el-icon><Setting /></el-icon> |
| | | <span>è¯å模åé
ç½®</span> |
| | | </el-button> |
| | | </div> --> |
| | | |
| | | <!-- ä¸é¨è§å¾åæ¢åº --> |
| | | <el-tabs v-model="activeView" class="view-tabs"> |
| | | <!-- å表è§å¾ --> |
| | | <el-tab-pane label="å表è§å¾" name="list"> |
| | | <el-table :data="filteredShopList" style="width: 100%"> |
| | | <el-table-column prop="shopName" label="åºéºåç§°" /> |
| | | <el-table-column prop="district" label="æå¨åºå¿" width="120" /> |
| | | <el-table-column prop="town" label="æå¨è¡é" width="150" /> |
| | | <el-table-column label="ç¯ä¿¡ç " width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getCodeType(scope.row.code)">{{ getCodeText(scope.row.code) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="score" label="å½åè¯å" width="120" sortable /> |
| | | <el-table-column label="è¯åååè¶å¿" width="150"> |
| | | <template #default="scope"> |
| | | <div class="trend"> |
| | | <el-icon :class="['trend-icon', scope.row.trend > 0 ? 'up' : 'down']"> |
| | | <ArrowUp v-if="scope.row.trend > 0" /> |
| | | <ArrowDown v-else /> |
| | | </el-icon> |
| | | <span :class="scope.row.trend > 0 ? 'up' : 'down'"> |
| | | {{ scope.row.trend > 0 ? '+' : '' }}{{ scope.row.trend }}å |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="lastUpdate" label="䏿¬¡æ´æ°æ¶é´" width="180" /> |
| | | <el-table-column label="æä½" width="200" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button size="small" @click="viewDetails(scope.row)">æ¥ç详æ
</el-button> |
| | | <!-- <el-button size="small" type="warning" @click="viewRiskWarnings(scope.row)" |
| | | >é£é©é¢è¦è®°å½</el-button |
| | | > --> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-tab-pane> |
| | | |
| | | <!-- å°å¾è§å¾ --> |
| | | <el-tab-pane label="å°å¾è§å¾" name="map"> |
| | | <div class="map-container"> |
| | | <div class="map-placeholder"> |
| | | <el-empty description="å°å¾å è½½ä¸..." /> |
| | | <!-- è¿éåºè¯¥éæçå®çå°å¾ç»ä»¶ --> |
| | | </div> |
| | | <div class="map-legend"> |
| | | <div class="legend-item"> |
| | | <div class="legend-dot green"></div> |
| | | <span>绿ç </span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <div class="legend-dot yellow"></div> |
| | | <span>é»ç </span> |
| | | </div> |
| | | <div class="legend-item"> |
| | | <div class="legend-dot red"></div> |
| | | <span>红ç </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <!-- 详æ
æ½å± --> |
| | | <el-drawer v-model="drawerVisible" title="åºéºè¯¦æ
" direction="rtl" size="70%"> |
| | | <div v-if="selectedShop" class="shop-details"> |
| | | <!-- ç¯ä¿¡ç 大徿 åå½åè¯å --> |
| | | <div class="code-header"> |
| | | <div class="code-icon" :class="selectedShop.code"> |
| | | {{ getCodeText(selectedShop.code) }} |
| | | </div> |
| | | <div class="score-info"> |
| | | <div class="score-label">å½åè¯å</div> |
| | | <div class="score-value">{{ selectedShop.score }}</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- è¯å维度é·è¾¾å¾ --> |
| | | <div class="chart-section"> |
| | | <h3>è¯å维度åæ</h3> |
| | | <div class="radar-chart"> |
| | | <!-- è¿éåºè¯¥éæçå®çé·è¾¾å¾ç»ä»¶ --> |
| | | <el-empty description="é·è¾¾å¾å è½½ä¸..." /> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- è¯ååå²è¶å¿å¾ --> |
| | | <div class="chart-section"> |
| | | <h3>è¯ååå²è¶å¿</h3> |
| | | <div class="trend-chart"> |
| | | <!-- è¿éåºè¯¥éæçå®çè¶å¿å¾ç»ä»¶ --> |
| | | <el-empty description="è¶å¿å¾å è½½ä¸..." /> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- é£é©é¢è¦è®°å½ --> |
| | | <div class="warning-section"> |
| | | <h3>é£é©é¢è¦è®°å½</h3> |
| | | <el-table :data="selectedShop.warnings" style="width: 100%"> |
| | | <el-table-column prop="time" label="é¢è¦æ¶é´" width="180" /> |
| | | <el-table-column prop="content" label="é¢è¦å
容" /> |
| | | <el-table-column prop="score" label="彿¶è¯å" width="120" /> |
| | | <el-table-column label="å¤çç¶æ" width="120"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.handled ? 'success' : 'danger'"> |
| | | {{ scope.row.handled ? 'å·²å¤ç' : 'æªå¤ç' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </el-drawer> |
| | | |
| | | <!-- è¯å模åé
ç½®å¼¹çª --> |
| | | <el-dialog v-model="modelConfigVisible" title="è¯å模åé
ç½®" width="80%"> |
| | | <div class="model-config-content"> |
| | | <!-- è¿éåºè¯¥éæçå®çé
置表å --> |
| | | <el-empty description="é
置表åå è½½ä¸..." /> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="modelConfigVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="saveModelConfig">ä¿åé
ç½®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted } from 'vue' |
| | | import { Setting, ArrowUp, ArrowDown } from '@element-plus/icons-vue' |
| | | |
| | | // ç¶æ |
| | | const activeView = ref('list') |
| | | const drawerVisible = ref(false) |
| | | const modelConfigVisible = ref(false) |
| | | const selectedShop = ref(null) |
| | | const isAdmin = ref(true) // 模æç®¡çåæé |
| | | const filterCode = ref('all') |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const statistics = reactive({ |
| | | greenCount: 125, |
| | | greenPercentage: 65.8, |
| | | yellowCount: 45, |
| | | yellowPercentage: 23.7, |
| | | redCount: 20, |
| | | redPercentage: 10.5, |
| | | }) |
| | | |
| | | // åºéºåç§°å表 |
| | | const shopNames = [ |
| | | 'ä»å°å§å¨æé½', |
| | | 'åå»èç', |
| | | 'å®¶å¨å¡å¦', |
| | | 'ç¼æ¥äº', |
| | | 'ä¹å¯æææ¸¸åº', |
| | | '馨è¿ç¾é£å°éï¼åå°¼ç¾é£å¹¿åºï¼', |
| | | 'æ£çº¦ç¿°', |
| | | 'å¼å åªé', |
| | | 'æ¨è®°é½é½åå°ç¤è', |
| | | '䏿µ·ç¨ä¼ é¤é¥®ç®¡çæéå
¬å¸ï¼äººçä¸ä¸²ï¼', |
| | | 'ç¼å®¶', |
| | | 'æ³çé¤é¥®ï¼ä¸æµ·ï¼æéå
¬å¸ï¼é£å
¶å®¶ï¼', |
| | | '丰èç¤ä¸²', |
| | | '䏿µ·æ³°ç
é¤é¥®ç®¡çæéå
¬å¸ï¼æ³°ç
鸡ï¼', |
| | | '徿±åºè¾°çé¤é¦(å°éå串ç§å±
é
å±)', |
| | | ] |
| | | |
| | | // 徿±åºè¡éå表 |
| | | const xuhuiTowns = [ |
| | | '天平路è¡é', |
| | | 'æ¹åè·¯è¡é', |
| | | 'æåè·¯è¡é', |
| | | 'æ«æè·¯è¡é', |
| | | 'é¿æ¡¥è¡é', |
| | | 'ç°æè¡é', |
| | | 'è¹æ¢
è·¯è¡é', |
| | | 'åº·å¥æ°æè¡é', |
| | | 'å¾å®¶æ±è¡é', |
| | | 'åäºè·¯è¡é', |
| | | 'é¾åè¡é', |
| | | 'æ¼æ²³æ³¾è¡é', |
| | | 'åæ³¾é', |
| | | ] |
| | | |
| | | // çæ2023å¹´8æå
çéæºæ¶é´ |
| | | function generateRandomDate() { |
| | | const year = 2023 |
| | | const month = 7 // 0-11ï¼8ææ¯7 |
| | | const day = Math.floor(Math.random() * 31) + 1 // 1-31 |
| | | const hour = Math.floor(Math.random() * 24) // 0-23 |
| | | const minute = Math.floor(Math.random() * 60) // 0-59 |
| | | |
| | | const date = new Date(year, month, day, hour, minute) |
| | | return date.toISOString().slice(0, 16).replace('T', ' ') |
| | | } |
| | | |
| | | // éæºéæ©æ°ç»å
ç´ |
| | | function getRandomElement(array) { |
| | | return array[Math.floor(Math.random() * array.length)] |
| | | } |
| | | |
| | | // çæéæºè¯åè¶å¿ |
| | | function generateRandomTrend() { |
| | | return Math.floor(Math.random() * 11) - 5 // -5 å° 5 |
| | | } |
| | | |
| | | // åºéºæ°æ® |
| | | const shopList = ref([ |
| | | { |
| | | id: 1, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'green', |
| | | score: 95, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'ååå¨è¿è¡æ¶é¿ä¸è¶³', |
| | | score: 90, |
| | | handled: true, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 2, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'yellow', |
| | | score: 75, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'æè¯æ¬¡æ°è¾å¤', |
| | | score: 80, |
| | | handled: false, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 3, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'red', |
| | | score: 60, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'ææ¾æµåº¦è¶
æ ', |
| | | score: 65, |
| | | handled: false, |
| | | }, |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'æ¸
æ´é¢æ¬¡ä¸è¶³', |
| | | score: 62, |
| | | handled: false, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 4, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'green', |
| | | score: 92, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [], |
| | | }, |
| | | { |
| | | id: 5, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'yellow', |
| | | score: 78, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: '飿ºèå¨çä½', |
| | | score: 75, |
| | | handled: true, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 6, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'green', |
| | | score: 90, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [], |
| | | }, |
| | | { |
| | | id: 7, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'red', |
| | | score: 55, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'æªå®è£
æ²¹çåå设å¤', |
| | | score: 60, |
| | | handled: false, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 8, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'yellow', |
| | | score: 72, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'åå卿¸
æ´ä¸åæ¶', |
| | | score: 75, |
| | | handled: true, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 9, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'green', |
| | | score: 93, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [], |
| | | }, |
| | | { |
| | | id: 10, |
| | | shopName: getRandomElement(shopNames), |
| | | district: '徿±åº', |
| | | town: getRandomElement(xuhuiTowns), |
| | | code: 'yellow', |
| | | score: 76, |
| | | trend: generateRandomTrend(), |
| | | lastUpdate: generateRandomDate(), |
| | | warnings: [ |
| | | { |
| | | time: generateRandomDate(), |
| | | content: 'ææ¾æµåº¦æ¥è¿æ åéå¼', |
| | | score: 78, |
| | | handled: true, |
| | | }, |
| | | ], |
| | | }, |
| | | ]) |
| | | |
| | | // è¿æ»¤åçåºéºå表 |
| | | const filteredShopList = computed(() => { |
| | | if (filterCode.value === 'all') { |
| | | return shopList.value |
| | | } |
| | | return shopList.value.filter((shop) => shop.code === filterCode.value) |
| | | }) |
| | | |
| | | // çå½å¨æ |
| | | onMounted(() => { |
| | | // è¿éå¯ä»¥ä»APIè·åæ°æ® |
| | | console.log('ç¯ä¿¡ç 管ç页é¢å è½½') |
| | | }) |
| | | |
| | | // æ¹æ³ |
| | | function onBack() { |
| | | // åéé»è¾ |
| | | console.log('åé') |
| | | } |
| | | |
| | | function filterByCode(code) { |
| | | filterCode.value = code === filterCode.value ? 'all' : code |
| | | activeView.value = 'list' // 忢å°å表è§å¾ |
| | | } |
| | | |
| | | function getCodeType(code) { |
| | | switch (code) { |
| | | case 'green': |
| | | return 'success' |
| | | case 'yellow': |
| | | return 'warning' |
| | | case 'red': |
| | | return 'danger' |
| | | default: |
| | | return '' |
| | | } |
| | | } |
| | | |
| | | function getCodeText(code) { |
| | | switch (code) { |
| | | case 'green': |
| | | return '绿ç ' |
| | | case 'yellow': |
| | | return 'é»ç ' |
| | | case 'red': |
| | | return '红ç ' |
| | | default: |
| | | return '' |
| | | } |
| | | } |
| | | |
| | | function viewDetails(shop) { |
| | | selectedShop.value = shop |
| | | drawerVisible.value = true |
| | | } |
| | | |
| | | function viewRiskWarnings(shop) { |
| | | selectedShop.value = shop |
| | | drawerVisible.value = true |
| | | // è¿éå¯ä»¥æ»å¨å°é£é©é¢è¦é¨å |
| | | } |
| | | |
| | | function openModelConfig() { |
| | | modelConfigVisible.value = true |
| | | } |
| | | |
| | | function saveModelConfig() { |
| | | // ä¿åé
ç½®é»è¾ |
| | | modelConfigVisible.value = false |
| | | console.log('ä¿åè¯å模åé
ç½®') |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .huanxin-code-manage { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .dashboard { |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .dashboard-card { |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .dashboard-card:hover { |
| | | transform: translateY(-5px); |
| | | } |
| | | |
| | | .card-content { |
| | | text-align: center; |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .card-value { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .card-percentage { |
| | | font-size: 14px; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .green-card .card-value { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .yellow-card .card-value { |
| | | color: #e6a23c; |
| | | } |
| | | |
| | | .red-card .card-value { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .model-config { |
| | | text-align: right; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .view-tabs { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .trend { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .trend-icon { |
| | | margin-right: 5px; |
| | | } |
| | | |
| | | .trend-icon.up { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .trend-icon.down { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .trend .up { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .trend .down { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .map-container { |
| | | position: relative; |
| | | height: 600px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .map-placeholder { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .map-legend { |
| | | position: absolute; |
| | | bottom: 20px; |
| | | right: 20px; |
| | | background: white; |
| | | padding: 10px; |
| | | border-radius: 4px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .legend-item { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .legend-dot { |
| | | width: 12px; |
| | | height: 12px; |
| | | border-radius: 50%; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .legend-dot.green { |
| | | background-color: #67c23a; |
| | | } |
| | | |
| | | .legend-dot.yellow { |
| | | background-color: #e6a23c; |
| | | } |
| | | |
| | | .legend-dot.red { |
| | | background-color: #f56c6c; |
| | | } |
| | | |
| | | .shop-details { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .code-header { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .code-icon { |
| | | width: 100px; |
| | | height: 100px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: white; |
| | | margin-right: 30px; |
| | | } |
| | | |
| | | .code-icon.green { |
| | | background-color: #67c23a; |
| | | } |
| | | |
| | | .code-icon.yellow { |
| | | background-color: #e6a23c; |
| | | } |
| | | |
| | | .code-icon.red { |
| | | background-color: #f56c6c; |
| | | } |
| | | |
| | | .score-info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .score-label { |
| | | font-size: 16px; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .score-value { |
| | | font-size: 48px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .chart-section { |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .chart-section h3 { |
| | | margin-bottom: 15px; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .radar-chart, |
| | | .trend-chart { |
| | | height: 300px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .warning-section { |
| | | margin-top: 30px; |
| | | } |
| | | |
| | | .warning-section h3 { |
| | | margin-bottom: 15px; |
| | | font-size: 18px; |
| | | } |
| | | </style> |
| | |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="å±åºææ±¡" name="third"> |
| | | <!-- <el-tab-pane label="å±åºææ±¡" name="third"> |
| | | <FormCol> |
| | | <div class="sub-title">å±åºææ±¡æ¸
å</div> |
| | | <CompHazardousWasteFile :form-info="formHazardousWasteFile" /> |
| | |
| | | <div class="sub-title">å±åºææ±¡è®°å½</div> |
| | | <CompHazardousWasteRecord :form-info="formHazardousWasteRecord" /> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | </el-tab-pane> --> |
| | | |
| | | <el-tab-pane label="è¡æ¿å¤ç½" name="fourth"> |
| | | <FormCol> |
| | | <div class="sub-title">è¡æ¿å¤ç½è¡¨</div> |
| | | <!-- <CompPunishment :form-info="formProblem" /> --> |
| | | </FormCol> |
| | | <!-- <FormCol> --> |
| | | <CompPunishment /> |
| | | <!-- </FormCol> --> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="信访æè¯" name="fifth"> |
| | | <FormCol> |
| | | <div class="sub-title">信访æè¯</div> |
| | | <!-- <CompLaint :form-info="formLaint" /> --> |
| | | </FormCol> |
| | | <!-- <FormCol> --> |
| | | <CompLaint /> |
| | | <!-- </FormCol> --> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="å·¡æ¥é®é¢è¡¨" name="sixth"> |
| | | <!-- <el-tab-pane label="å·¡æ¥é®é¢è¡¨" name="sixth"> |
| | | <FormCol> |
| | | <div class="sub-title">å·¡æ¥é®é¢è¡¨</div> |
| | | <!-- <CompProblem :form-info="formProblem" /> --> |
| | | <CompProblem :form-info="formProblem" /> |
| | | </FormCol> |
| | | </el-tab-pane> |
| | | </el-tab-pane> --> |
| | | </el-tabs> |
| | | |
| | | <!-- <ComBaseInformation v-model="drawer"></ComBaseInformation> --> |
| | |
| | | import CompDeviceInfo from './components/CompDeviceInfo.vue' |
| | | import CompHazardousWasteFile from './components/CompHazardousWasteFile.vue' |
| | | import CompHazardousWasteRecord from './components/CompHazardousWasteRecord.vue' |
| | | import CompLaint from './components/CompLaint.vue' |
| | | import CompPunishment from './components/CompPunishment.vue' |
| | | |
| | | export default { |
| | | components: { |
| | |
| | | CompSceneInfo, |
| | | CompCompanyInfo, |
| | | CompDeviceInfo, |
| | | CompHazardousWasteFile, |
| | | CompHazardousWasteRecord, |
| | | CompPunishment, |
| | | CompLaint, |
| | | // CompHazardousWasteFile, |
| | | // CompHazardousWasteRecord, |
| | | // CompPanyInfo, |
| | | // CompFumePurifyDevice, |
| | | // CompHazardousWasteFile, |
| | | // CompHazardousWasteRecord, |
| | | // CompProblem, |
| | | // CompPunishment, |
| | | // CompRestaurantBaseInfo, |
| | | // CompVehicleBaseInfo, |
| | | // CompUserInfos, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-row class="sub-title" justify="space-between"> |
| | | <div>信访æè¯è®°å½</div> |
| | | <el-button-group> |
| | | <el-button type="primary" @click="handleAdd"> |
| | | <el-icon><Plus /></el-icon> |
| | | <span>æ°å¢æè¯è®°å½</span> |
| | | </el-button> |
| | | <el-button type="success" @click="dialogImportVisible = true"> |
| | | <el-icon><Upload /></el-icon> |
| | | <span>导å
¥è®°å½</span> |
| | | </el-button> |
| | | </el-button-group> |
| | | </el-row> |
| | | |
| | | <!-- è¡¨æ ¼å±ç¤º --> |
| | | <el-table :data="laintList" style="width: 100%" :show-overflow-tooltip="true"> |
| | | <el-table-column prop="reason" label="æè¯åå " /> |
| | | <el-table-column prop="demand" label="æè¯è¯æ±" /> |
| | | <el-table-column prop="laintTime" label="æè¯æ¶é´" width="180" /> |
| | | <el-table-column prop="source" label="æè¯æ¥æº" width="150" /> |
| | | <el-table-column prop="department" label="å¤çé¨é¨" width="150" /> |
| | | <el-table-column prop="result" label="æè¯ç»æ" width="150" /> |
| | | <el-table-column label="æä½" width="150" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button size="small" @click="handleEdit(scope.row)">ä¿®æ¹</el-button> |
| | | <el-button size="small" type="danger" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- ç©ºç¶æ --> |
| | | <div v-if="laintList.length === 0" class="empty-state"> |
| | | <el-empty description="ææ ä¿¡è®¿æè¯è®°å½" /> |
| | | </div> |
| | | |
| | | <!-- æ°å¢/ç¼è¾å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-form-item label="æè¯åå " prop="reason"> |
| | | <el-input v-model="form.reason" placeholder="请è¾å
¥æè¯åå " type="textarea" rows="3" /> |
| | | </el-form-item> |
| | | <el-form-item label="æè¯è¯æ±" prop="demand"> |
| | | <el-input v-model="form.demand" placeholder="请è¾å
¥æè¯è¯æ±" type="textarea" rows="3" /> |
| | | </el-form-item> |
| | | <el-form-item label="æè¯æ¶é´" prop="laintTime"> |
| | | <el-date-picker |
| | | v-model="form.laintTime" |
| | | type="date" |
| | | placeholder="è¯·éæ©æè¯æ¶é´" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æè¯æ¥æº" prop="source"> |
| | | <el-input v-model="form.source" placeholder="请è¾å
¥æè¯æ¥æº" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤çé¨é¨" prop="department"> |
| | | <el-input v-model="form.department" placeholder="请è¾å
¥å¤çé¨é¨" /> |
| | | </el-form-item> |
| | | <el-form-item label="æè¯ç»æ" prop="result"> |
| | | <el-input v-model="form.result" placeholder="请è¾å
¥æè¯ç»æ" type="textarea" rows="2" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleSubmit">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- Excel导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialogImportVisible" title="导å
¥æè¯è®°å½" width="50%"> |
| | | <el-upload |
| | | class="upload-demo" |
| | | action="#" |
| | | :auto-upload="false" |
| | | :on-change="handleFileChange" |
| | | :show-file-list="false" |
| | | accept=".xlsx,.xls" |
| | | > |
| | | <el-button type="primary">éæ©Excelæä»¶</el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip">请ä¸ä¼ .xlsxæ.xlsæ ¼å¼çæä»¶</div> |
| | | </template> |
| | | </el-upload> |
| | | <div v-if="uploadedFile" class="uploaded-file"> |
| | | <el-icon><Document /></el-icon> |
| | | <span>{{ uploadedFile.name }}</span> |
| | | <el-button type="text" @click="uploadedFile = null">ç§»é¤</el-button> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogImportVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleImport" :loading="importLoading">导å
¥</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { Plus, Upload, Document } from '@element-plus/icons-vue' |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | reason: '', |
| | | demand: '', |
| | | laintTime: '', |
| | | source: '', |
| | | department: '', |
| | | result: '', |
| | | }) |
| | | |
| | | // éªè¯è§å |
| | | const rules = reactive({ |
| | | reason: [{ required: true, message: '请è¾å
¥æè¯åå ', trigger: 'blur' }], |
| | | demand: [{ required: true, message: '请è¾å
¥æè¯è¯æ±', trigger: 'blur' }], |
| | | laintTime: [{ required: true, message: '请è¾å
¥æè¯æ¶é´', trigger: 'blur' }], |
| | | source: [{ required: true, message: '请è¾å
¥æè¯æ¥æº', trigger: 'blur' }], |
| | | department: [{ required: true, message: '请è¾å
¥å¤çé¨é¨', trigger: 'blur' }], |
| | | result: [{ required: true, message: '请è¾å
¥æè¯ç»æ', trigger: 'blur' }], |
| | | }) |
| | | |
| | | // ç¶æ |
| | | const dialogVisible = ref(false) |
| | | const dialogImportVisible = ref(false) |
| | | const dialogTitle = ref('æ°å¢ä¿¡è®¿æè¯') |
| | | const formRef = ref(null) |
| | | const laintList = ref([]) |
| | | const currentRow = ref(null) |
| | | const uploadedFile = ref(null) |
| | | const importLoading = ref(false) |
| | | |
| | | // æ¨¡ææ°æ® |
| | | onMounted(() => { |
| | | // è¿éå¯ä»¥ä»APIè·åæ°æ® |
| | | // ææ¶ä½¿ç¨æ¨¡ææ°æ® |
| | | laintList.value = [ |
| | | { |
| | | id: 1, |
| | | reason: 'æ²¹çæ°æ°', |
| | | demand: 'è¦æ±å®è£
æ²¹çåå设å¤', |
| | | laintTime: '2026-01-10', |
| | | source: '叿°ç线', |
| | | department: 'ç¯ä¿å±', |
| | | result: '已责令å®è£
æ²¹çåå设å¤', |
| | | }, |
| | | { |
| | | id: 2, |
| | | reason: 'åªé³æ±¡æ', |
| | | demand: 'è¦æ±éä½è®¾å¤åªé³', |
| | | laintTime: '2026-02-15', |
| | | source: '信访å', |
| | | department: 'ç¯ä¿å±', |
| | | result: 'å·²è¦æ±æ´æ¹åªé³é®é¢', |
| | | }, |
| | | ] |
| | | }) |
| | | |
| | | // æ°å¢ |
| | | function handleAdd() { |
| | | form.reason = '' |
| | | form.demand = '' |
| | | form.laintTime = '' |
| | | form.source = '' |
| | | form.department = '' |
| | | form.result = '' |
| | | dialogTitle.value = 'æ°å¢ä¿¡è®¿æè¯' |
| | | currentRow.value = null |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | // ç¼è¾ |
| | | function handleEdit(row) { |
| | | currentRow.value = row |
| | | form.reason = row.reason |
| | | form.demand = row.demand |
| | | form.laintTime = row.laintTime |
| | | form.source = row.source |
| | | form.department = row.department |
| | | form.result = row.result |
| | | dialogTitle.value = 'ä¿®æ¹ä¿¡è®¿æè¯' |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | // å é¤ |
| | | function handleDelete(row) { |
| | | ElMessage.confirm('ç¡®å®è¦å é¤è¿æ¡è®°å½åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning', |
| | | }) |
| | | .then(() => { |
| | | const index = laintList.value.findIndex((item) => item.id === row.id) |
| | | if (index !== -1) { |
| | | laintList.value.splice(index, 1) |
| | | ElMessage.success('å 餿å') |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | // åæ¶å é¤ |
| | | }) |
| | | } |
| | | |
| | | // æäº¤ |
| | | function handleSubmit() { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | if (currentRow.value) { |
| | | // ä¿®æ¹ |
| | | const index = laintList.value.findIndex((item) => item.id === currentRow.value.id) |
| | | if (index !== -1) { |
| | | laintList.value[index] = { |
| | | ...currentRow.value, |
| | | ...form, |
| | | } |
| | | ElMessage.success('ä¿®æ¹æå') |
| | | } |
| | | } else { |
| | | // æ°å¢ |
| | | const newItem = { |
| | | id: Date.now(), |
| | | ...form, |
| | | } |
| | | laintList.value.push(newItem) |
| | | ElMessage.success('æ°å¢æå') |
| | | } |
| | | dialogVisible.value = false |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // å¤çæä»¶éæ© |
| | | function handleFileChange(file) { |
| | | uploadedFile.value = file.raw |
| | | } |
| | | |
| | | // å¤çExcel导å
¥ |
| | | function handleImport() { |
| | | if (!uploadedFile.value) { |
| | | ElMessage.warning('è¯·éæ©è¦å¯¼å
¥çExcelæä»¶') |
| | | return |
| | | } |
| | | |
| | | importLoading.value = true |
| | | |
| | | // è¿éå¯ä»¥æ·»å å®é
çExcelè§£æå导å
¥é»è¾ |
| | | // ææ¶æ¨¡æå¯¼å
¥è¿ç¨ |
| | | setTimeout(() => { |
| | | // 模æå¯¼å
¥æ°æ® |
| | | const importedData = [ |
| | | { |
| | | id: Date.now() + 1, |
| | | reason: 'åºæ°ææ¾è¶
æ ', |
| | | demand: 'è¦æ±è¾¾æ ææ¾', |
| | | laintTime: '2026-03-01', |
| | | source: 'ç¯ä¿ç线', |
| | | department: 'ç¯ä¿å±', |
| | | result: 'å·²è¦æ±æ´æ¹', |
| | | }, |
| | | { |
| | | id: Date.now() + 2, |
| | | reason: 'å¼å³æ°æ°', |
| | | demand: 'æ¶é¤å¼å³', |
| | | laintTime: '2026-03-10', |
| | | source: '叿°æè¯', |
| | | department: 'ç¯ä¿å±', |
| | | result: 'å·²ç°åºæ£æ¥', |
| | | }, |
| | | ] |
| | | |
| | | // æ·»å å°å表 |
| | | laintList.value.push(...importedData) |
| | | |
| | | ElMessage.success('导å
¥æåï¼å
±å¯¼å
¥2æ¡è®°å½') |
| | | dialogImportVisible.value = false |
| | | uploadedFile.value = null |
| | | importLoading.value = false |
| | | }, 1500) |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .empty-state { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | } |
| | | .sub-title { |
| | | margin-bottom: 20px; |
| | | } |
| | | .uploaded-file { |
| | | margin-top: 20px; |
| | | padding: 10px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | .uploaded-file span { |
| | | margin-left: 10px; |
| | | flex: 1; |
| | | } |
| | | .uploaded-file .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-row class="sub-title" justify="space-between"> |
| | | <div>è¡æ¿å¤ç½è®°å½</div> |
| | | <el-button-group> |
| | | <el-button type="primary" @click="handleAdd"> |
| | | <el-icon><Plus /></el-icon> |
| | | <span>æ°å¢å¤ç½è®°å½</span> |
| | | </el-button> |
| | | <el-button type="success" @click="dialogImportVisible = true"> |
| | | <el-icon><Upload /></el-icon> |
| | | <span>导å
¥è®°å½</span> |
| | | </el-button> |
| | | </el-button-group> |
| | | </el-row> |
| | | |
| | | <!-- è¡¨æ ¼å±ç¤º --> |
| | | <el-table :data="punishmentList" style="width: 100%"> |
| | | <el-table-column prop="name" label="å¤ç½äºé¡¹" width="180" /> |
| | | <el-table-column prop="punishTime" label="å¤ç½æ¶é´" width="180" /> |
| | | <el-table-column prop="reason" label="å¤ç½çç±" /> |
| | | <el-table-column prop="result" label="å¤ç½ç»æ" width="180" /> |
| | | <el-table-column prop="department" label="å¤ç½é¨é¨" width="180" /> |
| | | <el-table-column label="æä½" width="150" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button size="small" @click="handleEdit(scope.row)">ä¿®æ¹</el-button> |
| | | <el-button size="small" type="danger" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- ç©ºç¶æ --> |
| | | <div v-if="punishmentList.length === 0" class="empty-state"> |
| | | <el-empty description="ææ è¡æ¿å¤ç½è®°å½" /> |
| | | </div> |
| | | |
| | | <!-- æ°å¢/ç¼è¾å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-form-item label="è¡æ¿å¤ç½åç§°" prop="name"> |
| | | <el-input v-model="form.name" placeholder="请è¾å
¥è¡æ¿å¤ç½åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤ç½æ¶é´" prop="punishTime"> |
| | | <el-date-picker |
| | | v-model="form.punishTime" |
| | | type="date" |
| | | placeholder="è¯·éæ©å¤ç½æ¶é´" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤ç½çç±" prop="reason"> |
| | | <el-input v-model="form.reason" placeholder="请è¾å
¥å¤ç½çç±" type="textarea" rows="3" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤ç½ç»æ" prop="result"> |
| | | <el-input v-model="form.result" placeholder="请è¾å
¥å¤ç½ç»æ" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤ç½é¨é¨" prop="department"> |
| | | <el-input v-model="form.department" placeholder="请è¾å
¥å¤ç½é¨é¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleSubmit">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- Excel导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialogImportVisible" title="导å
¥å¤ç½è®°å½" width="50%"> |
| | | <el-upload |
| | | class="upload-demo" |
| | | action="#" |
| | | :auto-upload="false" |
| | | :on-change="handleFileChange" |
| | | :show-file-list="false" |
| | | accept=".xlsx,.xls" |
| | | > |
| | | <el-button type="primary">éæ©Excelæä»¶</el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip">请ä¸ä¼ .xlsxæ.xlsæ ¼å¼çæä»¶</div> |
| | | </template> |
| | | </el-upload> |
| | | <div v-if="uploadedFile" class="uploaded-file"> |
| | | <el-icon><Document /></el-icon> |
| | | <span>{{ uploadedFile.name }}</span> |
| | | <el-button type="text" @click="uploadedFile = null">ç§»é¤</el-button> |
| | | </div> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogImportVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="handleImport" :loading="importLoading">导å
¥</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Plus, Upload, Document } from '@element-plus/icons-vue' |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | name: '', |
| | | punishTime: '', |
| | | reason: '', |
| | | result: '', |
| | | department: '', |
| | | }) |
| | | |
| | | // éªè¯è§å |
| | | const rules = reactive({ |
| | | name: [{ required: true, message: '请è¾å
¥è¡æ¿å¤ç½åç§°', trigger: 'blur' }], |
| | | punishTime: [{ required: true, message: '请è¾å
¥å¤ç½æ¶é´', trigger: 'blur' }], |
| | | reason: [{ required: true, message: '请è¾å
¥å¤ç½çç±', trigger: 'blur' }], |
| | | result: [{ required: true, message: '请è¾å
¥å¤ç½ç»æ', trigger: 'blur' }], |
| | | department: [{ required: true, message: '请è¾å
¥å¤ç½é¨é¨', trigger: 'blur' }], |
| | | }) |
| | | |
| | | // ç¶æ |
| | | const dialogVisible = ref(false) |
| | | const dialogImportVisible = ref(false) |
| | | const dialogTitle = ref('æ°å¢è¡æ¿å¤ç½') |
| | | const formRef = ref(null) |
| | | const punishmentList = ref([]) |
| | | const currentRow = ref(null) |
| | | const uploadedFile = ref(null) |
| | | const importLoading = ref(false) |
| | | |
| | | // æ¨¡ææ°æ® |
| | | onMounted(() => { |
| | | // è¿éå¯ä»¥ä»APIè·åæ°æ® |
| | | // ææ¶ä½¿ç¨æ¨¡ææ°æ® |
| | | punishmentList.value = [ |
| | | { |
| | | id: 1, |
| | | name: 'è¿è§ææ¾åºæ°', |
| | | punishTime: '2026-01-15', |
| | | reason: 'æªæè§å®å¤çåºæ°ï¼è¶
æ ææ¾', |
| | | result: 'ç½æ¬¾5000å
', |
| | | department: 'ç¯ä¿å±', |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'æªå®è£
æ²¹çåå设å¤', |
| | | punishTime: '2026-02-20', |
| | | reason: 'é¤å
æªå®è£
æ²¹çåå设å¤', |
| | | result: 'è´£ä»¤éææ´æ¹', |
| | | department: 'ç¯ä¿å±', |
| | | }, |
| | | ] |
| | | }) |
| | | |
| | | // æ°å¢ |
| | | function handleAdd() { |
| | | form.name = '' |
| | | form.punishTime = '' |
| | | form.reason = '' |
| | | form.result = '' |
| | | form.department = '' |
| | | dialogTitle.value = 'æ°å¢è¡æ¿å¤ç½' |
| | | currentRow.value = null |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | // ç¼è¾ |
| | | function handleEdit(row) { |
| | | currentRow.value = row |
| | | form.name = row.name |
| | | form.punishTime = row.punishTime |
| | | form.reason = row.reason |
| | | form.result = row.result |
| | | form.department = row.department |
| | | dialogTitle.value = 'ä¿®æ¹è¡æ¿å¤ç½' |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | // å é¤ |
| | | function handleDelete(row) { |
| | | ElMessageBox.confirm('ç¡®å®è¦å é¤è¿æ¡è®°å½åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning', |
| | | }) |
| | | .then(() => { |
| | | const index = punishmentList.value.findIndex((item) => item.id === row.id) |
| | | if (index !== -1) { |
| | | punishmentList.value.splice(index, 1) |
| | | ElMessage.success('å 餿å') |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | // åæ¶å é¤ |
| | | }) |
| | | } |
| | | |
| | | // æäº¤ |
| | | function handleSubmit() { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | if (currentRow.value) { |
| | | // ä¿®æ¹ |
| | | const index = punishmentList.value.findIndex((item) => item.id === currentRow.value.id) |
| | | if (index !== -1) { |
| | | punishmentList.value[index] = { |
| | | ...currentRow.value, |
| | | ...form, |
| | | } |
| | | ElMessage.success('ä¿®æ¹æå') |
| | | } |
| | | } else { |
| | | // æ°å¢ |
| | | const newItem = { |
| | | id: Date.now(), |
| | | ...form, |
| | | } |
| | | punishmentList.value.push(newItem) |
| | | ElMessage.success('æ°å¢æå') |
| | | } |
| | | dialogVisible.value = false |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // å¤çæä»¶éæ© |
| | | function handleFileChange(file) { |
| | | uploadedFile.value = file.raw |
| | | } |
| | | |
| | | // å¤çExcel导å
¥ |
| | | function handleImport() { |
| | | if (!uploadedFile.value) { |
| | | ElMessage.warning('è¯·éæ©è¦å¯¼å
¥çExcelæä»¶') |
| | | return |
| | | } |
| | | |
| | | importLoading.value = true |
| | | |
| | | // è¿éå¯ä»¥æ·»å å®é
çExcelè§£æå导å
¥é»è¾ |
| | | // ææ¶æ¨¡æå¯¼å
¥è¿ç¨ |
| | | setTimeout(() => { |
| | | // 模æå¯¼å
¥æ°æ® |
| | | const importedData = [ |
| | | { |
| | | id: Date.now() + 1, |
| | | name: 'æªæè§å®ææ¾æ±¡æ°´', |
| | | punishTime: '2026-03-05', |
| | | reason: 'æªæè§å®å¤ç污水ï¼è¶
æ ææ¾', |
| | | result: 'ç½æ¬¾8000å
', |
| | | department: 'ç¯ä¿å±', |
| | | }, |
| | | { |
| | | id: Date.now() + 2, |
| | | name: 'è¿è§å¾ååºåº', |
| | | punishTime: '2026-03-12', |
| | | reason: 'è¿è§å¾ååºä½åºç©', |
| | | result: 'ç½æ¬¾10000å
', |
| | | department: 'ç¯ä¿å±', |
| | | }, |
| | | ] |
| | | |
| | | // æ·»å å°å表 |
| | | punishmentList.value.push(...importedData) |
| | | |
| | | ElMessage.success('导å
¥æåï¼å
±å¯¼å
¥2æ¡è®°å½') |
| | | dialogImportVisible.value = false |
| | | uploadedFile.value = null |
| | | importLoading.value = false |
| | | }, 1500) |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .empty-state { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | } |
| | | .sub-title { |
| | | margin-bottom: 20px; |
| | | } |
| | | .uploaded-file { |
| | | margin-top: 20px; |
| | | padding: 10px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | .uploaded-file span { |
| | | margin-left: 10px; |
| | | flex: 1; |
| | | } |
| | | .uploaded-file .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | </style> |
| | |
| | | </div> |
| | | <div class="form-row"> |
| | | <div class="form-item full-width"> |
| | | <TimeSelect @submit-time="giveTime" :useNewStyle="true"></TimeSelect> |
| | | <TimeSelect @submit-time="giveTime" :useNewStyle="false"></TimeSelect> |
| | | </div> |
| | | </div> |
| | | </div> |