| | |
| | | <template> |
| | | <div class="bocklogBox"> |
| | | <div class="block"> |
| | | <div class="title">待办事项</div> |
| | | |
| | | <div class="todo-items"> |
| | | <div |
| | | v-for="(item, index) in todos" |
| | | :key="index" |
| | | class="todo-item" |
| | | :class="`status-${item.status}`" |
| | | @click="jumporder()" |
| | | > |
| | | <div class="status-indicator"></div> |
| | | |
| | | <div class="content-wrapper"> |
| | | <div class="main-content"> |
| | | <span class="status-tag">{{ statusMap[item.status] }}</span> |
| | | <span class="todo-text">{{ item.title }}</span> |
| | | </div> |
| | | |
| | | <div class="action-area"> |
| | | <img :src="st7" alt=""> |
| | | <span class="todo-date">{{ item.date }}</span> |
| | | <div class="titleBox"> |
| | | <div class="title">待办事项</div> |
| | | <div class="rightTab"> |
| | | <div class="titleItem" :class="item.name === checked ? 'activeItem' : ''" v-for="(item, index) in titleList" |
| | | :key="index" @click="titleClick(item, index)"> |
| | | <div> |
| | | {{ item.name }} |
| | | <div class="dots">{{ item.number >= 100 ? '99+' : item.number }}</div> |
| | | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="todo-items" v-if="todos.length > 0" v-loading="loading" element-loading-background="rgba(255, 255, 255, 0.5)"> |
| | | <div v-for="(item, index) in todos" :key="index" class="todo-item" :style="getStatusStyle(item.status)" |
| | | @click="jumporder(item)"> |
| | | <div class="status-indicator"><img :src="getStatus(item.status)" alt=""></div> |
| | | |
| | | <div class="content-wrapper"> |
| | | <div class="main-content"> |
| | | <span class="status-tag" :style="{ color: getStatusColor(item.status) }">{{ |
| | | checked == '智飞工单' ? zfstatusMap[item.status] : statusMap[item.status] |
| | | }}</span> |
| | | <span class="reads" :class="item.is_read === 0 ? 'unread' : ''"></span> |
| | | <span class="todo-text">{{ item.event_num }}</span> |
| | | </div> |
| | | |
| | | <div class="action-area"> |
| | | <!-- <img :src="st7" alt="" /> --> |
| | | <!-- <span class="todo-date">{{ item.date?.slice(0, 10).replace(/-/g, '.') }}</span> --> |
| | | <span class="todo-date">{{ item.name }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <el-empty> |
| | | <template #description> |
| | | <span class="custom-text">暂无数据</span> |
| | | </template> |
| | | </el-empty> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import st7 from '@/assets/images/workbench/st7.png' |
| | | // 状态显示映射 |
| | | const statusMap = { |
| | | pending: '待审核', |
| | | processing: '处理中', |
| | | todo: '待处理', |
| | | }; |
| | | |
| | | // 待办事项数据 |
| | | const todos = ref([ |
| | | import db1 from '@/assets/images/workbench/db1.svg' |
| | | import db2 from '@/assets/images/workbench/db2.svg' |
| | | import db3 from '@/assets/images/workbench/db3.svg' |
| | | import db4 from '@/assets/images/workbench/db4.svg' |
| | | import db5 from '@/assets/images/workbench/db5.svg' |
| | | import { getOrderCountApi, addOrderRecordApi, getOrderOrEventApi } from '@/api/home/index' |
| | | import { onMounted } from 'vue' |
| | | import { useRouter } from 'vue-router' |
| | | import { useStore } from 'vuex' |
| | | |
| | | const router = useRouter() |
| | | const store = useStore() |
| | | const permission = computed(() => store.getters.permission) |
| | | const checked = ref('事件工单') |
| | | const todosCache = reactive({ |
| | | '事件工单': [], |
| | | '智飞工单': [] |
| | | }) |
| | | const titleList = ref([ |
| | | { |
| | | status: 'pending', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | label: 'event_order_count', |
| | | name: '事件工单', |
| | | number: 0, |
| | | }, |
| | | { |
| | | status: 'todo', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | label: 'wayline_order_count', |
| | | name: '智飞工单', |
| | | number: 0, |
| | | }, |
| | | { |
| | | status: 'processing', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'pending', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'todo', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | ]); |
| | | const jumporder=()=>{ |
| | | console.log('tiao'); |
| | | |
| | | ]) |
| | | |
| | | const titleClick = async (item, index) => { |
| | | checked.value = item.name |
| | | await getListMatter() |
| | | } |
| | | </script> |
| | | const userInfo = computed(() => store.getters.userInfo) |
| | | const todos = ref([]) |
| | | const loading = ref(false) |
| | | // * 事件工单中2=待审核,0=待处理,3=处理中 |
| | | // * 智飞工单中1: 待审核,2=已驳回,3=已通过 |
| | | const statusMap = { |
| | | 0: '待处理', |
| | | 2: '待审核', |
| | | 3: '处理中', |
| | | } |
| | | const statusMapColor = { |
| | | 0: { color: '#FF7411', backgroundImage: db3, borderLeftColor: '#FF7411' }, |
| | | 2: { color: '#FF472F', backgroundImage: db1, borderLeftColor: '#FF472F' }, |
| | | 3: { color: '#FFC300', backgroundImage: db4, borderLeftColor: '#FFC300' }, |
| | | } |
| | | const zfstatusMap = { |
| | | 1: '待审核', |
| | | 2: '已驳回', |
| | | 3: '已通过', |
| | | } |
| | | const zfstatusMapColor = { |
| | | 1: { color: '#FF472F', backgroundImage: db2, borderLeftColor: '#FF472F' }, |
| | | 2: { color: '#4200DD', backgroundImage: db5, borderLeftColor: '#4200DD' }, |
| | | 3: { color: '#FF472F', backgroundImage: db2, borderLeftColor: '#FF472F' }, |
| | | } |
| | | |
| | | const getStatus = statusIndex => { |
| | | if (checked.value === '智飞工单') { |
| | | const style = zfstatusMapColor[statusIndex] |
| | | return style ? style.backgroundImage : '' |
| | | } else { |
| | | const style = statusMapColor[statusIndex] |
| | | return style ? style.backgroundImage : '' |
| | | } |
| | | } |
| | | const getStatusStyle = statusIndex => { |
| | | if (checked.value === '智飞工单') { |
| | | const style = zfstatusMapColor[statusIndex] || { |
| | | color: '#999', |
| | | borderLeftColor: '#999', |
| | | } |
| | | return { |
| | | color: style.color, |
| | | borderLeft: `3px solid ${style.borderLeftColor}`, |
| | | } |
| | | } else { |
| | | const style = statusMapColor[statusIndex] || { |
| | | color: '#999', |
| | | borderLeftColor: '#999', |
| | | } |
| | | return { |
| | | color: style.color, |
| | | borderLeft: `3px solid ${style.borderLeftColor}`, |
| | | } |
| | | } |
| | | } |
| | | // 获取状态对应的文字颜色 |
| | | const getStatusColor = statusIndex => { |
| | | if (checked.value === '智飞工单') { |
| | | return zfstatusMapColor[statusIndex]?.color || '#999' |
| | | } else { |
| | | return statusMapColor[statusIndex]?.color || '#999' |
| | | } |
| | | } |
| | | // 跳转到对应详情页 |
| | | const jumporder = val => { |
| | | if (checked.value === '智飞工单') { |
| | | const id = val.id |
| | | getaddOrderRecord(id) |
| | | router.replace({ |
| | | path: `/tickets/orderLog`, |
| | | query: { |
| | | id, |
| | | }, |
| | | }) |
| | | } else { |
| | | getaddOrderRecord(val.id) |
| | | const orderNumber = val.event_num |
| | | router.replace({ |
| | | path: `/tickets/ticket`, |
| | | query: { orderNumber }, |
| | | }) |
| | | } |
| | | } |
| | | // 标记事件工单或智飞工单已读 |
| | | const getaddOrderRecord = async id => { |
| | | const ticketId = id |
| | | if (checked.value === '事件工单') { |
| | | loading.value = true |
| | | const type = 1 |
| | | const res = await addOrderRecordApi(type, ticketId) |
| | | |
| | | |
| | | } else if (checked.value === '智飞工单') { |
| | | loading.value = true |
| | | const type = 2 |
| | | const res = await addOrderRecordApi(type, ticketId) |
| | | } |
| | | } |
| | | // 获取事件工单和智飞工单的数量 |
| | | const getOrderCount = async () => { |
| | | const res = await getOrderCountApi(userInfo.value.detail.areaCode) |
| | | const data = res.data.data |
| | | titleList.value.forEach(item => { |
| | | if (data[item.label] !== undefined) { |
| | | item.number = data[item.label] |
| | | } |
| | | }) |
| | | } |
| | | // 获取事件工单或者智飞工单的信息 |
| | | |
| | | const getListMatter = async () => { |
| | | loading.value = true |
| | | const type = checked.value === '事件工单' ? 1 : 2 |
| | | |
| | | // 使用缓存数据 |
| | | if (todosCache[checked.value].length > 0) { |
| | | todos.value = todosCache[checked.value] |
| | | } |
| | | const todosParams = { |
| | | type:type, |
| | | area_code: userInfo.value.detail.areaCode, |
| | | } |
| | | try { |
| | | const res = await getOrderOrEventApi(todosParams) |
| | | const data = res.data.data || [] |
| | | todos.value = data.sort((a, b) => a.is_read - b.is_read) |
| | | todosCache[checked.value] = todos.value |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | onMounted(() => { |
| | | getListMatter() |
| | | getOrderCount() |
| | | }) |
| | | </script> |
| | | <style> |
| | | .el-empty__image { |
| | | width: 100px !important; |
| | | } |
| | | </style> |
| | | <style lang="scss" scoped> |
| | | .bocklogBox { |
| | | width: 100%; |
| | | height: 306px; |
| | | // height: 306px; |
| | | height: pxToVh(316); |
| | | background: rgba(255, 255, 255, 0.41); |
| | | box-shadow: 0px 3px 4px -1px rgba(125, 125, 125, 0.25); |
| | | border-radius: 8px 8px 8px 8px; |
| | | border: 2px solid #ffffff; |
| | | box-sizing: border-box; |
| | | |
| | | .block { |
| | | margin: 11px 21px 13px 22px; |
| | | |
| | | .titleBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .title { |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #363636; |
| | | } |
| | | |
| | | .rightTab { |
| | | display: flex; |
| | | text-align: center; |
| | | padding-right: 10px; |
| | | |
| | | .titleItem { |
| | | position: relative; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | margin-left: 18px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .activeItem { |
| | | border-radius: 0px 0px 0px 0px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #1c5cff; |
| | | border-bottom: 2px solid #1c5cff; |
| | | } |
| | | |
| | | .dots { |
| | | width: 17px; |
| | | // height: 17px; |
| | | height: pxToVh(17); |
| | | border-radius: 50%; |
| | | background: #366fff; |
| | | color: #fff; |
| | | font-size: 9px; |
| | | position: absolute; |
| | | top: -10px; |
| | | right: -13px; |
| | | padding: 1px; |
| | | line-height: 17px; |
| | | } |
| | | |
| | | .dots1 { |
| | | width: 17px; |
| | | // height: 17px; |
| | | height: pxToVh(17); |
| | | border-radius: 50%; |
| | | background: none !important; |
| | | color: #366fff !important; |
| | | font-size: 9px; |
| | | position: absolute; |
| | | top: -10px; |
| | | right: -13px; |
| | | padding: 1px; |
| | | line-height: 17px; |
| | | } |
| | | } |
| | | |
| | | .todo-items { |
| | | display: grid; |
| | | gap: 0.8rem; |
| | | margin-top: 10px; |
| | | transition: opacity 0.3s ease; |
| | | height: pxToVh(250); |
| | | overflow-y: scroll; |
| | | &:empty { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .todo-item { |
| | | transition: |
| | | transform 0.2s ease, |
| | | box-shadow 0.2s ease, |
| | | opacity 0.3s ease; |
| | | margin: 6px 0; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | background: #FFFFFF; |
| | | cursor: pointer; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | box-shadow: 0px 2px 4px 0px rgba(173, 173, 173, 0.18); |
| | | transition: all 0.2s ease; |
| | | border-left: 4px solid transparent; |
| | | height: 42px; |
| | | // height: 42px; |
| | | height: pxToVh(42); |
| | | |
| | | &:hover { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 3px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .status-indicator { |
| | | margin-left: 18px; |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | flex-shrink: 0; |
| | | margin-left: 3px; |
| | | width: 1.6rem; |
| | | height: 1.6rem; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | |
| | | .content-wrapper { |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | gap: 1rem; |
| | | // gap: 1rem; |
| | | } |
| | | |
| | | .main-content { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 0.8rem; |
| | | // gap: 0.8rem; |
| | | |
| | | .status-tag { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | |
| | | padding: 0.3rem 0.5rem; |
| | | margin-left: 2px; |
| | | // padding: 0.3rem 0; |
| | | border-radius: 12px; |
| | | } |
| | | |
| | | .todo-text { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #343434; |
| | | color: #5C6476; |
| | | } |
| | | |
| | | .unread { |
| | | width: 5px; |
| | | height: 5px; |
| | | background: #1c5cff !important; |
| | | border-radius: 50%; |
| | | margin: 0 4px; |
| | | } |
| | | |
| | | .reads { |
| | | width: 5px; |
| | | height: 5px; |
| | | background: transparent; |
| | | border-radius: 50%; |
| | | margin: 0 4px; |
| | | } |
| | | } |
| | | |
| | | .action-area { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-right: 42px; |
| | | margin-right: 42px; |
| | | |
| | | .todo-date { |
| | | color: #666; |
| | | font-size: 0.9rem; |
| | | img { |
| | | width: 15px; |
| | | height: 15px; |
| | | } |
| | | |
| | | |
| | | } |
| | | } |
| | | |
| | | // 状态颜色方案 |
| | | .status-pending { |
| | | border-left-color: #FF6560; |
| | | color: #FF6560; |
| | | .status-indicator { |
| | | background: #FF6560; |
| | | } |
| | | } |
| | | |
| | | .status-todo { |
| | | border-left-color: #5D77FB; |
| | | color: #5D77FB; |
| | | .status-indicator { |
| | | background: #5D77FB; |
| | | } |
| | | } |
| | | |
| | | .status-processing { |
| | | border-left-color: #FF8B26; |
| | | color: #FF8B26; |
| | | |
| | | .status-indicator { |
| | | background: #FF8B26; |
| | | .todo-date { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #343434; |
| | | margin-left: 2px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // @media (max-width: 768px) { |
| | | // .todo-list-container { |
| | | // padding: 1rem; |
| | | |
| | | // .content-wrapper { |
| | | // flex-direction: column; |
| | | // align-items: flex-start !important; |
| | | // gap: 0.5rem !important; |
| | | // } |
| | | |
| | | // .action-area { |
| | | // width: 100%; |
| | | // justify-content: space-between; |
| | | // } |
| | | // } |
| | | // } |
| | | |
| | | // @media (max-width: 480px) { |
| | | // .main-content { |
| | | // flex-direction: column; |
| | | // align-items: flex-start !important; |
| | | // } |
| | | |
| | | // .status-tag { |
| | | // margin-bottom: 0.3rem; |
| | | // } |
| | | // } |
| | | .custom-text { |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | .el-empty { |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | } |
| | | </style> |