linqilong 1 هفته پیش
والد
کامیت
41637e67c8

+ 3 - 0
.env.development

@@ -8,3 +8,6 @@ NODE_ENV = 'development'
 
 # 开发环境
 VUE_APP_BASE_API = '/pdcApi'
+
+# IP地址
+VUE_APP_BASE_HOST = 'https://27.156.118.74:19901'

+ 32 - 9
src/api/questions.js

@@ -1,5 +1,5 @@
 import request from "@/utils/request";
-import { useUserStore } from "@/stores/user";
+import {useUserStore} from "@/stores/user";
 
 const userStore = useUserStore()
 
@@ -11,14 +11,15 @@ export function getTacQuestionList() {
     return request({
         url: '/tac/pblm/info/pageNew',
         method: 'POST',
-        data: {"count":"false",
-            "orderBy":"INTM",
-            "pageNum":1,
-            "pageSize":200,
-            "pblmQlttvCd":0,
-            "persId":userid,
-            "sn":0,
-            "year":0
+        data: {
+            "count": "false",
+            "orderBy": "INTM",
+            "pageNum": 1,
+            "pageSize": 200,
+            "pblmQlttvCd": 0,
+            "persId": userid,
+            "sn": 0,
+            "year": 0
         }
     })
 }
@@ -36,3 +37,25 @@ export function getIllegalActList(data) {
         data: data
     })
 }
+
+/**
+ * 稽查 - 稽查单位
+ */
+export function getTacUnitList(rgstrId, sysType) {
+    return request({
+        url: '/tac/pawp/unit/sctn/list',
+        method: 'POST',
+        data: {"pageNum": 1, "pageSize": 1000, "rgstrId": rgstrId, "sysType": sysType}
+    })
+}
+
+/**
+ * 稽查 - 新增问题
+ */
+export function addTacQuestion(data) {
+    return request({
+        url: '/tac/pblm/info',
+        method: 'POST',
+        data: data
+    })
+}

+ 37 - 33
src/components/GwSelect02.vue

@@ -1,58 +1,62 @@
 <template>
-    <div class="filter-item">
-            <van-field   v-model="name"    is-link  readonly  :label="props.label"    :placeholder="`选择${props.label}`"      @click="showPicker = true"  />
-        <van-popup v-model:show="showPicker" round position="bottom">
-            <van-picker :columns="props.columns" @cancel="showPicker = false" @confirm="onConfirm" />
-        </van-popup>
-    </div>
+  <div class="filter-item">
+    <van-field v-model="name" :label="props.label" :placeholder="`选择${props.label}`" is-link readonly
+               @click="showPicker = true"/>
+    <van-popup v-model:show="showPicker" position="bottom" round>
+      <van-picker :columns="props.columns" @cancel="showPicker = false" @confirm="onConfirm"/>
+    </van-popup>
+  </div>
 </template>
 <script setup>
-import { ref, defineProps, defineEmits, watch } from "vue";
+import {defineEmits, defineProps, ref, watch} from "vue";
 
 const emits = defineEmits(['update:value']);
 
 const props = defineProps({
-    label: {
-        type: String,
-        default: '',
-    },
-    columns: {
-        type: Array,
-        default: () => [],
-    },
-    value: {
-        type: null,
-    }
+  label: {
+    type: String,
+    default: '',
+  },
+  columns: {
+    type: Array,
+    default: () => [],
+  },
+  value: {
+    type: null,
+  }
 })
 
-const name = ref('')
+const name = ref('');
 const showPicker = ref(false);
-const onConfirm = ({ selectedOptions }) => {
-    showPicker.value = false;
-    emits('update:value', selectedOptions[0].value);
+const onConfirm = ({selectedOptions}) => {
+  showPicker.value = false;
+  emits('update:value', selectedOptions[0].value);
 };
 
 function getTypeName(code) {
-    if (!code) return '';
+  debugger
+  if (!code) return '';
+  if (props.columns && props.columns.length > 0) {
     return props.columns.find(item => item.value === code)?.text;
+  }
 }
 
 watch(() => props.value, (newValue) => {
-    name.value = getTypeName(newValue);
-}, { immediate: true })
+  name.value = getTypeName(newValue);
+}, {immediate: true})
 </script>
 <style lang="scss" scoped>
 @import '@/assets/styles/filter.scss';
 
 .content-wrapper {
-    padding-top: 8px;
-    height: 100%;
-    overflow: auto;
+  padding-top: 8px;
+  height: 100%;
+  overflow: auto;
 
-    .ducha-group-wrapper {
-        height: calc(100% - 35px);
-        overflow: auto;
-    }
+  .ducha-group-wrapper {
+    height: calc(100% - 35px);
+    overflow: auto;
+  }
 
 }
-</style>
+</style>

+ 58 - 47
src/components/card01.vue

@@ -1,67 +1,78 @@
 <template>
-    <div class="card-01-wrapper">
+  <div class="card-01-wrapper">
+    <van-row>
+      <van-col :span="$slots.right ? 20 : 24">
         <div class="card-01-header">
-            <van-icon v-if="props.icon && isString(props.icon)" style="margin-right: 5px;" :name="props.icon" color="#1989fa" size="1.3rem" />
-            <van-tag  v-else-if="props.icon && props.icon.type === 'tag'"  style="margin-right: 5px;height: 1rem;white-space: nowrap;" :color="props.icon.color" text-color="#fff">{{ props.icon.value }}</van-tag>
-            <span>{{ props.title }}</span>
+          <van-icon v-if="props.icon && isString(props.icon)" :name="props.icon" color="#1989fa"
+                    size="1.3rem" style="margin-right: 5px;"/>
+          <van-tag v-else-if="props.icon && props.icon.type === 'tag'"
+                   :color="props.icon.color" style="margin-right: 5px;height: 1rem;white-space: nowrap;"
+                   text-color="#fff">{{ props.icon.value }}
+          </van-tag>
+          <span>{{ props.title }}</span>
         </div>
         <div v-if="props.description" class="card-01-description">
-            <van-text-ellipsis v-if="props.ellipsisDescription" :content="props.description" />
-            <span v-else v-html="props.description"></span>
+          <van-text-ellipsis v-if="props.ellipsisDescription" :content="props.description"/>
+          <span v-else v-html="props.description"></span>
         </div>
-    </div>
+      </van-col>
+      <van-col v-if="$slots.right" span="4" style="display: flex;justify-content: center;align-items: center;">
+        <slot name="right"></slot>
+      </van-col>
+    </van-row>
+  </div>
 </template>
 <script setup>
-import { defineProps } from 'vue';
-import { isString } from '@/utils/validate';
+import {defineProps} from 'vue';
+import {isString} from '@/utils/validate';
 
 const props = defineProps({
-    icon: {
-        default: ''
-    },
-    title: {
-        type: String,
-        default: ''
-    },
-    description: {
-        type: String,
-        default: ''
-    },
-    ellipsisDescription: {
-        type: Boolean,
-        default: false
-    }
+  icon: {
+    default: ''
+  },
+  title: {
+    type: String,
+    default: ''
+  },
+  description: {
+    type: String,
+    default: ''
+  },
+  ellipsisDescription: {
+    type: Boolean,
+    default: false
+  }
 })
 
 </script>
 <style lang="scss" scoped>
 .card-01-wrapper {
-    background-color: #fff;
-    border-radius: 10px;
-    padding: 10px;
-    margin: 10px;
-
-    .card-01-header {
-        display: flex;
-        flex-direction: row;
-        align-items: center;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 10px;
+  margin: 10px;
 
-        span {
-            font-size: 1rem;
-            color: #303133;
-            font-weight: bold;
-        }
+  .card-01-header {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
 
+    span {
+      font-size: 1rem;
+      color: #303133;
+      font-weight: bold;
     }
 
-    .card-01-description {
-        font-size: 0.9rem;
-        color:#A8ABB2;
-        margin-top: 10px;
-    }
+  }
 
-    &:last-child {
-        margin-bottom: 20px;
-    }
+  .card-01-description {
+    font-size: 0.9rem;
+    color: #A8ABB2;
+    margin-top: 10px;
+  }
+
+  &:last-child {
+    margin-bottom: 20px;
+  }
 }
-</style>
+</style>

+ 3 - 4
src/components/list01.vue

@@ -5,9 +5,9 @@
     </van-list>
 </template>
 <script setup>
-import { ref, defineProps, watch, defineEmits } from 'vue';
+import {defineEmits, defineProps, ref, watch} from 'vue';
 import card01 from './card01.vue';
-import { getCurrGroup, getInspBaseByPersid } from '@/api/inspect.js';
+import {getCurrGroup, getInspBaseByPersid} from '@/api/inspect.js';
 
 const emits = defineEmits(['onClick']);
 
@@ -29,7 +29,6 @@ function onLoad() {
     if (props.type === 'history' && props.batch) {
         getInspBaseByPersid(props.batch).then(res => {
             list.value = res.data;
-            debugger
             loading.value = false;
             finished.value = true;
         })
@@ -52,4 +51,4 @@ watch(() => props.batch, batch => {
         onLoad()
     }
 })
-</script>
+</script>

+ 17 - 7
src/layout/index.vue

@@ -1,20 +1,26 @@
 <template>
   <div :style="{ '--current-color': theme }" class="app-wrapper">
-    <van-nav-bar :title="route.meta.title || '福建水利监管工作平台'" />
+    <van-nav-bar :left-arrow="showBackButton" :title="route.meta.title || '福建水利监管工作平台'" @click-left="back"/>
     <!-- 展示页 -->
-    <app-main />
+    <app-main/>
     <!-- 底部 -->
-    <bottom-nav />
+    <bottom-nav/>
   </div>
 </template>
 <script setup>
-import { ref } from 'vue';
-import { AppMain, BottomNav } from '@/layout/components/index.js'
-import { useRoute } from "vue-router";
+import {computed, ref} from 'vue';
+import {AppMain, BottomNav} from '@/layout/components/index.js'
+import {useRoute, useRouter} from "vue-router";
+
+const router = useRouter()
 const route = useRoute()
 
 const theme = ref(localStorage.getItem('theme'))
+const showBackButton = computed(() => route.meta.showBack)
 
+function back() {
+  router.go(-1)
+}
 </script>
 <style lang="scss" scoped>
 .app-wrapper {
@@ -37,4 +43,8 @@ const theme = ref(localStorage.getItem('theme'))
 .app-wrapper .van-nav-bar__content {
   background-color: #007BFF;
 }
-</style>
+
+.app-wrapper .van-nav-bar .van-icon {
+  color: #fff;
+}
+</style>

+ 16 - 12
src/router/index.js

@@ -1,5 +1,5 @@
 // import {createRouter, createWebHistory} from '@ionic/vue-router';
-import { createRouter, createWebHistory } from 'vue-router';
+import {createRouter, createWebHistory} from 'vue-router';
 import layout from '@/layout/index.vue'
 
 const routes = [
@@ -28,31 +28,35 @@ const routes = [
                 name: 'inspect',
                 component: () => import('@/views/Inspect/index.vue'),
             },
+            {
+                path: 'problem',
+                name: 'problem',
+                component: () => import('@/views/Problem/index.vue'),
+                meta: {title: '问题列表'}
+            },
+            {
+                path: 'about',
+                name: 'about',
+                component: () => import('@/views/AboutView.vue'),
+                meta: {title: '我的'}
+            },
             {
                 path: 'inspect/:id/objects',
                 name: 'inspectObjects',
                 component: () => import('@/views/Inspect/Object/index.vue'),
+                meta: {title: '工程列表', showBack: true}
             },
             {
                 path: 'inspect/:id/object/:objId/problems',
                 name: 'inspectObjectQuestions',
                 component: () => import('@/views/Inspect/Object/Problem/index.vue'),
-            },
-            {
-                path: 'problem',
-                name: 'problem',
-                component: () => import('@/views/Problem/index.vue'),
+                meta: {title: '问题列表', showBack: true}
             },
             {
                 path: 'problem/:id',
                 name: 'problemDetail',
                 component: () => import('@/views/Problem/detail/index.vue'),
-            },
-            {
-                path: 'about',
-                name: 'about',
-                component: () => import('@/views/AboutView.vue'),
-                meta: { title: '我的' }
+                meta: {title: '问题详情', showBack: true}
             },
         ],
     },

+ 317 - 0
src/utils/ruoyi.js

@@ -0,0 +1,317 @@
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+// 日期格式化
+export function parseTime(time, pattern) {
+  if (arguments.length === 0 || !time) {
+    return null;
+  }
+  const format = pattern || "{y}-{m}-{d} {h}:{i}:{s}";
+  let date;
+  if (typeof time === "object") {
+    date = time;
+  } else {
+    if (typeof time === "string" && /^[0-9]+$/.test(time)) {
+      time = parseInt(time);
+    } else if (typeof time === "string") {
+      time = time
+          .replace(new RegExp(/-/gm), "/")
+          .replace("T", " ")
+          .replace(new RegExp(/\.[\d]{3}/gm), "");
+    }
+    if (typeof time === "number" && time.toString().length === 10) {
+      time = time * 1000;
+    }
+    date = new Date(time);
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay(),
+  };
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key];
+    // Note: getDay() returns 0 on Sunday
+    if (key === "a") {
+      return ["日", "一", "二", "三", "四", "五", "六"][value];
+    }
+    if (result.length > 0 && value < 10) {
+      value = "0" + value;
+    }
+    return value || 0;
+  });
+  return time_str;
+}
+
+// 新建日期范围
+export function addDateRange(params, dateRange, propName) {
+  let search = params;
+  search.params =
+      typeof search.params === "object" &&
+      search.params !== null &&
+      !Array.isArray(search.params)
+          ? search.params
+          : {};
+  dateRange = Array.isArray(dateRange) ? dateRange : [];
+  if (typeof propName === "undefined") {
+    search.params["beginTime"] = dateRange[0];
+    search.params["endTime"] = dateRange[1];
+  } else {
+    search.params["begin" + propName] = dateRange[0];
+    search.params["end" + propName] = dateRange[1];
+  }
+  return search;
+}
+
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+  var actions = [];
+  Object.keys(datas).some((key) => {
+    if (datas[key].value == "" + value) {
+      actions.push(datas[key].label);
+      return true;
+    }
+  });
+  return actions.join("");
+}
+
+// 回显数据字典(字符串数组)
+export function selectDictLabels(datas, value, separator) {
+  var actions = [];
+  var currentSeparator = undefined === separator ? "," : separator;
+  var temp = value.split(currentSeparator);
+  Object.keys(value.split(currentSeparator)).some((val) => {
+    Object.keys(datas).some((key) => {
+      if (datas[key].value == "" + temp[val]) {
+        actions.push(datas[key].label + currentSeparator);
+      }
+    });
+  });
+  return actions.join("").substring(0, actions.join("").length - 1);
+}
+
+// 字符串格式化(%s )
+export function sprintf(str) {
+  var args = arguments,
+      flag = true,
+      i = 1;
+  str = str.replace(/%s/g, function () {
+    var arg = args[i++];
+    if (typeof arg === "undefined") {
+      flag = false;
+      return "";
+    }
+    return arg;
+  });
+  return flag ? str : "";
+}
+
+// 转换字符串,undefined,null等转化为""
+export function praseStrEmpty(str) {
+  if (!str || str == "undefined" || str == "null") {
+    return "";
+  }
+  return str;
+}
+
+// 数据合并
+export function mergeRecursive(source, target) {
+  for (var p in target) {
+    try {
+      if (target[p].constructor == Object) {
+        source[p] = mergeRecursive(source[p], target[p]);
+      } else {
+        source[p] = target[p];
+      }
+    } catch (e) {
+      source[p] = target[p];
+    }
+  }
+  return source;
+}
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ */
+export function handleTree(data, id, parentId, children) {
+  let config = {
+    id: id || "id",
+    parentId: parentId || "parentId",
+    childrenList: children || "children",
+  };
+
+  var childrenListMap = {};
+  var nodeIds = {};
+  var tree = [];
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (childrenListMap[parentId] == null) {
+      childrenListMap[parentId] = [];
+    }
+    nodeIds[d[config.id]] = d;
+    childrenListMap[parentId].push(d);
+  }
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (nodeIds[parentId] == null) {
+      tree.push(d);
+    }
+  }
+
+  for (let t of tree) {
+    adaptToChildrenList(t);
+  }
+
+  function adaptToChildrenList(o) {
+    if (childrenListMap[o[config.id]] !== null) {
+      o[config.childrenList] = childrenListMap[o[config.id]];
+    }
+    if (o[config.childrenList]) {
+      for (let c of o[config.childrenList]) {
+        adaptToChildrenList(c);
+      }
+    }
+  }
+
+  return tree;
+}
+
+export function treeToList(treeList) {
+  let list = [];
+
+  function traverse(node) {
+    if (node) {
+      list.push(node); // 将节点的值新建到列表中
+      if (node.children) {
+        for (let child of node.children) {
+          traverse(child); // 递归遍历子节点
+        }
+      }
+    }
+  }
+
+  treeList.forEach((tree) => traverse(tree))
+  return list;
+}
+
+
+export function handleTree2(list, parentId, id, value) {
+  if (!list || list.length === 0) {
+    return list;
+  }
+
+  let config = {
+    value: value || "0",
+    parentId: parentId || "pid",
+    id: id || "id",
+    children: "children",
+  };
+
+  return createTree(list, config.value, config.parentId, config.id);
+}
+
+export function createTree(list, value, parentId, id) {
+  let tree = [];
+  for (let num = 0; num < list.length; num++) {
+    let data = list[num];
+    if (data[parentId] === value) {
+      let children = createTree(list, data[id], parentId, id);
+      if (children && children.length > 0) {
+        data["children"] = children;
+      }
+      tree.push(data);
+    }
+  }
+  return tree;
+}
+
+export function copyObj(obj) {
+  let newObjStr = JSON.stringify(obj);
+  return JSON.parse(newObjStr);
+}
+
+/**
+ * * 生成一个不重复的ID
+ * @param { Number } randomLength
+ */
+export const getUUID = (randomLength = 10) => {
+  return Number(
+      Math.random().toString().substr(2, randomLength) + Date.now()
+  ).toString(36);
+};
+
+export function dateFYMDHM(val) {
+  if (val) {
+    return (
+        val.substr(0, 4) +
+        "-" +
+        val.substr(4, 2) +
+        "-" +
+        val.substr(6, 2) +
+        " " +
+        val.substr(8, 2) +
+        ":" +
+        val.substr(10, 2)
+    );
+  }
+  return "";
+}
+
+/**
+ * 列表筛重
+ * @param list  列表
+ * @param key   筛选字段
+ * @returns {Set<any>[]|*|*[]}
+ */
+export function listFilterDuplicateData(list, key) {
+  if (!list || list.length === 0) {
+    return list
+  }
+  if (!key) {
+    return Array.from(new Set(list))
+  }
+
+  const fdd = new Set(list.map(i => i[key]))
+
+  let retList = []
+  list.forEach(i => {
+    let param = i[key];
+    if (fdd.has(param)) {
+      retList.push(i);
+      fdd.delete(param)
+    }
+  })
+
+  return retList
+}
+
+export function getObjectSize(obj) {
+  let count = 0
+  for (let key in obj)
+    count++
+  return count
+}
+
+// a 数组是否包含 b 数组的值
+export function isHasByOtherArray(a = [], b = []) {
+  for (let i in a) {
+    for (let j in b) {
+      if (a[i] == b[j]) {
+        return true
+      }
+    }
+  }
+  return false
+}

+ 32 - 20
src/views/Inspect/Object/Problem/index.vue

@@ -1,35 +1,43 @@
 <template>
   <div style="height: 100%;padding: 10px 0;">
-    <card01 style="margin-top: 0;" :title="object.ojbNm + ''" icon="label" :description="renderData(object, objectConfig.description2)" />
-    <van-collapse class="pblm-list-wrapper" v-model="activeNames">
+    <card01 :description="renderData(object, objectConfig.description2)" :title="object.ojbNm + ''" icon="label"
+            style="margin-top: 0;"/>
+    <van-collapse v-model="activeNames" class="pblm-list-wrapper">
       <van-collapse-item v-for="item in list" :key="item.id" :name="item.id">
         <template #title>
-          <div>{{ item.name }}&nbsp;&nbsp;<van-tag v-if="item.pblmList && item.pblmList.length > 0" round type="primary">{{item.pblmList.length}}</van-tag></div>
+          <div>{{ item.name }}&nbsp;&nbsp;<van-tag v-if="item.pblmList && item.pblmList.length > 0" round
+                                                   type="primary">{{ item.pblmList.length }}
+          </van-tag>
+          </div>
         </template>
         <card01 v-for="pblm in item.pblmList" :key="pblm.pblmId" :title="pblm.pblmNm" icon="question"
-        @click="jumpPage(`/problem/${pblm.id}`)" />
+                @click="jumpPage(`/problem/${pblm.id}`)">
+          <template #right>
+            <van-icon color="#000" name="delete-o" size="1rem" @click="deletePblm()"/>
+          </template>
+        </card01>
       </van-collapse-item>
     </van-collapse>
   </div>
 </template>
 <script setup>
-import { onMounted, ref } from "vue";
-import { useRoute } from "vue-router";
+import {onMounted, ref} from "vue";
+import {useRoute} from "vue-router";
 import card01 from '@/components/card01.vue';
-import { getTacQuestionList } from "@/api/inspect";
-import { getBaseByInspectType } from "@/assets/js/base";
-import { renderData } from "@/utils/template";
-import { jumpPage } from "@/utils/page";
+import {getTacQuestionList} from "@/api/inspect";
+import {getBaseByInspectType} from "@/assets/js/base";
+import {renderData} from "@/utils/template";
+import {jumpPage} from "@/utils/page";
 
 const route = useRoute();
 const activeNames = ref(['1']);
 const list = ref([
-  { id: '1', name: '前期与设计专业', pblmList:[] },
-  { id: '2', name: '建设管理专业', pblmList:[] },
-  { id: '3', name: '计划下达与执行专业', pblmList:[] },
-  { id: '4', name: '资金使用与管理专业', pblmList:[] },
-  { id: '5', name: '工程质量专业', pblmList:[] },
-  { id: '6', name: '工程安全专业', pblmList:[] }
+  {id: '1', name: '前期与设计专业', pblmList: []},
+  {id: '2', name: '建设管理专业', pblmList: []},
+  {id: '3', name: '计划下达与执行专业', pblmList: []},
+  {id: '4', name: '资金使用与管理专业', pblmList: []},
+  {id: '5', name: '工程质量专业', pblmList: []},
+  {id: '6', name: '工程安全专业', pblmList: []}
 ]);
 const loading = ref(false);
 const inspectType = route.query.inspectType;
@@ -45,6 +53,10 @@ function getData() {
   })
 }
 
+function deletePblm() {
+  console.log('deletePblm');
+}
+
 onMounted(() => {
   getData();
 })
@@ -53,15 +65,15 @@ onMounted(() => {
 
 </style>
 <style lang="scss">
-.pblm-list-wrapper{
+.pblm-list-wrapper {
   padding: 0 10px;
   height: calc(100% - 120px);
   overflow: auto;
-  
-  .van-collapse-item__content{
+
+  .van-collapse-item__content {
     padding: 0;
     background-color: transparent;
   }
 }
 
-</style>
+</style>

+ 81 - 0
src/views/Problem/detail/TacObjPblmstbList.vue

@@ -0,0 +1,81 @@
+<template>
+  <van-search v-model="name" placeholder="请输入搜索关键词" @search="onSearch"/>
+  <div class="tac-obj-pblmstb-list-wrapper">
+    <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
+      <card01 v-for="item in list" :key="item.id" :title="item.pblmsDesc + ''" icon="file"
+              :description="item.class1Name"
+              @click="handleClick(item)"/>
+    </van-list>
+  </div>
+</template>
+<script setup>
+import {defineEmits, defineProps, ref} from 'vue';
+import card01 from '@/components/card01.vue';
+import {getIllegalActList} from '@/api/questions';
+
+const emits = defineEmits(['change']);
+
+const props = defineProps({
+  listType: {
+    type: String,
+    default: '1',
+  },
+})
+
+const list = ref([]);
+const name = ref("");
+const pageNum = ref(0);
+const total = ref(0);
+const loading = ref(false);
+const finished = ref(false);
+
+const onSearch = () => {
+  pageNum.value = 0;
+  total.value = 0;
+  finished.value = false;
+  list.value = [];
+  onLoad()
+}
+
+const onLoad = () => {
+  loading.value = true;
+  pageNum.value++;
+  const params = {
+    "class1Name": name.value,
+    "pageNum": pageNum.value,
+    "pageSize": 20,
+    "pblmType": props.listType,
+    "realPageNum": 0
+  }
+
+  getIllegalActList(params).then(res => {
+    list.value = [...list.value, ...res.data.list];
+    total.value = res.data.total;
+
+    // 加载状态结束
+    loading.value = false;
+
+    // 数据全部加载完成
+    if (total.value !== 0 && list.value.length >= total.value) {
+      finished.value = true;
+    }
+  })
+};
+
+function handleClick(item) {
+  emits('change', item);
+}
+</script>
+<style lang="scss" scoped>
+.tac-obj-pblmstb-list-wrapper {
+  height: calc(100% - 59px);
+  background-color: #ebecf0;
+  padding-top: 10px;
+  overflow: auto;
+
+  .card-01-wrapper:first-child {
+    margin-top: 0;
+  }
+
+}
+</style>

+ 182 - 101
src/views/Problem/detail/index.vue

@@ -1,137 +1,218 @@
 <template>
-    <div class="pblm-detail-wrapper">
-        <van-form @submit="onSubmit">
-            <card01 style="margin-top: 0;" :title="pblm.name + ''" icon="label"
-                :description="`工程地址:${pblm.location}<br/>问题类型:${listTypeConvert(pblm.listType)}`" />
-            <div class="pblm-detail-label">
-                <span>违规事项</span>
-                <van-button size="mini" type="primary" @click="changeTacObjPblmstb()">选择违规事项</van-button>
-            </div>
-            <van-cell-group inset>
-                <van-field v-model="tacObjPblmstb.pblmTypeDesc" label="问题类型" placeholder="问题类型" label-align="top"
-                    rows="1" autosize type="textarea" readonly />
-                <van-field v-model="tacObjPblmstb.pblmsDesc" label="违规事项" placeholder="违规事项" label-align="top" rows="2"
-                    autosize type="textarea" readonly />
-                <van-field v-model="tacObjPblmstb.relativeLaw" label="法规条款" placeholder="法规条款" label-align="top"
-                    rows="2" autosize type="textarea" readonly />
-                <van-field v-model="tacObjPblmstb.lawContent" label="法规内容" placeholder="法规内容" label-align="top" rows="2"
-                    autosize type="textarea" readonly />
-                <van-field v-model="pblm.note" label="备注" placeholder="备注" label-align="top" rows="2" autosize
-                    type="textarea" />
-            </van-cell-group>
-            <div class="pblm-detail-label">问题描述</div>
-            <van-cell-group inset>
-                <van-field v-model="pblm.pblmNm" label="发现问题" placeholder="发现问题" label-align="top" rows="2" autosize
-                    type="textarea" />
-                <van-field v-model="pblm.pblmDesc" label="问题阐述" placeholder="问题阐述" label-align="top" rows="2" autosize
-                    type="textarea" />
-                <van-field v-model="pblm.pblmReason" label="主要原因分析" placeholder="主要原因分析" label-align="top" rows="2"
-                    autosize type="textarea" />
-                <van-field v-model="pblm.pblmSggtn" label="整改意见及建议" placeholder="整改意见及建议" label-align="top" rows="2"
-                    autosize type="textarea" />
-                <van-field v-model="pblm.spclRvwOptn" label="稽查组长复核意见" placeholder="稽查组长复核意见" label-align="top" rows="2"
-                    autosize type="textarea" />
-                <GwSelect02 label="问题严重性" :columns="cateObjList" v-model:value="pblm.pblmPasi"></GwSelect02>
-                <van-field name="radio" label="是否典型问题">
-                    <template #input>
-                        <van-radio-group v-model="pblm.ifCasePblm" direction="horizontal">
-                            <van-radio name="1">是</van-radio>
-                            <van-radio name="0">否</van-radio>
-                        </van-radio-group>
-                    </template>
-                </van-field>
-                <van-field name="stepper" label="排序序号">
-                    <template #input>
-                        <van-stepper v-model="pblm.sn" />
-                    </template>
-                </van-field>
-                <van-field name="uploader" label="文件上传">
-                    <template #input>
-                        <van-uploader v-model="gwComFileList" />
-                    </template>
-                </van-field>
-            </van-cell-group>
-            <div class="pblm-detail-label">责任主体</div>
-            <van-cell-group inset>
-                <div class="pblmSubjectList" v-for="item in pblm.pblmSubjectList" :key="item.id">
-                    <GwSelect02 label="单位性质" :columns="objSubjectColumns" v-model:value="item.subId"></GwSelect02>
-                    <van-field v-model="item.unitNm" label="单位名称" placeholder="单位名称" />
-                </div>
-                <van-button round plain hairline block>
-                    <van-icon style="margin-right: 5px;" name="plus" color="#000" size="1rem" />
-                    添加单位
-                </van-button>
-            </van-cell-group>
-            <div style="margin: 16px;">
-                <van-button round block type="primary" native-type="submit">
-                    提交
-                </van-button>
-            </div>
-        </van-form>
-
-        <van-popup v-model:show="tacObjPblmstbShow" position="left" :style="{ width: '80%', height: '100%' }">
-
-        </van-popup>
-    </div>
+  <div class="pblm-detail-wrapper">
+    <van-form @submit="onSubmit">
+      <card01 :description="`工程地址:${pblm.location}<br/>问题类型:${listTypeConvert(pblm.listType)}`"
+              :title="pblm.name + ''" icon="label"
+              style="margin-top: 0;"/>
+      <div class="pblm-detail-label">
+        <span>违规事项</span>
+        <van-button size="mini" type="primary" @click="showTacObjPblmstbPopup()">选择违规事项</van-button>
+      </div>
+      <van-cell-group inset>
+        <van-field v-model="tacObjPblmstb.pblmTypeDesc" autosize label="问题类型" label-align="top"
+                   placeholder="问题类型" readonly rows="1" type="textarea"/>
+        <van-field v-model="tacObjPblmstb.pblmsDesc" autosize label="违规事项" label-align="top" placeholder="违规事项"
+                   readonly rows="2" type="textarea"/>
+        <van-field v-model="tacObjPblmstb.relativeLaw" autosize label="法规条款" label-align="top"
+                   placeholder="法规条款" readonly rows="2" type="textarea"/>
+        <van-field v-model="tacObjPblmstb.lawContent" autosize label="法规内容" label-align="top" placeholder="法规内容"
+                   readonly rows="2" type="textarea"/>
+        <van-field v-model="pblm.note" autosize label="备注" label-align="top" placeholder="备注" rows="2"
+                   type="textarea"/>
+      </van-cell-group>
+      <div class="pblm-detail-label">问题描述</div>
+      <van-cell-group inset>
+        <van-field v-model="pblm.pblmNm" autosize label="发现问题" label-align="top" placeholder="发现问题" rows="2"
+                   type="textarea"/>
+        <van-field v-model="pblm.pblmDesc" autosize label="问题阐述" label-align="top" placeholder="问题阐述" rows="2"
+                   type="textarea"/>
+        <van-field v-model="pblm.pblmReason" autosize label="主要原因分析" label-align="top" placeholder="主要原因分析"
+                   rows="2" type="textarea"/>
+        <van-field v-model="pblm.pblmSggtn" autosize label="整改意见及建议" label-align="top"
+                   placeholder="整改意见及建议"
+                   rows="2" type="textarea"/>
+        <van-field v-model="pblm.spclRvwOptn" autosize label="稽查组长复核意见" label-align="top"
+                   placeholder="稽查组长复核意见"
+                   rows="2" type="textarea"/>
+        <GwSelect02 v-model:value="pblm.pblmPasi" :columns="cateObjList" label="问题严重性"></GwSelect02>
+        <van-field label="是否典型问题" name="radio">
+          <template #input>
+            <van-radio-group v-model="pblm.ifCasePblm" direction="horizontal">
+              <van-radio name="1">是</van-radio>
+              <van-radio name="0">否</van-radio>
+            </van-radio-group>
+          </template>
+        </van-field>
+        <van-field label="排序序号" name="stepper">
+          <template #input>
+            <van-stepper v-model="pblm.sn"/>
+          </template>
+        </van-field>
+        <van-field label="文件上传" label-align="top" name="uploader">
+          <template #input>
+            <van-uploader v-model="gwComFileList"/>
+          </template>
+        </van-field>
+      </van-cell-group>
+      <div class="pblm-detail-label">责任主体</div>
+      <van-cell-group inset>
+        <div v-for="(item, index) in subjectList" :key="item.id" class="pblmSubjectList">
+
+          <van-row style="border-bottom: 1px dashed #CDD0D6;">
+            <van-col span="20">
+              <GwSelect02 v-model:value="item.subId" :columns="objSubjectTypeColumns" label="单位性质"></GwSelect02>
+              <GwSelect02 v-model:value="item.unitNm" :columns="getObjSubjectColumns(index)"
+                          label="单位名称">
+              </GwSelect02>
+            </van-col>
+            <van-col span="4" style="display: flex;justify-content: center;align-items: center;"
+                     @click="removePblmSubject(index)">
+              <van-icon color="#000" name="delete-o" size="1rem"/>
+            </van-col>
+          </van-row>
+
+        </div>
+        <van-button block hairline plain round @click="addPblmSubject">
+          <van-icon color="#000" name="plus" size="1rem" style="margin-right: 5px;"/>
+          添加单位
+        </van-button>
+      </van-cell-group>
+      <div style="margin: 16px;">
+        <van-button block native-type="submit" round type="primary">
+          提交
+        </van-button>
+      </div>
+    </van-form>
+
+    <van-popup v-model:show="tacObjPblmstbShow" :style="{ width: '80%', height: '100%' }" position="left">
+      <tacObjPblmstbList :listType="pblm.listType" style="z-index:3000;" @change="changeTacObjPblmstb">
+      </tacObjPblmstbList>
+    </van-popup>
+  </div>
 </template>
 <script setup>
-import { onMounted, ref, computed, watch } from "vue";
-import { useRoute } from "vue-router";
+import {computed, onMounted, ref, watch} from "vue";
+import {useRoute} from "vue-router";
+import {showNotify} from 'vant';
 import card01 from '@/components/card01.vue';
 import GwSelect02 from '@/components/GwSelect02.vue';
-import { getTacQuestionById } from "@/api/inspect";
-import { listTypeConvert } from "@/utils/convert"
+import tacObjPblmstbList from './TacObjPblmstbList.vue';
+import {listTypeConvert} from "@/utils/convert";
+import {getTacQuestionById} from "@/api/inspect";
+import {addTacQuestion, getTacUnitList} from "@/api/questions";
+import {copyObj} from "@/utils/ruoyi";
 
 const route = useRoute();
 const pblm = ref({});
 const tacObjPblmstb = computed(() => pblm.value.tacObjPblmstb || {});
-const cateObjList = computed(() => tacObjPblmstb.value?.cateObjList?.map(i => { return { text: i.desc, value: i.cate } }) || []);
+const cateObjList = computed(() => tacObjPblmstb.value?.cateObjList?.map(i => {
+  return {text: i.desc, value: i.cate}
+}) || []);
 const objSubjectList = computed(() => pblm.value.tacObjPblmstb.objSubjectList || []);
-const objSubjectColumns = computed(() => objSubjectList.value?.map(i => { return { text: i.subName, value: i.id } }) || []);
-const gwComFileList = computed(() => pblm.value.gwComFileList?.map(i => process.env.VUE_APP_BASE_API + i.filePath) || []);
+const objSubjectTypeColumns = computed(() => objSubjectList.value?.map(i => {
+  return {text: i.subName, value: i.id}
+}) || []);
+const objSubjects = ref({});
+const gwComFileList = computed(() => pblm.value.gwComFileList?.map(i => {
+  return {url: process.env.VUE_APP_BASE_HOST + process.env.VUE_APP_BASE_API + i.filePath}
+}) || []);
+/**
+ * 责任主体
+ */
+const subjectList = ref([])
 
 const tacObjPblmstbShow = ref(false);
 
 function getQuestionData() {
-    getTacQuestionById(route.params.id).then(res => {
-        pblm.value = res.data
-    })
+  getTacQuestionById(route.params.id).then(res => {
+    pblm.value = res.data
+    subjectList.value = res.data.pblmSubjectList;
+  })
 }
 
 /**
  * 选择违规事项
  */
-function changeTacObjPblmstb() {
-    console.log('changeTacObjPblmstb')
+function showTacObjPblmstbPopup() {
+  tacObjPblmstbShow.value = true;
 }
 
+function changeTacObjPblmstb(data) {
+  tacObjPblmstbShow.value = false;
+  pblm.value.tacObjPblmstb = data;
+  pblm.value.pblmstdId = data.id;
+}
 
+/**
+ * 保存问题
+ */
 function onSubmit() {
-    console.log(e)
+  const data = copyObj(pblm.value)
+  data.pblmSubjectList = subjectList.value
+  addTacQuestion(data).then(() => {
+    showNotify({type: 'success', message: '保存成功'});
+  })
+}
+
+async function getObjSubjects(rgstrId, subId) {
+  if (rgstrId && subId) {
+    return await getTacUnitList(rgstrId, subId).then(res => res.data) || []
+  } else {
+    return []
+  }
+}
+
+function getObjSubjectColumns(index) {
+  return (objSubjects.value[index] || []).map(i => {
+    return {text: i.sysNm, value: i.sysNm}
+  })
+}
+
+/**
+ * 添加责任主体
+ */
+function addPblmSubject() {
+  subjectList.value.push({});
+}
+
+function removePblmSubject(index) {
+  subjectList.value.splice(index, 1);
 }
 
 onMounted(() => {
-    getQuestionData();
+  getQuestionData();
 })
+
+watch(() => subjectList, (list) => {
+  if (list.value && list.value.length > 0) {
+    list.value.forEach((item, index) => {
+      if (item.subId) {
+        getObjSubjects(pblm.value.rgstrId, item.subId).then(res => {
+          objSubjects.value[index] = res;
+        })
+      }
+    })
+  }
+}, {deep: true, immediate: true})
 </script>
 <style lang="scss" scoped>
 .pblm-detail-wrapper {
-    height: 100%;
-    padding: 10px 0;
-    overflow: auto;
-
-    .pblm-detail-label {
-        padding: 10px 16px;
-        color: #606266;
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-    }
+  height: 100%;
+  padding: 10px 0;
+  overflow: auto;
+
+  .pblm-detail-label {
+    padding: 10px 16px;
+    color: #606266;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
 
 }
 </style>
 <style lang="scss">
 .van-cell-group--inset {
-    margin: 0 10px;
+  margin: 0 10px;
 }
-</style>
+</style>