Procházet zdrojové kódy

Merge branch 'question-alert' into 'dev'

Question alert

See merge request skyeye/skyeye_frontend/skyeye-admin!28
航飞 楼 před 1 rokem
rodič
revize
824a06738b

+ 2 - 2
src/api/datamanagement/alert-show.ts

@@ -24,7 +24,7 @@ export interface AddForm {
   description: String,    // 问题描述
   pictures: Array<string>,// 图片
   workspaceId: Number,    // 工位id/地点
-  issueTime: String,      // 问题时间(默认是creatAt)
+  createdAt: String,      // 问题时间(默认是createdAt)
   issueState: Number,     // 问题单状态:1-待审核、2-待处理、3-待复核、4-已退回、5-已处理
 };
 export const addShowTableData = (body: AddForm) => {
@@ -51,7 +51,7 @@ export interface EditForm {
   description: String,    // 问题描述
   pictures: Array<string>,// 图片
   workspaceId: Number,    // 工位id/地点
-  issueTime: String,      // 问题时间(默认是creatAt)
+  createdAt: String,      // 问题时间(默认是createdAt)
   issueState: Number,     // 问题单状态:1-待审核、2-待处理、3-待复核、4-已退回、5-已处理
   isHide?: Boolean,       // 问题单是否隐藏(根据UI编辑/添加表单没有这个选项。改变隐藏显示另有接口) 
 };

+ 6 - 0
src/store/modules/user.ts

@@ -126,7 +126,13 @@ export const useUserStore = defineStore({
       storage.remove('lxUsername');
       return Promise.resolve('');
     },
+
+    checkPermission(permission: string) {
+      return this.permissions.find(x => x.value === permission)
+    }
   },
+
+
 });
 
 // Need to be used outside the setup

+ 7 - 2
src/views/datamanager/alertformdata/AlertformData.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="container-box">
-    <div class="control-btn">
+    <div class="control-btn" v-if="hasPermisson()">
       <div class="btn" :class="{ 'btn-active': activeName === 'default' }" @click="activeName = 'default'">默认数据</div>
       <div class="btn" :class="{ 'btn-active': activeName === 'show' }" @click="activeName = 'show'">展示数据</div>
     </div>
@@ -13,9 +13,14 @@
 import { ref } from 'vue';
 import Default from './components/default/Default.vue';
 import Show from './components/show/Show.vue';
+import { useUserStore } from '@/store/modules/user';
 
 const activeName = ref('default');
 
+const userStore = useUserStore();
+const hasPermisson = () => {
+  return userStore.checkPermission("question_mock_edit_admin");
+};
 </script>
 
 <style scoped lang="scss">
@@ -67,4 +72,4 @@ const activeName = ref('default');
 .content-box {
   flex: 1;
 }
-</style>
+</style>

+ 12 - 7
src/views/datamanager/alertformdata/components/common/AlertTable.vue

@@ -26,21 +26,23 @@
       </el-table-column>
       <el-table-column label="时间" prop="createdAt" width="250"></el-table-column>
       <el-table-column label="负责人" prop="personNameInCharge" width="100"></el-table-column>
-      <el-table-column label="处理状态" prop="issueState" width="100">
+      <el-table-column label="处理状态" prop="issueState">
         <template #default="{ row }">
           {{ getNameByState(row.issueState) }}
         </template>
       </el-table-column>
       <el-table-column label="操作" width="130" fixed="right">
         <template #default="{ row }">
-          <img src="/src/assets/images/alert/urgent.png" alt="" v-if="!isShowTab && !row.priority"
-            @click="handleUrgent(row)">
-          <img src="/src/assets/images/alert/urgent-active.png" alt="" v-if="!isShowTab && row.priority"
+          <img src="/src/assets/images/alert/urgent.png" alt="" title="点击标记为加急问题" v-if="!isShowTab && !row.priority"
             @click="handleUrgent(row)">
+          <img src="/src/assets/images/alert/urgent-active.png" alt="" title="点击取消问题加急"
+            v-if="!isShowTab && row.priority" @click="handleUrgent(row)">
           <img src="/src/assets/images/alert/edit.png" alt="" v-if="isShowTab" @click="handleEdit(row)">
-          <img src="/src/assets/images/alert/show-on.png" alt="" v-if="!row.isHide" @click="handleShow(row)">
-          <img src="/src/assets/images/alert/show-off.png" alt="" v-if="row.isHide" @click="handleShow(row)">
-          <img src="/src/assets/images/alert/delete.png" alt="" @click="handleDelete(row)">
+          <img src="/src/assets/images/alert/show-on.png" alt="" title="点击隐藏问题展示" v-if="!row.isHide"
+            @click="handleShow(row)">
+          <img src="/src/assets/images/alert/show-off.png" alt="" title="点击恢复问题展示" v-if="row.isHide"
+            @click="handleShow(row)">
+          <img src="/src/assets/images/alert/delete.png" alt="" title="点击删除问题数据" @click="handleDelete(row)">
         </template>
       </el-table-column>
     </el-table>
@@ -107,6 +109,9 @@ const colorOfState = ({ row, columnIndex }) => {
     if (row.issueState === 4) return { color: "#FF4D4F" };
     else if (row.issueState === 5) return { color: "#52C41A " };
     else return { color: "#1890FF " };
+  };
+  if (row.isHide) {
+    return { color: "#A8ABB2" };
   }
 };
 

+ 14 - 5
src/views/datamanager/alertformdata/components/common/QueryForm.vue

@@ -22,8 +22,9 @@
           </el-select>
         </el-form-item>
         <el-form-item label="日期:" v-if="!isShowTab">
-          <el-date-picker v-model="dateRange" type="datetimerange" range-separator="~" start-placeholder="开始时间"
-            end-placeholder="结束时间" clearable value-format="YYYY-MM-DD HH:mm:ss.SSS" @change="handleDateChange" />
+          <el-date-picker v-model="dateRange" type="daterange" range-separator="~" start-placeholder="开始时间"
+            end-placeholder="结束时间" clearable unlink-panels value-format="YYYY-MM-DD HH:mm:ss.SSS"
+            @change="handleDateChange" />
         </el-form-item>
       </div>
       <div class="btn-group">
@@ -79,6 +80,8 @@ const workLocation = ref([]);   // 级联选择器,为二维数组(提取wor
 const dateRange = ref([]);  // 时间段,拆分成startTime/endTime
 
 const handleSearch = () => {
+  console.log(queryForm);
+
   emits('onSearch', queryForm);
 };
 
@@ -115,9 +118,15 @@ const handleCascaderChange = () => {
 };
 
 const handleDateChange = () => {
-  queryForm.startTime = dateRange.value[0];
-  queryForm.endTime = dateRange.value[1];
-}
+  if (dateRange.value != null) {
+    queryForm.startTime = dateRange.value[0];
+    queryForm.endTime = dateRange.value[1];
+  } else {
+    Reflect.deleteProperty(queryForm, "startTime");
+    Reflect.deleteProperty(queryForm, "endTime");
+  }
+  console.log(queryForm);
+};
 </script>
 
 <style scoped lang="scss">

+ 83 - 25
src/views/datamanager/alertformdata/components/common/QuestionFormBase.vue

@@ -3,20 +3,23 @@
     <el-drawer v-model="visible" title="问题详情" direction="rtl" size="30%" :close-on-click-modal="false"
       @close="handleCancel">
       <el-form ref="formRef" :model="formData">
-        <el-form-item label="问题来源:" prop="source">
+        <el-form-item label="问题来源:" prop="source" :rules="{ required: true, message: '请完成必填项' }">
           <el-select v-model="formData.source" placeholder="请选择问题来源" clearable @change="handleSelectChange">
             <el-option v-for="item in sourceOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
-        <el-form-item label="问题类型:" prop="issueType">
+        <el-form-item label="问题类型:" prop="issueType" :rules="{ required: true, message: '请完成必填项' }">
           <el-select v-model="formData.issueType" placeholder="请选择问题类型" clearable>
             <el-option v-for="item in options" :label="item.name" :value="item.id" />
           </el-select>
         </el-form-item>
-        <el-form-item label="问题描述:" prop="description">
-          <el-input v-model="formData.description" type="textarea"></el-input>
+        <el-form-item label="问题描述:" prop="description" :rules="{ required: true, message: '请完成必填项' }">
+          <el-input v-model="formData.description" type="textarea" maxlength="100" autosize show-word-limit
+            placeholder="请输入问题描述,不超过100个字"></el-input>
         </el-form-item>
-        <el-form-item label="问题图片:" prop="pictures">
+        <el-form-item class="pic-form-item" label="问题图片:" prop="pictures"
+          :rules="{ required: true, message: '请完成必填项' }">
+          <p>(建议尺寸192*108,大小10M以下)</p>
           <el-upload v-model:file-list="fileList" action="/skyeye-admin-api/issue/uploadPicture"
             list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
             :on-success="handleAvatarSuccess" :headers="getHeaders()" :data="{ bizType: 'PROBLEM_REPORT' }">
@@ -28,22 +31,24 @@
             <img w-full :src="dialogImageUrl" alt="Preview Image" />
           </el-dialog>
         </el-form-item>
-        <el-form-item label="问题地点:" prop="workspaceId">
-          <el-cascader v-model="workLocation" :options="locationOptions" :props="location" clearable
-            @change="handleCascaderChange" />
+        <el-form-item label="问题地点:" prop="workspaceId" :rules="{ required: true, message: '请完成必填项' }">
+          <el-cascader v-model="workLocation" :options="locationOptions" :props="location" placeholder="请选择问题地点"
+            clearable @change="handleCascaderChange" />
         </el-form-item>
-        <el-form-item label="问题时间:" prop="issueTime">
-          <el-date-picker v-model="formData.issueTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss.SSS"
-            placeholder="请选择时间" />
+        <el-form-item label="问题时间:" prop="createdAt" :rules="{ required: true, message: '请完成必填项' }">
+          <el-date-picker v-model="formData.createdAt" type="datetime" value-format="YYYY-MM-DD HH:mm:ss.SSS"
+            placeholder="请选择问题时间" />
         </el-form-item>
-        <el-form-item label="问题状态:" prop="issueState">
-          <el-select v-model="formData.issueState" placeholder="请选择问题状态">
+        <el-form-item label="问题状态:" prop="issueState" :rules="{ required: true, message: '请完成必填项' }">
+          <el-select v-model="formData.issueState" placeholder="请选择问题状态" clearable>
             <el-option v-for="item in issueStateOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
         <el-form-item>
-          <el-button @click="handleCancel">取消</el-button>
-          <el-button type="primary" @click="handleSubmit">保存</el-button>
+          <div class="btn-box">
+            <el-button @click="handleCancel">取消</el-button>
+            <el-button type="primary" @click="handleSubmit(formRef)">保存</el-button>
+          </div>
         </el-form-item>
       </el-form>
     </el-drawer>
@@ -75,14 +80,16 @@ interface FormModel {
   description?: string,    // 描述
   pictures?: string[],     // 图片
   workshopId?: number,     // 车间id
+  workshopName?: string,
   workspaceId?: number,    // 工位id
-  issueTime?: string,      // 时间(issueTime为空时填充createdAt)
+  workspaceName?: string,
+  createdAt?: string,      // 时间
   issueState?: number,     // 状态
 };
 
 const visible = ref(true);
 const { aiOptions, manualOptions, getAIOptions, getManualOptions } = useIssueType();
-const { locationOptions, getLocationOptions } = useWorkLocation();
+const { locationOptions, getLocationOptions, getNameByWorkid } = useWorkLocation();
 
 const props = defineProps<Props>();
 const emits = defineEmits(['saveForm', 'closeForm']);
@@ -96,7 +103,7 @@ const formData = reactive<FormModel>({
   pictures: [],
   workshopId: undefined,
   workspaceId: undefined,
-  issueTime: '',
+  createdAt: '',
   issueState: undefined
 });
 
@@ -107,7 +114,6 @@ const handleSelectChange = () => {
   formData.issueType = undefined;
 };
 const options = computed(() => {
-
   if (Number(formData.source) === SourceType.ai && aiOptions.value.length > 0) {
     return aiOptions.value;
   }
@@ -117,8 +123,17 @@ const options = computed(() => {
   return []
 });
 const handleCascaderChange = () => {
-  formData.workshopId = workLocation.value[0];
-  formData.workspaceId = workLocation.value[1];
+  if (workLocation.value != null) {
+    formData.workshopId = workLocation.value[0];
+    formData.workspaceId = workLocation.value[1];
+    const tempString = getNameByWorkid(formData.workshopId, formData.workspaceId, locationOptions.value);
+    const strFlag = tempString.indexOf('-');
+    formData.workshopName = tempString.slice(0, strFlag);
+    formData.workspaceName = tempString.slice(strFlag + 1);
+  } else {
+    Reflect.deleteProperty(formData, "workshopId");
+    Reflect.deleteProperty(formData, "workspaceId");
+  }
 };
 
 const handleCopyData = () => {
@@ -129,7 +144,7 @@ const handleCopyData = () => {
   formData.pictures = props.initialData?.pictures;
   formData.workshopId = props.initialData?.workshopId;
   formData.workspaceId = props.initialData?.workspaceId;
-  formData.issueTime = props.initialData?.issueTime;
+  formData.createdAt = props.initialData?.createdAt;
   formData.issueState = props.initialData?.issueState;
 
   workLocation.value = [props.initialData?.workshopId, props.initialData?.workspaceId!];
@@ -142,8 +157,16 @@ const handleCancel = () => {
 };
 
 // 保存
-const handleSubmit = () => {
-  emits('saveForm', formData);
+const handleSubmit = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log('submit!', formData);
+      emits('saveForm', formData);
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
 };
 
 // 图片上传
@@ -178,4 +201,39 @@ onBeforeMount(() => {
 });
 </script>
 
-<style scoped></style>
+<style scoped>
+:deep(.el-drawer__header) {
+  position: relative;
+
+  >:first-child {
+    margin-left: 32px;
+    font-weight: 600;
+    font-size: 16px;
+    color: rgba(0, 0, 0, 0.88);
+  }
+
+  .el-drawer__close-btn {
+    position: absolute;
+    color: #000;
+  }
+}
+
+.btn-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  margin-top: 10px;
+}
+
+.pic-form-item {
+  :deep(.el-form-item__content) {
+    display: block;
+  }
+
+  p {
+    font-size: 10px;
+    color: #A8ABB2;
+  }
+}
+</style>

+ 16 - 4
src/views/datamanager/alertformdata/components/default/Default.vue

@@ -101,7 +101,13 @@ const handleHideAll = () => {
   };
   updateDefaultTableData(updateList).then(() => {
     getTableData();
-    isActiveHide.value = !isActiveHide.value;
+    ElMessage({
+      message: '隐藏成功',
+      type: 'success',
+    });
+    setTimeout(function () {
+      isActiveHide.value = !isActiveHide.value;
+    }, 1000);
   });
 };
 
@@ -147,7 +153,13 @@ const handleUrgentAll = () => {
   };
   updateDefaultTableData(updateList).then(() => {
     getTableData();
-    isActiveUrgent.value = !isActiveUrgent.value;
+    ElMessage({
+      message: '已加急',
+      type: 'success',
+    });
+    setTimeout(function () {
+      isActiveUrgent.value = !isActiveUrgent.value;
+    }, 1000);
   });
 };
 
@@ -156,7 +168,7 @@ const handleCopyToShow = () => {
   if (showActionBar.value) isActiveCopy.value = !isActiveCopy.value;
   copyToShowTableData(chooseId.value).then(() => {
     ElMessage({
-      message: '复制成功',
+      message: '复制成功',
       type: 'success',
     });
     setTimeout(function () {
@@ -265,7 +277,7 @@ onBeforeMount(() => {
 }
 
 .table-list {
-  height: calc(100vh - 400px);
+  height: calc(100vh - 350px);
   overflow-y: scroll;
 
   .action-bar {

+ 8 - 2
src/views/datamanager/alertformdata/components/show/Show.vue

@@ -109,7 +109,13 @@ const handleHideAll = () => {
   };
   updateShowTableData(updateList).then(() => {
     getTableData();
-    isActiveHide.value = !isActiveHide.value;
+    ElMessage({
+      message: '隐藏成功',
+      type: 'success',
+    });
+    setTimeout(function () {
+      isActiveHide.value = !isActiveHide.value;
+    }, 1000);
   });
 };
 
@@ -258,7 +264,7 @@ onBeforeMount(() => {
 }
 
 .table-list {
-  height: calc(100vh - 400px);
+  height: calc(100vh - 350px);
   overflow-y: scroll;
 
   .action-bar {