From 446823f71c9f7b867244035433febb3d8fd66573 Mon Sep 17 00:00:00 2001
From: 张含笑 <zhx18749296735@163.com>
Date: Sat, 11 Oct 2025 17:25:17 +0800
Subject: [PATCH] feat:事件工单
---
src/api/work/index.js | 24 ++
src/subPackages/workDetail/index.vue | 247 ++++++++++++++++++++++++++-
src/pages/work/index.vue | 255 ++++++++++++++++++++++------
3 files changed, 456 insertions(+), 70 deletions(-)
diff --git a/src/api/work/index.js b/src/api/work/index.js
new file mode 100644
index 0000000..0658350
--- /dev/null
+++ b/src/api/work/index.js
@@ -0,0 +1,24 @@
+import {request} from "@/utils/index.js";
+export const getList = (data) => {
+ return request({
+ url: '/drone-device-core/jobEvent/eventPage',
+ method: 'post',
+ data,
+ })
+}
+// 获取状态统计数据
+export const getstatusCount = (params) => {
+ return request({
+ url: '/drone-device-core/jobEvent/getstatusCount',
+ method: 'get',
+ params,
+ })
+}
+
+export const getStepInfo = (eventNum) => {
+ return request({
+ url: '/drone-device-core/jobEvent/getStepInfo',
+ method: 'get',
+ params: { eventNum }
+ })
+}
\ No newline at end of file
diff --git a/src/pages/work/index.vue b/src/pages/work/index.vue
index 8682ae9..60f780c 100644
--- a/src/pages/work/index.vue
+++ b/src/pages/work/index.vue
@@ -1,67 +1,208 @@
-<!-- 事件工单 -->
<template>
- <view class="min-h-screen flex flex-col items-center">
- <image
- class="mb-50rpx mt-200rpx h-200rpx w-200rpx"
- src="@/static/images/logo.png"
- width="200rpx"
- height="200rpx"
- />
- <view class="flex justify-center">
- <text class="font-size-36rpx">
- {{ $t("home.intro") }}
- </text>
- </view>
- <view class="mt-100rpx flex gap-30rpx">
- <lang-select />
- <view class="cursor-pointer" @click="toGithub">
- <view class="i-mdi-github text-40rpx" />
- </view>
- </view>
+ <view class="flex flex-col eventTickets">
+ <view class="searchTop">
+ <up-search placeholder="请输入关键字搜索" :animation="true" v-model="listParams.keyword" :show-action="false"></up-search>
+ <div>111</div>
+ </view>
+ <view>
+ <up-tabs :list="tabList" @click="handleClick"></up-tabs>
+ <view class="eventBox">
+ <view class="eventItem" v-for="(item,index) in dataList" :key="index">
+ <img :src="item.photo_url" alt="" @click="detailHandle(item)" />
+ <div class="itemTitle">{{item.event_name}}</div>
+ <div class="itemContent">
+ <div class="itemStatus">
+ <span v-if="item.status === 0" style="background-color: #ff7411;"></span>
+ <span v-else-if="item.status === 2" style="background-color: #ff472f;"></span>
+ <span v-else-if="item.status === 3" style="background-color: #ffc300;"></span>
+ <span v-else-if="item.status === 4" style="background-color: #06d957;"></span>
+ <p>{{formatDate(item.create_time) }}</p>
+ </div>
+ <div>全屏</div>
+ </div>
+ </view>
+ </view>
+ </view>
+ </view>
- <!-- #ifdef MP-WEIXIN -->
- <!-- 隐私协议组件 -->
- <agree-privacy
- v-model="showAgreePrivacy"
- :disable-check-privacy="false"
- @agree="handleAgree"
- />
- <!-- #endif -->
- </view>
</template>
<script setup>
-// #ifdef MP-WEIXIN
-import { useShare } from "@/hooks";
-// #endif
-// #ifdef MP-WEIXIN
-// 分享使用示例
-const { onShareAppMessage, onShareTimeline } = useShare({
- title: "首页",
- path: "pages/tab/map/index",
- imageUrl: "",
-});
-onShareAppMessage();
-onShareTimeline();
-// #endif
+import {getList,getstatusCount} from '/src/api/work/index.js'
+ import dayjs from 'dayjs';
+ const dataList = ref([])
+ const keyword = ref('')
+ const tabList = ref([{
+ name: '我的工单',
+ key: 'myTickets',
+ badge: {
+ value: 1
+ }
+ },
+ {
+ name: '全部状态',
+ key: 'all',
+ badge: {
+ value: 2
+ },
+ status: null
+ },
+ {
+ name: '待审核',
+ key: 'pending',
+ badge: {
+ value: 3
+ },
+ status: '2'
+ },
+ {
+ name: '待处理',
+ key: 'processing',
+ badge: {
+ value: 4
+ },
+ status: '0'
+ },
+ {
+ name: '处理中',
+ key: 'inProgress',
+ badge: {
+ value: 5
+ },
+ status: '3'
+ },
+ {
+ name: '已完成',
+ key: 'completed',
+ badge: {
+ value: 6
+ },
+ status: '4'
+ }
+ ])
+ const formatDate = (dateString) => {
+ return dayjs(dateString).format('MM/DD HH:mm');
+ };
+ const listParams = ref({
+ status: null,
+ current: 1,
+ size: 9999,
+ source: 1,
+ department:'',
+ keyword:''
-const title = ref();
-title.value = import.meta.env.VITE_APP_TITLE;
+ })
+ const getDataList = () => {
+ const params = {
+ current: 1,
+ size: 9999,
+ source: 1,
+ status:listParams.value.status,
+ event_name:listParams.value.keyword
+ }
+ getList(params).then(res => {
+
+ const response = res.data.data.records
+ dataList.value = response
+ })
+ }
+ const getstatusCountData=()=>{
+ getstatusCount().then(res=>{
+ const response = res.data.data
+ const { statusCount, totalCount, userCount } = response
+ tabList.value.forEach(tab=>{
+
+ if(tab.key === 'all'){
+ tab.badge.value = totalCount || 0
-const showAgreePrivacy = ref(false);
+ }else if(tab.key === 'myTickets'){
+ tab.badge.value = userCount || 0
+ }else{
+ tab.badge.value=statusCount[String(tab.status)] || 0
+ }
+ })
+
+ })
+ }
-// 同意隐私协议
-function handleAgree() {
- console.log("同意隐私政策");
-}
-
-// 打开github
-function toGithub() {
- if (window?.open) {
- window.open("https://github.com/oyjt/uniapp-vue3-template");
- } else {
- uni.$u.toast("请使用浏览器打开");
- }
-}
+ const handleClick = (item) => {
+ listParams.value.status = item.status
+ getDataList()
+ }
+ const detailHandle = (val) => {
+ uni.navigateTo({
+ url: `/subPackages/workDetail/index?eventNum=${val.event_num}`,
+ })
+ }
+ onShow(() => {
+ getDataList()
+ getstatusCountData()
+ })
</script>
+
+<style scoped lang="scss">
+ .eventTickets {
+ padding: 0 10px;
+
+ .searchTop {
+ display: flex;
+ align-items: center;
+ margin-top: 10px;
+ }
+
+ :deep(.u-badge) {
+ background-color: #1d6fe9 !important;
+ }
+
+ .eventBox {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ padding: 10px 0;
+ background-color: #ebeff2;
+
+ .eventItem {
+ width: calc(50% - 5px);
+ background-color: #fff;
+ border-radius: 5px;
+ overflow: hidden;
+
+ img {
+ width: 100%;
+ height: 100px;
+ border-radius: 5px;
+ overflow: hidden;
+ }
+
+ .itemTitle {
+ padding: 0 5px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .itemContent {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+
+ .itemStatus {
+ display: flex;
+ align-items: center;
+
+ span {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ margin-right: 5px;
+ }
+ }
+
+ }
+ }
+ }
+ }
+</style>
\ No newline at end of file
diff --git a/src/subPackages/workDetail/index.vue b/src/subPackages/workDetail/index.vue
index 7a6c92d..dedac24 100644
--- a/src/subPackages/workDetail/index.vue
+++ b/src/subPackages/workDetail/index.vue
@@ -1,18 +1,239 @@
-<!--
- * @Author : yuan
- * @Date : 2025-09-29 13:52:16
- * @LastEditors : yuan
- * @LastEditTime : 2025-09-29 13:53:32
- * @FilePath : \src\subPackages\workDetail\index.vue
- * @Description :
- * Copyright 2025 OBKoro1, All Rights Reserved.
- * 2025-09-29 13:52:16
--->
<!-- 工单详情 - 包含待审核、待处理、处理中、已完成 -->
<template>
- <view> 基础 </view>
+ <view class="workDetailContainer">
+ <div class="detailTop">
+ <div class="image-container">
+ <u-image class="detailImage" :src="workDetailData.photo_url" mode="cover" width="100%" height="200px"
+ @click="previewImage(workDetailData.photo_url)"></u-image>
+ <div class="detailTitle">
+ <div class="titleText">
+ <p>{{workDetailData.event_name}}</p>
+ <p>{{workDetailData.create_time}}</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- 步骤条 -->
+ <div class="stepContainer">
+ <up-steps :current="currentStep" direction="column">
+ <up-steps-item
+ v-for="(step, index) in stepTitles"
+ :key="index"
+ >
+ <template #title>
+ <div class="horizontal-step">
+ <span class="step-title">{{ step.title }}</span>
+ <div class="step-desc" v-if="stepResponse[index]">
+ <span>{{ stepResponse[index].name || '' }}</span>
+ <span>{{ stepResponse[index].create_time || '' }}</span>
+ </div>
+ </div>
+ </template>
+ </up-steps-item>
+ </up-steps>
+ </div>
+ <!-- 工单内容 -->
+ <div class="workOrderContent">
+ <div class="workOrderTitle">工单内容</div>
+ <div class="workOrderContainer">
+ <div>工单名称:{{workDetailData.event_name}}</div>
+ <div>工单类型:{{workDetailData.$type}}</div>
+ <div>关联任务:{{workDetailData.job_name}}</div>
+ <div>工单创建人:{{workDetailData.creator}}</div>
+ <div>事件地址:{{workDetailData.address}}</div>
+ <div>关联算法:{{workDetailData.ai_types}}</div>
+ <div>发起部门:{{workDetailData.dept_name}}</div>
+ <div>发起任务时间:{{workDetailData.create_time}}</div>
+ <div>工单内容:{{workDetailData.remark}}</div>
+ </div>
+ </div>
+ <!-- 操作按钮 -->
+ <div class="actionButton">
+ <div class="leftBtn" @click="leftClick">
+ 上一页
+ </div>
+ <div class="btngroups">
+ <up-button type="primary" text="通过"></up-button>
+ <up-button type="error" text="不通过"></up-button>
+ </div>
+ <div class="leftBtn" @click="rightClick">
+ 下一页
+ </div>
+ </div>
+
+ </view>
</template>
-<script setup></script>
+<script setup>
+ import {getStepInfo,getList} from '/src/api/work/index.js'
+ const eventNum = ref('');
+ const currentStatus = ref('')
+ const stepResponse = ref([]);
+ const currentStep = ref(0);
+ // 工单内容
+ const workDetailData = ref({})
+ const stepTitles =ref([
+ {
+ title: '待审核',
+ status: '2'
+ },
+ {
+ title: '待处理',
+ status: '0'
+ },
+
+ {
+ title: '处理中',
+ status: '3'
+ },{
+ title: '已完成',
+ status: '4'
+ }
+ ])
+ onLoad(async (options) => {
+ eventNum.value = options.eventNum;
+ await getDataList(eventNum.value);
+ await getStepInfoData(eventNum.value);
+ });
+ const getDataList = async (val) => {
+ const params = {
+ current: 1,
+ size: 9999,
+ source: 1,
+ event_name: val
+ }
+ const res = await getList(params);
+ const response = res.data.data.records;
+ workDetailData.value = response[0];
+ currentStatus.value = workDetailData.value.status;
+
+ }
+ // 步骤条
+ const calculateCurrentStep = (status) => {
+ const statusToStep = {
+ '2': 0, // 待审核 -> 第0步
+ '0': 1, // 待处理 -> 第1步
+ '3': 2, // 处理中 -> 第2步
+ '4': 3 // 已完成 -> 第3步
+ }
+ return statusToStep[String(status)] || 0
+ }
+ const getStepInfoData = async (val) => {
+ const res = await getStepInfo(val);
+ stepResponse.value = res.data.data;
+ currentStep.value = calculateCurrentStep(currentStatus.value);
+ }
+ // 图片预览
+ const previewImage = (url) => {
+ uni.previewImage({
+ urls: [url],
+ current: 0
+ });
+ };
+</script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+ .workDetailContainer {
+ padding: 0 10px;
+
+ .detailTop {
+ .image-container {
+ position: relative;
+ width: 100%;
+ height: 200px;
+
+ .detailImage {
+ width: 100%;
+ height: 100%;
+ display: block;
+ object-fit: cover
+ }
+
+ .detailTitle {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ }
+
+ .titleText {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ align-items: center;
+ }
+ }
+ }
+
+ .stepContainer {
+ margin-top: 10px;
+ display: flex;
+ background-color: aquamarine;
+ border-radius: 5px;
+ padding: 10px;
+ .horizontal-step {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .step-title {
+ min-width: 60px;
+ }
+
+ .step-desc {
+ display: flex;
+ justify-content: space-around;
+ gap: 8px;
+ // color: #666;
+ font-size: 14px;
+ }
+ }
+
+ }
+
+
+ .actionButton{
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ .btngroups {
+ display: flex;
+ justify-content: space-between;
+ .u-button {
+ padding: 9px 20px;
+ height: 32px;
+ &:last-child {
+ margin-left: 12px;
+ margin-right: 12px;
+ }
+ }
+ }
+ .leftBtn {
+ width: 70px;
+ height: 32px;
+ background-color: #999;
+ border-radius: 5px;
+ text-align: center;
+ line-height: 32px;
+ color: #fff;
+ cursor: pointer;
+ opacity: 0.8;
+ }
+ .disableds {
+ background: #999 !important;
+ cursor: not-allowed !important;
+ pointer-events: none;
+ opacity: 0.3 !important;
+ }
+ }
+ .workOrderContent {
+ margin-top: 15px;
+ .workOrderContainer {
+ div {
+ margin-bottom: 10px;
+ }
+ }
+ }
+
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3