ソースを参照

项目资料库

bzkf30 2 年 前
コミット
de5ca8be67

+ 511 - 0
src/pages/projectManager/projectDatabase/detail/index.vue

@@ -0,0 +1,511 @@
+<script setup>
+import { closeToast, showLoadingToast, showSuccessToast, showFailToast, showConfirmDialog } from 'vant'
+import axios from 'axios'
+import { useUserStore } from "~/store/user";
+const userInfo = useUserStore();
+const loading = ref(false);
+const { currentRoute } = useRouter()
+const route = currentRoute.value
+const xm_id = route.query.xm_id
+const detailData = ref({})
+const jdData = ref([
+  { v: "1", n: "项目立项" },
+  { v: "2", n: "项目招标" },
+  { v: "3", n: "项目施工" },
+  { v: "4", n: "项目付款" }
+])
+const scrollHeight = ref(0);
+const currentStep = ref(0);
+const stepData = ref([])
+
+const currentData = ref({});
+const dialogVisible = ref(false);
+const dialogTitle = ref("");
+const dialogType = ref("");
+const fileData = ref([]);
+
+initDetailInfo();
+function initDetailInfo() {
+  loading.value = true;
+  request({
+    url: '/jdbg/xmgl_xmzlk/detail',
+    data: {
+      xm_id,
+    },
+  }).then((res) => {
+    loading.value = false;
+    closeToast()
+    detailData.value = res.data.one_info;
+    detailData.value.xm_start_time = detailData.value.xm_start_time.substring(0, 10);
+
+    stepData.value = [];
+    currentStep.value = 0;
+    detailData.value.xmlc.map((item, i) => {
+      item.order = i + 1;
+      item.lcIndex = i;
+      item.fileData = [];
+      if (item.lc_fj) {
+        let lc_fj = item.lc_fj.split(";");
+        lc_fj.map(v => {
+          let arr = v.split("|");
+          item.fileData.push({
+            url: arr[0],
+            name: arr[1]
+          })
+        })
+      }
+
+      if (item.xmlc_wc == 1) {
+        currentStep.value = i + 1;
+      }
+      let index = stepData.value.findIndex(val => val.lc_jd == item.lc_jd);
+      if (index == -1) {
+        let obj = {
+          lc_jd: item.lc_jd,
+          name: "",
+          children: [item]
+        }
+        jdData.value.map(val => {
+          if (obj.lc_jd == val.v) {
+            obj.name = val.n;
+          }
+        })
+        stepData.value.push(obj);
+      } else {
+        stepData.value[index].children.push(item);
+      }
+    })
+
+    handleScroll();
+  })
+}
+
+function fillIn(data) {
+  if (currentStep.value != data.lcIndex) {
+    return
+  }
+  currentData.value = data;
+  dialogVisible.value = true;
+  if (data.lc_bt == 1) {
+    dialogTitle.value = "必填项";
+    dialogType.value = 2;
+  } else {
+    dialogTitle.value = "填写";
+    dialogType.value = 3;
+  }
+}
+
+function beforeCloseDialog(action) {
+  if (action == 'confirm') {
+    if (dialogType.value != 1) {
+      if (currentData.value.lc_bt == 1 && currentData.value.xmlc_bt_value == "") {
+        showFailToast("请输入必填项!");
+        return false;
+      }
+      handleClose();
+    } else {
+      handleUpload();
+    }
+  } else {
+    handleClose();
+  }
+}
+
+
+function handleClose() {
+  dialogVisible.value = false;
+  currentData.value = {};
+  dialogType.value = "";
+  dialogTitle.value = "";
+  fileData.value = [];
+}
+
+function handleFinish(data, type) {
+  if (type == 2) {
+    return
+  }
+  if (data.lc_bt == 1) {
+    if (data.xmlc_bt_value == "") {
+      showFailToast("请输入" + data.lc_bt_name + "!");
+    } else {
+      commit(data, type);
+    }
+  } else {
+    if (data.lc_bt_name == "") {
+      commit(data, type);
+    } else {
+      if (data.xmlc_bt_value != "") {
+        commit(data, type);
+        return;
+      }
+      showConfirmDialog({
+        title: '提示',
+        message: data.lc_bt_name + "未填写,是否确定完成",
+      })
+        .then(() => {
+          commit(data, type);
+        })
+        .catch(() => {
+        });
+    }
+  }
+}
+
+async function commit(data, type, close) {
+  let obj = {
+    xm_id: xm_id,
+    xmlc_id: data.xmlc_id,
+    xmlc_wc: type,
+    lc_bt_name: data.lc_bt_name,
+    xmlc_bt_value: data.xmlc_bt_value,
+    lc_fj: data.lc_fj,
+    lc_wc_name: userInfo.real_name,
+  }
+
+  loading.value = true;
+  request({
+    url: '/jdbg/xmgl_xmzlk/edit_lc',
+    data: obj,
+  }).then(({ code }) => {
+    loading.value = false;
+    if (code == 1) {
+      let con = document.querySelector(".xmgktParentDiv");
+      scrollHeight.value = con.scrollTop;
+
+      if (close) {
+        handleClose();
+      } else {
+        showSuccessToast('事项完成!');
+      }
+      initDetailInfo();
+    }
+  })
+}
+
+function handleScroll() {
+  setTimeout(() => {
+    let con = document.querySelector(".xmgktParentDiv");
+    con.scrollTo({
+      top: scrollHeight.value
+    })
+  }, 0)
+}
+
+function handleOpen(data) {
+  currentData.value = data;
+  dialogVisible.value = true;
+  dialogTitle.value = data.lc_sx;
+  dialogType.value = 1;
+  fileData.value = data.fileData;
+}
+
+function handleAfterRead(file) {
+  if (file.file) {
+    const formData = new FormData();
+    formData.append("api", "json");
+    formData.append("token", userInfo.token);
+    formData.append("urltype", "0");
+    formData.append("filedata", file.file);
+    loading.value = true;
+    axios({
+      method: 'post',
+      url: window.globalVariables.api + "/upload/main/file",
+      headers: { 'Content-Type': 'multipart/form-data' },
+      data: formData
+    })
+      .then((res) => {
+        loading.value = false;
+        if (res.data.code === '1') {
+          fileData.value.unshift({
+            url: res.data.data.url,
+            name: res.data.data.file_name
+          })
+        } else {
+          showFailToast("上传失败!");
+        }
+      })
+      .catch(error => {
+        console.log(error)
+      })
+  }
+}
+
+function handleUpload() {
+  let arr = fileData.value.map(item => {
+    return `${item.url}|${item.name}`
+  })
+  currentData.value.lc_fj = arr.join(";");
+  commit(currentData.value, currentData.value.xmlc_wc, true);
+}
+
+function handleRemove(index) {
+  fileData.value.splice(index, 1);
+}
+
+const dialogPreviewVisible = ref(false);
+const showUrl = ref("");
+const suffix = ref("");
+const previewUrl = ref("https://view.officeapps.live.com/op/view.aspx?src=");
+function handlePreview(data) {
+  showUrl.value = getFullUrl(data.url);
+  suffix.value = showUrl.value.substr(showUrl.value.lastIndexOf(".") + 1).toLowerCase();
+  // dialogPreviewVisible.value = true;
+
+  if (suffix.value == "mp3" || suffix.value == "mp4" || suffix.value == "pdf" || suffix.value == "jpg" || suffix.value == "jpeg" || suffix.value == "png") {
+    window.open(showUrl.value);
+  } else {
+    window.open(previewUrl.value + showUrl.value);
+  }
+}
+
+function getFullUrl(url) {
+  if (!url) return '';
+  return url.startsWith('http') ? url : window.GLOBAL_CONFIG.api + '/' + url
+}
+</script>
+
+<template>
+  <div v-show="loading" class="h-100vh w-full absolute z-3000 bg-hex-000000b3 flex items-center justify-center">
+    <van-loading color="#ffffffcc" text-color="#ffffffcc" vertical>加载中...</van-loading>
+  </div>
+  <div class="xmgktParentDiv h-100vh overflow-auto">
+    <div class="tableContainer">
+      <div class="topPart">
+        <table class="Tb" width="100%" cellspacing="0" cellpadding="0">
+          <tr>
+            <td class="titleOpt">
+              项目名称:
+            </td>
+            <td>{{ detailData.xm_name }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              项目类别:
+            </td>
+            <td>{{ detailData.xm_type_option_n }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              经办科室:
+            </td>
+            <td>{{ detailData.department_name }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              经办人:
+            </td>
+            <td>{{ detailData.xm_zrr }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              项目开始时间:
+            </td>
+            <td>{{ detailData.xm_start_time }}</td>
+          </tr>
+        </table>
+      </div>
+    </div>
+
+    <div class="xmgktManageContent">
+      <div class="stepDiv" v-for="(item, index) in stepData" :key="index">
+        <div class="parent-head nowrap" :class="item.children[0].xmlc_wc==1?'finished':''">
+          <div class="step-head">
+            <div class="parent-head-line"></div>
+          </div>
+          <div class="parent-name whitespace-nowrap">{{item.name}}</div>
+        </div>
+        <div class="parent">
+          <div class="child d-flex" :class="value.xmlc_wc==1?'finished':''" v-for="(value, i) in item.children" :key="i">
+            <div class="step-head">
+              <div class="step-line" v-if="index!=stepData.length-1 || i!=item.children.length-1"></div>
+              <div class="step-check d-flex flex-v-mid flex-l-mid">
+                <van-icon name="success" />
+              </div>
+            </div>
+            <div class="mainCon flex-1 flex-row">
+              <div>
+                <div class="flex">
+                  <div class="w-130px">{{value.order}}.{{value.lc_sx}}</div>
+                  <div class="w-80px">事项权值 {{value.lc_sxqz}}</div>
+                </div>
+                <div class="flex mt-5px">
+                  <div v-if="value.lc_fj && value.lc_fj!=''" class="w-130px text-hex-265CD4" @click="handleOpen(value)">查看附件</div>
+                  <div v-else class="w-130px">未上传附件</div>
+                  <div v-if="value.lc_bt_name=='' || value.lc_bt_name==undefined"></div>
+                  <div v-else class="d-flex whitespace-nowrap">
+                    <div>{{value.lc_bt_name}}: </div>
+                    <div class="hand" @click="fillIn(value)">{{value.xmlc_bt_value == "" ? "待填" : value.xmlc_bt_value + "万元"}}</div>
+                  </div>
+                </div>
+                <div class="attach">*{{value.lc_fj_bz}}</div>
+              </div>
+              <div class="text-right">
+                <div class="whitespace-nowrap text-hex-A2A2A2 text-8px mt-3px" v-if="value.xmlc_wc==1">{{value.lc_wc_name}}点击完成</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <van-dialog v-model:show="dialogVisible" :title="dialogTitle" show-cancel-button :show-confirm-button="false" :before-close="beforeCloseDialog">
+      <!-- <div v-if="dialogType!=1" class="flex items-center flex-v-mid px-2 py-3">
+        <div class="whitespace-nowrap"><span class="" style="color: red;" v-if="currentData.lc_bt==1">*</span>{{currentData.lc_bt_name}}:</div>
+        <input class="flex-1 border px-1 py-5px rounded-6px" type="number" v-model="currentData.xmlc_bt_value" oninput="if(value.length>10)value=value.slice(0,10)" />
+      </div> -->
+      <div v-if="dialogType==1" class="px-2 py-3">
+        <!-- <van-uploader accept="*" :after-read="handleAfterRead">
+          <van-button size="small" type="primary">点击上传</van-button>
+        </van-uploader> -->
+        <div class="mt-8px text-14px text-hex-666 leading-30px">
+          <div v-for="(item, index) in fileData" :key="index">
+            <div class="flex items-center space-x-8px">
+              <van-icon name="description" />
+              <div class="flex-1 truncate" @click="handlePreview(item)">{{ item.name }}</div>
+              <!-- <van-icon name="cross" @click="handleRemove(index)" /> -->
+            </div>
+          </div>
+        </div>
+      </div>
+    </van-dialog>
+
+    <van-dialog class="previewDiv" v-model:show="dialogPreviewVisible" title="查看" show-cancel-button :show-confirm-button="false">
+      <div class="h-full">
+        <video ref="videoPlay" v-if="suffix=='mp4' || suffix=='MP4'" controls>
+          <source :src="showUrl" type="video/mp4" />
+          <source :src="showUrl" type="video/ogg" />
+        </video>
+        <audio ref="audioPlay" v-else-if="suffix=='mp3' || suffix=='MP3'" controls :src="showUrl"></audio>
+        <img v-else-if="suffix=='jpg' || suffix=='JPG' || suffix=='jpeg' || suffix=='JPEG' || suffix=='png' || suffix=='PNG'" :src="showUrl" alt="" style="width: 100%;max-height: 100%;">
+        <iframe v-else-if="suffix=='pdf' || suffix=='PDF'" class="iframe" :src="showUrl" width="100%" frameborder="0" scrolling="auto"></iframe>
+        <iframe v-else class="iframe" :src="previewUrl+showUrl" width="100%" frameborder="0" scrolling="auto"></iframe>
+      </div>
+    </van-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+$color: #4351ff;
+$color1: #d2e7fd;
+.flex-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.d-flex {
+  display: flex;
+}
+.xmgktManageContent {
+  padding: 10px;
+  font-size: 12px;
+  .stepDiv {
+    .step-head {
+      width: 30px;
+      height: 100%;
+      position: relative;
+    }
+    .parent-head {
+      position: relative;
+      display: inline-block;
+      margin-bottom: -5px;
+      .parent-head-line {
+        width: 1px;
+        height: 50px;
+        margin: auto;
+        background: #e2e2e2;
+      }
+      .parent-name {
+        position: absolute;
+        top: 0;
+        left: -15px;
+        background: #fff;
+        padding: 5px 0;
+        left: 60%;
+        transform: translateX(-50%);
+      }
+      &.finished {
+        .parent-head-line {
+          background: $color1;
+        }
+      }
+    }
+    .parent {
+      .child {
+        height: 70px;
+        .step-line {
+          width: 1px;
+          height: 100%;
+          margin: auto;
+          background: #e2e2e2;
+        }
+        .step-check {
+          width: 22px;
+          height: 22px;
+          border-radius: 50%;
+          color: #fff;
+          background: #c7c7c7;
+          box-shadow: 0 0 0 3px #e2e2e2;
+          position: absolute;
+          top: 5px;
+          left: 50%;
+          transform: translateX(-50%);
+          display: flex;
+          justify-content: center;
+          align-items: center;
+        }
+        .mainCon {
+          border-bottom: 1px solid #e6e6e6;
+          margin-left: 10px;
+          margin-top: -15px;
+          height: 100%;
+          .attach {
+            font-size: 12px;
+            color: #ff0000;
+            min-width: 100px;
+            // width: 200px;
+          }
+          .van-button {
+            width: 60px;
+            height: 28px;
+            padding: 0;
+            &.van-button--info {
+              background: #969696;
+              border-color: #969696;
+              color: #fff;
+            }
+          }
+        }
+        &.finished {
+          .step-line {
+            background: $color1;
+          }
+          .step-check {
+            background: #0976f8;
+            box-shadow: 0 0 0 3px $color1;
+          }
+        }
+      }
+    }
+  }
+}
+:deep() {
+  .previewDiv {
+    height: 80%;
+    top: 50%;
+    .van-dialog__header {
+      padding: 0;
+      line-height: 50px;
+    }
+    .van-dialog__content {
+      padding: 0 10px;
+      height: calc(100% - 100px);
+    }
+    video,
+    audio,
+    iframe {
+      width: 100%;
+      height: 100%;
+    }
+  }
+}
+</style>

+ 41 - 0
src/pages/projectManager/projectDatabase/index.vue

@@ -0,0 +1,41 @@
+<script setup>
+const router = useRouter()
+function cellClick(xm_id) {
+  router.push({ path: '/projectManager/projectDatabase/detail', query: { xm_id } })
+}
+
+const listMyApplyFor = ref([])
+const loadingMyApplyFor = ref(false)
+const finishedMyApplyFor = ref(false)
+let pageMyApplyFor = 1
+function onLoadMyApplyFor() {
+  loadingMyApplyFor.value = true
+  request({
+    url: '/jdbg/xmgl_xmzlk/index',
+    data: {
+      page: pageMyApplyFor,
+      limit: 20,
+      xm_dqjd: "100"
+    },
+  }).then((res) => {
+    const data = res.data
+    listMyApplyFor.value = [...listMyApplyFor.value, ...data.page_data]
+    finishedMyApplyFor.value = data.total_page === pageMyApplyFor
+    pageMyApplyFor++
+    loadingMyApplyFor.value = false
+  })
+}
+</script>
+
+<template>
+  <van-list
+    v-model:loading="loadingMyApplyFor" :finished="finishedMyApplyFor" finished-text="没有更多了"
+    @load="onLoadMyApplyFor"
+  >
+    <van-cell v-for="(item, index) in listMyApplyFor" :key="item" @click="cellClick(item.xm_id)">
+      <template #title>
+        <span>{{ `${index + 1}.\u00A0\u00A0${item.xm_name}` }}</span>
+      </template>
+    </van-cell>
+  </van-list>
+</template>

+ 458 - 0
src/pages/projectManager/projectManageControl/detail/index.vue

@@ -0,0 +1,458 @@
+<script setup>
+import { closeToast, showLoadingToast, showSuccessToast, showFailToast, showConfirmDialog } from 'vant'
+import axios from 'axios'
+import { useUserStore } from "~/store/user";
+const userInfo = useUserStore();
+const loading = ref(false);
+const { currentRoute } = useRouter()
+const route = currentRoute.value
+const xm_id = route.query.xm_id
+const detailData = ref({})
+const jdData = ref([
+  { v: "1", n: "项目立项" },
+  { v: "2", n: "项目招标" },
+  { v: "3", n: "项目施工" },
+  { v: "4", n: "项目付款" }
+])
+const scrollHeight = ref(0);
+const currentStep = ref(0);
+const stepData = ref([])
+
+const currentData = ref({});
+const dialogVisible = ref(false);
+const dialogTitle = ref("");
+const dialogType = ref("");
+const fileData = ref([]);
+
+initDetailInfo();
+function initDetailInfo() {
+  loading.value = true;
+  request({
+    url: '/jdbg/xmgl_xmzlk/detail',
+    data: {
+      xm_id,
+    },
+  }).then((res) => {
+    loading.value = false;
+    closeToast()
+    detailData.value = res.data.one_info;
+    detailData.value.xm_start_time = detailData.value.xm_start_time.substring(0, 10);
+
+    stepData.value = [];
+    currentStep.value = 0;
+    detailData.value.xmlc.map((item, i) => {
+      item.order = i + 1;
+      item.lcIndex = i;
+      item.fileData = [];
+      if (item.lc_fj) {
+        let lc_fj = item.lc_fj.split(";");
+        lc_fj.map(v => {
+          let arr = v.split("|");
+          item.fileData.push({
+            url: arr[0],
+            name: arr[1]
+          })
+        })
+      }
+
+      if (item.xmlc_wc == 1) {
+        currentStep.value = i + 1;
+      }
+      let index = stepData.value.findIndex(val => val.lc_jd == item.lc_jd);
+      if (index == -1) {
+        let obj = {
+          lc_jd: item.lc_jd,
+          name: "",
+          children: [item]
+        }
+        jdData.value.map(val => {
+          if (obj.lc_jd == val.v) {
+            obj.name = val.n;
+          }
+        })
+        stepData.value.push(obj);
+      } else {
+        stepData.value[index].children.push(item);
+      }
+    })
+
+    handleScroll();
+  })
+}
+
+function fillIn(data) {
+  if (currentStep.value != data.lcIndex) {
+    return
+  }
+  currentData.value = data;
+  dialogVisible.value = true;
+  if (data.lc_bt == 1) {
+    dialogTitle.value = "必填项";
+    dialogType.value = 2;
+  } else {
+    dialogTitle.value = "填写";
+    dialogType.value = 3;
+  }
+}
+
+function beforeCloseDialog(action) {
+  if (action == 'confirm') {
+    if (dialogType.value != 1) {
+      if (currentData.value.lc_bt == 1 && currentData.value.xmlc_bt_value == "") {
+        showFailToast("请输入必填项!");
+        return false;
+      }
+      handleClose();
+    } else {
+      handleUpload();
+    }
+  } else {
+    handleClose();
+  }
+}
+
+
+function handleClose() {
+  dialogVisible.value = false;
+  currentData.value = {};
+  dialogType.value = "";
+  dialogTitle.value = "";
+  fileData.value = [];
+}
+
+function handleFinish(data, type) {
+  if (type == 2) {
+    return
+  }
+  if (data.lc_bt == 1) {
+    if (data.xmlc_bt_value == "") {
+      showFailToast("请输入" + data.lc_bt_name + "!");
+    } else {
+      commit(data, type);
+    }
+  } else {
+    if (data.lc_bt_name == "") {
+      commit(data, type);
+    } else {
+      if (data.xmlc_bt_value != "") {
+        commit(data, type);
+        return;
+      }
+      showConfirmDialog({
+        title: '提示',
+        message: data.lc_bt_name + "未填写,是否确定完成",
+      })
+        .then(() => {
+          commit(data, type);
+        })
+        .catch(() => {
+        });
+    }
+  }
+}
+
+async function commit(data, type, close) {
+  let obj = {
+    xm_id: xm_id,
+    xmlc_id: data.xmlc_id,
+    xmlc_wc: type,
+    lc_bt_name: data.lc_bt_name,
+    xmlc_bt_value: data.xmlc_bt_value,
+    lc_fj: data.lc_fj,
+    lc_wc_name: userInfo.real_name,
+  }
+
+  loading.value = true;
+  request({
+    url: '/jdbg/xmgl_xmzlk/edit_lc',
+    data: obj,
+  }).then(({ code }) => {
+    loading.value = false;
+    if (code == 1) {
+      let con = document.querySelector(".xmgktParentDiv");
+      scrollHeight.value = con.scrollTop;
+
+      if (close) {
+        handleClose();
+      } else {
+        showSuccessToast('事项完成!');
+      }
+      initDetailInfo();
+    }
+  })
+}
+
+function handleScroll() {
+  setTimeout(() => {
+    let con = document.querySelector(".xmgktParentDiv");
+    con.scrollTo({
+      top: scrollHeight.value
+    })
+  }, 0)
+}
+
+function handleOpen(data) {
+  currentData.value = data;
+  dialogVisible.value = true;
+  dialogTitle.value = data.lc_sx;
+  dialogType.value = 1;
+  fileData.value = data.fileData;
+}
+
+function handleAfterRead(file) {
+  if (file.file) {
+    const formData = new FormData();
+    formData.append("api", "json");
+    formData.append("token", userInfo.token);
+    formData.append("urltype", "0");
+    formData.append("filedata", file.file);
+    loading.value = true;
+    axios({
+      method: 'post',
+      url: window.globalVariables.api + "/upload/main/file",
+      headers: { 'Content-Type': 'multipart/form-data' },
+      data: formData
+    })
+      .then((res) => {
+        loading.value = false;
+        if (res.data.code === '1') {
+          fileData.value.unshift({
+            url: res.data.data.url,
+            name: res.data.data.file_name
+          })
+        } else {
+          showFailToast("上传失败!");
+        }
+      })
+      .catch(error => {
+        console.log(error)
+      })
+  }
+}
+
+function handleUpload() {
+  let arr = fileData.value.map(item => {
+    return `${item.url}|${item.name}`
+  })
+  currentData.value.lc_fj = arr.join(";");
+  commit(currentData.value, currentData.value.xmlc_wc, true);
+}
+
+function handleRemove(index) {
+  fileData.value.splice(index, 1);
+}
+</script>
+
+<template>
+  <div v-show="loading" class="h-100vh w-full absolute z-3000 bg-hex-000000b3 flex items-center justify-center">
+    <van-loading color="#ffffffcc" text-color="#ffffffcc" vertical>加载中...</van-loading>
+  </div>
+  <div class="xmgktParentDiv h-100vh overflow-auto">
+    <div class="tableContainer">
+      <div class="topPart">
+        <table class="Tb" width="100%" cellspacing="0" cellpadding="0">
+          <tr>
+            <td class="titleOpt">
+              项目名称:
+            </td>
+            <td>{{ detailData.xm_name }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              项目类别:
+            </td>
+            <td>{{ detailData.xm_type_option_n }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              经办科室:
+            </td>
+            <td>{{ detailData.department_name }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              经办人:
+            </td>
+            <td>{{ detailData.xm_zrr }}</td>
+          </tr>
+          <tr>
+            <td class="titleOpt">
+              项目开始时间:
+            </td>
+            <td>{{ detailData.xm_start_time }}</td>
+          </tr>
+        </table>
+      </div>
+    </div>
+
+    <div class="xmgktManageContent">
+      <div class="stepDiv" v-for="(item, index) in stepData" :key="index">
+        <div class="parent-head nowrap" :class="item.children[0].xmlc_wc==1?'finished':''">
+          <div class="step-head">
+            <div class="parent-head-line"></div>
+          </div>
+          <div class="parent-name whitespace-nowrap">{{item.name}}</div>
+        </div>
+        <div class="parent">
+          <div class="child d-flex" :class="value.xmlc_wc==1?'finished':''" v-for="(value, i) in item.children" :key="i">
+            <div class="step-head">
+              <div class="step-line" v-if="index!=stepData.length-1 || i!=item.children.length-1"></div>
+              <div class="step-check d-flex flex-v-mid flex-l-mid">
+                <van-icon name="success" />
+              </div>
+            </div>
+            <div class="mainCon flex-1 flex-row">
+              <div>
+                <div class="flex">
+                  <div class="w-130px">{{value.order}}.{{value.lc_sx}}</div>
+                  <div class="w-80px">事项权值 {{value.lc_sxqz}}</div>
+                </div>
+                <div class="flex mt-5px">
+                  <div class="w-130px text-hex-265CD4" @click="handleOpen(value)">点击上传</div>
+                  <div v-if="value.lc_bt_name=='' || value.lc_bt_name==undefined"></div>
+                  <div v-else class="d-flex whitespace-nowrap">
+                    <div>{{value.lc_bt_name}}: </div>
+                    <div class="hand" @click="fillIn(value)">{{value.xmlc_bt_value == "" ? "待填" : value.xmlc_bt_value + "万元"}}</div>
+                  </div>
+                </div>
+                <div class="attach">*{{value.lc_fj_bz}}</div>
+              </div>
+              <div class="text-right">
+                <van-button size="small" v-if="value.xmlc_wc==1" type="info" @click="handleFinish(value, 2)">已完成</van-button>
+                <van-button size="small" v-if="value.xmlc_wc==2" :disabled="currentStep==value.lcIndex?false:true" type="primary" @click="handleFinish(value, 1)">完成</van-button>
+                <div class="whitespace-nowrap text-hex-A2A2A2 text-8px mt-3px" v-if="value.xmlc_wc==1">{{value.lc_wc_name}}点击完成</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <van-dialog v-model:show="dialogVisible" :title="dialogTitle" show-cancel-button :before-close="beforeCloseDialog">
+      <div v-if="dialogType!=1" class="flex items-center flex-v-mid px-2 py-3">
+        <div class="whitespace-nowrap"><span class="" style="color: red;" v-if="currentData.lc_bt==1">*</span>{{currentData.lc_bt_name}}:</div>
+        <input class="flex-1 border px-1 py-5px rounded-6px" type="number" v-model="currentData.xmlc_bt_value" oninput="if(value.length>10)value=value.slice(0,10)" />
+      </div>
+      <div v-if="dialogType==1" class="px-2 py-3">
+        <van-uploader accept="*" :after-read="handleAfterRead">
+          <van-button size="small" type="primary">点击上传</van-button>
+        </van-uploader>
+        <div class="mt-8px text-14px text-hex-666 leading-30px">
+          <div v-for="(item, index) in fileData" :key="index">
+            <div class="flex items-center space-x-8px">
+              <van-icon name="description" />
+              <div class="flex-1 truncate">{{ item.name }}</div>
+              <van-icon name="cross" @click="handleRemove(index)" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </van-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+$color: #4351ff;
+$color1: #d2e7fd;
+.flex-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.d-flex {
+  display: flex;
+}
+.xmgktManageContent {
+  padding: 10px;
+  font-size: 12px;
+  .stepDiv {
+    .step-head {
+      width: 30px;
+      height: 100%;
+      position: relative;
+    }
+    .parent-head {
+      position: relative;
+      display: inline-block;
+      margin-bottom: -5px;
+      .parent-head-line {
+        width: 1px;
+        height: 50px;
+        margin: auto;
+        background: #e2e2e2;
+      }
+      .parent-name {
+        position: absolute;
+        top: 0;
+        left: -15px;
+        background: #fff;
+        padding: 5px 0;
+        left: 60%;
+        transform: translateX(-50%);
+      }
+      &.finished {
+        .parent-head-line {
+          background: $color1;
+        }
+      }
+    }
+    .parent {
+      .child {
+        height: 70px;
+        .step-line {
+          width: 1px;
+          height: 100%;
+          margin: auto;
+          background: #e2e2e2;
+        }
+        .step-check {
+          width: 22px;
+          height: 22px;
+          border-radius: 50%;
+          color: #fff;
+          background: #c7c7c7;
+          box-shadow: 0 0 0 3px #e2e2e2;
+          position: absolute;
+          top: 5px;
+          left: 50%;
+          transform: translateX(-50%);
+          display: flex;
+          justify-content: center;
+          align-items: center;
+        }
+        .mainCon {
+          border-bottom: 1px solid #e6e6e6;
+          margin-left: 10px;
+          margin-top: -15px;
+          height: 100%;
+          .attach {
+            font-size: 12px;
+            color: #ff0000;
+            min-width: 100px;
+            // width: 200px;
+          }
+          .van-button {
+            width: 60px;
+            height: 28px;
+            padding: 0;
+            &.van-button--info {
+              background: #969696;
+              border-color: #969696;
+              color: #fff;
+            }
+          }
+        }
+        &.finished {
+          .step-line {
+            background: $color1;
+          }
+          .step-check {
+            background: #0976f8;
+            box-shadow: 0 0 0 3px $color1;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 40 - 0
src/pages/projectManager/projectManageControl/index.vue

@@ -0,0 +1,40 @@
+<script setup>
+const router = useRouter()
+function cellClick(xm_id) {
+  router.push({ path: '/projectManager/projectManageControl/detail', query: { xm_id } })
+}
+
+const listMyApplyFor = ref([])
+const loadingMyApplyFor = ref(false)
+const finishedMyApplyFor = ref(false)
+let pageMyApplyFor = 1
+function onLoadMyApplyFor() {
+  loadingMyApplyFor.value = true
+  request({
+    url: '/jdbg/xmgl_xmzlk/index',
+    data: {
+      page: pageMyApplyFor,
+      limit: 20,
+    },
+  }).then((res) => {
+    const data = res.data
+    listMyApplyFor.value = [...listMyApplyFor.value, ...data.page_data]
+    finishedMyApplyFor.value = data.total_page === pageMyApplyFor
+    pageMyApplyFor++
+    loadingMyApplyFor.value = false
+  })
+}
+</script>
+
+<template>
+  <van-list
+    v-model:loading="loadingMyApplyFor" :finished="finishedMyApplyFor" finished-text="没有更多了"
+    @load="onLoadMyApplyFor"
+  >
+    <van-cell v-for="(item, index) in listMyApplyFor" :key="item" @click="cellClick(item.xm_id)">
+      <template #title>
+        <span>{{ `${index + 1}.\u00A0\u00A0${item.xm_name}` }}</span>
+      </template>
+    </van-cell>
+  </van-list>
+</template>