bill hace 2 años
padre
commit
ba26ff0311

+ 2 - 2
.eslintrc.json

@@ -2,9 +2,9 @@
   "root": true,
   "rules": {
     //强制使用单引号
-    "quotes": ["error", "single"],
+//    "quotes": ["error", "single"],
     //强制不使用分号结尾
-    "semi": ["error", "never"],
+//    "semi": ["error", "never"],
     // 允许使用{}
     "@typescript-eslint/ban-types": [
       "error",

+ 1 - 1
src/api/instance.ts

@@ -25,7 +25,7 @@ export const {
 } = instance
 
 export const gotoLogin = () => {
-  router.push({ name: RoutesName.login })
+  router.replace({ name: RoutesName.login })
 }
 
 addReqErrorHandler(err => {

BIN
src/assets/images/logo-back.png


+ 2 - 0
src/components.d.ts

@@ -8,6 +8,7 @@ export {}
 declare module '@vue/runtime-core' {
   export interface GlobalComponents {
     AAvatar: typeof import('ant-design-vue/es')['Avatar']
+    ABadge: typeof import('ant-design-vue/es')['Badge']
     AButton: typeof import('ant-design-vue/es')['Button']
     ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
     AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
@@ -25,6 +26,7 @@ declare module '@vue/runtime-core' {
     AMenu: typeof import('ant-design-vue/es')['Menu']
     AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
     AModal: typeof import('ant-design-vue/es')['Modal']
+    APopover: typeof import('ant-design-vue/es')['Popover']
     ARadio: typeof import('ant-design-vue/es')['Radio']
     ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
     ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']

+ 3 - 3
src/layout/sider.vue

@@ -2,7 +2,7 @@
   <a-layout-sider class="sider">
     <h2>
       <!-- 四维工地管家 -->
-      <i class="iconfont icon-logo" />
+      <img src="@/assets/images/logo-back.png" />
     </h2>
 
     <a-menu
@@ -64,8 +64,8 @@ h2 {
   color: #fff;
   // text-align: center;
 
-  i {
-    font-size: 30px;
+  img {
+    width: 80%;
   }
 }
 </style>

+ 1 - 1
src/views/member/columns.ts

@@ -32,7 +32,7 @@ export const memberColumns: ColumnsType<Member> = [
     }
   },
   {
-    title: '绑定号',
+    title: '绑定手机号',
     dataIndex: 'bindAccount',
     key: 'bindAccount'
   },

+ 6 - 3
src/views/member/edit.vue

@@ -41,7 +41,10 @@
       <a-form-item
         name="nickName"
         label="成员名称"
-        :rules="[{ required: true, message: '请输入成员名称' }]"
+        :rules="[
+          { required: true, message: '请输入成员名称' },
+          { max: 50, message: '成员名称最多50字' },
+        ]"
       >
         <a-input
           v-model:value="editMember.nickName"
@@ -61,7 +64,7 @@
           >
         </a-select>
       </a-form-item>
-      <a-form-item name="bindAccount" label="绑定号" :rules="[phoneRule]">
+      <a-form-item name="bindAccount" label="绑定手机号" :rules="[phoneRule]">
         <a-input
           v-model:value="editMember.bindAccount"
           placeholder="请输入当前用户绑定的手机号"
@@ -70,7 +73,7 @@
       <a-form-item
         name="remark"
         label="备注"
-        :rules="[{ required: false, max: 50, message: '备注最多50字' }]"
+        :rules="[{ required: false, max: 200, message: '备注最多200字' }]"
       >
         <a-textarea
           v-model:value.trim="editMember.remark"

+ 4 - 6
src/views/project/detailed.vue

@@ -28,7 +28,7 @@
         <a-tab-pane
           v-for="option in tabOptions"
           :key="option.key"
-          :tab="option.label"
+          :tab="option.label as any"
         />
       </a-tabs>
     </div>
@@ -44,13 +44,12 @@
 </template>
 
 <script setup lang="ts">
-import Simples from '@/components/simples/index.vue'
 import EditProject from './edit.vue'
 import { Modal } from 'ant-design-vue'
 import { HeadPanl, BodyPanl } from '@/layout/panl'
 import { router, RoutesName, routesMetas } from '@/router'
 import { computed, onActivated, onDeactivated, ref, toRef, watch } from 'vue'
-import { useProject, ProjectStatus, useUserStore } from '@/store'
+import { useProject, ProjectStatus } from '@/store'
 import { useRealtime } from '@/hook'
 import { renderModal } from '@/helper'
 import { uploadFile } from '@/api'
@@ -98,16 +97,15 @@ useRealtime(() => {
   const id = Number(router.currentRoute.value.params.id)
   const back = () => router.back()
   if (!id || id < 0) {
-    back()
+    // back()
     throw '错误页面'
   }
-  return projectStore.setCurrent(id).catch(back)
+  return projectStore.setCurrent(id)
 })
 
 watch(
   () => router.currentRoute.value.params,
   params => {
-    console.log(params)
     if (params.id) {
       projectStore.setRoles(Number(params.id))
     }

+ 1 - 0
src/views/project/list.vue

@@ -61,6 +61,7 @@
       <a-button type="primary" @click="createProject">新建项目</a-button>
     </template>
     <a-table
+      :scroll="{ x: '100%', y: 510 }"
       :data-source="list"
       :columns="projectColumns"
       :pagination="pagination"

+ 1 - 0
src/views/scene/columns.ts

@@ -23,6 +23,7 @@ export const sceneColumns: ColumnsType<ProjectScene> = [
   {
     title: '名称',
     dataIndex: 'name',
+    width: '400px',
     key: 'name'
   },
   {

+ 14 - 2
src/views/scene/list.vue

@@ -16,7 +16,19 @@
       :data-source="filterScene"
       :columns="sceneColumns"
       :pagination="pagination"
-    />
+    >
+      <template #bodyCell="{ column, text }">
+        <template v-if="column.dataIndex === 'name'">
+          <template v-if="text.length <= maxNameLength">
+            {{ text }}
+          </template>
+          <a-popover v-else>
+            <template #content>{{ text }}</template>
+            {{text.substring(0, maxNameLength)}}...
+          </a-popover>
+        </template>
+      </template>
+    </a-table>
   </BodyPanlBody>
 </template>
 
@@ -35,7 +47,7 @@ const filterScene = computed(() =>
     scene => !scene.name || scene.name?.includes(filterName.value)
   )
 )
-
+const maxNameLength = 50
 const pagination = reactive({
   current: 1,
   total: filterScene.value.length,

+ 7 - 9
src/views/scene/select-scenes.vue

@@ -3,7 +3,7 @@
     <a-tab-pane
       v-for="option in tabOptions"
       :key="option.key"
-      :tab="option.label"
+      :tab="option.label as any"
     />
   </a-tabs>
   <a-input-search
@@ -44,14 +44,12 @@ const emit = defineEmits<{
   (e: 'update:typeNums', value: SelectTypeScenes): void
 }>()
 
-const tabOptions = [
-  SceneType.SWKJ,
-  SceneType.SWKK,
-  SceneType.SWSS
-].map(type => ({
-  key: type,
-  label: SceneTypeDesc[type]
-}))
+const tabOptions = [SceneType.SWKJ, SceneType.SWKK, SceneType.SWSS].map(
+  type => ({
+    key: type,
+    label: SceneTypeDesc[type]
+  })
+)
 
 const defaultTypeNums = { ...props.typeNums }
 const sceneName = ref('')

+ 79 - 36
src/views/taggings/list.vue

@@ -1,18 +1,22 @@
 <template>
   <BodyPanlHeader>
-    <div>
+    <div class="project-detail-body">
       <a-radio-group v-model:value="type">
-        <a-radio-button value="all">所有</a-radio-button>
-        <a-radio-button v-for="option in types" :key="option" :value="option">
-          {{ TaggingStatusDesc[option] }}
-        </a-radio-button>
+        <a-badge :count="Object.values(totals).reduce((t,c) => t + c,0)">
+          <a-radio-button value="all">所有</a-radio-button>
+        </a-badge>
+        <a-badge v-for="option in types" :count="totals[option]">
+          <a-radio-button :key="option" :value="option as any">
+            {{ TaggingStatusDesc[option] }}
+          </a-radio-button>
+        </a-badge>
       </a-radio-group>
     </div>
     <div>
       <a-input-search
         v-model:value="filterName"
-        style="width: 280px"
         placeholder="请输入标注关键字"
+        style="width: 280px"
         @search="updateMaterials"
       />
     </div>
@@ -20,15 +24,14 @@
 
   <BodyPanlBody>
     <a-table
-      :data-source="materials"
       :columns="materialColumns"
+      :data-source="materials"
       :pagination="pagination"
     >
-      <template #bodyCell="{ column }">
+      <template #bodyCell="{ column, record }">
         <template v-if="column.key === 'action'">
           <div class="table-actions">
-            <a>查看</a>
-            <a>前往</a>
+            <a target="_blank" :href="`smart-viewer.html?projectId=${record.projectId}&m=${record.num}`">查看</a>
           </div>
         </template>
       </template>
@@ -37,41 +40,66 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, computed, watch } from 'vue'
-import { BodyPanlHeader, BodyPanlBody } from '@/layout/panl'
-import { useRealtime } from '@/hook'
-import { router } from '@/router'
-import { taggingColumns as baseColumns } from './columns'
-import { fetchTaggings, TaggingStatus, TaggingStatusDesc } from '@/api'
-import type { FetchTaggingsProps } from '@/api'
+import { computed, reactive, ref, watch } from "vue";
+import { BodyPanlBody, BodyPanlHeader } from "@/layout/panl";
+import { useRealtime } from "@/hook";
+import { router } from "@/router";
+import { taggingColumns as baseColumns } from "./columns";
+import type { FetchTaggingsProps } from "@/api";
+import { fetchTaggings, TaggingStatus, TaggingStatusDesc } from "@/api";
 
 const materialColumns = [
   ...baseColumns,
   {
-    title: '操作',
-    dataIndex: 'action',
-    key: 'action'
+    title: "操作",
+    dataIndex: "action",
+    key: "action"
   }
-]
+];
 
 const types = [
   TaggingStatus.pending,
   TaggingStatus.progress,
   TaggingStatus.unsolved,
   TaggingStatus.solved
-]
-const type = ref<TaggingStatus | 'all'>('all')
-const filterName = ref('')
-const projectId = computed(() => Number(router.currentRoute.value.params.id))
+];
+const type = ref<TaggingStatus | "all">("all");
+const filterName = ref("");
+const projectId = computed(() => Number(router.currentRoute.value.params.id));
 const pagination = reactive({
   current: 1,
   total: 0,
   pageSize: 12,
   onChange: (current: number) => {
-    pagination.current = current
-    updateMaterials()
+    pagination.current = current;
+    updateMaterials();
   }
-})
+});
+
+const totals = ref({
+  [TaggingStatus.pending]: 0,
+  [TaggingStatus.progress]: 0,
+  [TaggingStatus.unsolved]: 0,
+  [TaggingStatus.solved]: 0
+});
+
+watch(() => projectId.value, () => {
+  if (!projectId.value) {
+    return;
+  }
+  types.forEach(async type => {
+    const params = {
+      pageNum: 1,
+      pageSize: 1,
+      markingStatus: type,
+      markingTitle: "",
+      projectId: projectId.value
+    };
+    const result = await fetchTaggings(params);
+    totals.value[type] = result.total;
+    console.log(totals);
+  });
+}, { immediate: true });
 
 const [materials, updateMaterials] = useRealtime(async () => {
   const params: FetchTaggingsProps = {
@@ -79,15 +107,30 @@ const [materials, updateMaterials] = useRealtime(async () => {
     projectId: projectId.value,
     pageNum: pagination.current,
     pageSize: pagination.pageSize
+  };
+  if (type.value !== "all") {
+    params.markingStatus = type.value;
   }
-  if (type.value !== 'all') {
-    params.markingStatus = type.value
+  const result = await fetchTaggings(params);
+  pagination.total = result.total;
+  if (type.value !== "all") {
+    totals.value[type.value] = result.total;
   }
-  const result = await fetchTaggings(params)
-  pagination.total = result.total
-
-  return result.list
-}, [])
+  return result.list;
+}, []);
 
-watch(() => type.value + filterName.value, updateMaterials)
+watch(() => type.value + filterName.value, updateMaterials);
 </script>
+
+<style lang="scss">
+.project-detail-body .ant-badge:first-child .ant-radio-button-wrapper {
+  margin-left: -1px;
+}
+
+.project-detail-body
+.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) {
+  z-index: auto;
+  border-left: 1px solid #2997ff !important;
+  margin-left: -1px;
+}
+</style>