Преглед изворни кода

feature:(个人中心)仪器预约信息功能完善、预约增加token校验

liuzhenlin пре 11 месеци
родитељ
комит
6214d1c065

+ 1 - 1
src/App.vue

@@ -22,7 +22,7 @@
               <el-menu-item index="/appointment/equipment">
                 仪器设备
               </el-menu-item>
-              <el-menu-item index="/appointment/equipment-details">
+              <el-menu-item index="/appointment/equipment-details" v-if="false">
                 仪器设备详情
               </el-menu-item>
               <el-menu-item index="2-2">中心平台</el-menu-item>

+ 9 - 8
src/api/instr/index.js

@@ -188,16 +188,17 @@ export function getMySelfProjectGroup(data) {
 export function getInstrListByUser(data) {
   return request.postRequestWithClientInfo(
     insrtPath,
-    "TusInstrumentAppointment",
-    "GetListByUser",
+    "JiangSuUniversity",
+    "MineAppointmentList",
     data
   );
 }
-// 使用人取消送样预约 
+// 使用人取消预约
 export function userCancelAppoint(query) {
-  return request.postRequest(insrtPath, 'TusInstrumentSampleDelivery', 'UserCancel', query);
+  return request.postRequest(
+    insrtPath,
+    "TusInstrumentAppointment",
+    "UserCancel",
+    query
+  );
 }
-// 取消送样预约 
-export function cancelAppoint(query) {
-  return request.postRequest(insrtPath, 'TusInstrumentSampleDelivery', 'AdminCancel', query);
-}

+ 21 - 21
src/utils/micro_request.js

@@ -11,7 +11,7 @@ import store from "@/store";
 import { getToken, getProject } from "@/utils/auth";
 import errorCode from "@/utils/errorCode";
 import Cookies from "js-cookie";
-import router from '../router'
+import router from "../router";
 
 axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
 
@@ -19,12 +19,12 @@ const service = axios.create({
   // axios中请求配置有baseURL选项,表示请求URL公共部分
   baseURL: $GlobalConfig.VUE_APP_MicroSrvProxy_API,
   // 超时
-  timeout: 60000
+  timeout: 60000,
 });
 
 // request拦截器
 service.interceptors.request.use(
-  config => {
+  (config) => {
     config.headers["Tenant"] = $GlobalConfig.VUE_APP_TENANT;
     // 是否需要设置 token
     const isToken = (config.headers || {}).isToken === false;
@@ -33,7 +33,7 @@ service.interceptors.request.use(
     }
     return config;
   },
-  error => {
+  (error) => {
     console.log(error);
     Promise.reject(error);
   }
@@ -41,12 +41,12 @@ service.interceptors.request.use(
 
 // 响应拦截器
 service.interceptors.response.use(
-  res => {
+  (res) => {
     if (res.request.responseType == "blob") {
       // 判断是否是文件流
       let fileReader = new FileReader();
       fileReader.readAsText(res.data);
-      fileReader.onload = function() {
+      fileReader.onload = function () {
         try {
           let jsonData = JSON.parse(this.result); // 解析成功说明是普通对象数据,后端返回的是文件上传的错误信息
           res.data = jsonData;
@@ -63,12 +63,12 @@ service.interceptors.response.use(
     // 常规响应处理
     return processResponse(res);
   },
-  error => {
+  (error) => {
     console.log("err" + error);
     Message({
       message: error.message,
       type: "error",
-      duration: 5 * 1000
+      duration: 5 * 1000,
     });
     return Promise.reject(error);
   }
@@ -77,7 +77,7 @@ service.interceptors.response.use(
 service.postRequest = function postRequest(basePath, srvName, funcName, data) {
   if (data == undefined) {
     let nullParam = {
-      nullparam: 0
+      nullparam: 0,
     };
     data = nullParam;
   } else {
@@ -99,9 +99,9 @@ service.postRequest = function postRequest(basePath, srvName, funcName, data) {
       "X-RPCX-SerializeType": "1",
       "X-RPCX-ServicePath": srvName,
       "X-RPCX-ServiceMethod": funcName,
-      "Srvenv": "dev"
+      Srvenv: "dev",
     },
-    data: data
+    data: data,
   });
 };
 // 发出请求并要求把客户端信息传输给后端(IP和User-Agent)
@@ -123,9 +123,9 @@ service.postRequestWithClientInfo = function postRequest(
       "X-RPCX-SerializeType": "1",
       "X-RPCX-ServicePath": srvName,
       "X-RPCX-ServiceMethod": funcName,
-      "X-RPCX-Meta": "need_clint_Info=1"
+      "X-RPCX-Meta": "need_clint_Info=1",
     },
-    data: data
+    data: data,
   });
 };
 
@@ -138,7 +138,7 @@ service.downloadExcel = function downloadExcel(
 ) {
   if (data == undefined) {
     let nullParam = {
-      nullparam: 0
+      nullparam: 0,
     };
     data = nullParam;
   }
@@ -156,9 +156,9 @@ service.downloadExcel = function downloadExcel(
       "Content-Type": "application/rpcx",
       "X-RPCX-SerializeType": "1",
       "X-RPCX-ServicePath": srvName,
-      "X-RPCX-ServiceMethod": funcName
+      "X-RPCX-ServiceMethod": funcName,
     },
-    data: data
+    data: data,
   });
 };
 
@@ -174,22 +174,22 @@ function processResponse(res) {
       {
         confirmButtonText: "重新登录",
         cancelButtonText: "取消",
-        type: "warning"
+        type: "warning",
       }
     ).then(() => {
       store.dispatch("logOut").then(() => {
-        router.push('/')
+        router.push("/");
       });
     });
   } else if (code === 500) {
     Message({
       message: message,
-      type: "error"
+      type: "error",
     });
     return Promise.reject(new Error(message));
   } else if (code !== 200) {
     Notification.error({
-      title: message
+      title: res.data.message || message,
     });
     return Promise.reject("error");
   } else {
@@ -209,7 +209,7 @@ function downLoadBlobFile(res, mimeType) {
   }
   const aLink = document.createElement("a");
   var blob = new Blob([res.data], {
-    type: mimeType
+    type: mimeType,
   });
   // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
   var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");

Разлика између датотеке није приказан због своје велике величине
+ 582 - 497
src/views/PersonalCenter.vue


+ 1413 - 0
src/views/PersonalCenter.vue.orig

@@ -0,0 +1,1413 @@
+<template>
+  <div class="news">
+    <div class="center-banner">
+      <div class="content">
+        <div class="user">
+          <img v-if="userInfo.avatar" :src="userInfo.avatar" />
+          <img v-else src="../assets/img/default-avatar.png">
+          <p>
+            <span>Hi~{{ userInfo.nickName }}</span>
+            <span>{{ userInfo.roleNames }}</span>
+            <span>{{ userInfo.pgName || '未加入课题组' }}</span>
+          </p>
+        </div>
+        <div class="btns">
+          <p>安全积分:<span>100</span></p>
+          <el-button size="medium"
+                     round>个人设置</el-button>
+        </div>
+      </div>
+    </div>
+    <div class="common-container">
+      <el-container>
+        <div class="left-tabs">
+          <h4>个人中心</h4>
+          <ul>
+            <li
+              v-for="(item, index) in options"
+              :key="index"
+              :class="{ active: index === active }"
+              @click="tabSelect(item, index)"
+            >
+              {{ item.label }}
+            </li>
+          </ul>
+        </div>
+        <div v-show="active === 0" class="w100">
+          <el-row class="flex mt12" :gutter="12">
+            <el-col :span="12">
+              <el-card>
+                <div slot="header" class="header">
+                  <h4>科研仪器</h4>
+                </div>
+                <ul class="cage-list">
+                  <li v-for="v in instrList" :key="v.id">
+                    <header>
+                      <p>{{ v.instName }}</p>
+                      <el-tag
+                        v-if="v.instStatus == '10'"
+                        type="primary"
+                        size="mini"
+                      >
+                        正常
+                      </el-tag>
+                      <el-tag
+                        v-else-if="v.instStatus == '20'"
+                        type="warning"
+                        size="mini"
+                      >
+                        故障
+                      </el-tag>
+                      <el-tag
+                        v-else-if="v.instStatus == '30'"
+                        type="danger"
+                        size="mini"
+                      >
+                        报废
+                      </el-tag>
+                    </header>
+                    <p>型号:{{ v.instNameEn }}</p>
+                    <p>仪器负责人:{{ v.instHeadName }}</p>
+                  </li>
+                </ul>
+              </el-card>
+            </el-col>
+            <el-col :span="12">
+              <el-card header="通知公告">
+                <div slot="header" class="header">
+                  <h4>通知公告</h4>
+                </div>
+                <div class="link-list">
+                  <ul>
+                    <li v-for="item in noticeList" :key="item.id">
+                      <div>
+                        {{ item.noticeTitle }}
+                      </div>
+                      <span>{{ item.noticeTime.split(" ")[0] }}</span>
+                    </li>
+                  </ul>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
+          <el-row class="flex mt12" :gutter="12">
+            <el-col :span="12">
+              <el-card>
+                <div slot="header" class="header">
+                  <h4>科研平台</h4>
+                </div>
+                <ul class="platform-list">
+                  <li>
+                    <div class="text">
+                      <header>
+                        <p>分子生物平台</p>
+                        <span>单价:¥100/小时</span>
+                      </header>
+                      <p>位置:7栋6层-分子生物平台中心-12号终端</p>
+                      <p>有效时间:1月1日 12:00 -- 1月15日 12:00</p>
+                    </div>
+                    <div class="btn">
+                      <header>
+                        <p>剩余时长</p>
+                        <p class="remain-time">2天18小时</p>
+                      </header>
+                      小计:¥300
+                    </div>
+                  </li>
+                  <li>
+                    <div class="text">
+                      <header>
+                        <p>分子生物平台</p>
+                        <span>单价:¥100/小时</span>
+                      </header>
+                      <p>位置:7栋6层-分子生物平台中心-12号终端</p>
+                      <p>有效时间:1月1日 12:00 -- 1月15日 12:00</p>
+                    </div>
+                    <div class="btn">
+                      <header>
+                        <p>剩余时长</p>
+                        <p class="remain-time">2天18小时</p>
+                      </header>
+                      小计:¥300
+                    </div>
+                  </li>
+                </ul>
+              </el-card>
+              <el-card class="mt12">
+                <div slot="header" class="header">
+                  <h4>笼位管理(共3个)</h4>
+                </div>
+                <ul class="cage-list">
+                  <li>
+                    <header>
+                      <p>实验用小鼠-3只</p>
+                      <el-tag type="primary" size="mini">正常</el-tag>
+                    </header>
+                    <p>位置:7栋6层-602室 4区12号架 8号笼</p>
+                    <p>到期时间:2月1日(剩余10天)</p>
+                  </li>
+                  <li>
+                    <header>
+                      <p>实验用小鼠-3只-笼位申请</p>
+                      <el-tag type="warning" size="mini">待分配</el-tag>
+                    </header>
+                    <p>位置:待分配</p>
+                    <p>申请时间:2月1日</p>
+                  </li>
+                  <li>
+                    <header>
+                      <p>实验用小鼠-3只</p>
+                      <el-tag type="primary" size="mini">正常</el-tag>
+                    </header>
+                    <p>位置:7栋6层-602室 4区12号架 8号笼</p>
+                    <p>到期时间:2月1日(剩余10天)</p>
+                  </li>
+                </ul>
+              </el-card>
+            </el-col>
+            <el-col :span="12">
+              <el-card class="calendar">
+                <div slot="header" class="header">
+                  <h4>日程安排</h4>
+                </div>
+                <FullCalendar
+                  class="fullCalendar"
+                  ref="fullCalendar"
+                  :options="calendarOptions"
+                />
+                <ul>
+                  <li>仪器:需要进行第二期临床实验使用仪器</li>
+                  <li>平台:需要使用平台查找相应的案例</li>
+                  <li>笼位:进行第二次动物实验</li>
+                  <li>技术:约李老师进行第三次技术咨询</li>
+                </ul>
+              </el-card>
+              <el-card class="mt12 cost">
+                <div slot="header" class="header">
+                  <h4>费用统计</h4>
+                </div>
+                <div class="chart-container">
+                  <div class="text">
+                    <header>课题组:人血球免疫蛋白应用研究课题组</header>
+                    <ul>
+                      <li>费用账单:6条待确认</li>
+                      <li>本月支出:¥567.89</li>
+                      <li>累计支出:¥1234.56</li>
+                    </ul>
+                  </div>
+                  <div id="chart"></div>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
+          <el-row class="flex mt12 technical" :gutter="12">
+            <el-col :span="24">
+              <el-card>
+                <div slot="header" class="header">
+                  <h4>技术服务</h4>
+                </div>
+                <p>技术服务 - No.123456 - 李老师</p>
+                <ul>
+                  <li>11-20:委托发起</li>
+                  <li>11-21:项目确定</li>
+                  <li>11-23:项目开始</li>
+                  <li>11-23:阶段性结果</li>
+                  <li>当前:结尾验收</li>
+                  <li>费用结算</li>
+                  <li>结果上传</li>
+                </ul>
+                <p>技术服务 - No.123456 - 李老师</p>
+                <ul>
+                  <li>11-20:委托发起</li>
+                  <li>11-21:项目确定</li>
+                  <li>11-23:项目开始</li>
+                  <li>11-23:阶段性结果</li>
+                  <li>当前:结尾验收</li>
+                  <li>费用结算</li>
+                  <li>结果上传</li>
+                </ul>
+              </el-card>
+            </el-col>
+          </el-row>
+        </div>
+        <div v-show="active === 1" class="w100">
+          <el-card>
+            <div class="toolbar-wrap">
+              <div class="switch-date">
+                <div
+                  class="btn day"
+                  :class="curSelectedDate == 'd' ? 'actived' : ''"
+                  @click="selectDate('d')"
+                >
+                  日
+                </div>
+                <div
+                  class="btn week"
+                  :class="curSelectedDate == 'w' ? 'actived' : ''"
+                  @click="selectDate('w')"
+                >
+                  周
+                </div>
+                <div
+                  class="btn month"
+                  :class="curSelectedDate == 'm' ? 'actived' : ''"
+                  @click="selectDate('m')"
+                >
+                  月
+                </div>
+              </div>
+              <div class="date-wrap">
+                <div class="prev" @click="handlePrev">
+                  <el-button icon="el-icon-arrow-left" size="small" circle />
+                </div>
+                <div class="date">
+                  <el-popover
+                    :width="200"
+                    placement="top-start"
+                    trigger="click"
+                  >
+                    <div slot="reference">
+                      <span class="time">{{ curTime }}</span>
+                    </div>
+                    <el-date-picker
+                      @change="getAppointList"
+                      style="width: 100%"
+                      v-model="curTime"
+                      type="date"
+                      placeholder="选择日期"
+                      value-format="yyyy-MM-dd"
+                      :clearable="false"
+                    />
+                  </el-popover>
+                  <span class="week">{{ WEEKS[moment(curTime).day()] }}</span>
+                </div>
+                <div class="next" @click="handleNext">
+                  <el-button icon="el-icon-arrow-right" size="small" circle />
+                </div>
+              </div>
+            </div>
+            <div class="table-wrap">
+              <el-table
+                :data="appointData"
+                border
+                height="500"
+                style="width: 922px"
+              >
+                <el-table-column
+                  type="index"
+                  width="50"
+                  align="center"
+                ></el-table-column>
+                <el-table-column
+                  prop="instName"
+                  label="仪器名称"
+                  min-width="160"
+                />
+                <el-table-column
+                  prop="projectName"
+                  label="课题组/服务"
+                  min-width="160"
+                >
+                  <template #default="{ row }">
+                    <span v-if="row.projectName">{{ row.projectName }}</span>
+                    <span v-else>{{ row.serviceName }}</span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="startTime" label="开始时间" width="160">
+                  <template #default="{ row }">
+                    {{ parseTime(row.startTime, "{y}-{m}-{d} {h}:{i}") }}
+                  </template>
+                </el-table-column>
+                <el-table-column prop="endTime" label="结束时间" width="160">
+                  <template #default="{ row }">
+                    {{ parseTime(row.endTime, "{y}-{m}-{d} {h}:{i}") }}
+                  </template>
+                </el-table-column>
+                <el-table-column prop="userName" label="预约人" width="140" />
+                <el-table-column
+                  prop="userContact"
+                  label="联系方式"
+                  width="160"
+                />
+                <el-table-column
+                  prop="appointStatus"
+                  label="预约状态"
+                  width="160"
+                >
+                  <template #default="{ row }">
+                    {{ setStatus(row.appointStatus) }}
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="appointStatus"
+                  label="违约情况"
+                  width="160"
+                >
+                  <template #default="{ row }">
+                    {{ getBreachTypes(row) }}
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="breachScore"
+                  label="扣分明细"
+                  width="160"
+                >
+                  <template #default="{ row }">
+                    <span>{{ row.breachScore }}分</span>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作" fixed="right" width="100">
+                  <template #default="{ row }">
+                    <el-button
+                      type="text"
+                      v-if="row.appointStatus == '10'"
+                      @click="handleEditAppoint(row)"
+                      text
+                    >
+                      编辑
+                    </el-button>
+                    <el-button
+                      type="text"
+                      style="color: #f56c6c"
+                      v-if="
+                        row.appointStatus == '10' || row.appointStatus == '20'
+                      "
+                      @click="cancelAppoint(row)"
+                      text
+                    >
+                      取消
+                    </el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+            <div class="pagination">
+              <el-pagination
+                background
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :current-page="searchForm.pageNum"
+                :page-sizes="[10, 50, 100]"
+                :page-size="searchForm.pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="total"
+              ></el-pagination>
+            </div>
+          </el-card>
+        </div>
+      </el-container>
+    </div>
+<<<<<<< Updated upstream
+    <PersonalInfoDialog ref="personalInfoDialogRef" />
+=======
+    <AppointCreate
+      ref="appointCreateRef"
+      @refresh="
+        searchForm.pageNum = 1;
+        getAppointList();
+      "
+    ></AppointCreate>
+>>>>>>> Stashed changes
+  </div>
+</template>
+
+<script>
+<<<<<<< Updated upstream
+import Banner from "../components/Banner";
+import LeftTabs from "@/components/LeftTabs";
+import RightContent from "@/components/RightContent";
+import * as echarts from "echarts";
+import FullCalendar from "@fullcalendar/vue";
+import dayGridPlugin from "@fullcalendar/daygrid";
+import interactionPlugin from "@fullcalendar/interaction";
+import { getNoticeList } from "@/api/login";
+import {
+  getInstrList,
+  getInstrListByUser,
+  userCancelAppoint,
+  cancelAppoint,
+} from "@/api/instr";
+import moment from "moment";
+import to from "await-to-js";
+import { mapGetters } from "vuex";
+import PersonalInfoDialog from "@/components/PersonalInfo";
+export default {
+  name: "PersonalCenter",
+  components: {
+    Banner,
+    LeftTabs,
+    RightContent,
+    FullCalendar,
+    PersonalInfoDialog,
+  },
+  computed: {
+    ...mapGetters(["userInfo"]),
+  },
+  data() {
+    return {
+      active: -1,
+      loading: true,
+      selectTab: {},
+      options: [
+        {
+          label: "工作台",
+        },
+        {
+          label: "预约信息",
+        },
+      ],
+      routeList: [
+        {
+          name: "首页",
+          path: "/",
+        },
+        {
+          name: "个人中心",
+        },
+      ],
+      breadList: [],
+      calendarOptions: {
+        height: 300,
+        plugins: [dayGridPlugin, interactionPlugin], // 需要用哪个插件引入后放到这个数组里
+        initialDate: new Date(), // 日历第一次加载时显示的初始日期。可以解析为Date的任何职包括ISO8601日期字符串,例如"2014-02-01"。
+        initialView: "dayGridMonth", // 日历加载时的初始视图,默认值为'dayGridMonth',可以为任何可用视图的值,如例如'dayGridWeek','timeGridDay','listWeek'
+        locale: "zh-cn", // 设置日历的语言,中文为 “zh-cn”
+        firstDay: "1", // 设置每周的第一天,默认值取决于当前语言环境,该值为代表星期几的数字,且值必须为整数,星期日=0
+        weekNumberCalculation: "ISO", // 指定"ISO"结果为ISO8601周数。指定"ISO"将firstDay的默认值更改为1(Monday)
+        buttonText: {
+          // 文本将显示在headerToolbar / footerToolbar的按钮上。不支持HTML注入。所有特殊字符将被转义。
+          today: "今天",
+          month: "月",
+          week: "周",
+          day: "天",
+        },
+        headerToolbar: {
+          // 在日历顶部定义按钮和标题。将headerToolbar选项设置为false不会显示任何标题工具栏。可以为对象提供属性start/center/end或left/center/right。这些属性包含带有逗号/空格分隔值的字符串。用逗号分隔的值将相邻显示。用空格分隔的值之间会显示一个很小的间隙。
+          right: "today prev,next",
+          center: "title",
+          left: "dayGridMonth,dayGridWeek,dayGridDay",
+        },
+        eventTimeFormat: {
+          // 在每个事件上显示的时间的格式
+          hour: "numeric",
+          minute: "2-digit",
+          hour12: false,
+        },
+        events: [],
+        dateClick: this.handleDateClick, // 当用户单击日期或时间时,触发该回调,触发此回调,您必须加载interaction插件
+      },
+      instrList: [],
+      noticeList: [],
+      curSelectedDate: "",
+      curTime: "",
+      appointData: [],
+      WEEKS: [
+        "星期日",
+        "星期一",
+        "星期二",
+        "星期三",
+        "星期四",
+        "星期五",
+        "星期六",
+      ],
+    };
+  },
+  mounted() {
+    this.tabSelect(this.options[0], 0);
+    this.curTime = this.getToday();
+    this.initChart();
+    this.getNotice();
+    this.getInstr();
+  },
+  methods: {
+    moment,
+    // 獲取當前日期
+    getToday() {
+      return moment(moment().startOf("day").valueOf()).format("YYYY-MM-DD");
+=======
+  import Banner from "../components/Banner";
+  import LeftTabs from "@/components/LeftTabs";
+  import RightContent from "@/components/RightContent";
+  import * as echarts from "echarts";
+  import FullCalendar from "@fullcalendar/vue";
+  import dayGridPlugin from "@fullcalendar/daygrid";
+  import interactionPlugin from "@fullcalendar/interaction";
+  import { getNoticeList } from "@/api/login";
+  import {
+    getInstrList,
+    getInstrListByUser,
+    userCancelAppoint,
+  } from "@/api/instr";
+  import { mapGetters } from "vuex";
+  import moment from "moment";
+  import to from "await-to-js";
+  import { getToken } from "@/utils/auth";
+  import AppointCreate from "./equipment/components/appoint-create.vue";
+  export default {
+    name: "PersonalCenter",
+    components: {
+      Banner,
+      LeftTabs,
+      RightContent,
+      FullCalendar,
+      AppointCreate,
+>>>>>>> Stashed changes
+    },
+
+<<<<<<< Updated upstream
+      // 获取下一周的周一0点
+      var startOfNextWeek = moment(this.curTime)
+        .startOf("isoWeek")
+        .add(1, "weeks")
+        .format("YYYY-MM-DD HH:mm:ss");
+      return [startOfWeek, startOfNextWeek];
+    },
+    getMonthDate() {
+      const date = moment(this.curTime);
+      // 获取当前月份的最后一天
+      return [
+        date.startOf("month").format("YYYY-MM-DD HH:mm:ss"),
+        date.endOf("month").add(1, "days").format("YYYY-MM-DD") + " 00:00:00",
+      ];
+    },
+    // 上一周、天、月
+    handlePrev() {
+      if (this.curSelectedDate == "d") {
+        this.getYesterday();
+      } else if (this.curSelectedDate == "w") {
+        this.getPrevWeekDays();
+      } else if (this.curSelectedDate == "m") {
+        this.getPrevMonthDays();
+      }
+      this.getAppointList();
+    },
+    // 下一周、天、月
+    handleNext() {
+      if (this.curSelectedDate == "d") {
+        this.getTomorrow();
+      } else if (this.curSelectedDate == "w") {
+        this.getNextWeekDays();
+      } else if (this.curSelectedDate == "m") {
+        this.getNextMonthDays();
+      }
+      this.getAppointList();
+    },
+    selectDate(date) {
+      this.curSelectedDate = date;
+      this.getAppointList();
+    },
+    async getAppointList() {
+      let startTimeStart = "";
+      let startTimeEnd = "";
+      if (this.curSelectedDate == "d") {
+        startTimeStart = moment(this.curTime).format("YYYY-MM-DD HH:mm:ss");
+        startTimeEnd = moment(this.curTime)
+          .add(1, "days")
+          .format("YYYY-MM-DD HH:mm:ss");
+      } else if (this.curSelectedDate == "w") {
+        startTimeStart = this.getWeekDate()[0];
+        startTimeEnd = this.getWeekDate()[1];
+      } else if (this.curSelectedDate == "m") {
+        startTimeStart = moment(this.curTime)
+          .startOf("month")
+          .format("YYYY-MM-DD HH:mm:ss");
+        startTimeEnd = this.getMonthDate()[1];
+      }
+      const [err, res] = await to(
+        getInstrListByUser({ startTimeStart, startTimeEnd })
+      );
+      if (err) return;
+      this.appointData = res.data.list;
+    },
+    setStatus(key) {
+      let str = "";
+      switch (key) {
+        case "10":
+          str = "待审核";
+          break;
+        case "11":
+          str = "已退回";
+          break;
+        case "20":
+          str = "已通过";
+          break;
+        case "30":
+          str = "已驳回";
+          break;
+        case "40":
+          str = "已取消";
+          break;
+        case "50":
+          str = "已上机";
+          break;
+        case "60":
+          str = "已完成";
+          break;
+        case "70":
+          str = "审核超时";
+          break;
+        case "80":
+          str = "超时取消";
+          break;
+        case "90":
+          str = "超时未上机";
+          break;
+      }
+      return str;
+    },
+    getBreachTypes(row) {
+      let breachTypes = [];
+      if (row.isLate) breachTypes.push("迟到");
+      if (row.isOvertime) breachTypes.push("超时");
+      if (row.isLeaveEarly) breachTypes.push("早退");
+      if (row.isAbsence) breachTypes.push("爽约");
+      return breachTypes.join("、") || "-";
+    },
+    cancelAppoint(row) {
+      // 删除附件
+      this.$confirm("确认取消预约?", "提示", {
+        confirmButtonText: "确认",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(async () => {
+          const post =
+            row.userId == props.curUserId
+              ? userCancelAppoint({ id: Number(row.id) })
+              : cancelAppoint({ id: Number(row.id) });
+          const [err] = await to(post);
+          if (err) return;
+          this.$message.success("取消成功");
+          this.getAppointList();
+        })
+        .catch(() => {});
+    },
+    editAppoint() {},
+    // 选择tab
+    tabSelect(row, index) {
+      this.active = index;
+      this.selectTab = { ...row };
+      this.breadList = [...this.routeList, { name: this.selectTab.label }];
+    },
+    async getNotice() {
+      const [err, res] = await to(getNoticeList());
+      if (err) return;
+      this.noticeList = res.data.list || [];
+    },
+    async getInstr() {
+      const [err, res] = await to(getInstrList({ pageSize: 4, pageNum: 1 }));
+      if (err) return;
+      this.instrList = res.data.list || [];
+    },
+    initChart() {
+      let chart = echarts.init(document.getElementById("chart"));
+      const options = {
+        series: [
+=======
+    data() {
+      return {
+        active: -1,
+        loading: true,
+        selectTab: {},
+        searchForm: {
+          pageNum: 1,
+          pageSize: 10,
+        },
+        total: 0,
+        options: [
+>>>>>>> Stashed changes
+          {
+            label: "工作台",
+          },
+          {
+            label: "预约信息",
+          },
+        ],
+        routeList: [
+          {
+            name: "首页",
+            path: "/",
+          },
+          {
+            name: "个人中心",
+          },
+        ],
+        breadList: [],
+        calendarOptions: {
+          height: 300,
+          plugins: [dayGridPlugin, interactionPlugin], // 需要用哪个插件引入后放到这个数组里
+          initialDate: new Date(), // 日历第一次加载时显示的初始日期。可以解析为Date的任何职包括ISO8601日期字符串,例如"2014-02-01"。
+          initialView: "dayGridMonth", // 日历加载时的初始视图,默认值为'dayGridMonth',可以为任何可用视图的值,如例如'dayGridWeek','timeGridDay','listWeek'
+          locale: "zh-cn", // 设置日历的语言,中文为 “zh-cn”
+          firstDay: "1", // 设置每周的第一天,默认值取决于当前语言环境,该值为代表星期几的数字,且值必须为整数,星期日=0
+          weekNumberCalculation: "ISO", // 指定"ISO"结果为ISO8601周数。指定"ISO"将firstDay的默认值更改为1(Monday)
+          buttonText: {
+            // 文本将显示在headerToolbar / footerToolbar的按钮上。不支持HTML注入。所有特殊字符将被转义。
+            today: "今天",
+            month: "月",
+            week: "周",
+            day: "天",
+          },
+          headerToolbar: {
+            // 在日历顶部定义按钮和标题。将headerToolbar选项设置为false不会显示任何标题工具栏。可以为对象提供属性start/center/end或left/center/right。这些属性包含带有逗号/空格分隔值的字符串。用逗号分隔的值将相邻显示。用空格分隔的值之间会显示一个很小的间隙。
+            right: "today prev,next",
+            center: "title",
+            left: "dayGridMonth,dayGridWeek,dayGridDay",
+          },
+          eventTimeFormat: {
+            // 在每个事件上显示的时间的格式
+            hour: "numeric",
+            minute: "2-digit",
+            hour12: false,
+          },
+          events: [],
+          dateClick: this.handleDateClick, // 当用户单击日期或时间时,触发该回调,触发此回调,您必须加载interaction插件
+        },
+        instrList: [],
+        noticeList: [],
+        curSelectedDate: "w",
+        curTime: "",
+        appointData: [],
+        WEEKS: [
+          "星期日",
+          "星期一",
+          "星期二",
+          "星期三",
+          "星期四",
+          "星期五",
+          "星期六",
+        ],
+      };
+    },
+    computed: {
+      ...mapGetters(["userInfo"]),
+    },
+    mounted() {
+      this.tabSelect(this.options[0], 0);
+      this.curTime = this.getToday();
+      this.initChart();
+      this.getNotice();
+      this.getInstr();
+    },
+    methods: {
+      moment,
+      // 獲取當前日期
+      getToday() {
+        return moment(moment().startOf("day").valueOf()).format("YYYY-MM-DD");
+      },
+      getYesterday() {
+        this.curTime = moment(
+          moment(this.curTime).add(-1, "days").startOf("day").valueOf()
+        ).format("YYYY-MM-DD");
+      },
+      getTomorrow() {
+        this.curTime = moment(
+          moment(this.curTime).add(+1, "days").startOf("day").valueOf()
+        ).format("YYYY-MM-DD");
+      },
+      getPrevWeekDays() {
+        this.curTime = moment(this.curTime)
+          .subtract(1, "week")
+          .format("YYYY-MM-DD");
+      },
+      getNextWeekDays() {
+        this.curTime = moment(this.curTime).add(1, "week").format("YYYY-MM-DD");
+      },
+      getPrevMonthDays() {
+        this.curTime = moment(this.curTime)
+          .subtract(1, "months")
+          .format("YYYY-MM-DD");
+      },
+      getNextMonthDays() {
+        this.curTime = moment(this.curTime)
+          .add(1, "months")
+          .format("YYYY-MM-DD");
+      },
+      getWeekDate() {
+        // 获取当前周的周一0点
+        var startOfWeek = moment(this.curTime)
+          .startOf("isoWeek")
+          .format("YYYY-MM-DD HH:mm:ss");
+
+        // 获取下一周的周一0点
+        var startOfNextWeek = moment(this.curTime)
+          .startOf("isoWeek")
+          .add(1, "weeks")
+          .format("YYYY-MM-DD HH:mm:ss");
+        return [startOfWeek, startOfNextWeek];
+      },
+      getMonthDate() {
+        const date = moment(this.curTime);
+        // 获取当前月份的最后一天
+        return [
+          date.startOf("month").format("YYYY-MM-DD HH:mm:ss"),
+          date.endOf("month").add(1, "days").format("YYYY-MM-DD") + " 00:00:00",
+        ];
+      },
+      // 上一周、天、月
+      handlePrev() {
+        if (this.curSelectedDate == "d") {
+          this.getYesterday();
+        } else if (this.curSelectedDate == "w") {
+          this.getPrevWeekDays();
+        } else if (this.curSelectedDate == "m") {
+          this.getPrevMonthDays();
+        }
+        this.getAppointList();
+      },
+      // 下一周、天、月
+      handleNext() {
+        if (this.curSelectedDate == "d") {
+          this.getTomorrow();
+        } else if (this.curSelectedDate == "w") {
+          this.getNextWeekDays();
+        } else if (this.curSelectedDate == "m") {
+          this.getNextMonthDays();
+        }
+        this.getAppointList();
+      },
+      selectDate(date) {
+        this.curSelectedDate = date;
+        this.getAppointList();
+      },
+      async getAppointList() {
+        let startTimeStart = "";
+        let startTimeEnd = "";
+        if (this.curSelectedDate == "d") {
+          startTimeStart = moment(this.curTime).format("YYYY-MM-DD HH:mm:ss");
+          startTimeEnd = moment(this.curTime)
+            .add(1, "days")
+            .format("YYYY-MM-DD HH:mm:ss");
+        } else if (this.curSelectedDate == "w") {
+          startTimeStart = this.getWeekDate()[0];
+          startTimeEnd = this.getWeekDate()[1];
+        } else if (this.curSelectedDate == "m") {
+          startTimeStart = moment(this.curTime)
+            .startOf("month")
+            .format("YYYY-MM-DD HH:mm:ss");
+          startTimeEnd = this.getMonthDate()[1];
+        }
+        console.log(startTimeStart);
+        const [err, res] = await to(
+          getInstrListByUser({
+            startTimeStart,
+            startTimeEnd,
+            ...this.searchForm,
+          })
+        );
+        if (err) return;
+        this.appointData = res.data.list;
+        this.total = res.data.total;
+      },
+      setStatus(key) {
+        let str = "";
+        switch (key) {
+          case "10":
+            str = "待审核";
+            break;
+          case "11":
+            str = "已退回";
+            break;
+          case "20":
+            str = "已通过";
+            break;
+          case "30":
+            str = "已驳回";
+            break;
+          case "40":
+            str = "已取消";
+            break;
+          case "50":
+            str = "已上机";
+            break;
+          case "60":
+            str = "已完成";
+            break;
+          case "70":
+            str = "审核超时";
+            break;
+          case "80":
+            str = "超时取消";
+            break;
+          case "90":
+            str = "超时未上机";
+            break;
+        }
+        return str;
+      },
+      getBreachTypes(row) {
+        let breachTypes = [];
+        if (row.isLate) breachTypes.push("迟到");
+        if (row.isOvertime) breachTypes.push("超时");
+        if (row.isLeaveEarly) breachTypes.push("早退");
+        if (row.isAbsence) breachTypes.push("爽约");
+        return breachTypes.join("、") || "-";
+      },
+      // 取消预约
+      cancelAppoint(row) {
+        // 删除附件
+        this.$confirm("确认取消预约?", "提示", {
+          confirmButtonText: "确认",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+          .then(async () => {
+            const post = userCancelAppoint({ id: Number(row.id) });
+            const [err] = await to(post);
+            if (err) return;
+            this.$message.success("取消成功");
+            this.getAppointList();
+          })
+          .catch(() => {});
+      },
+      // 编辑预约
+      handleEditAppoint(row) {
+        const token = getToken();
+        if (!token) {
+          return this.$router.push("/login");
+        }
+        this.$refs.appointCreateRef.openDialog(row);
+      },
+      // 选择tab
+      tabSelect(row, index) {
+        this.active = index;
+        this.selectTab = { ...row };
+        this.breadList = [...this.routeList, { name: this.selectTab.label }];
+        if (index == 1) {
+          this.getAppointList();
+        }
+      },
+      async getNotice() {
+        const [err, res] = await to(getNoticeList());
+        if (err) return;
+        this.noticeList = res.data.list || [];
+      },
+      async getInstr() {
+        const [err, res] = await to(getInstrList({ pageSize: 4, pageNum: 1 }));
+        if (err) return;
+        this.instrList = res.data.list || [];
+      },
+      initChart() {
+        let chart = echarts.init(document.getElementById("chart"));
+        const options = {
+          series: [
+            {
+              type: "gauge",
+              startAngle: 180,
+              endAngle: 0,
+              center: ["50%", "75%"],
+              radius: "90%",
+              min: 0,
+              max: 1,
+              splitNumber: 8,
+              axisLine: {
+                lineStyle: {
+                  width: 6,
+                  color: [
+                    [0.25, "#FF6E76"],
+                    [0.5, "#FDDD60"],
+                    [0.75, "#58D9F9"],
+                    [1, "#7CFFB2"],
+                  ],
+                },
+              },
+              pointer: {
+                icon: "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z",
+                length: "12%",
+                width: 20,
+                offsetCenter: [0, "-60%"],
+                itemStyle: {
+                  color: "auto",
+                },
+              },
+              axisTick: {
+                length: 12,
+                lineStyle: {
+                  color: "auto",
+                  width: 2,
+                },
+              },
+              splitLine: {
+                length: 20,
+                lineStyle: {
+                  color: "auto",
+                  width: 5,
+                },
+              },
+              axisLabel: {
+                color: "#464646",
+                fontSize: 14,
+                distance: -40,
+                rotate: "tangential",
+                formatter: function (value) {
+                  if (value === 0.875) {
+                    return "充足";
+                  } else if (value === 0.625) {
+                    return "可控";
+                  } else if (value === 0.375) {
+                    return "紧张";
+                  } else if (value === 0.125) {
+                    return "危险";
+                  }
+                  return "";
+                },
+              },
+              title: {
+                offsetCenter: [0, "-10%"],
+                fontSize: 14,
+              },
+              detail: {
+                fontSize: 20,
+                offsetCenter: [0, "-35%"],
+                valueAnimation: true,
+                formatter: function (value) {
+                  return Math.round(value * 100) + "";
+                },
+                color: "inherit",
+              },
+              data: [
+                {
+                  value: 0.7,
+                  name: "危险预算余额",
+                },
+              ],
+            },
+          ],
+        };
+        chart.setOption(options);
+      },
+      handleDateClick(dateClickInfo) {
+        console.log(dateClickInfo);
+      },
+      handleSizeChange(val) {
+        this.searchForm.pageSize = val;
+        this.getAppointList();
+      },
+      handleCurrentChange(val) {
+        this.searchForm.pageNum = val;
+        this.getAppointList();
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+<<<<<<< Updated upstream
+.center-banner {
+  background: url(../assets/img/login-bg.png) top no-repeat;
+  height: 240px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  .content {
+    height: 180px;
+    width: 1200px;
+    border-radius: 16px;
+    background-color: rgba($color: #fff, $alpha: 0.5);
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 0 40px;
+    .user {
+      display: flex;
+      align-items: center;
+      img {
+        height: 100px;
+        width: 100px;
+        border-radius: 50%;
+      }
+      p {
+        height: 100px;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+        margin-left: 12px;
+        span:nth-child(1) {
+          font-weight: bold;
+          font-size: 18px;
+        }
+        span:nth-child(3) {
+          font-weight: bold;
+        }
+      }
+    }
+    .btns {
+      display: flex;
+      align-items: center;
+      > p {
+        display: flex;
+        align-items: center;
+        margin-right: 20px;
+        line-height: 30px;
+        font-weight: bold;
+        span {
+          font-size: 30px;
+          font-weight: bold;
+          color: #1d66dc;
+          font-style: italic;
+        }
+      }
+    }
+  }
+}
+.flex {
+  width: 100%;
+  flex-wrap: wrap;
+  .el-card {
+    flex: 0 0 calc(50% - 14px);
+    height: 400px;
+    ::v-deep .el-card__body {
+      padding: 10px;
+      height: calc(100% - 79px);
+    }
+    &.calendar {
+      height: 500px;
+      ul {
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+        height: 130px;
+        li {
+          font-size: 14px;
+=======
+  .flex {
+    width: 100%;
+    flex-wrap: wrap;
+    .el-card {
+      flex: 0 0 calc(50% - 14px);
+      height: 400px;
+      ::v-deep .el-card__body {
+        padding: 10px;
+        height: calc(100% - 79px);
+      }
+      &.calendar {
+        height: 500px;
+        ul {
+>>>>>>> Stashed changes
+          display: flex;
+          flex-direction: column;
+          justify-content: space-around;
+          height: 130px;
+          li {
+            font-size: 14px;
+            display: flex;
+            align-items: center;
+            &:before {
+              content: "";
+              display: inline-block;
+              width: 6px;
+              height: 6px;
+              border-radius: 3px;
+              background-color: #a30014;
+              margin-right: 4px;
+            }
+          }
+        }
+      }
+      &.cost {
+        height: 300px;
+      }
+    }
+    &.technical .el-card {
+      height: auto;
+      ::v-deep .el-card__body {
+        height: auto;
+      }
+    }
+  }
+  .cage-list {
+    display: flex;
+    flex-wrap: wrap;
+    list-style: none;
+    li {
+      height: 160px;
+      width: 221px;
+      font-size: 14px;
+      border: 1px solid #ebeef5;
+      border-radius: 6px;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-around;
+      padding: 10px;
+      &:nth-child(2n) {
+        margin-left: 4px;
+      }
+      &:nth-child(n + 3) {
+        margin-top: 4px;
+      }
+      header {
+        display: flex;
+        justify-content: space-between;
+        p {
+          color: #1d66dc;
+        }
+      }
+    }
+  }
+  .platform-list {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    li {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      margin: 12px;
+      border-radius: 8px;
+      overflow: hidden;
+      border: 1px solid #ebeef5;
+      .text {
+        flex: 1;
+        height: 100%;
+        padding: 12px;
+      }
+      .btn {
+        width: 120px;
+        height: 100%;
+        color: #fff;
+        font-size: 20px;
+        background-color: #73b9b9;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: space-around;
+        header {
+          font-size: 14px;
+        }
+        .remain-time {
+          color: #f56c6c;
+        }
+      }
+    }
+  }
+  .chart-container {
+    display: flex;
+    .text {
+      flex: 1;
+      font-size: 14px;
+      display: flex;
+      flex-direction: column;
+      header {
+        color: #1d66dc;
+      }
+      ul {
+        margin-top: 12px;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+      }
+      li {
+        background-color: #e4b5bb;
+        border-radius: 4px;
+        padding: 4px 8px;
+      }
+    }
+    #chart {
+      width: 233px;
+      height: 220px;
+    }
+  }
+  .technical {
+    p {
+      font-size: 16px;
+      height: 24px;
+      line-height: 24px;
+    }
+    ul {
+      display: flex;
+      height: 50px;
+      line-height: 50px;
+      border-radius: 4px;
+      overflow: hidden;
+      margin: 20px 0;
+      li {
+        flex: 1;
+        text-align: center;
+        background-color: #d9fba5;
+        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+        &:nth-child(2) {
+          background-color: #98ca49;
+        }
+        &:nth-child(3) {
+          background-color: #a4dffa;
+        }
+        &:nth-child(4) {
+          background-color: #48bff4;
+        }
+        &:nth-child(5) {
+          background-color: #b6b6f1;
+        }
+        &:nth-child(6) {
+          background-color: #ebcda7;
+        }
+        &:nth-child(7) {
+          background-color: #f2a4ad;
+        }
+      }
+    }
+  }
+  .toolbar-wrap {
+    height: 30px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    // margin-bottom: 20px;
+    .switch-date {
+      width: 108px;
+      height: 28px;
+      border-radius: 2px;
+      border: 1px solid #b5c1d8;
+      display: flex;
+      padding: 4px 6px 0;
+      .btn {
+        cursor: pointer;
+        flex: 1;
+        font-size: 13px;
+        color: #585858;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        &.actived {
+          background: #eef3fe;
+          font-weight: bold;
+          color: #2c78ff;
+        }
+      }
+    }
+    .date-wrap {
+      display: flex;
+      align-items: center;
+      :deep(.el-button--small.is-circle) {
+        width: 26px;
+        height: 26px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+      .date {
+        margin: 0 10px;
+        font-size: 14px;
+        color: #585858;
+        display: flex;
+        align-items: center;
+      }
+      .week {
+        color: #2c78ff;
+        padding-left: 6px;
+      }
+    }
+  }
+  .table-wrap {
+    flex: 1;
+    margin: 20px 0 0;
+    // overflow: hidden;
+  }
+  .pagination {
+    width: 100%;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
+</style>

+ 651 - 0
src/views/componetns/user-appoint-record.vue

@@ -0,0 +1,651 @@
+<template>
+  <div>
+    <el-card>
+      <div class="toolbar-wrap">
+        <div class="switch-date">
+          <div
+            class="btn day"
+            :class="curSelectedDate == 'd' ? 'actived' : ''"
+            @click="selectDate('d')"
+          >
+            日
+          </div>
+          <div
+            class="btn week"
+            :class="curSelectedDate == 'w' ? 'actived' : ''"
+            @click="selectDate('w')"
+          >
+            周
+          </div>
+          <div
+            class="btn month"
+            :class="curSelectedDate == 'm' ? 'actived' : ''"
+            @click="selectDate('m')"
+          >
+            月
+          </div>
+        </div>
+        <div class="date-wrap">
+          <div class="prev" @click="handlePrev">
+            <el-button icon="el-icon-arrow-left" size="small" circle />
+          </div>
+          <div class="date">
+            <el-popover :width="200" placement="top-start" trigger="click">
+              <div slot="reference">
+                <span class="time">{{ curTime }}</span>
+              </div>
+              <el-date-picker
+                @change="getAppointList"
+                style="width: 100%"
+                v-model="curTime"
+                type="date"
+                placeholder="选择日期"
+                value-format="yyyy-MM-dd"
+                :clearable="false"
+              />
+            </el-popover>
+            <span class="week">{{ WEEKS[moment(curTime).day()] }}</span>
+          </div>
+          <div class="next" @click="handleNext">
+            <el-button icon="el-icon-arrow-right" size="small" circle />
+          </div>
+        </div>
+      </div>
+      <div class="table-wrap">
+        <el-table :data="appointData" border height="500" style="width: 922px">
+          <el-table-column
+            type="index"
+            width="50"
+            align="center"
+          ></el-table-column>
+          <el-table-column prop="instName" label="仪器名称" min-width="160" />
+          <el-table-column
+            prop="projectName"
+            label="课题组/服务"
+            min-width="160"
+          >
+            <template #default="{ row }">
+              <span v-if="row.projectName">{{ row.projectName }}</span>
+              <span v-else>{{ row.serviceName }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="startTime" label="开始时间" width="160">
+            <template #default="{ row }">
+              {{ parseTime(row.startTime, "{y}-{m}-{d}") }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="endTime" label="结束时间" width="160">
+            <template #default="{ row }">
+              {{ parseTime(row.endTime, "{y}-{m}-{d}") }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="userName" label="预约人" width="140" />
+          <el-table-column prop="userContact" label="联系方式" width="160" />
+          <el-table-column prop="appointStatus" label="预约状态" width="160">
+            <template #default="{ row }">
+              {{ setStatus(row.appointStatus) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="appointStatus" label="违约情况" width="160">
+            <template #default="{ row }">
+              {{ getBreachTypes(row) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="breachScore" label="扣分明细" width="160">
+            <template #default="{ row }">
+              <span>{{ row.breachScore }}分</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" fixed="right" width="160">
+            <template #default="{ row }">
+              <el-button
+                type="primary"
+                v-if="row.appointStatus == '10'"
+                @click="editAppoint(row)"
+                text
+              >
+                编辑
+              </el-button>
+              <el-button
+                type="danger"
+                v-if="showCancelBtn(row)"
+                @click="cancelAppoint(row)"
+                text
+              >
+                取消
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+  import { userCancelAppoint, cancelAppoint } from "@/api/instr";
+  import moment from "moment";
+  import to from "await-to-js";
+  export default {
+    name: "UserAppointRecord",
+    data() {
+      return {
+        curSelectedDate: "",
+      };
+    },
+    mounted() {
+      this.tabSelect(this.options[0], 0);
+      this.curTime = this.getToday();
+      this.initChart();
+      this.getNotice();
+      this.getInstr();
+    },
+    methods: {
+      moment,
+      // 獲取當前日期
+      getToday() {
+        return moment(moment().startOf("day").valueOf()).format("YYYY-MM-DD");
+      },
+      getYesterday() {
+        this.curTime = moment(
+          moment(this.curTime).add(-1, "days").startOf("day").valueOf()
+        ).format("YYYY-MM-DD");
+      },
+      getTomorrow() {
+        this.curTime = moment(
+          moment(this.curTime).add(+1, "days").startOf("day").valueOf()
+        ).format("YYYY-MM-DD");
+      },
+      getPrevWeekDays() {
+        this.curTime = moment(this.curTime)
+          .subtract(1, "week")
+          .format("YYYY-MM-DD");
+      },
+      getNextWeekDays() {
+        this.curTime = moment(this.curTime).add(1, "week").format("YYYY-MM-DD");
+      },
+      getPrevMonthDays() {
+        this.curTime = moment(this.curTime)
+          .subtract(1, "months")
+          .format("YYYY-MM-DD");
+      },
+      getNextMonthDays() {
+        this.curTime = moment(this.curTime)
+          .add(1, "months")
+          .format("YYYY-MM-DD");
+      },
+      getWeekDate() {
+        // 获取当前周的周一0点
+        var startOfWeek = moment(this.curTime)
+          .startOf("isoWeek")
+          .format("YYYY-MM-DD HH:mm:ss");
+
+        // 获取下一周的周一0点
+        var startOfNextWeek = moment(this.curTime)
+          .startOf("isoWeek")
+          .add(1, "weeks")
+          .format("YYYY-MM-DD HH:mm:ss");
+        return [startOfWeek, startOfNextWeek];
+      },
+      getMonthDate() {
+        const date = moment(this.curTime);
+        // 获取当前月份的最后一天
+        return [
+          date.startOf("month").format("YYYY-MM-DD HH:mm:ss"),
+          date.endOf("month").add(1, "days").format("YYYY-MM-DD") + " 00:00:00",
+        ];
+      },
+      // 上一周、天、月
+      handlePrev() {
+        if (this.curSelectedDate == "d") {
+          this.getYesterday();
+        } else if (this.curSelectedDate == "w") {
+          this.getPrevWeekDays();
+        } else if (this.curSelectedDate == "m") {
+          this.getPrevMonthDays();
+        }
+        this.getAppointList();
+      },
+      // 下一周、天、月
+      handleNext() {
+        if (this.curSelectedDate == "d") {
+          this.getTomorrow();
+        } else if (this.curSelectedDate == "w") {
+          this.getNextWeekDays();
+        } else if (this.curSelectedDate == "m") {
+          this.getNextMonthDays();
+        }
+        this.getAppointList();
+      },
+      selectDate(date) {
+        this.curSelectedDate = date;
+        this.getAppointList();
+      },
+      async getAppointList() {
+        let startTimeStart = "";
+        let startTimeEnd = "";
+        if (this.curSelectedDate == "d") {
+          startTimeStart = moment(this.curTime).format("YYYY-MM-DD HH:mm:ss");
+          startTimeEnd = moment(this.curTime)
+            .add(1, "days")
+            .format("YYYY-MM-DD HH:mm:ss");
+        } else if (this.curSelectedDate == "w") {
+          startTimeStart = this.getWeekDate()[0];
+          startTimeEnd = this.getWeekDate()[1];
+        } else if (this.curSelectedDate == "m") {
+          startTimeStart = moment(this.curTime)
+            .startOf("month")
+            .format("YYYY-MM-DD HH:mm:ss");
+          startTimeEnd = this.getMonthDate()[1];
+        }
+        const [err, res] = await to(
+          getInstrListByUser({ startTimeStart, startTimeEnd })
+        );
+        if (err) return;
+        this.appointData = res.data.list;
+      },
+      setStatus(key) {
+        let str = "";
+        switch (key) {
+          case "10":
+            str = "待审核";
+            break;
+          case "11":
+            str = "已退回";
+            break;
+          case "20":
+            str = "已通过";
+            break;
+          case "30":
+            str = "已驳回";
+            break;
+          case "40":
+            str = "已取消";
+            break;
+          case "50":
+            str = "已上机";
+            break;
+          case "60":
+            str = "已完成";
+            break;
+          case "70":
+            str = "审核超时";
+            break;
+          case "80":
+            str = "超时取消";
+            break;
+          case "90":
+            str = "超时未上机";
+            break;
+        }
+        return str;
+      },
+      getBreachTypes(row) {
+        let breachTypes = [];
+        if (row.isLate) breachTypes.push("迟到");
+        if (row.isOvertime) breachTypes.push("超时");
+        if (row.isLeaveEarly) breachTypes.push("早退");
+        if (row.isAbsence) breachTypes.push("爽约");
+        return breachTypes.join("、") || "-";
+      },
+      cancelAppoint(row) {
+        // 删除附件
+        this.$confirm("确认取消预约?", "提示", {
+          confirmButtonText: "确认",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+          .then(async () => {
+            const post =
+              row.userId == props.curUserId
+                ? userCancelAppoint({ id: Number(row.id) })
+                : cancelAppoint({ id: Number(row.id) });
+            const [err] = await to(post);
+            if (err) return;
+            this.$message.success("取消成功");
+            this.getAppointList();
+          })
+          .catch(() => {});
+      },
+      editAppoint() {},
+      // 选择tab
+      tabSelect(row, index) {
+        this.active = index;
+        this.selectTab = { ...row };
+        this.breadList = [...this.routeList, { name: this.selectTab.label }];
+      },
+      async getNotice() {
+        const [err, res] = await to(getNoticeList());
+        if (err) return;
+        this.noticeList = res.data.list || [];
+      },
+      async getInstr() {
+        const [err, res] = await to(getInstrList({ pageSize: 4, pageNum: 1 }));
+        if (err) return;
+        this.instrList = res.data.list || [];
+      },
+      initChart() {
+        let chart = echarts.init(document.getElementById("chart"));
+        const options = {
+          series: [
+            {
+              type: "gauge",
+              startAngle: 180,
+              endAngle: 0,
+              center: ["50%", "75%"],
+              radius: "90%",
+              min: 0,
+              max: 1,
+              splitNumber: 8,
+              axisLine: {
+                lineStyle: {
+                  width: 6,
+                  color: [
+                    [0.25, "#FF6E76"],
+                    [0.5, "#FDDD60"],
+                    [0.75, "#58D9F9"],
+                    [1, "#7CFFB2"],
+                  ],
+                },
+              },
+              pointer: {
+                icon: "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z",
+                length: "12%",
+                width: 20,
+                offsetCenter: [0, "-60%"],
+                itemStyle: {
+                  color: "auto",
+                },
+              },
+              axisTick: {
+                length: 12,
+                lineStyle: {
+                  color: "auto",
+                  width: 2,
+                },
+              },
+              splitLine: {
+                length: 20,
+                lineStyle: {
+                  color: "auto",
+                  width: 5,
+                },
+              },
+              axisLabel: {
+                color: "#464646",
+                fontSize: 14,
+                distance: -40,
+                rotate: "tangential",
+                formatter: function (value) {
+                  if (value === 0.875) {
+                    return "充足";
+                  } else if (value === 0.625) {
+                    return "可控";
+                  } else if (value === 0.375) {
+                    return "紧张";
+                  } else if (value === 0.125) {
+                    return "危险";
+                  }
+                  return "";
+                },
+              },
+              title: {
+                offsetCenter: [0, "-10%"],
+                fontSize: 14,
+              },
+              detail: {
+                fontSize: 20,
+                offsetCenter: [0, "-35%"],
+                valueAnimation: true,
+                formatter: function (value) {
+                  return Math.round(value * 100) + "";
+                },
+                color: "inherit",
+              },
+              data: [
+                {
+                  value: 0.7,
+                  name: "危险预算余额",
+                },
+              ],
+            },
+          ],
+        };
+        chart.setOption(options);
+      },
+      handleDateClick(dateClickInfo) {
+        console.log(dateClickInfo);
+      },
+    },
+  };
+</script>
+
+<style lang="scss" scoped>
+  .flex {
+    width: 100%;
+    flex-wrap: wrap;
+    .el-card {
+      flex: 0 0 calc(50% - 14px);
+      height: 400px;
+      ::v-deep .el-card__body {
+        padding: 10px;
+        height: calc(100% - 79px);
+      }
+      &.calendar {
+        height: 500px;
+        ul {
+          display: flex;
+          flex-direction: column;
+          justify-content: space-around;
+          height: 130px;
+          li {
+            font-size: 14px;
+            display: flex;
+            align-items: center;
+            &:before {
+              content: "";
+              display: inline-block;
+              width: 6px;
+              height: 6px;
+              border-radius: 3px;
+              background-color: #a30014;
+              margin-right: 4px;
+            }
+          }
+        }
+      }
+      &.cost {
+        height: 300px;
+      }
+    }
+    &.technical .el-card {
+      height: auto;
+      ::v-deep .el-card__body {
+        height: auto;
+      }
+    }
+  }
+  .cage-list {
+    display: flex;
+    flex-wrap: wrap;
+    list-style: none;
+    li {
+      height: 160px;
+      width: 221px;
+      font-size: 14px;
+      border: 1px solid #ebeef5;
+      border-radius: 6px;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-around;
+      padding: 10px;
+      &:nth-child(2n) {
+        margin-left: 4px;
+      }
+      &:nth-child(n + 3) {
+        margin-top: 4px;
+      }
+      header {
+        display: flex;
+        justify-content: space-between;
+        p {
+          color: #1d66dc;
+        }
+      }
+    }
+  }
+  .platform-list {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    li {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      margin: 12px;
+      border-radius: 8px;
+      overflow: hidden;
+      border: 1px solid #ebeef5;
+      .text {
+        flex: 1;
+        height: 100%;
+        padding: 12px;
+      }
+      .btn {
+        width: 120px;
+        height: 100%;
+        color: #fff;
+        font-size: 20px;
+        background-color: #73b9b9;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: space-around;
+        header {
+          font-size: 14px;
+        }
+        .remain-time {
+          color: #f56c6c;
+        }
+      }
+    }
+  }
+  .chart-container {
+    display: flex;
+    .text {
+      flex: 1;
+      font-size: 14px;
+      display: flex;
+      flex-direction: column;
+      header {
+        color: #1d66dc;
+      }
+      ul {
+        margin-top: 12px;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+      }
+      li {
+        background-color: #e4b5bb;
+        border-radius: 4px;
+        padding: 4px 8px;
+      }
+    }
+    #chart {
+      width: 233px;
+      height: 220px;
+    }
+  }
+  .technical {
+    p {
+      font-size: 16px;
+      height: 24px;
+      line-height: 24px;
+    }
+    ul {
+      display: flex;
+      height: 50px;
+      line-height: 50px;
+      border-radius: 4px;
+      overflow: hidden;
+      margin: 20px 0;
+      li {
+        flex: 1;
+        text-align: center;
+        background-color: #d9fba5;
+        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+        &:nth-child(2) {
+          background-color: #98ca49;
+        }
+        &:nth-child(3) {
+          background-color: #a4dffa;
+        }
+        &:nth-child(4) {
+          background-color: #48bff4;
+        }
+        &:nth-child(5) {
+          background-color: #b6b6f1;
+        }
+        &:nth-child(6) {
+          background-color: #ebcda7;
+        }
+        &:nth-child(7) {
+          background-color: #f2a4ad;
+        }
+      }
+    }
+  }
+  .toolbar-wrap {
+    height: 30px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    // margin-bottom: 20px;
+    .switch-date {
+      width: 108px;
+      height: 28px;
+      border-radius: 2px;
+      border: 1px solid #b5c1d8;
+      display: flex;
+      padding: 4px 6px 0;
+      .btn {
+        cursor: pointer;
+        flex: 1;
+        font-size: 13px;
+        color: #585858;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        &.actived {
+          background: #eef3fe;
+          font-weight: bold;
+          color: #2c78ff;
+        }
+      }
+    }
+    .date-wrap {
+      display: flex;
+      align-items: center;
+      :deep(.el-button--small.is-circle) {
+        width: 26px;
+        height: 26px;
+      }
+      .date {
+        margin: 0 10px;
+        font-size: 14px;
+        color: #585858;
+      }
+      .week {
+        color: #2c78ff;
+        padding-left: 6px;
+      }
+    }
+  }
+  .table-wrap {
+    flex: 1;
+    margin: 20px 0 0;
+    // overflow: hidden;
+  }
+</style>

+ 7 - 8
src/views/equipment/components/appoint-create.vue

@@ -52,7 +52,7 @@
                     <el-row :gutter="20" class="w100">
                       <el-col :span="12" v-if="activateService">
                         <el-select
-                          :disabled="form.id"
+                          :disabled="form.id ? true : false"
                           v-model="form.projectType"
                           class="w100"
                           placeholder="请选择"
@@ -68,7 +68,7 @@
                         <el-select
                           style="width: 100%"
                           v-if="form.projectType === 'project'"
-                          :disabled="form.id"
+                          :disabled="form.id ? true : false"
                           v-model.number="form.projectId"
                           class="w100"
                           placeholder="请选择"
@@ -83,7 +83,7 @@
                           />
                         </el-select>
                         <el-select
-                          :disabled="form.id"
+                          :disabled="form.id ? true : false"
                           v-if="form.projectType === 'service'"
                           v-model.number="form.serviceId"
                           class="w100"
@@ -428,7 +428,7 @@
           this.form.projectName = this.projectOptions.find(
             (item) => item.projectId === id
           ).projectName;
-          getFundsData();
+          this.getFundsData();
         } else {
           this.form.expenseCardId = null;
           this.fundsList = [];
@@ -627,17 +627,16 @@
               )
                 .then(() => {
                   this.$emit("refresh");
-                  this.closeDialog();
+                  this.onCancel();
                   window.open(this.form.appointJumpLink, "_blank");
                 })
                 .catch(() => {
                   this.$emit("refresh");
-
-                  this.closeDialog();
+                  this.onCancel();
                 });
             } else {
               this.$emit("refresh");
-              this.closeDialog();
+              this.onCancel();
             }
           }
         });

+ 98 - 92
src/views/equipment/components/eqpt-details.vue

@@ -56,13 +56,19 @@
           <el-col :span="8">
             <div class="item">
               <h4 class="title">出厂日期</h4>
-              <div class="text-item">{{ instrDetails.productDate }}</div>
+              <div class="text-item">
+                {{ parseTime(instrDetails.productDate, "{y}-{m}-{d} {h}:{i}") }}
+              </div>
             </div>
           </el-col>
           <el-col :span="8">
             <div class="item">
               <h4 class="title">购置日期</h4>
-              <div class="text-item">{{ instrDetails.purchaseDate }}</div>
+              <div class="text-item">
+                {{
+                  parseTime(instrDetails.purchaseDate, "{y}-{m}-{d} {h}:{i}")
+                }}
+              </div>
             </div>
           </el-col>
         </el-row>
@@ -139,109 +145,109 @@
 </template>
 
 <script>
-export default {
-  name: "equipmentDetails",
-  props: {
-    instrDetails: {
-      type: Object,
-      required: true,
+  export default {
+    name: "equipmentDetails",
+    props: {
+      instrDetails: {
+        type: Object,
+        required: true,
+      },
     },
-  },
-  data() {
-    return {
-      menuActive: "1",
-      activeName: "first",
-    };
-  },
-  created() {},
+    data() {
+      return {
+        menuActive: "1",
+        activeName: "first",
+      };
+    },
+    created() {},
 
-  mounted() {},
+    mounted() {},
 
-  methods: {},
-};
+    methods: {},
+  };
 </script>
 
 <style lang="scss" scoped>
-.details-wrap {
-  .msg-item {
-    padding: 3px 30px;
-    background: #fafbfc;
-    border: 1px solid #e8ecf2;
-    border-radius: 2px;
-    font-size: 14px;
-    color: #666;
-    line-height: 24px;
-    .item-group:first-child {
-      border-top: 0;
-    }
-    .item-group {
-      border-top: 1px dashed #e1e4ee;
-      padding: 9px 0 10px;
-      .item {
-        padding: 5px 0;
-        .title {
-          width: 78px;
-          float: left;
-          color: #666;
-        }
-        .text-item {
-          padding-left: 78px;
-        }
-      }
-    }
-  }
-  .msg-tab {
-    margin: 24px 0 0;
-    min-height: 554px;
-    height: 554px;
-    background: #fff;
-    border: 1px solid #e8ecf2;
-    display: flex;
-    .left-menu {
-      width: 180px;
-      height: 100%;
-      padding: 10px 0;
+  .details-wrap {
+    .msg-item {
+      padding: 3px 30px;
       background: #fafbfc;
-      .menu {
-        height: 60px;
-        line-height: 60px;
-        text-align: left;
-        padding-left: 18px;
-        cursor: pointer;
-        &.active {
-          background: #deecff;
+      border: 1px solid #e8ecf2;
+      border-radius: 2px;
+      font-size: 14px;
+      color: #666;
+      line-height: 24px;
+      .item-group:first-child {
+        border-top: 0;
+      }
+      .item-group {
+        border-top: 1px dashed #e1e4ee;
+        padding: 9px 0 10px;
+        .item {
+          padding: 5px 0;
+          .title {
+            width: 78px;
+            float: left;
+            color: #666;
+          }
+          .text-item {
+            padding-left: 78px;
+          }
         }
       }
     }
-    .right-content {
-      flex: 1;
-      width: 0;
-      height: 100%;
-      padding: 10px 10px 10px 20px;
-      .mod-title {
-        margin-top: 15px;
-        padding-left: 17px;
-        font-size: 18px;
-        line-height: 24px;
-        padding-bottom: 16px;
-        position: relative;
-        &::before {
-          display: block;
-          content: "";
-          position: absolute;
-          left: 0;
-          top: 0;
-          width: 5px;
-          height: 24px;
-          background: #1677ff;
-          border-radius: 4px;
+    .msg-tab {
+      margin: 24px 0 0;
+      min-height: 554px;
+      height: 554px;
+      background: #fff;
+      border: 1px solid #e8ecf2;
+      display: flex;
+      .left-menu {
+        width: 180px;
+        height: 100%;
+        padding: 10px 0;
+        background: #fafbfc;
+        .menu {
+          height: 60px;
+          line-height: 60px;
+          text-align: left;
+          padding-left: 18px;
+          cursor: pointer;
+          &.active {
+            background: #deecff;
+          }
         }
       }
-      .text-item {
-        font-size: 16px;
-        line-height: 32px;
+      .right-content {
+        flex: 1;
+        width: 0;
+        height: 100%;
+        padding: 10px 10px 10px 20px;
+        .mod-title {
+          margin-top: 15px;
+          padding-left: 17px;
+          font-size: 18px;
+          line-height: 24px;
+          padding-bottom: 16px;
+          position: relative;
+          &::before {
+            display: block;
+            content: "";
+            position: absolute;
+            left: 0;
+            top: 0;
+            width: 5px;
+            height: 24px;
+            background: #1677ff;
+            border-radius: 4px;
+          }
+        }
+        .text-item {
+          font-size: 16px;
+          line-height: 32px;
+        }
       }
     }
   }
-}
 </style>

+ 53 - 49
src/views/equipment/components/instr-file.vue

@@ -11,7 +11,11 @@
       </el-table-column>
       <el-table-column prop="docType" label="附件类型"></el-table-column>
       <el-table-column prop="createdName" label="操作人"></el-table-column>
-      <el-table-column prop="createdTime" label="更新时间"></el-table-column>
+      <el-table-column prop="createdTime" label="更新时间">
+        <template #default="{ row }">
+          {{ parseTime(row.createdTime, "{y}-{m}-{d}") }}
+        </template>
+      </el-table-column>
     </el-table>
     <div class="pagination">
       <el-pagination
@@ -29,59 +33,59 @@
 </template>
 
 <script>
-import to from "await-to-js";
-import { getFileTable } from "@/api/instr/index";
-export default {
-  name: "equipment",
-  components: {},
-  data() {
-    return {
-      tableData: [],
-      searchForm: {
-        pageNum: 1,
-        pageSize: 10,
-        instId: 0,
-      },
-      total: 0,
-    };
-  },
-  created() {},
-
-  mounted() {
-    this.searchForm.instId = this.$route.query.id * 1;
-    this.getFileListData();
-  },
-
-  methods: {
-    async getFileListData() {
-      const [err, res] = await to(getFileTable(this.searchForm));
-      if (err) return;
-      if (res.code == 200) {
-        this.tableData = res.data.list;
-        this.total = res.data.total;
-      }
+  import to from "await-to-js";
+  import { getFileTable } from "@/api/instr/index";
+  export default {
+    name: "equipment",
+    components: {},
+    data() {
+      return {
+        tableData: [],
+        searchForm: {
+          pageNum: 1,
+          pageSize: 10,
+          instId: 0,
+        },
+        total: 0,
+      };
     },
-    handleSizeChange(val) {
-      this.searchForm.pageSize = val;
+    created() {},
+
+    mounted() {
+      this.searchForm.instId = this.$route.query.id * 1;
       this.getFileListData();
     },
-    handleCurrentChange(val) {
-      this.searchForm.pageNum = val;
-      this.getFileListData();
+
+    methods: {
+      async getFileListData() {
+        const [err, res] = await to(getFileTable(this.searchForm));
+        if (err) return;
+        if (res.code == 200) {
+          this.tableData = res.data.list;
+          this.total = res.data.total;
+        }
+      },
+      handleSizeChange(val) {
+        this.searchForm.pageSize = val;
+        this.getFileListData();
+      },
+      handleCurrentChange(val) {
+        this.searchForm.pageNum = val;
+        this.getFileListData();
+      },
     },
-  },
-};
+  };
 </script>
 
 <style lang="scss" scoped>
-.container {
-  padding: 10px 0;
-}
-.pagination {
-  width: 100%;
-  height: 50px;
-  display: flex;
-  align-items: center;
-  justify-content: flex-end;
-}
+  .container {
+    padding: 10px 0;
+  }
+  .pagination {
+    width: 100%;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
 </style>

+ 62 - 60
src/views/equipment/components/instr-notice.vue

@@ -7,15 +7,17 @@
         label="公告标题"
       ></el-table-column>
       <el-table-column prop="createdName" label="创建人"></el-table-column>
-      <el-table-column prop="noticeTime" label="公告时间"></el-table-column>
+      <el-table-column prop="noticeTime" label="公告时间">
+        <template #default="{ row }">
+          {{ parseTime(row.noticeTime, "{y}-{m}-{d}") }}
+        </template>
+      </el-table-column>
       <el-table-column width="100">
         <template #header>
           <span>操作</span>
         </template>
         <template #default="{ row }">
-          <el-button type="text" @click="openDialog(row)">
-            查看公告
-          </el-button>
+          <el-button type="text" @click="openDialog(row)">查看公告</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -43,67 +45,67 @@
 </template>
 
 <script>
-import to from "await-to-js";
-import { getNoticeTable } from "@/api/instr/index";
-export default {
-  name: "equipment",
-  components: {},
-  data() {
-    return {
-      tableData: [],
-      searchForm: {
-        pageNum: 1,
-        pageSize: 10,
-        instId: 0,
-      },
-      total: 0,
-      noticeTitle: "",
-      noticeTitleDialog: false,
-      noticeContent: "",
-    };
-  },
-  created() {},
-
-  mounted() {
-    this.searchForm.instId = this.$route.query.id * 1;
-    this.getNoticeListData();
-  },
-
-  methods: {
-    openDialog(row) {
-      this.noticeTitle = row.noticeTitle;
-      this.noticeTitleDialog = true;
-      this.noticeContent = row.noticeContent;
-    },
-    async getNoticeListData() {
-      const [err, res] = await to(getNoticeTable(this.searchForm));
-      if (err) return;
-      if (res.code == 200) {
-        this.tableData = res.data.list;
-        this.total = res.data.total;
-      }
+  import to from "await-to-js";
+  import { getNoticeTable } from "@/api/instr/index";
+  export default {
+    name: "equipment",
+    components: {},
+    data() {
+      return {
+        tableData: [],
+        searchForm: {
+          pageNum: 1,
+          pageSize: 10,
+          instId: 0,
+        },
+        total: 0,
+        noticeTitle: "",
+        noticeTitleDialog: false,
+        noticeContent: "",
+      };
     },
-    handleSizeChange(val) {
-      this.searchForm.pageSize = val;
+    created() {},
+
+    mounted() {
+      this.searchForm.instId = this.$route.query.id * 1;
       this.getNoticeListData();
     },
-    handleCurrentChange(val) {
-      this.searchForm.pageNum = val;
-      this.getNoticeListData();
+
+    methods: {
+      openDialog(row) {
+        this.noticeTitle = row.noticeTitle;
+        this.noticeTitleDialog = true;
+        this.noticeContent = row.noticeContent;
+      },
+      async getNoticeListData() {
+        const [err, res] = await to(getNoticeTable(this.searchForm));
+        if (err) return;
+        if (res.code == 200) {
+          this.tableData = res.data.list;
+          this.total = res.data.total;
+        }
+      },
+      handleSizeChange(val) {
+        this.searchForm.pageSize = val;
+        this.getNoticeListData();
+      },
+      handleCurrentChange(val) {
+        this.searchForm.pageNum = val;
+        this.getNoticeListData();
+      },
     },
-  },
-};
+  };
 </script>
 
 <style lang="scss" scoped>
-.container {
-  padding: 10px 0;
-}
-.pagination {
-  width: 100%;
-  height: 50px;
-  display: flex;
-  align-items: center;
-  justify-content: flex-end;
-}
+  .container {
+    padding: 10px 0;
+  }
+  .pagination {
+    width: 100%;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
 </style>

+ 5 - 0
src/views/equipment/details.vue

@@ -177,6 +177,7 @@
 
 <script>
   import to from "await-to-js";
+  import { getToken } from "@/utils/auth";
   import { getInstrDetails, getChargeCfg } from "@/api/instr/index";
   import EqptDetails from "./components/eqpt-details.vue";
   import FileTable from "./components/instr-file.vue";
@@ -209,6 +210,10 @@
 
     methods: {
       handleAppoint() {
+        const token = getToken();
+        if (!token) {
+          return this.$router.push("/login");
+        }
         this.$refs.appointRef.openDialog(this.instrDetails);
       },
       async getInstrDetails() {

+ 7 - 1
src/views/equipment/index.vue

@@ -183,7 +183,7 @@
                     v-if="v.instStatus == '10' && v.isAppointment == '10'"
                     @click="handleAppoint(v)"
                   >
-                    仪器预约
+                    使用预约
                   </el-button>
                 </div>
                 <div>
@@ -220,6 +220,7 @@
 
 <script>
   import to from "await-to-js";
+  import { getToken } from "@/utils/auth";
   import { Loading } from "element-ui";
   import { getInstrList, getInstNameEnCount } from "@/api/instr/index";
   import appoint from "./components/appoint.vue";
@@ -257,6 +258,10 @@
 
     methods: {
       handleAppoint(row) {
+        const token = getToken();
+        if (!token) {
+          return this.$router.push("/login");
+        }
         this.$refs.appointRef.openDialog(row);
       },
       // 获取型号数量
@@ -515,6 +520,7 @@
       padding: 24px 30px;
       margin: 0 30px;
       display: flex;
+      border-bottom: 1px solid rgba(112, 112, 112, 0.06);
       .img-item {
         width: 180px;
         height: 180px;

Неке датотеке нису приказане због велике количине промена