Browse Source

feature : 上报问题,上报服务基础接口调试通

梦辉 1 tháng trước cách đây
mục cha
commit
667c0e90ce

+ 1 - 1
.env.development

@@ -1 +1 @@
-VITE_STORAGE_NAMESPACE=dev/vote-wechat
+VITE_STORAGE_NAMESPACE=dev/jiangbei

+ 1 - 1
.env.production

@@ -1 +1 @@
-VITE_STORAGE_NAMESPACE=prod/vote-wechat
+VITE_STORAGE_NAMESPACE=prod/jiangbei

+ 1 - 0
components.d.ts

@@ -8,6 +8,7 @@ export {}
 declare module 'vue' {
   export interface GlobalComponents {
     VanButton: typeof import('vant/es')['Button']
+    VanCascader: typeof import('vant/es')['Cascader']
     VanCell: typeof import('vant/es')['Cell']
     VanCellGroup: typeof import('vant/es')['CellGroup']
     VanDivider: typeof import('vant/es')['Divider']

+ 29 - 0
src/api/questionReqort/index.ts

@@ -0,0 +1,29 @@
+import { service } from '@/utils/request'
+import { AddQuestionReportDataReq, PageQuestionReportDataReq, QuestionDetailRes, QuestionListRes } from './types'
+import { ApiResponse, PageReq, PageResp } from '../types'
+export enum questionApi {
+  /** 新增上报问题  */
+  ADD_QUESTION_REPORT_DATA = '/questionReport/addQuestionReportData',
+  /** 上报问题列表  */
+  QUESTION_REPORT_LIST = '/questionReport/pageQuestionReportData',
+  /** 上报问题详情
+   * /questionReport/detailsQuestionReportData/{uuid}
+   */
+  QUESTION_REPORT_DETAIL = '/questionReport/detailsQuestionReportData',
+}
+
+/** 新增上报问题  */
+export const addQuestionReportData = (data: AddQuestionReportDataReq) => {
+  return service.post<ApiResponse<boolean>>(questionApi.ADD_QUESTION_REPORT_DATA, data)
+}
+
+/** 上报问题列表 */
+export const pageQuestionReportData = (params: PageQuestionReportDataReq) => {
+  return service.get<ApiResponse<PageResp<QuestionListRes>>>(questionApi.QUESTION_REPORT_LIST, { params })
+}
+
+
+/** 上报问题详情 */
+export const getQuestionReportDetail = (id: string) => {
+  return service.get<ApiResponse<QuestionDetailRes>>(questionApi.QUESTION_REPORT_DETAIL + '/' + id)
+}

+ 100 - 0
src/api/questionReqort/types.ts

@@ -0,0 +1,100 @@
+import { PageReq } from '../types'
+
+/** 新增上报问题req */
+export interface AddQuestionReportDataReq {
+  /**
+   * 地址名称
+   */
+  addrName?: string
+  /**
+   * 纬度
+   */
+  latitude?: string
+  /**
+   * 经度
+   */
+  longitude?: string
+  /**
+   * 问题内容
+   */
+  questionContent?: string
+  /**
+   * 问题标题
+   */
+  questionTitle?: string
+  /**
+   * 问题类型
+   */
+  questionType?: string
+}
+
+/** 上报问题列表req */
+export interface PageQuestionReportDataReq extends PageReq {
+  /**
+   * 问题标题
+   */
+  questionTitle?: string
+  /**
+   * 问题类型
+   */
+  questionType?: string
+  /**
+   * 发布状态(0待解答;1已解答)
+   */
+  status?: number
+  /**
+   * 发布时间
+   */
+  createTime?: number
+}
+
+/** 问题列表res */
+export interface QuestionListRes {
+  uuid: string
+  questionType: string
+  questionTitle: string
+  questionContent: string
+  longitude: string
+  latitude: string
+  addrName: string
+  status: number
+  expandStr: string
+  createUser: string
+  createTime: number
+  updateUser: string
+  updateTime: string
+  isDelete: number
+  questionAnswer: string
+}
+
+/** 问题详情res */
+export interface QuestionDetailRes {
+  /**
+   * 地址名称
+   */
+  addrName: string
+  /**
+   * 时间
+   */
+  createTime: number
+  /**
+   * 问题内容
+   */
+  questionContent: string
+  /**
+   * 问题标题
+   */
+  questionTitle: string
+  /**
+   * 问题类型
+   */
+  questionType: string
+  /**
+   * 主键id
+   */
+  uuid: string
+  /** 发布状态(0待解答;1已解答) */
+  status: 0 | 1
+  /** 问题解答 */
+  questionAnswer:string
+}

+ 28 - 0
src/api/reportService/index.ts

@@ -0,0 +1,28 @@
+import { service } from '@/utils/request'
+import { addReportServiceDataReq, PageServiceReportDataReq, ReportServiceRes } from './types'
+import { ApiResponse, PageResp } from '../types'
+
+export enum reportAPi {
+  /** 新增上报服务 */
+  ADD_SERVICE_REPORT_DATA = '/serviceReport/addServiceReportData',
+  /** 上报服务列表 */
+  SERVICE_REPORT_LIST = '/serviceReport/pageServiceReportData',
+  /** 上报服务详情 */
+  // /serviceReport/detailsServiceReportData/{uuid}
+  SERVICE_REPORT_DETAIL = '/serviceReport/detailsServiceReportData',
+}
+
+/** 新增上报服务 */
+export const addServiceReportData = (data: Partial<addReportServiceDataReq>) => {
+  return service.post<ApiResponse<boolean>>(reportAPi.ADD_SERVICE_REPORT_DATA, data)
+}
+
+/** 上报服务列表 */
+export const pageServiceReportData = (params: PageServiceReportDataReq) => {
+  return service.get<ApiResponse<PageResp<ReportServiceRes>>>(reportAPi.SERVICE_REPORT_LIST, { params })
+}
+
+/** 上报服务详情 */
+export const getServiceReportDetail = (uuid: string) => {
+  return service.get<ApiResponse<ReportServiceRes>>(reportAPi.SERVICE_REPORT_DETAIL + `/${uuid}`)
+}

+ 80 - 0
src/api/reportService/types.ts

@@ -0,0 +1,80 @@
+import { PageReq } from '../types'
+
+/** 新增上报服务req */
+export interface addReportServiceDataReq {
+  /**
+   * 所在区域
+   */
+  area: string
+  /**
+   * 联系人姓名
+   */
+  contactPerson: string
+  /**
+   * 联系人电话
+   */
+  contactPhone: string
+  /**
+   * 内容
+   */
+  serviceContent: string
+  /**
+   * 所需服务标题
+   */
+  serviceTitle: string
+  /**
+   * 服务类型
+   */
+  serviceType: string
+}
+
+/** 上报服务列表req */
+export interface PageServiceReportDataReq extends PageReq {
+  /**
+   * 所在区域
+   */
+  area?: string
+  endCreateTime?: string
+  /**
+   * 当前页码
+   */
+  pageNumber?: number
+  /**
+   * 每 1 页的数据量
+   */
+  pageSize?: number
+  /**
+   * 所需服务标题
+   */
+  serviceTitle?: string
+  /**
+   * 服务类型
+   */
+  serviceType?: string
+  startCreateTime?: string
+  /**
+   * 状态(0:待回复1:已回复)
+   */
+  status?: string
+}
+
+
+/** 上报服务列表resp */
+export interface ReportServiceRes {
+  uuid: string
+  serviceType: number
+  serviceTitle: string
+  area: string
+  contactPerson: string
+  contactPhone: string
+  status: number
+  areaCode: string
+  serviceContent: string
+  expandStr: string
+  createUser: string
+  createTime: number
+  updateUser: string
+  updateTime: string
+  isDelete: number
+  serviceAnswer: string
+}

+ 14 - 10
src/api/types.ts

@@ -1,13 +1,12 @@
-import {BusinessErrCode, ErrCode} from "@/utils/request/errcode";
+import { BusinessErrCode, ErrCode } from '@/utils/request/errcode'
 
 /**
  * 接口响应类型
  */
 export interface ApiResponse<T = null> {
-  code: BusinessErrCode | ErrCode;
-  data: T;
-  msg: string;
-  success: boolean;
+  code: BusinessErrCode | ErrCode
+  data: T
+  msg: string
 }
 
 /**
@@ -23,8 +22,13 @@ export interface ApiResponse<T = null> {
  *     }
  */
 export interface PageResp<T> {
-    result: T[];
-    total: number;
+  records: T[]
+  /** 单页数据数量 */
+  pageSize: number
+  /** 当前页码 */
+  pageNumber: number
+  totalPage: number
+  totalRow: number
 }
 
 /**
@@ -40,6 +44,6 @@ export interface PageResp<T> {
  * }
  */
 export interface PageReq {
-    page?: number;
-    size?: number;
-}
+  pageNumber?: number
+  pageSize?: number
+}

+ 6 - 6
src/config/proxy.ts

@@ -1,12 +1,12 @@
 import { ProxyOptions } from 'vite'
 
 const proxy: Record<string, string | ProxyOptions> = {
-    /** 请求的后端地址  */
-    '/api': {
-        target: 'https://apifoxmock.com/m1/4859341-4514943-default',
-        changeOrigin: true,
-        rewrite: (path) => path.replace(/^\/api/, '')
-    }
+  /** 请求的后端地址  */
+  '/api': {
+    target: 'http://192.168.3.72:8081/',
+    changeOrigin: true,
+    rewrite: (path) => path.replace(/^\/api/, ''),
+  },
 }
 
 export default proxy

+ 25 - 1
src/pages.json

@@ -18,10 +18,34 @@
           }
         },
         {
-          "path": "pages/reportProblems/questDetail",
+          "path": "pages/reportProblems/detail",
           "style": {
             "navigationBarTitleText": "问题详情"
           }
+        },
+        {
+          "path": "pages/reportServer/index",
+          "style": {
+            "navigationBarTitleText": "上报服务"
+          }
+        },
+        {
+          "path": "pages/reportServer/detail",
+          "style": {
+            "navigationBarTitleText": "服务详情"
+          }
+        },
+        {
+          "path": "pages/inspectionResults/index",
+          "style": {
+            "navigationBarTitleText": "检查结果"
+          }
+        },
+        {
+          "path": "pages/my/index",
+          "style": {
+            "navigationBarTitleText": "我的"
+          }
         }
       ]
     }

+ 3 - 3
src/pages/index/index.vue

@@ -3,9 +3,9 @@
 <template>
   <view class="container">
     <navigator url="/subPages/pages/reportProblems/index">上报问题</navigator>
-    <navigator url="/pages/somepage/somepage">上报服务</navigator>
-    <navigator url="/pages/somepage/somepage">店铺/企业检查结果</navigator>
-    <navigator url="/pages/somepage/somepage">我的管理</navigator>
+    <navigator url="/subPages/pages/reportServer/index">上报服务</navigator>
+    <navigator url="/subPages/pages/inspectionResults/index">店铺/企业检查结果</navigator>
+    <navigator url="/subPages/pages/my/index">我的管理</navigator>
   </view>
 </template>
 

+ 38 - 0
src/subPages/pages/inspectionResults/index.vue

@@ -0,0 +1,38 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const loading = ref(false)
+const finished = ref(false)
+const list = ref([])
+const onLoad = () => {
+  loading.value = true
+  setTimeout(() => {
+    for (let i = 0; i < 10; i++) {
+      list.value.push('列表' + list.value.length)
+    }
+    loading.value = false
+    if (list.value.length >= 40) {
+      finished.value = true
+    }
+  }, 500)
+}
+
+const handleGoDetail = () => {
+  uni.navigateTo({
+    url: '/subPages/pages/reportProblems/questDetail',
+  })
+}
+</script>
+
+<template>
+  <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
+    <view>
+      <view class="top">
+        <view class="title">xxxx</view>
+        <van-button plain hairline size="mini" type="primary" @click="handleGoDetail">查看详情</van-button>
+      </view>
+    </view>
+  </van-list>
+</template>
+
+<style lang="scss" scoped></style>

+ 19 - 0
src/subPages/pages/my/index.vue

@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { ref } from 'vue'
+
+const form = ref({})
+</script>
+
+<template>
+  <view class="pt-[12px]">
+    <van-form>
+      <van-cell-group inset>
+        <van-field label="姓名" :model-value="form.name" readonly />
+        <van-field label="身份证号" :model-value="form.idCard" readonly />
+        <van-field label="手机号码" :model-value="form.phone" readonly />
+      </van-cell-group>
+    </van-form>
+  </view>
+</template>
+
+<style lang="scss" scoped></style>

+ 65 - 0
src/subPages/pages/reportProblems/detail.vue

@@ -0,0 +1,65 @@
+<script lang="ts" setup>
+import { getQuestionReportDetail } from '@/api/questionReqort';
+import { QuestionDetailRes } from '@/api/questionReqort/types';
+import { onLoad } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+
+const questDetail = ref<QuestionDetailRes>()
+onLoad(async (option) => {
+  if (option && option.id) {
+    const { id } = option;
+    const { data } = await getQuestionReportDetail(id);
+    questDetail.value = data;
+  }
+})
+</script>
+
+<template>
+  <view class="p-[20px]">
+    <view class="form-item">
+      <view class="label">问题类型:</view>
+      <view class="flex value">
+        <view class="value">{{ questDetail?.questionType }}</view>
+        <van-tag v-if="questDetail?.status === 0" color="red">未解答</van-tag>
+        <van-tag v-if="questDetail?.status === 1" color="green">已解答</van-tag>
+      </view>
+    </view>
+    <!-- 问题标题 -->
+    <view class="form-item">
+      <view class="label">问题标题:</view>
+      <view class="value">{{ questDetail?.questionTitle }}</view>
+    </view>
+    <!-- 问题内容 -->
+    <view class="form-item">
+      <view class="label">问题内容:</view>
+      <view class="value">{{ questDetail?.questionContent }}</view>
+    </view>
+    <!-- 问题所在地 -->
+    <view class="form-item">
+      <view class="label">问题所在地:</view>
+      <view class="value">{{ questDetail?.addrName }}</view>
+    </view>
+    <van-divider></van-divider>
+    <!-- 问题解答 -->
+    <view class="form-item">
+      <view class="label">问题解答:</view>
+      <view class="value" v-if="questDetail?.questionAnswer">{{ questDetail?.questionAnswer }}</view>
+      <view class="value text-[#e3e3e3]" v-else>暂无</view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.form-item {
+  display: flex;
+  align-items: center;
+  padding: 10px;
+  .label {
+    width: 100px;
+  }
+  .value {
+    flex: 1;
+  }
+}
+</style>

+ 62 - 67
src/subPages/pages/reportProblems/index.vue

@@ -1,58 +1,60 @@
 <script lang="ts" setup>
+import { addQuestionReportData, pageQuestionReportData } from '@/api/questionReqort';
+import { AddQuestionReportDataReq, QuestionListRes } from '@/api/questionReqort/types'
 import { ref } from 'vue'
 
 const active = ref(0)
 
-const formData = ref({})
-const range = ref([
-  {
-    text: '功能问题',
-    value: '1',
-  },
-  {
-    text: '界面问题',
-    value: '2',
-  },
-  {
-    text: '其他问题',
-    value: '3',
-  },
-])
-/**
- * 上传图片
- */
-const imageValue = ref([])
-const select = (e) => {}
-const progress = (e) => {
-  console.log(e)
-}
-const success = (e) => {
-  console.log(e)
-}
-const fail = (e) => {
-  console.log(e)
-}
+const formData = ref<AddQuestionReportDataReq & { location?: string }>({})
+const range = ref([])
+const rules = ref({
+  type: [{ required: true, message: '请选择问题类型' }],
+  title: [{ required: true, message: '请输入问题标题' }],
+  content: [{ required: true, message: '请输入问题内容' }],
+  location: [{ required: true, message: '请输入问题所在地' }],
+})
 
-const submit = () => {
-  console.log(formData.value)
+/** 上报问题 */
+const submit = async () => {
+  const { data } = await addQuestionReportData(formData.value)
+  if (data) {
+    uni.showToast({
+      title: '上报成功',
+      icon: 'success',
+      duration: 1000,
+    })
+    formData.value = {}
+  }
 }
 
 /**
  * 已上报问题
  */
-const list = ref([])
-const onLoad = () => {
-  list.value.push('列表')
+const list = ref<QuestionListRes[]>([])
+const pageInfo = ref({
+  pageNumber: 1,
+  pageSize: 10,
+})
+const questList = async () => {
+  const { data } = await pageQuestionReportData({
+    pageNumber: pageInfo.value.pageNumber,
+    pageSize: pageInfo.value.pageSize,
+  })
+  list.value = list.value.concat(data.records)
+  pageInfo.value.pageNumber++
+  finished.value = data.records.length < pageInfo.value.pageSize
+  loading.value = false
+  if (data.records.length === 0 || !data.records) {
+    finished.value = true
+  }
 }
 const loading = ref(false)
 const finished = ref(false)
 
-
-
 /** 跳转问题详情 */
-const handleGoDetail = () => {
+const handleGoDetail = (item: QuestionListRes) => {
   uni.navigateTo({
-    url: '/subPages/pages/reportProblems/questDetail',
+    url: `/subPages/pages/reportProblems/detail?id=${item.uuid}`,
   })
 }
 
@@ -62,51 +64,38 @@ const handleGoDetail = () => {
   <van-tabs v-model:active="active" type="card" class="top-tabs">
     <van-tab title="上报问题">
       <view class="tab-container">
-        <uni-forms :modelValue="formData">
-          <uni-forms-item label="问题类型" name="type">
-            <uni-data-select v-model="formData.type" :localdata="range"></uni-data-select>
+        <uni-forms :modelValue="formData" :rules="rules" label-align="right" label-width="80">
+          <uni-forms-item label="问题类型" required name="questionType">
+            <uni-data-select v-model="formData.questionType" :localdata="range"></uni-data-select>
           </uni-forms-item>
           <!-- 问题标题 -->
-          <uni-forms-item label="问题标题" name="title">
-            <uni-easyinput v-model="formData.title" placeholder="请输入问题标题"></uni-easyinput>
+          <uni-forms-item label="问题标题" required name="questionTitle">
+            <uni-easyinput v-model="formData.questionTitle" placeholder="请输入问题标题"></uni-easyinput>
           </uni-forms-item>
           <!-- 问题内容 -->
-          <uni-forms-item label="问题内容" name="content">
-            <uni-easyinput v-model="formData.content" type="textarea" placeholder="请输入问题内容"></uni-easyinput>
+          <uni-forms-item label="问题内容" required name="questionContent">
+            <uni-easyinput v-model="formData.questionContent" type="textarea" placeholder="请输入问题内容"></uni-easyinput>
           </uni-forms-item>
           <!-- 问题所在地 -->
-          <uni-forms-item label="问题所在地" name="location">
-            <uni-easyinput v-model="formData.location" placeholder="请输入问题所在地"></uni-easyinput>
-          </uni-forms-item>
-          <!-- 上传附件 -->
-          <uni-forms-item label="上传附件" name="attachment">
-            <uni-file-picker
-              v-model="imageValue"
-              fileMediatype="image"
-              mode="grid"
-              @select="select"
-              @progress="progress"
-              @success="success"
-              @fail="fail"
-            />
-            <view class="mt-[10px]">支持上传jpg、png、jpeg、pdf的格式</view>
+          <uni-forms-item label="问题所在地" required name="addrName">
+            <uni-easyinput v-model="formData.addrName" placeholder="请输入问题所在地"></uni-easyinput>
           </uni-forms-item>
         </uni-forms>
-        <van-button type="primary" @click="submit">提交</van-button>
+        <van-button class="w-full mb-3" type="primary" @click="submit">提交</van-button>
       </view>
     </van-tab>
     <van-tab title="已上报问题">
       <view class="tab-container">
-        <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
-          <view class="list-item-style">
+        <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="questList">
+          <view  v-for="item in list" :key="item.uuid"  class="list-item-style">
             <view class="top">
-              <view class="title">xxx</view>
-              <van-button plain hairline size="mini" type="primary" @click="handleGoDetail">查看详情</van-button>
+              <view class="title">{{ item.questionTitle }}</view>
+              <van-button plain hairline size="mini" type="primary" @click="handleGoDetail(item)">查看详情</van-button>
             </view>
-            <view>定位:xxxx</view>
+            <view>定位:{{ item.addrName }}</view>
             <view class="flex gap-3">
               <view class="type">问题类型</view>
-              <van-tag color="#7232dd">标签</van-tag>
+              <van-tag color="#CFFECE" text-color="black">{{ item.questionType }}</van-tag>
             </view>
           </view>
         </van-list>
@@ -123,8 +112,14 @@ const handleGoDetail = () => {
 }
 .tab-container {
   padding: 20px;
+  padding-bottom: 30px;
   min-height: calc(100vh - var(--van-tabs-card-height));
   box-sizing: border-box;
+   display: flex;
+   flex-direction: column;
+  > uni-view:first-child {
+    flex: 1;
+  }
 }
 .list-item-style {
   padding: 20px;

+ 0 - 53
src/subPages/pages/reportProblems/questDetail.vue

@@ -1,53 +0,0 @@
-<script lang="ts" setup></script>
-
-<template>
-  <view class="p-[20px]">
-    <view class="form-item">
-      <view class="label">问题类型:</view>
-      <view class="flex value">
-        <view class="value">xx</view>
-        <van-tag color="#7232dd">xx</van-tag>
-      </view>
-    </view>
-    <!-- 问题标题 -->
-    <view class="form-item">
-      <view class="label">问题标题:</view>
-      <view class="value">xx</view>
-    </view>
-    <!-- 问题内容 -->
-    <view class="form-item">
-      <view class="label">问题内容:</view>
-      <view class="value">xx</view>
-    </view>
-    <!-- 问题所在地 -->
-    <view class="form-item">
-      <view class="label">问题所在地:</view>
-      <view class="value">xx</view>
-    </view>
-    <!-- 附件 -->
-    <view class="form-item">
-      <view class="label">附件:</view>
-      <view class="value">xx</view>
-    </view>
-    <van-divider></van-divider>
-    <!-- 问题解答 -->
-    <view class="form-item">
-      <view class="label">问题解答:</view>
-      <view class="value">xx</view>
-    </view>
-  </view>
-</template>
-
-<style lang="scss" scoped>
-.form-item {
-  display: flex;
-  align-items: center;
-  padding: 10px;
-  .label {
-    flex: 1;
-  }
-  .value {
-    flex: 1;
-  }
-}
-</style>

+ 66 - 0
src/subPages/pages/reportServer/detail.vue

@@ -0,0 +1,66 @@
+<script lang="ts" setup>
+import { QuestionDetailRes } from '@/api/questionReqort/types';
+import { getServiceReportDetail } from '@/api/reportService';
+import { ReportServiceRes } from '@/api/reportService/types';
+import { onLoad } from '@dcloudio/uni-app';
+import { ref } from 'vue';
+
+
+const reportServiceDetail = ref<ReportServiceRes>()
+onLoad(async (option) => {
+  if (option && option.id) {
+    const { id } = option;
+    const { data } = await getServiceReportDetail(id);
+    reportServiceDetail.value = data;
+  }
+})
+</script>
+
+<template>
+  <view class="p-[20px]">
+    <view class="form-item">
+      <view class="label">问题类型:</view>
+      <view class="flex value">
+        <view class="value">{{ reportServiceDetail?.serviceType }}</view>
+        <van-tag v-if="reportServiceDetail?.status === 0" color="red">未解答</van-tag>
+        <van-tag v-if="reportServiceDetail?.status === 1" color="green">已解答</van-tag>
+      </view>
+    </view>
+    <!-- 问题标题 -->
+    <view class="form-item">
+      <view class="label">问题标题:</view>
+      <view class="value">{{ reportServiceDetail?.serviceTitle }}</view>
+    </view>
+    <!-- 问题内容 -->
+    <view class="form-item">
+      <view class="label">问题内容:</view>
+      <view class="value">{{ reportServiceDetail?.serviceContent }}</view>
+    </view>
+    <!-- 问题所在地 -->
+    <view class="form-item">
+      <view class="label">问题所在地:</view>
+      <view class="value">{{ reportServiceDetail?.area }}</view>
+    </view>
+    <van-divider></van-divider>
+    <!-- 问题解答 -->
+    <view class="form-item">
+      <view class="label">问题解答:</view>
+      <view class="value" v-if="reportServiceDetail?.serviceAnswer">{{ reportServiceDetail?.serviceAnswer }}</view>
+      <view class="value text-[#e3e3e3]" v-else>暂无</view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.form-item {
+  display: flex;
+  align-items: center;
+  padding: 10px;
+  .label {
+    width: 100px;
+  }
+  .value {
+    flex: 1;
+  }
+}
+</style>

+ 203 - 0
src/subPages/pages/reportServer/index.vue

@@ -0,0 +1,203 @@
+<script lang="ts" setup>
+import { addServiceReportData, pageServiceReportData } from '@/api/reportService'
+import { addReportServiceDataReq, ReportServiceRes } from '@/api/reportService/types'
+import { CascaderOption } from 'vant'
+import { ref } from 'vue'
+
+const active = ref(0)
+
+const formData = ref<Partial<addReportServiceDataReq>>({})
+const rules = ref({
+  type: [{ required: true, message: '请选择服务类型' }],
+  title: [{ required: true, message: '请输入服务标题' }],
+  content: [{ required: true, message: '请输入服务内容' }],
+  contactPerson: [{ required: true, message: '请输入联系人' }],
+  contactPhone: [{ required: true, message: '请输入联系电话' }],
+  area: [{ required: true, message: '请选择服务区域' }],
+})
+// 服务类型
+const range = ref([])
+
+const submit = async () => {
+  const { data } = await addServiceReportData(formData.value)
+  if (data) {
+    uni.showToast({
+      title: '上报成功',
+      icon: 'success',
+      duration: 1000,
+    })
+    formData.value = {}
+  }
+}
+
+/**
+ * 已上报问题
+ */
+const list = ref<ReportServiceRes[]>([])
+const loading = ref(false)
+const finished = ref(false)
+const pageInfo = ref({
+  pageNumber: 1,
+  pageSize: 10,
+})
+const reportServiceList = async () => {
+  loading.value = true
+  const { data } = await pageServiceReportData({
+    pageNumber: pageInfo.value.pageNumber,
+    pageSize: pageInfo.value.pageSize,
+  })
+  list.value = list.value.concat(data.records)
+  pageInfo.value.pageNumber++
+  loading.value = false
+  finished.value = data.records.length < pageInfo.value.pageSize
+  if (data.records.length === 0 || !data.records) {
+    finished.value = true
+  }
+}
+
+/** 跳转服务详情 */
+const handleGoDetail = (item: ReportServiceRes) => {
+  uni.navigateTo({
+    url: `/subPages/pages/reportServer/detail?id=${item.uuid}`,
+  })
+}
+
+/** 选择地区 */
+const areaShow = ref(false)
+const options = ref<CascaderOption[]>([
+  {
+    text: '广东省',
+    value: '440000',
+    children: [
+      {
+        text: '广州市',
+        value: '440100',
+        children: [
+          {
+            text: '荔湾区',
+            value: '440103',
+          },
+          {
+            text: '越秀区',
+            value: '440104',
+          },
+        ],
+      },
+    ],
+  },
+])
+const cascaderValue = ref('')
+const onChange = (e) => {
+  console.log(e)
+}
+const onFinish = (e) => {
+  areaShow.value = false
+  console.log(e)
+}
+const hanleSelectArea = () => {
+  console.log('121212')
+  areaShow.value = true
+  console.log('12')
+}
+</script>
+
+<template>
+  <van-tabs v-model:active="active" type="card" class="top-tabs">
+    <van-tab title="上报服务">
+      <view class="tab-container">
+        <uni-forms :modelValue="formData" :rules="rules" label-width="110px" label-align="right">
+          <uni-forms-item label="服务类型" required name="serviceType">
+            <uni-data-select v-model="formData.serviceType" :localdata="range"></uni-data-select>
+          </uni-forms-item>
+          <!-- 问题标题 -->
+          <uni-forms-item label="所需服务标题" required name="serviceTitle">
+            <uni-easyinput v-model="formData.serviceTitle" placeholder="所需服务标题"></uni-easyinput>
+          </uni-forms-item>
+          <!-- 问题内容 -->
+          <uni-forms-item label="所需服务内容" required name="serviceContent">
+            <uni-easyinput v-model="formData.serviceContent" type="textarea" placeholder="所需服务内容"></uni-easyinput>
+          </uni-forms-item>
+          <!-- 问题所在地 -->
+          <uni-forms-item label="所在区域" required name="area">
+            <uni-easyinput :value="formData.area" placeholder="所在区域" @focus="hanleSelectArea"></uni-easyinput>
+            <van-popup v-model:show="areaShow" round position="bottom">
+              <van-cascader
+                v-model="cascaderValue"
+                title="请选择所在地区"
+                :options="options"
+                @close="areaShow = false"
+                @change="onChange"
+                @finish="onFinish"
+              />
+            </van-popup>
+          </uni-forms-item>
+          <!-- 联系人姓名 -->
+          <uni-forms-item label="联系人姓名" required name="contactPerson">
+            <uni-easyinput v-model="formData.contactPerson" placeholder="联系人姓名"></uni-easyinput>
+          </uni-forms-item>
+          <!-- 联系人电话 -->
+          <uni-forms-item label="联系人电话" required name="contactPhone">
+            <uni-easyinput v-model="formData.contactPhone" placeholder="联系人电话"></uni-easyinput>
+          </uni-forms-item>
+        </uni-forms>
+        <van-button type="primary" @click="submit">提交</van-button>
+      </view>
+    </van-tab>
+    <van-tab title="已上报服务">
+      <view class="tab-container">
+        <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="reportServiceList">
+          <view v-for="item in list" :key="item.uuid" class="list-item-style">
+            <view class="top">
+              <view class="title">{{ item.serviceTitle }}</view>
+              <van-button plain hairline size="mini" type="primary" @click="handleGoDetail(item)">查看详情</van-button>
+            </view>
+            <view>定位:{{ item.area }}</view>
+            <view class="flex gap-3">
+              <view class="type">问题类型</view>
+              <van-tag color="#CFFECE" text-color="black">{{ item.serviceType }}</van-tag>
+            </view>
+          </view>
+        </van-list>
+      </view>
+    </van-tab>
+  </van-tabs>
+</template>
+
+<style lang="scss" scoped>
+.top-tabs {
+  :deep(.van-tabs__nav) {
+    margin: 0;
+  }
+}
+.tab-container {
+  padding: 20px;
+  padding-bottom: 30px;
+  min-height: calc(100vh - var(--van-tabs-card-height));
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  > uni-view:first-child {
+    flex: 1;
+  }
+}
+.list-item-style {
+  padding: 20px;
+  margin-bottom: 10px;
+  background-color: white;
+  > view {
+    margin-bottom: 10px;
+  }
+  .top {
+    display: flex;
+    align-items: center;
+    .title {
+      font-size: 20px;
+      font-weight: bold;
+      flex: 1;
+    }
+    .type {
+      margin-right: 10px;
+    }
+  }
+}
+</style>

+ 2 - 2
src/utils/request/responseHandler.ts

@@ -6,12 +6,12 @@ import { showNotify } from 'vant';
 
 
 /**
- * 处理resp.data.success为false的情况
+ * 处理resp.data.code不为200
  *
  * @returns 返回响应success
  */
 export function handleInnerCodeErr(respData:ApiResponse) {
-    if(!respData.success) {
+    if(respData.code !== 200) {
         // 展示默认错误提示信息
         const outMsgInfo = businessErrCodeMsgKV[respData.code as BusinessErrCode]
         if(outMsgInfo) {