From 95b6a6388e4cc4e6ed0f54cc04212a86cd8cf829 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期五, 23 五月 2025 13:37:09 +0800
Subject: [PATCH] 1、用户管理新增和编辑用户时设置工单为必填项 2、新增终端登录、首页、设备点检、故障上报、上下班打卡、停机原因维护页面(未与后端联调且客户未确定页面设计)并调整全局路由守卫相关逻辑 3、调整设备结构树设备层级和车间层级区分的判断条件 4、调整电子样板检索与部件借用弹窗列表与搜索区域样式

---
 src/permission.js                                                                        |   90 ++-
 src/components/layouts/index.js                                                          |    3 
 src/views/dnc/base/OperatorLogin.vue                                                     |  268 +++++++++++
 src/components/layouts/TerminalLayout.vue                                                |  126 +++++
 src/views/user/Login.vue                                                                 |    5 
 src/assets/operator-login-bg.png                                                         |    0 
 src/views/dnc/base/modules/TerminalIndex/ReportEquipmentFault.vue                        |   66 ++
 src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/MaintainShutdownModal.vue  |   68 ++
 src/views/system/modules/UserModal.vue                                                   |    1 
 src/views/dnc/base/modules/ProductStructure/Document/NcDocumentSearchModal.vue           |   10 
 src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/SplitShutdownInfoModal.vue |  121 +++++
 src/views/dnc/base/modules/ProductStructure/Document/NcComponentBorrowModal.vue          |   31 
 src/views/dnc/base/modules/TerminalIndex/EquipmentSpotCheck.vue                          |  169 +++++++
 src/config/router.config.js                                                              |   45 +
 src/views/dnc/base/TerminalIndex.vue                                                     |  109 ++++
 src/views/dnc/base/modules/TerminalIndex/EquipmentStartWork.vue                          |  128 +++++
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue                       |    2 
 src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose.vue                        |  175 +++++++
 18 files changed, 1,357 insertions(+), 60 deletions(-)

diff --git a/src/assets/operator-login-bg.png b/src/assets/operator-login-bg.png
new file mode 100644
index 0000000..55de0cf
--- /dev/null
+++ b/src/assets/operator-login-bg.png
Binary files differ
diff --git a/src/components/layouts/TerminalLayout.vue b/src/components/layouts/TerminalLayout.vue
new file mode 100644
index 0000000..01ef462
--- /dev/null
+++ b/src/components/layouts/TerminalLayout.vue
@@ -0,0 +1,126 @@
+<template>
+  <div class="full-screen-container">
+    <router-view class="router-view">
+      <template v-slot:function>
+        <a-space>
+          <button class="button" @click="handleLogout">鍒囨崲鐢ㄦ埛</button>
+          <button class="button" @click="backToIndex">杩斿洖涓婚〉</button>
+          <button class="button">璁剧疆</button>
+        </a-space>
+      </template>
+    </router-view>
+
+    <div class="footer" v-if="$route.path!=='/terminal/login'">
+      <div>濮撳悕锛歿{nickname()}}</div>
+      <div>褰撳墠鏃堕棿锛歿{currentDateAndTime}}</div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import { mapActions, mapGetters } from 'vuex'
+
+  import moment from 'moment'
+
+  export default {
+    name: 'TerminalLayout',
+    data() {
+      return {
+        currentDateAndTime: null,
+        getDateAndTimeInterval: null
+      }
+    },
+    watch: {
+      '$route.path': {
+        handler(val) {
+          if (val === '/terminal/index' || val === '/terminal/login') document.title = 'MDC鏅烘収杞﹂棿'
+        }
+      }
+    },
+    created() {
+      this.getCurrentDateAndTime()
+
+    },
+    beforeDestroy() {
+      if (this.getDateAndTimeInterval) {
+        clearInterval(this.getDateAndTimeInterval)
+        this.getDateAndTimeInterval = null
+      }
+    },
+    methods: {
+      ...mapActions(['Logout']),
+
+      ...mapGetters(['nickname']),
+
+      handleLogout() {
+        const that = this
+
+        this.$confirm({
+          title: '鎻愮ず',
+          content: '纭畾瑕佸垏鎹㈢敤鎴峰悧 ?',
+          onOk() {
+            return that.Logout({}).then(() => {
+              window.location.reload()
+            }).catch(err => {
+              that.$message.error({
+                title: '閿欒',
+                description: err.message
+              })
+            })
+          },
+          onCancel() {
+          }
+        })
+      },
+
+      backToIndex() {
+        if (this.$route.path !== '/terminal/index') this.$router.push('/terminal/index')
+      },
+
+      // 鑾峰彇褰撳墠鏃ユ湡鍜屾椂闂达紙1绉掓洿鏂�1娆★級
+      getCurrentDateAndTime() {
+        this.getDateAndTimeInterval = setInterval(() => this.currentDateAndTime = moment().format('YYYY-MM-DD HH:mm:ss'), 1000)
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .full-screen-container {
+    display: flex;
+    flex-direction: column;
+    height: 100vh;
+
+    .router-view {
+      flex: 1;
+      padding: 24px;
+      display: flex;
+      flex-direction: column;
+    }
+  }
+
+  .button {
+    font-weight: bold;
+    padding: 15px 15px;
+    border: 1px solid rgba(0, 0, 0, .2);
+    border-radius: 5px;
+    cursor: pointer;
+    box-shadow: 6px 6px 16px rgba(0, 0, 0, 0.2),
+      -6px -6px 16px rgba(255, 255, 255, 0.8),
+    inset 0 0 0 transparent;
+
+    &:hover {
+      box-shadow: 0 0 0 transparent,
+      inset 6px 6px 12px rgba(0, 0, 0, 0.2),
+        inset -6px -6px 12px rgba(255, 255, 255, 0.8);
+    }
+  }
+
+  .footer {
+    font-size: 16px;
+    padding: 12px 24px;
+    color: #000;
+    display: flex;
+    justify-content: space-between;
+  }
+</style>
\ No newline at end of file
diff --git a/src/components/layouts/index.js b/src/components/layouts/index.js
index 7cf0f77..644c25b 100644
--- a/src/components/layouts/index.js
+++ b/src/components/layouts/index.js
@@ -4,5 +4,6 @@
 import RouteView from '@/components/layouts/RouteView'
 import PageView from '@/components/layouts/PageView'
 import TabLayout from '@/components/layouts/TabLayout'
+import TerminalLayout from '@/components/layouts/TerminalLayout'
 
-export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView, TabLayout }
\ No newline at end of file
+export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView, TabLayout, TerminalLayout }
\ No newline at end of file
diff --git a/src/config/router.config.js b/src/config/router.config.js
index 2154e1f..9f2dac3 100644
--- a/src/config/router.config.js
+++ b/src/config/router.config.js
@@ -1,4 +1,4 @@
-import { UserLayout, TabLayout, RouteView, BlankLayout, PageView } from '@/components/layouts'
+import { UserLayout, TabLayout, RouteView, BlankLayout, PageView, TerminalLayout } from '@/components/layouts'
 
 /**
  * 璧拌彍鍗曪紝璧版潈闄愭帶鍒�
@@ -49,7 +49,7 @@
         path: 'alteration',
         name: 'alteration',
         component: () => import(/* webpackChunkName: "user" */ '@/views/user/alteration/Alteration')
-      },
+      }
     ]
   },
   {
@@ -63,7 +63,7 @@
         path: 'login',
         name: 'oauth2-app-login',
         component: () => import(/* webpackChunkName: "oauth2-app.login" */ '@/views/user/oauth2/OAuth2Login')
-      },
+      }
     ]
   },
 
@@ -84,8 +84,45 @@
     component: () => import('@/views/mdc/base/MdcWorkshopSignage.vue')
   },
   {
+    path: '/terminal',
+    redirect: '/terminal/login',
+    component: TerminalLayout,
+    children: [
+      {
+        path: 'login',
+        name: 'operatorLogin',
+        component: () => import('@/views/dnc/base/OperatorLogin.vue')
+      },
+      {
+        path: 'index',
+        name: 'terminalIndex',
+        component: () => import('@/views/dnc/base/TerminalIndex.vue')
+      },
+      {
+        path: 'work',
+        name: 'equipmentStartWork',
+        component: () => import('@/views/dnc/base/modules/TerminalIndex/EquipmentStartWork.vue')
+      },
+      {
+        path: 'fault',
+        name: 'reportEquipmentFault',
+        component: () => import('@/views/dnc/base/modules/TerminalIndex/ReportEquipmentFault.vue')
+      },
+      {
+        path: 'close',
+        name: 'reportEquipmentClose',
+        component: () => import('@/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose.vue')
+      },
+      {
+        path: 'spotCheck',
+        name: 'equipmentSpotCheck',
+        component: () => import('@/views/dnc/base/modules/TerminalIndex/EquipmentSpotCheck.vue')
+      }
+    ]
+  },
+  {
     path: '/404',
     component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')
-  },
+  }
 
 ]
diff --git a/src/permission.js b/src/permission.js
index fe8d825..ddd93e2 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -4,12 +4,12 @@
 import NProgress from 'nprogress' // progress bar
 import 'nprogress/nprogress.css' // progress bar style
 import notification from 'ant-design-vue/es/notification'
-import { ACCESS_TOKEN,INDEX_MAIN_PAGE_PATH, OAUTH2_LOGIN_PAGE_PATH } from '@/store/mutation-types'
+import { ACCESS_TOKEN, INDEX_MAIN_PAGE_PATH, OAUTH2_LOGIN_PAGE_PATH } from '@/store/mutation-types'
 import { generateIndexRouter, isOAuth2AppEnv } from '@/utils/util'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
-const whiteList = ['/user/login', '/user/register', '/user/register-result','/user/alteration'] // no redirect whitelist
+const whiteList = ['/user/login', '/user/register', '/user/register-result', '/user/alteration', '/terminal/login'] // no redirect whitelist
 whiteList.push(OAUTH2_LOGIN_PAGE_PATH)
 
 router.beforeEach((to, from, next) => {
@@ -21,8 +21,8 @@
     to.matched.splice(2, to.matched.length - 3)
   }
   //update-end---author:scott ---date::2022-10-13  for锛歔jeecg-boot/issues/4091]澶氱骇璺敱缂撳瓨闂 #4091--------------
-  
-  
+
+
   NProgress.start() // start progress bar
 
   if (Vue.ls.get(ACCESS_TOKEN)) {
@@ -30,57 +30,75 @@
     if (to.path === '/user/login' || to.path === OAUTH2_LOGIN_PAGE_PATH) {
       next({ path: INDEX_MAIN_PAGE_PATH })
       NProgress.done()
-    } else {
+    }
+    else {
       if (store.getters.permissionList.length === 0) {
         store.dispatch('GetPermissionList').then(res => {
-              const menuData = res.result.menu;
-              //console.log(res.message)
-              if (menuData === null || menuData === "" || menuData === undefined) {
-                return;
+          const menuData = res.result.menu
+          //console.log(res.message)
+          if (menuData === null || menuData === '' || menuData === undefined) {
+            return
+          }
+          let constRoutes = []
+          constRoutes = generateIndexRouter(menuData)
+          // 娣诲姞涓荤晫闈㈣矾鐢�
+          store.dispatch('UpdateAppRouter', { constRoutes }).then(() => {
+            // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+            // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+            router.addRoutes(store.getters.addRouters)
+            const redirect = decodeURIComponent(from.query.redirect || to.path)
+            if (to.path === redirect) {
+              // hack鏂规硶 纭繚addRoutes宸插畬鎴� ,set the replace: true so the navigation will not leave a history record
+              next({ ...to, replace: true })
+            } else {
+              // 璺宠浆鍒扮洰鐨勮矾鐢�
+              if (to.path !== '/terminal/login' && from.path !== '/terminal/login' && redirect.split('/')[1] === 'terminal') {
+                next({ path: '/terminal/login' })
+              } else {
+                next({ path: redirect })
               }
-              let constRoutes = [];
-              constRoutes = generateIndexRouter(menuData);
-              // 娣诲姞涓荤晫闈㈣矾鐢�
-              store.dispatch('UpdateAppRouter',  { constRoutes }).then(() => {
-                // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
-                // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
-                router.addRoutes(store.getters.addRouters)
-                const redirect = decodeURIComponent(from.query.redirect || to.path)
-                if (to.path === redirect) {
-                  // hack鏂规硶 纭繚addRoutes宸插畬鎴� ,set the replace: true so the navigation will not leave a history record
-                  next({ ...to, replace: true })
-                } else {
-                  // 璺宠浆鍒扮洰鐨勮矾鐢�
-                  next({ path: redirect })
-                }
-              })
-            })
+            }
+          })
+        })
           .catch(() => {
-           /* notification.error({
-              message: '绯荤粺鎻愮ず',
-              description: '璇锋眰鐢ㄦ埛淇℃伅澶辫触锛岃閲嶈瘯锛�'
-            })*/
+            /* notification.error({
+               message: '绯荤粺鎻愮ず',
+               description: '璇锋眰鐢ㄦ埛淇℃伅澶辫触锛岃閲嶈瘯锛�'
+             })*/
             store.dispatch('Logout').then(() => {
               next({ path: '/user/login', query: { redirect: to.fullPath } })
             })
           })
-      } else {
-        next()
+      }
+      else {
+        // 璺宠浆鍒扮洰鐨勮矾鐢�
+        if (to.path !== '/terminal/login' && from.path !== '/' && from.path.split('/') [1] !== 'terminal' && to.path.split('/')[1] === 'terminal') {
+          next({ path: '/terminal/login' })
+        } else {
+          next()
+        }
       }
     }
-  } else {
+  }
+  else {
     if (whiteList.indexOf(to.path) !== -1) {
       // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝濡傛灉杩涘叆鐨勯〉闈㈡槸login椤甸潰骞朵笖褰撳墠鏄疧Auth2app鐜锛屽氨杩涘叆OAuth2鐧诲綍椤甸潰
       if (to.path === '/user/login' && isOAuth2AppEnv()) {
-        next({path: OAUTH2_LOGIN_PAGE_PATH})
+        next({ path: OAUTH2_LOGIN_PAGE_PATH })
       } else {
         // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
         next()
       }
       NProgress.done()
-    } else {
+    }
+    else {
       // 濡傛灉褰撳墠鏄湪OAuth2APP鐜锛屽氨璺宠浆鍒癘Auth2鐧诲綍椤甸潰
-      let path = isOAuth2AppEnv() ? OAUTH2_LOGIN_PAGE_PATH : '/user/login'
+      let path
+      if (isOAuth2AppEnv()) path = OAUTH2_LOGIN_PAGE_PATH
+      else {
+        if (to.path.split('/')[1] !== 'terminal') path = '/user/login'
+        else path = '/terminal/login'
+      }
       next({ path: path, query: { redirect: to.fullPath } })
       NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
     }
diff --git a/src/views/dnc/base/OperatorLogin.vue b/src/views/dnc/base/OperatorLogin.vue
new file mode 100644
index 0000000..1f57fad
--- /dev/null
+++ b/src/views/dnc/base/OperatorLogin.vue
@@ -0,0 +1,268 @@
+<template>
+  <div class="login-bg">
+    <div class="login-container">
+      <a-card class="login-card">
+        <h2 class="title">鐧诲綍</h2>
+
+        <a-form-model :model="model" ref="form" :rules="validateRules" @keyup.enter.native="handleLogin">
+          <!-- 鍒峰崱鐧诲綍杈撳叆妗� -->
+          <a-form-model-item prop="workNo" :has-feedback="feedbackConfig.workNoFeedback">
+            <a-input v-model="model.workNo" placeholder="璇峰埛鍗℃垨杈撳叆鍗″彿" size="large" autocomplete="off"
+                     @change="clearAnotherLoginInfo('workNo')">
+              <a-icon slot="prefix" type="credit-card"/>
+            </a-input>
+          </a-form-model-item>
+
+          <div class="divider">
+            <span class="line"></span>
+            <span class="text">鎴�</span>
+            <span class="line"></span>
+          </div>
+
+          <!-- 甯歌鐧诲綍琛ㄥ崟 -->
+          <a-form-model-item prop="username" :has-feedback="feedbackConfig.usernameFeedback">
+            <a-input
+              v-model="model.username"
+              placeholder="鐢ㄦ埛鍚�"
+              size="large"
+              @change="clearAnotherLoginInfo('username')"
+              autocomplete="off"
+            >
+              <a-icon slot="prefix" type="user"/>
+            </a-input>
+          </a-form-model-item>
+
+          <a-form-model-item prop="password" :has-feedback="feedbackConfig.passwordFeedback">
+            <a-input-password
+              v-model="model.password"
+              placeholder="瀵嗙爜"
+              size="large"
+              @change="clearAnotherLoginInfo('password')"
+              autocomplete="off"
+            >
+              <a-icon slot="prefix" type="lock"/>
+            </a-input-password>
+          </a-form-model-item>
+
+          <a-button type="primary" size="large" block :loading="loading" @click="handleLogin">鐧诲綍</a-button>
+        </a-form-model>
+        <!--<div class="footer">-->
+        <!--<a @click="handleRegister">娉ㄥ唽璐﹀彿</a>-->
+        <!--<a @click="handleForget">蹇樿瀵嗙爜</a>-->
+        <!--</div>-->
+      </a-card>
+    </div>
+  </div>
+</template>
+
+<script>
+  import { mapActions } from 'vuex'
+  import { timeFix } from '@/utils/util'
+
+  export default {
+    name: 'OperatorLogin',
+    data() {
+      return {
+        model: {
+          isOperator: true // 鍒ゆ柇鏄摢涓櫥褰曢〉鐧诲綍
+        },
+        feedbackConfig: {
+          workNoFeedback: true,
+          usernameFeedback: true,
+          passwordFeedback: true
+        },
+        loading: false,
+        validateRules: {
+          workNo: [
+            { validator: this.checkWorkNo, trigger: 'blur' }
+          ],
+          username: [
+            { validator: this.checkUsername, trigger: 'blur' }
+          ],
+          password: [
+            { validator: this.checkPassword, trigger: 'blur' }
+          ]
+        }
+      }
+    },
+    methods: {
+      ...mapActions(['Login']),
+
+      handleLogin() {
+        this.$refs.form.validate(valid => {
+          if (valid) {
+            this.loading = true
+
+            if (this.model.workNo) this.$refs.form.clearValidate(['username', 'password'])
+            else this.$refs.form.clearValidate('workNo')
+
+            console.log('鐧诲綍淇℃伅:', this.model)
+
+            this.Login(this.model)
+              .then((res) => {
+                this.loginSuccess(res.result)
+              })
+              .catch((err) => {
+                this.loginFailed(err, this.model.username)
+              })
+          } else {
+            return false
+          }
+        })
+      },
+
+      loginSuccess() {
+        this.$router.push({ path: '/terminal/index' }).catch(() => {
+        })
+
+        this.$notification.success({
+          message: '娆㈣繋',
+          description: `${timeFix()}锛屾杩庡洖鏉
+        })
+        this.loading = false
+      },
+
+      //鐧诲綍鍚庡彴澶辫触
+      loginFailed(err, username) {
+        let description = ((err.response || {}).data || {}).message || err.message || '璇锋眰鍑虹幇閿欒锛岃绋嶅悗鍐嶈瘯'
+
+        this.$notification.error({
+          message: '鐧诲綍澶辫触',
+          description: description
+        })
+        this.loading = false
+      },
+
+      /**
+       * 杈撳叆妗嗗�兼敼鍙樻椂瑙﹀彂
+       * @param inputProp 杈撳叆妗嗗搴斿睘鎬�
+       */
+      clearAnotherLoginInfo(inputProp) {
+        this.feedbackConfig[inputProp + 'Feedback'] = true
+
+        if (inputProp === 'workNo') {
+          delete this.model.username
+          delete this.model.password
+          this.$refs.form.clearValidate(['username', 'password'])
+        } else {
+          delete this.model.workNo
+          this.$refs.form.clearValidate('workNo')
+        }
+      },
+
+      checkWorkNo(rule, value, callback) {
+        if (!this.model.username && !this.model.password) {
+          if (!value) {
+            callback(new Error('璇峰埛鍗℃垨杈撳叆鍗″彿锛�'))
+            this.feedbackConfig.usernameFeedback = this.feedbackConfig.passwordFeedback = true
+          } else {
+            callback()
+          }
+        } else {
+          this.feedbackConfig.workNoFeedback = false
+          callback()
+        }
+      },
+
+      checkUsername(rule, value, callback) {
+        if (!this.model.workNo) {
+          if (!value) {
+            callback(new Error('璇疯緭鍏ョ敤鎴峰悕锛�'))
+            if (!this.model.password) this.feedbackConfig.workNoFeedback = true
+          } else {
+            callback()
+          }
+        } else {
+          this.feedbackConfig.usernameFeedback = false
+          callback()
+        }
+      },
+
+      checkPassword(rule, value, callback) {
+        if (!this.model.workNo) {
+          if (!value) {
+            callback(new Error('璇疯緭鍏ュ瘑鐮侊紒'))
+            if (!this.model.username) this.feedbackConfig.workNoFeedback = true
+          } else {
+            callback()
+          }
+        } else {
+          this.feedbackConfig.passwordFeedback = false
+          callback()
+        }
+      }
+
+      // handleRegister() {
+      //   this.$router.push('/register')
+      // },
+      // handleForget() {
+      //   this.$message.info('璇疯仈绯荤鐞嗗憳閲嶇疆瀵嗙爜')
+      // }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  .login-bg {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    min-height: 100vh;
+    background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
+    url('../../../assets/operator-login-bg.png') no-repeat center;
+    background-size: cover;
+
+    .login-container {
+      width: 100%;
+      max-width: 420px;
+      padding: 0 20px;
+
+      .login-card {
+        border-radius: 8px;
+        box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
+        background: rgba(255, 255, 255, 0.95);
+
+        .title {
+          margin-bottom: 24px;
+          text-align: center;
+          color: #1890ff;
+          font-size: 24px;
+          font-weight: 500;
+        }
+
+        .divider {
+          display: flex;
+          align-items: center;
+          margin: 20px 0;
+
+          .line {
+            flex: 1;
+            height: 1px;
+            background: rgba(0, 0, 0, 0.15);
+          }
+
+          .text {
+            padding: 0 16px;
+            color: rgba(0, 0, 0, 0.45);
+          }
+        }
+
+        .footer {
+          display: flex;
+          justify-content: space-between;
+          margin-top: 16px;
+
+          a {
+            color: #1890ff;
+            cursor: pointer;
+
+            &:hover {
+              text-decoration: underline;
+            }
+          }
+        }
+      }
+    }
+
+  }
+</style>
diff --git a/src/views/dnc/base/TerminalIndex.vue b/src/views/dnc/base/TerminalIndex.vue
new file mode 100644
index 0000000..0289c4e
--- /dev/null
+++ b/src/views/dnc/base/TerminalIndex.vue
@@ -0,0 +1,109 @@
+<template>
+  <div class="page-view-container">
+    <slot name="function"/>
+    <div class="header-container">鐜板満鎯呭喌涓婃姤骞冲彴</div>
+    <div class="content-container">
+      <a-row>
+        <a-col :span="8">
+          <div class="button" @click="navigateTo('work','涓婄彮')">涓婄彮</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button">涓嬬彮</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button" @click="navigateTo('fault','璁惧鏁呴殰')">璁惧鏁呴殰</div>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="8">
+          <div class="button" @click="navigateTo('close','鍋滄満涓婃姤')">鍋滄満涓婃姤</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button" @click="navigateTo('spotCheck','鐐规')">鐐规</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button">鍚堟牸鐜�</div>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="8">
+          <div class="button">绋嬪簭鍛煎彨</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button">寮�宸ュ畬宸�</div>
+        </a-col>
+        <a-col :span="8">
+          <div class="button">绋嬪簭鍥炰紶</div>
+        </a-col>
+      </a-row>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'TerminalIndex',
+    methods: {
+      navigateTo(url, projectTitle) {
+        this.$router.push('/terminal/' + url)
+        document.title = 'MDC鏅烘収杞﹂棿-' + projectTitle
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .page-view-container {
+    background: linear-gradient(to bottom, #fff -15%, #000 55%,);
+
+    .header-container {
+      font-size: 50px;
+      color: #eee;
+      text-align: center;
+      height: 15%;
+      display: flex;
+      justify-content: center;
+      align-items: flex-end;
+      -webkit-align-items: flex-end;
+    }
+
+    .content-container {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      padding: 3% 10%;
+
+      .ant-row {
+        flex: 1;
+
+        .ant-col {
+          height: 100%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+
+          .button {
+            width: 250px;
+            height: 125px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            background-color: #E3F2D9;
+            font-size: 45px;
+            border: 2px solid #33579D;
+            box-shadow: inset -5px 5px 12px rgba(0, 0, 0, 0.6);
+            cursor: pointer;
+            transition: all .1s ease-in-out;
+
+            &:hover {
+              transform: scale(1.05);
+            }
+          }
+        }
+        /*display: flex;*/
+        /*flex-direction: column;*/
+      }
+    }
+  }
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
index 3003661..41d4ac9 100644
--- a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
@@ -242,7 +242,7 @@
      * @param treeNode
      */
     setTreeNodeIcon(treeNode) {
-      if (!treeNode.equipmentId) {
+      if (+treeNode.type === 1) {
         treeNode.slots = { icon: 'workshop' }
       } else {
         treeNode.slots = { icon: 'device' }
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/NcComponentBorrowModal.vue b/src/views/dnc/base/modules/ProductStructure/Document/NcComponentBorrowModal.vue
index 95d5ab0..8dd02fc 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/NcComponentBorrowModal.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/NcComponentBorrowModal.vue
@@ -12,44 +12,43 @@
             <div class="table-page-search-wrapper">
               <a-form layout="inline" @keyup.enter.native="searchQuery">
                 <a-row :gutter="24">
-                  <a-col :md="7" :sm="7">
+                  <a-col :md="5" :sm="5">
                     <a-form-item label="閮ㄤ欢鍚嶇О">
                       <a-input placeholder="璇疯緭鍏ラ儴浠跺悕绉�" v-model="queryParam.componentName" allow-clear></a-input>
                     </a-form-item>
                   </a-col>
 
-                  <a-col :md="7" :sm="7">
+                  <a-col :md="5" :sm="5">
                     <a-form-item label="閮ㄤ欢浠e彿">
                       <a-input placeholder="璇疯緭鍏ラ儴浠朵唬鍙�" v-model="queryParam.componentCode" allow-clear></a-input>
                     </a-form-item>
                   </a-col>
 
-                  <a-col :md="7" :sm="7">
+                  <a-col :md="5" :sm="5">
                     <a-form-item label="閮ㄤ欢鍨嬪彿">
                       <a-input placeholder="璇疯緭鍏ラ儴浠跺瀷鍙�" v-model="queryParam.componentModel" allow-clear></a-input>
                     </a-form-item>
                   </a-col>
 
-                  <a-col :md="7" :sm="7">
+                  <a-col :md="4" :sm="4">
                     <a-form-item label="瑙勬牸">
                       <a-input placeholder="璇疯緭鍏ヨ鏍�" v-model="queryParam.componentScale" allow-clear></a-input>
                     </a-form-item>
                   </a-col>
 
-                  <a-col :md="7" :sm="7">
+                  <a-col :md="4" :sm="4">
                     <a-form-item label="鏉愯川">
                       <a-input placeholder="璇疯緭鍏ユ潗璐�" v-model="queryParam.structureType" allow-clear></a-input>
                     </a-form-item>
                   </a-col>
-
-                  <a-col :md="4" :sm="4">
-                    <a-space>
-                      <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
-                      <a-button type="primary" @click="searchReset" icon="reload">閲嶇疆</a-button>
-                    </a-space>
-                  </a-col>
                 </a-row>
               </a-form>
+            </div>
+
+            <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+            <div class="table-operator">
+              <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload">閲嶇疆</a-button>
             </div>
 
             <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :loading="loading"
@@ -137,13 +136,13 @@
           title: '鍒涘缓鏃堕棿',
           dataIndex: 'createTime',
           align: 'center',
-          width: 150,
+          width: 100,
         },
         {
           title: '鍒涘缓浜�',
           dataIndex: 'createBy_dictText',
           align: 'center',
-          width: 100,
+          width: 60,
         }
       ],
       searchValue: '',
@@ -305,6 +304,10 @@
 
 <style scoped lang="less">
 /deep/ .ant-modal {
+  .ant-modal-body{
+      padding: 0 24px 12px;
+  }
+
   .tabs-container {
     display: flex;
     justify-content: space-between;
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentSearchModal.vue b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentSearchModal.vue
index 29b0cb7..cba2b4a 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentSearchModal.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentSearchModal.vue
@@ -44,7 +44,7 @@
                     </a-form-item>
                   </a-col>
 
-                  <a-col :md="4" :sm="4">
+                  <a-col :md="2" :sm="2">
                     <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
                   </a-col>
                 </a-row>
@@ -173,11 +173,11 @@
           ]
         },
         {
-          title: '鐘�  鎬�',
+          title: '鐘� 鎬�',
           dataIndex: 'docDispatchStatus_dictText',
           key: 'docDispatchStatus',
           align: 'center',
-          width: 60,
+          width: 80,
           filters: [
             { text: '缂栧埗', value: 1 },
             { text: '鏍″', value: 2 },
@@ -498,6 +498,10 @@
 
 <style scoped lang="less">
 /deep/ .ant-modal {
+  .ant-modal-body{
+    padding: 0 24px 12px;
+  }
+
   .tabs-container {
     display: flex;
     justify-content: space-between;
diff --git a/src/views/dnc/base/modules/TerminalIndex/EquipmentSpotCheck.vue b/src/views/dnc/base/modules/TerminalIndex/EquipmentSpotCheck.vue
new file mode 100644
index 0000000..a1503d1
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/EquipmentSpotCheck.vue
@@ -0,0 +1,169 @@
+<template>
+  <div>
+    <slot name="function"/>
+
+    <div class="content-container">
+      <!-- 鏌ヨ鍖哄煙 -->
+      <div class="table-page-search-wrapper" style="width: 100%">
+        <a-form-model ref="form" :model="model" layout="inline" :rules="validateRules">
+          <a-row :gutter="64" type="flex" justify="center">
+            <a-col :span="5">
+              <a-form-model-item label="璁惧" prop="equipmentId">
+                <a-select placeholder="璇烽�夋嫨璁惧" v-model="model.equipmentId">
+                  <a-select-option v-for="item in equipmentList" :key="item.key">
+                    {{item.label}}
+                  </a-select-option>
+                </a-select>
+              </a-form-model-item>
+            </a-col>
+            <a-col :span="5">
+              <a-form-model-item label="鐐规鏃ユ湡" prop="checkDate">
+                <a-date-picker style="width: 100%" placeholder="璇烽�夋嫨寮�濮嬫椂闂�" v-model="model.checkDate"/>
+              </a-form-model-item>
+            </a-col>
+          </a-row>
+        </a-form-model>
+      </div>
+
+      <div class="check-content-container">
+        <div v-for="item in checkList" :key="item.id">
+          <div>{{item.content}}</div>
+          <div>
+            <a-radio-group v-model="item.status">
+              <a-radio :value="1">姝e父</a-radio>
+              <a-radio :value="2">寮傚父</a-radio>
+              <a-radio :value="3">宸茬淮淇�</a-radio>
+            </a-radio-group>
+          </div>
+        </div>
+      </div>
+
+      <div class="button-container">
+        <a-button @click="handleSubmit" icon="check" :loading="loading">淇濆瓨</a-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'EquipmentSpotCheck',
+    data() {
+      return {
+        model: {},
+        validateRules: {
+          equipmentId: [{ required: true, message: '璇烽�夋嫨璁惧锛�', trigger: 'change' }],
+          checkDate: [{ required: true, message: '璇烽�夋嫨鐐规鏃ユ湡锛�', trigger: 'change' }]
+        },
+        equipmentList: [
+          {
+            key: '3140221',
+            label: '3140221'
+          },
+          {
+            key: '3121542',
+            label: '3121542'
+          },
+          {
+            key: '3150324',
+            label: '3150324'
+          }
+        ],
+        checkList: [
+          {
+            content: '妫�鏌ヨ澶囧懆鍥存绾便�佸伐鍏枫�侀浂浠躲�佸伐浣嶅櫒鍏风瓑鏄惁鎸夎瀹氬畾缃憜鏀�',
+            status: 1
+          },
+          {
+            content: '妫�鏌ヨ澶嘝E绾挎帴鍦版槸鍚﹀畬濂芥棤鐮存崯',
+            status: 1
+          },
+          {
+            content: '妫�鏌ヨ澶囧悇寮�鍏虫槸鍚︾伒娲伙紝鍙潬',
+            status: 1
+          },
+          {
+            content: '妫�鏌ユ补绠辨补闈㈡槸鍚﹀湪鍒诲害绾夸笂銆佹补鏄惁鍙樿川銆佽繃婊ょ綉鏄惁鍫靛銆佹补姘旂璺槸鍚︽紡娌规紡姘�',
+            status: 1
+          },
+          {
+            content: '淇濇寔璁惧琛ㄩ潰娓呮磥锛屾鏌ユ満鍣ㄤ笂鏈夋棤娌规薄涓庡紓鐗╋紝鑻ユ湁椤诲強鏃舵竻鐞�',
+            status: 1
+          },
+          {
+            content: '妫�鏌ヨ澶囧悇绫昏绋嬮檺浣嶏紝鑱旈攣淇濇姢瑁呯疆銆侀槻鎶ょ僵鍙婂叾浠栦繚鎶よ缃畬濂斤紝鍙潬',
+            status: 1
+          },
+          {
+            content: '妫�鏌ヨ澶囦华鍣ㄤ华琛ㄨ澶囩姸鎬佹爣绀烘槸鍚﹀湪鏈夋晥鏈熷唴',
+            status: 1
+          },
+          {
+            content: '妫�鏌ヨ澶囧惎鍔ㄥ悗鍚勫杩愯(杞�)鏄惁鏈夊紓鍝嶅紓瑁�',
+            status: 1
+          }
+        ],
+        loading: false
+      }
+    },
+    methods: {
+      handleSubmit() {
+        const that = this
+        this.$refs.form.validate(valid => {
+          if (valid) {
+            that.loading = true
+
+            setTimeout(() => {
+              that.loading = false
+            }, 2000)
+          } else {
+            return false
+          }
+        })
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .content-container {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+
+    .check-content-container {
+      display: flex;
+      flex-direction: column;
+      margin: 40px auto;
+      width: 70%;
+
+      > div {
+        display: flex;
+        justify-content: center;
+        border-bottom: 1px dashed #bbb;
+        margin-bottom: 20px;
+        padding-bottom: 5px;
+
+        > div:first-child {
+          flex: 0.5;
+          text-align: right;
+          margin-right: 30px;
+        }
+
+        > div:last-child {
+          flex: 0.5;
+
+          /deep/ .ant-radio-wrapper {
+            margin-right: 30px;
+          }
+        }
+      }
+    }
+
+    .button-container {
+      text-align: center;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/TerminalIndex/EquipmentStartWork.vue b/src/views/dnc/base/modules/TerminalIndex/EquipmentStartWork.vue
new file mode 100644
index 0000000..9ca8f85
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/EquipmentStartWork.vue
@@ -0,0 +1,128 @@
+<template>
+  <div class="full-screen-container">
+    <slot name="function"/>
+
+    <a-tabs default-active-key="1">
+      <a-tab-pane tab="鎵撳崱涓婁笅鐝�" key="1" dataset="first">
+        <a-space>
+          <div>璁惧鍚嶇О锛�</div>
+          <a-select style="width: 250px">
+
+          </a-select>
+        </a-space>
+
+
+        <div class="button">涓婄彮</div>
+      </a-tab-pane>
+
+      <a-tab-pane tab="褰撳墠璁惧鐘舵��" key="2">
+        <a-table :dataSource="dataSource" :columns="columns" rowKey="id" bordered :pagination="false"/>
+      </a-tab-pane>
+    </a-tabs>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'EquipmentStartWork',
+    data() {
+      return {
+        columns: [
+          {
+            title: '鐢ㄦ埛缂栧彿',
+            align: 'center',
+            dataIndex: 'userId'
+          },
+          {
+            title: '鐢ㄦ埛鍚嶇О',
+            align: 'center',
+            dataIndex: 'username'
+          },
+          {
+            title: '璁惧缂栧彿',
+            align: 'center',
+            dataIndex: 'equipmentId'
+          },
+          {
+            title: '涓婄彮鎵撳崱鏃堕棿',
+            align: 'center',
+            dataIndex: 'startWorkTime'
+          },
+          {
+            title: '涓嬬彮鎵撳崱鏃堕棿',
+            align: 'center',
+            dataIndex: 'finishWorkTime'
+          }
+        ],
+        dataSource: [
+          {
+            id: 1,
+            equipmentId: '3140132',
+            userId: '140016',
+            username: '鏉庨獮',
+            startWorkTime: '2023/11/13 9:29',
+            finishWorkTime: ''
+          },
+          {
+            id: 2,
+            equipmentId: '3140130',
+            userId: '140016',
+            username: '鏉庨獮',
+            startWorkTime: '2023/11/13 9:29',
+            finishWorkTime: ''
+          }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    created() {
+
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .full-screen-container {
+    padding: 24px;
+    display: flex;
+    flex-direction: column;
+
+    /deep/ .ant-tabs {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+
+      .ant-tabs-content {
+        width: 100%;
+        flex: 1;
+
+        .ant-tabs-tabpane[dataset='first'] {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+
+          .button {
+            font-weight: bold;
+            padding: 40px 80px;
+            border: 1px solid rgba(0, 0, 0, .2);
+            border-radius: 10px;
+            margin-top: 200px;
+            cursor: pointer;
+            box-shadow: 6px 6px 16px rgba(0, 0, 0, 0.2),
+              -6px -6px 16px rgba(255, 255, 255, 0.8),
+            inset 0 0 0 transparent;
+
+            &:hover {
+              box-shadow: 0 0 0 transparent,
+              inset 6px 6px 12px rgba(0, 0, 0, 0.2),
+                inset -6px -6px 12px rgba(255, 255, 255, 0.8);
+            }
+          }
+        }
+      }
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose.vue b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose.vue
new file mode 100644
index 0000000..0f5f685
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose.vue
@@ -0,0 +1,175 @@
+<template>
+  <div class="page-view-container">
+    <slot name="function"/>
+
+    <a-card :bordered="false">
+      <!-- 鏌ヨ鍖哄煙 -->
+      <div class="table-page-search-wrapper">
+        <a-form layout="inline">
+          <a-row :gutter="24">
+            <a-col :span="4">
+              <a-form-item label="璁惧">
+                <a-select placeholder="璇烽�夋嫨璁惧" v-model="queryParam.equipmentId"></a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :span="4">
+              <a-form-item label="寮�濮嬫椂闂�">
+                <a-date-picker style="width: 100%" show-time placeholder="璇烽�夋嫨寮�濮嬫椂闂�" v-model="queryParam.startTime"/>
+              </a-form-item>
+            </a-col>
+
+            <a-col :span="4">
+              <a-form-item label="缁撴潫鏃堕棿">
+                <a-date-picker style="width: 100%" show-time placeholder="璇烽�夋嫨缁撴潫鏃堕棿" v-model="queryParam.endTime"/>
+              </a-form-item>
+            </a-col>
+
+            <a-col :span="4">
+              <a-form-item label="鍋滄満鍘熷洜">
+                <a-select placeholder="璇烽�夋嫨鍋滄満鍘熷洜" v-model="queryParam.closeReason"></a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :span="4">
+              <a-form-item label="鍋滄満鏃堕棿">
+                <a-date-picker style="width: 100%" placeholder="璇烽�夋嫨鍋滄満鏃堕棿" v-model="queryParam.closeTime"/>
+              </a-form-item>
+            </a-col>
+
+            <a-col :span="4">
+              <a-space>
+                <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
+                <a-button @click="searchReset" icon="reload">閲嶇疆</a-button>
+              </a-space>
+            </a-col>
+          </a-row>
+
+
+        </a-form>
+      </div>
+
+      <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+      <div class="table-operator">
+        <a-button type="primary" @click="handleMaintainShutdown">缁存姢鍋滄満</a-button>
+        <a-button type="primary" @click="handleSplitShutdownInfo">鎷嗗垎鍋滄満淇℃伅</a-button>
+      </div>
+
+      <a-table :dataSource="dataSource" :columns="columns" rowKey="id" bordered :pagination="false"
+               :rowSelection="{selectedRowKeys, onChange: onSelectChange}"/>
+    </a-card>
+
+    <maintain-shutdown-modal ref="maintainShutdownModal"/>
+
+    <split-shutdown-info-modal ref="splitShutdownInfoModal"/>
+  </div>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import MaintainShutdownModal from './ReportEquipmentClose/MaintainShutdownModal'
+  import SplitShutdownInfoModal from './ReportEquipmentClose/SplitShutdownInfoModal'
+
+  export default {
+    name: 'ReportEquipmentClose',
+    components: { SplitShutdownInfoModal, MaintainShutdownModal },
+    mixins: [JeecgListMixin],
+    data() {
+      return {
+        columns: [
+          {
+            title: '璁惧缂栧彿',
+            align: 'center',
+            dataIndex: 'equipmentId',
+            width: 150
+          },
+          {
+            title: '璁惧鍚嶇О',
+            align: 'center',
+            dataIndex: 'equipmentName'
+          },
+          {
+            title: '鍋滄満缂栧彿',
+            align: 'center',
+            dataIndex: 'shutdownId'
+          },
+          {
+            title: '鍋滄満绫诲瀷',
+            align: 'center',
+            dataIndex: 'shutdownType'
+          },
+          {
+            title: '鍋滄満鏃堕棿',
+            align: 'center',
+            width: 150,
+            dataIndex: 'shutdownDuration'
+          },
+          {
+            title: '寮�濮嬫椂闂�',
+            align: 'center',
+            width: 200,
+            dataIndex: 'startTime'
+          },
+          {
+            title: '缁撴潫鏃堕棿',
+            align: 'center',
+            width: 200,
+            dataIndex: 'endTime'
+          },
+          {
+            title: '褰曞叆绫诲瀷',
+            align: 'center',
+            width: 100,
+            dataIndex: 'recordType'
+          }
+        ],
+        dataSource: [
+          {
+            id: 1,
+            equipmentId: '3140221',
+            equipmentName: '鏁版帶鏈哄簥',
+            shutdownDuration: 360,
+            startTime: '2025-05-20 02:21:49',
+            endTime: '2525-05-20 08:21:59',
+            recordType: '鑷姩涓婃姤'
+          },
+          {
+            id: 2,
+            equipmentId: '3140221',
+            equipmentName: '鏁版帶鏈哄簥',
+            shutdownDuration: 360,
+            startTime: '2025-05-20 02:21:49',
+            endTime: '2525-05-20 08:21:59',
+            recordType: '鑷姩涓婃姤'
+          },
+          {
+            id: 3,
+            equipmentId: '3140221',
+            equipmentName: '鏁版帶鏈哄簥',
+            shutdownDuration: 360,
+            startTime: '2025-05-20 02:21:49',
+            endTime: '2525-05-20 08:21:59',
+            recordType: '鑷姩涓婃姤'
+          }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    methods: {
+      handleMaintainShutdown() {
+        this.$refs.maintainShutdownModal.visible = true
+        this.$refs.maintainShutdownModal.model = {}
+      },
+
+      handleSplitShutdownInfo() {
+        this.$refs.splitShutdownInfoModal.visible = true
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/MaintainShutdownModal.vue b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/MaintainShutdownModal.vue
new file mode 100644
index 0000000..36053ea
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/MaintainShutdownModal.vue
@@ -0,0 +1,68 @@
+<template>
+  <a-modal :visible="visible" title="缁存姢鍋滄満" @ok="handleSubmit" @cancel="handleCancel">
+    <a-form-model ref="form" :model="model" :rules="validateRules" :labelCol="{span:5}" :wrapperCol="{span:18}">
+      <a-form-model-item prop="closeReason" label="鍋滄満鍘熷洜">
+        <a-select v-model="model.closeReason" placeholder="璇烽�夋嫨鍋滄満鍘熷洜">
+          <a-select-option v-for="item in closeReasonList" :key="item.id">
+            {{item.label}}
+          </a-select-option>
+        </a-select>
+      </a-form-model-item>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+  export default {
+    name: 'MaintainShutdownModal',
+    data() {
+      return {
+        visible: false,
+        model: {},
+        validateRules: {
+          closeReason: [{ required: true, message: '璇烽�夋嫨鍋滄満鍘熷洜锛�' }]
+        },
+        closeReasonList: [
+          {
+            id: 1,
+            label: '鍚冮キ鏃堕棿浼戞伅'
+          },
+          {
+            id: 2,
+            label: '宸ヤ綔鏃堕棿浼戞伅'
+          },
+          {
+            id: 3,
+            label: '璁″垝鎬у仠鐢�'
+          },
+          {
+            id: 4,
+            label: '寰呮枡鍋滄満'
+          },
+          {
+            id: 5,
+            label: '棣栦欢璋冭瘯'
+          },
+          {
+            id: 6,
+            label: '鍒�閲忓叿鍑嗗'
+          }
+        ]
+      }
+    },
+    methods: {
+      handleSubmit() {
+
+      },
+
+      handleCancel() {
+        this.$refs.form.clearValidate()
+        this.visible = false
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/SplitShutdownInfoModal.vue b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/SplitShutdownInfoModal.vue
new file mode 100644
index 0000000..967c357
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentClose/SplitShutdownInfoModal.vue
@@ -0,0 +1,121 @@
+<template>
+  <a-modal :visible="visible" :width="800" title="鎷嗗垎鍋滄満淇℃伅" @ok="handleSubmit" @cancel="handleCancel">
+    <a-form-model ref="form" :model="model" :rules="validateRules" :labelCol="{span:8}" :wrapperCol="{span:12}">
+      <a-row>
+        <a-col :span="10">
+          <a-form-model-item prop="startTime" label="寮�濮嬫椂闂�">
+            <a-date-picker show-time value-format="YYYY-MM-DD HH:mm:ss" v-model="model.startTime"/>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <div v-for="item in splitList" :key="item.title">
+        <a-divider orientation="left">{{item.title}}</a-divider>
+
+        <a-row>
+          <a-col :span="10">
+            <a-form-model-item prop="endTime" label="缁撴潫鏃ユ湡">
+              <a-date-picker show-time value-format="YYYY-MM-DD HH:mm:ss" v-model="item.splitParams.endTime"/>
+            </a-form-model-item>
+          </a-col>
+
+          <a-col :span="10">
+            <a-form-model-item prop="closeReason" label="鍋滄満鍘熷洜">
+              <a-select v-model="item.splitParams.closeReason" placeholder="璇烽�夋嫨鍋滄満鍘熷洜">
+                <a-select-option v-for="item in closeReasonList" :key="item.id">
+                  {{item.label}}
+                </a-select-option>
+              </a-select>
+            </a-form-model-item>
+          </a-col>
+
+          <a-col :span="4">
+            <a-form-model-item label="閫夋嫨">
+              <a-checkbox @change="handleCheckboxChange(item,$event)"/>
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+      </div>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+  export default {
+    name: 'SplitShutdownInfoModal',
+    data() {
+      return {
+        visible: false,
+        model: {},
+        validateRules: {
+          startTime: [{ required: true, message: '璇烽�夋嫨寮�濮嬫椂闂达紒', trigger: 'change' }]
+        },
+        closeReasonList: [
+          {
+            id: 1,
+            label: '鍚冮キ鏃堕棿浼戞伅'
+          },
+          {
+            id: 2,
+            label: '宸ヤ綔鏃堕棿浼戞伅'
+          },
+          {
+            id: 3,
+            label: '璁″垝鎬у仠鐢�'
+          },
+          {
+            id: 4,
+            label: '寰呮枡鍋滄満'
+          },
+          {
+            id: 5,
+            label: '棣栦欢璋冭瘯'
+          },
+          {
+            id: 6,
+            label: '鍒�閲忓叿鍑嗗'
+          }
+        ],
+        splitList: [
+          {
+            title: '鎷嗗垎涓�娈�',
+            splitParams: {}
+          },
+          {
+            title: '鎷嗗垎浜屾',
+            splitParams: {}
+          },
+          {
+            title: '鎷嗗垎涓夋',
+            splitParams: {}
+          }
+        ]
+      }
+    },
+    methods: {
+      handleCheckboxChange(record, event) {
+        console.log('record', record)
+        record.splitParams.checked = event.target.checked
+      },
+
+      handleSubmit() {
+        this.$refs.form.validate(valid => {
+          if (valid) {
+
+          } else {
+            return false
+          }
+        })
+      },
+
+      handleCancel() {
+        this.$refs.form.clearValidate()
+        this.visible = false
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentFault.vue b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentFault.vue
new file mode 100644
index 0000000..8514266
--- /dev/null
+++ b/src/views/dnc/base/modules/TerminalIndex/ReportEquipmentFault.vue
@@ -0,0 +1,66 @@
+<template>
+  <div>
+    <slot name="function"/>
+
+    <div class="content-container">
+      <a-form-model ref="form" :model="model" :rules="validateRules" :labelCol="{span:10}" :wrapperCol="{span:6}">
+        <a-form-model-item label="璁惧鍚嶇О" prop="equipmentId">
+          <a-select placeholder="璇烽�夋嫨璁惧" v-model="model.equipmentId"></a-select>
+        </a-form-model-item>
+        <a-form-model-item label="鏁呴殰鍘熷洜" prop="faultReasonId">
+          <a-select placeholder="璇烽�夋嫨鏁呴殰鍘熷洜" v-model="model.faultReasonId"></a-select>
+        </a-form-model-item>
+        <a-form-model-item label="鏁呴殰鎻忚堪" prop="faultDescription">
+          <a-textarea placeholder="璇疯緭鍏ユ晠闅滄弿杩�" v-model="model.faultDescription"/>
+        </a-form-model-item>
+
+        <div style="text-align: center">
+          <a-space>
+            <a-button @click="handleReportFault">鏁呴殰涓婃姤</a-button>
+            <a-button>鏁呴殰瑙i櫎</a-button>
+          </a-space>
+        </div>
+      </a-form-model>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'ReportEquipmentFault',
+    data() {
+      return {
+        model: {},
+        validateRules: {
+          equipmentId: [{ required: true, message: '璇烽�夋嫨璁惧锛�' }],
+          faultReasonId: [{ required: true, message: '璇烽�夋嫨鏁呴殰鍘熷洜锛�' }],
+          faultDescription: [{ required: true, message: '璇疯緭鍏ユ晠闅滄弿杩帮紒' }]
+        }
+      }
+    },
+    methods: {
+      handleReportFault() {
+        this.$refs.form.validate(valid => {
+          if (valid) {
+
+          } else {
+            return false
+          }
+        })
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .content-container {
+    flex: 1;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    /deep/ .ant-form {
+      width: 100%;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/system/modules/UserModal.vue b/src/views/system/modules/UserModal.vue
index f8df9c9..32c2078 100644
--- a/src/views/system/modules/UserModal.vue
+++ b/src/views/system/modules/UserModal.vue
@@ -380,6 +380,7 @@
       disableSubmit: false,
       dateFormat: 'YYYY-MM-DD',
       validatorRules: {
+        workNo:[{ required: true, message: '璇疯緭鍏ュ伐鍙�!' }],
         username: [{ required: true, message: '璇疯緭鍏ョ敤鎴疯处鍙�!' },
           { validator: this.validateUsername }],
         password: [
diff --git a/src/views/user/Login.vue b/src/views/user/Login.vue
index e7d4f86..13e478f 100644
--- a/src/views/user/Login.vue
+++ b/src/views/user/Login.vue
@@ -163,9 +163,13 @@
         // this.$router.push({ path: "/isps/userAnnouncement" }).catch(() => {
         //   console.log('鐧诲綍璺宠浆棣栭〉鍑洪敊,杩欎釜閿欒浠庡摢閲屾潵鐨�')
         // })
+
         this.$router.push({ path: '/dashboard/analysis' }).catch(() => {
           console.log('鐧诲綍璺宠浆棣栭〉鍑洪敊,杩欎釜閿欒浠庡摢閲屾潵鐨�')
         })
+
+        if(this.$route.query.redirect.split('/')[1] === 'terminal') return
+
         this.$notification.success({
           message: '娆㈣繋',
           description: `${timeFix()}锛屾杩庡洖鏉
@@ -181,7 +185,6 @@
                 duration: 60,
                 icon: <a-icon type = 'exclamation-circle'style = 'color:red' / >,
             })
-
             }
           }
         })

--
Gitblit v1.9.3