倚楼听风雨 hace 3 años
padre
commit
bc137dbe2d

+ 50 - 50
package.json

@@ -1,52 +1,52 @@
 {
-    "name": "gin-vue-admin",
-    "version": "2.5.3",
-    "private": true,
-    "scripts": {
-        "serve": "node openDocument.js && vite --host --mode development",
-        "build": "vite build --mode production",
-        "limit-build": "npm install increase-memory-limit-fixbug cross-env -g && npm run fix-memory-limit && node ./limit && npm run build",
-        "preview": "vite preview",
-        "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit"
-    },
-    "dependencies": {
-        "@element-plus/icons-vue": "^0.2.7",
-        "axios": "^0.19.2",
-        "core-js": "^3.6.5",
-        "echarts": "5.3.2",
-        "element-plus": "2.2.5",
-        "highlight.js": "^10.6.0",
-        "marked": "^2.0.0",
-        "mitt": "^3.0.0",
-        "path": "^0.12.7",
-        "pinia": "^2.0.9",
-        "qs": "^6.8.0",
-        "quill": "^1.3.7",
-        "screenfull": "^5.0.2",
-        "script-ext-html-webpack-plugin": "^2.1.4",
-        "spark-md5": "^3.0.1",
-        "vue": "^3.2.25",
-        "vue-router": "^4.0.0-0"
-    },
-    "devDependencies": {
-        "@vitejs/plugin-legacy": "^1.4.4",
-        "@vitejs/plugin-vue": "^2.3.3",
-        "@vue/cli-plugin-babel": "~4.5.0",
-        "@vue/cli-plugin-eslint": "~4.5.0",
-        "@vue/cli-plugin-router": "~4.5.0",
-        "@vue/cli-plugin-vuex": "~4.5.0",
-        "@vue/cli-service": "~4.5.0",
-        "@vue/compiler-sfc": "^3.1.5",
-        "babel-eslint": "^10.1.0",
-        "babel-plugin-import": "^1.13.3",
-        "chalk": "^4.1.2",
-        "dotenv": "^10.0.0",
-        "eslint": "^6.7.2",
-        "eslint-plugin-vue": "^7.0.0",
-        "sass": "^1.26.5",
-        "sass-loader": "^8.0.2",
-        "vite": "^2.8.0",
-        "vite-plugin-banner": "^0.1.3",
-        "vite-plugin-importer": "^0.2.5"
-    }
+  "name": "gin-vue-admin",
+  "version": "2.5.3",
+  "private": true,
+  "scripts": {
+    "dev": "node openDocument.js && vite --host --mode development",
+    "build": "vite build --mode production",
+    "limit-build": "npm install increase-memory-limit-fixbug cross-env -g && npm run fix-memory-limit && node ./limit && npm run build",
+    "preview": "vite preview",
+    "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^0.2.7",
+    "axios": "^0.19.2",
+    "core-js": "^3.6.5",
+    "echarts": "5.3.2",
+    "element-plus": "2.2.5",
+    "highlight.js": "^10.6.0",
+    "marked": "^2.0.0",
+    "mitt": "^3.0.0",
+    "path": "^0.12.7",
+    "pinia": "^2.0.9",
+    "qs": "^6.8.0",
+    "quill": "^1.3.7",
+    "screenfull": "^5.0.2",
+    "script-ext-html-webpack-plugin": "^2.1.4",
+    "spark-md5": "^3.0.1",
+    "vue": "^3.2.25",
+    "vue-router": "^4.0.0-0"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-legacy": "^1.4.4",
+    "@vitejs/plugin-vue": "^2.3.3",
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/compiler-sfc": "^3.1.5",
+    "babel-eslint": "^10.1.0",
+    "babel-plugin-import": "^1.13.3",
+    "chalk": "^4.1.2",
+    "dotenv": "^10.0.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^7.0.0",
+    "sass": "^1.26.5",
+    "sass-loader": "^8.0.2",
+    "vite": "^2.8.0",
+    "vite-plugin-banner": "^0.1.3",
+    "vite-plugin-importer": "^0.2.5"
+  }
 }

+ 171 - 0
src/api/rentComputer.js

@@ -0,0 +1,171 @@
+/*
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2023-01-09 16:01:45
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-01-16 17:21:43
+ * @FilePath: \log-server-web\src\api\rentComputer.js
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import service from "@/utils/request";
+
+export const listRentComputerShopList = (data) => {
+  return service({
+    url: "/rentComputerShop/getRentComputerShopList",
+    method: "post",
+    data,
+  });
+};
+
+export const getRentComputerShopNum = (data) => {
+  return service({
+    url: "/rentComputerShop/getRentComputerShopNum",
+    method: "post",
+    data,
+  });
+};
+export const getRentComputerShopById = (data) => {
+  return service({
+    url: "/rentComputerShop/getRentComputerShopById",
+    method: "post",
+    data,
+  });
+};
+export const addRentComputerShop = (data) => {
+  return service({
+    url: "/rentComputerShop/addRentComputerShop",
+    method: "post",
+    data,
+  });
+};
+export const editRentComputerShop = (data) => {
+  return service({
+    url: "/rentComputerShop/editRentComputerShop",
+    method: "put",
+    data,
+  });
+};
+export const deleteRentComputerShopById = (data) => {
+  return service({
+    url: "/rentComputerShop/deleteRentComputerShopById",
+    method: "delete",
+    data,
+  });
+};
+export const deleteRentComputerShopByIds = (data) => {
+  return service({
+    url: "/rentComputerShop/deleteRentComputerShopByIds",
+    method: "delete",
+    data,
+  });
+};
+
+//RentSetMeal============================================================================
+export const listRentSetMealList = (data) => {
+  return service({
+    url: "/rentSetMeal/getRentSetMealList",
+    method: "post",
+    data,
+  });
+};
+export const getRentSetMealNum = (data) => {
+  return service({
+    url: "/rentSetMeal/getRentSetMealNum",
+    method: "post",
+    data,
+  });
+};
+export const getRentSetMealById = (data) => {
+  return service({
+    url: "/rentSetMeal/getRentSetMealById",
+    method: "post",
+    data,
+  });
+};
+export const addRentSetMeal = (data) => {
+  return service({
+    url: "/rentSetMeal/addRentSetMeal",
+    method: "post",
+    data,
+  });
+};
+export const editRentSetMeal = (data) => {
+  return service({
+    url: "/rentSetMeal/editRentSetMeal",
+    method: "put",
+    data,
+  });
+};
+export const deleteRentSetMealById = (data) => {
+  return service({
+    url: "/rentSetMeal/deleteRentSetMealById",
+    method: "delete",
+    data,
+  });
+};
+export const deleteRentSetMealByIds = (data) => {
+  return service({
+    url: "/rentSetMeal/deleteRentSetMealByIds",
+    method: "delete",
+    data,
+  });
+};
+//RentSetMeal============================================================================
+//RentComputer============================================================================
+export const getRentComputerList = (data) => {
+  return service({
+    url: "/rentComputer/getRentComputerList",
+    method: "post",
+    data,
+  });
+};
+export const getRentComputerNum = (data) => {
+  return service({
+    url: "/rentComputer/getRentComputerNum",
+    method: "post",
+    data,
+  });
+};
+export const addRentComputer = (data) => {
+  return service({
+    url: "/rentComputer/addRentComputer",
+    method: "post",
+    data,
+  });
+};
+export const getRentComputerById = (data) => {
+  return service({
+    url: "/rentComputer/getRentComputerById",
+    method: "post",
+    data,
+  });
+};
+export const editRentComputer = (data) => {
+  return service({
+    url: "/rentComputer/editRentComputer",
+    method: "put",
+    data,
+  });
+};
+export const deleteRentComputerById = (data) => {
+  return service({
+    url: "/rentComputer/deleteRentComputerById",
+    method: "delete",
+    data,
+  });
+};
+export const deleteRentComputerByIds = (data) => {
+  return service({
+    url: "/rentComputer/deleteRentComputerByIds",
+    method: "delete",
+    data,
+  });
+};
+export const uploadExcel = (data) => {
+  return service({
+    url: "/rentComputer/importExcel",
+    method: "post",
+    data,
+  });
+};
+
+//RentComputer============================================================================

+ 25 - 17
src/utils/format.js

@@ -1,28 +1,36 @@
-import { formatTimeToStr } from '@/utils/date'
-import { getDict } from '@/utils/dictionary'
+/*
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2023-01-09 14:37:34
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-01-16 19:45:18
+ * @FilePath: \log-server-web\src\utils\format.js
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { formatTimeToStr } from "@/utils/date";
+import { getDict } from "@/utils/dictionary";
 
 export const formatBoolean = (bool) => {
   if (bool !== null) {
-    return bool ? '是' : '否'
+    return bool ? "是" : "否";
   } else {
-    return ''
+    return "";
   }
-}
+};
 export const formatDate = (time) => {
-  if (time !== null && time !== '') {
-    var date = new Date(time)
-    return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss')
+  if (time !== null && time !== "") {
+    var date = new Date(time);
+    return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
   } else {
-    return ''
+    return "";
   }
-}
+};
 
 export const filterDict = (value, options) => {
-  const rowLabel = options && options.filter(item => item.value === value)
-  return rowLabel && rowLabel[0] && rowLabel[0].label
-}
+  const rowLabel = options && options.filter((item) => item.value === value);
+  return rowLabel && rowLabel[0] && rowLabel[0].label;
+};
 
-export const getDictFunc = async(type) => {
-  const dicts = await getDict(type)
-  return dicts
-}
+export const getDictFunc = async (type) => {
+  const dicts = await getDict(type);
+  return dicts;
+};

+ 847 - 0
src/view/rentComputer/rent_computer.vue

@@ -0,0 +1,847 @@
+<!--
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2022-11-16 17:16:17
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-02-01 09:58:23
+ * @FilePath: \log-server-web\src\view\logComputer\list_computer_distinct.vue
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+-->
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-form ref="searchForm" :inline="true" :model="searchInfo">
+          <el-form-item label="电脑编号">
+            <el-input
+              v-model="searchInfo.pc_num"
+              placeholder="编号"
+              size="small"
+            />
+          </el-form-item>
+          <el-form-item label="供应商">
+            <el-select v-model="searchInfo.shop_id" size="small">
+              <el-option
+                v-for="item in shopOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="套餐">
+            <el-select v-model="searchInfo.set_meal_id" size="small"
+              ><el-option
+                v-for="item in setMealOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+            /></el-select>
+          </el-form-item>
+          <el-form-item label="是否到期">
+            <el-select v-model="searchInfo.is_expire" size="small">
+              <el-option label="否" value="0" />
+              <el-option label="是" value="1" />
+              <el-option label="明日到期" value="2" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="是否下架">
+            <el-select v-model="searchInfo.is_off_shelf" size="small">
+              <el-option label="否" value="0" />
+              <el-option label="是" value="1" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              size="small"
+              type="primary"
+              icon="search"
+              @click="onSubmit"
+              >查询</el-button
+            >
+            <el-button size="small" icon="refresh" @click="onReset"
+              >重置</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="gva-btn-list">
+        <el-button size="small" type="primary" icon="plus" @click="addMenu('0')"
+          >新增</el-button
+        >
+        <el-button
+          class="excel-btn"
+          size="small"
+          type="success"
+          icon="download"
+          @click="downloadExcelTemplate()"
+          >下载模板</el-button
+        >
+        <el-upload
+          style="margin-left: 1%"
+          class="excel-btn"
+          :action="`${path}/rentComputer/importExcel`"
+          :headers="{ 'x-token': userStore.token }"
+          :on-success="loadExcel"
+          :show-file-list="false"
+        >
+          <el-button size="small" type="primary" icon="upload">导入</el-button>
+        </el-upload>
+      </div>
+    </div>
+    <div class="row center">
+      <el-tag size="large">电脑数量 : {{ computerNum }} </el-tag>
+    </div>
+    <div class="gva-table-box">
+      <!-- <el-scrollbar height="550px"> -->
+      <el-table
+        height="500px"
+        :data="tableData"
+        @sort-change="sortChange"
+        @selection-change="handleSelectionChange"
+        border
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column
+          align="left"
+          label="供应商"
+          min-width="100"
+          prop="shop_name"
+        />
+        <!-- <el-table-column
+            align="left"
+            label="套餐"
+            min-width="100"
+            prop="set_meal_name"
+          /> -->
+        <el-table-column
+          align="center"
+          label="套餐"
+          min-width="150"
+          prop="set_meal_name"
+        >
+          <template #default="scope">
+            <span v-if="scope.row.price_type == 0">{{
+              scope.row.set_meal_name + "-天卡(" + scope.row.rent_price + "元)"
+            }}</span>
+            <span v-else-if="scope.row.price_type == 1">{{
+              scope.row.set_meal_name + "-周卡(" + scope.row.rent_price + "元)"
+            }}</span>
+            <span v-else>{{
+              scope.row.set_meal_name + "-月卡(" + scope.row.rent_price + "元)"
+            }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="left"
+          label="编号"
+          min-width="80"
+          prop="pc_num"
+        />
+        <el-table-column
+          align="left"
+          label="名称"
+          min-width="80"
+          prop="pc_name"
+        />
+        <el-table-column
+          align="left"
+          label="起租时间"
+          min-width="150"
+          prop="rent_start"
+        />
+        <el-table-column
+          align="left"
+          label="到期时间"
+          min-width="150"
+          prop="rent_end"
+        />
+        <el-table-column
+          align="left"
+          label="租期"
+          min-width="50"
+          prop="rent_duration"
+        />
+        <el-table-column
+          align="center"
+          label="是否到期"
+          min-width="100"
+          prop="is_expire"
+        >
+          <template #default="scope">
+            <el-button
+              v-if="scope.row.is_expire == 2"
+              size="small"
+              type="warning"
+              plain
+              >即将到期</el-button
+            >
+            <el-button
+              v-if="scope.row.is_expire == 1"
+              size="small"
+              type="info"
+              plain
+              >到期未续</el-button
+            >
+            <el-button
+              v-if="scope.row.is_expire == 0"
+              size="small"
+              type="success"
+              plain
+              >在租期中</el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          label="是否下架"
+          min-width="150"
+          prop="is_off_shelf"
+        >
+          <template #default="scope">
+            <el-button
+              v-if="scope.row.is_off_shelf == 1"
+              size="small"
+              type="warning"
+              plain
+              >是</el-button
+            >
+            <el-button v-else size="small" type="success" plain>否</el-button>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="left"
+          label="TD号"
+          min-width="100"
+          prop="todesk_id"
+        />
+        <el-table-column
+          align="left"
+          label="TD密码"
+          min-width="100"
+          prop="todesk_password"
+        />
+        <el-table-column
+          align="left"
+          label="向日葵号"
+          min-width="100"
+          prop="sunflower_id"
+        />
+        <el-table-column
+          align="left"
+          label="向日葵密码"
+          min-width="100"
+          prop="sunflower_password"
+        />
+        <el-table-column
+          align="left"
+          label="备注"
+          min-width="50"
+          prop="remark"
+        />
+        <el-table-column
+          align="left"
+          label="更新时间"
+          min-width="150"
+          prop="update_time"
+        />
+        <el-table-column align="left" fixed="right" label="操作" width="300">
+          <template #default="scope">
+            <el-button
+              size="small"
+              type="primary"
+              link
+              icon="link"
+              @click="linkTd(scope.row)"
+              >TD连接</el-button
+            >
+            <el-button
+              size="small"
+              type="primary"
+              link
+              icon="edit"
+              @click="editMenu(scope.row.id)"
+              >编辑</el-button
+            >
+            <el-button
+              size="small"
+              type="primary"
+              link
+              icon="delete"
+              @click="deleteMenu(scope.row.id)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- </el-scrollbar> -->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+
+    <el-dialog v-model="dialogFormVisible" :title="dialogTitle">
+      <el-form
+        v-if="dialogFormVisible"
+        ref="menuForm"
+        :inline="true"
+        :model="form"
+        :rules="rules"
+        label-position="left"
+        label-width="85px"
+      >
+        <el-row :gutter="10">
+          <el-col :span="6">
+            <el-form-item label="电脑编号" prop="pc_num">
+              <el-input v-model="form.pc_num" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="电脑名称" prop="pc_name">
+              <el-input v-model="form.pc_name" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="供应商" prop="shop_id">
+              <el-select v-model="form.shop_id">
+                <el-option
+                  v-for="item in shopOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="套餐名" prop="set_meal_id">
+              <el-select v-model="form.set_meal_id">
+                <el-option
+                  v-for="item in setMealOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="6">
+            <el-form-item label="Todesk号" prop="todesk_id">
+              <el-input v-model="form.todesk_id" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="Todesk密码" prop="todesk_password">
+              <el-input v-model="form.todesk_password" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="向日葵号" prop="sunflower_id">
+              <el-input v-model="form.sunflower_id" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="向日葵密码" prop="sunflower_password">
+              <el-input v-model="form.sunflower_password" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="8">
+            <el-form-item label="起租时间" prop="rent_start">
+              <el-date-picker
+                v-model="form.rent_start"
+                type="datetime"
+                placeholder="起租时间"
+                :default-time="defaultTime"
+                @change="calculateRentDuration(form)"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="租赁天数" prop="rent_duration">
+              <el-input
+                v-model="form.rent_duration"
+                @change="calculateRentDuration(form)"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="到期时间" prop="rent_end">
+              <el-date-picker
+                v-model="form.rent_end"
+                type="datetime"
+                placeholder="到期时间"
+                :default-time="defaultTime"
+                readonly
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="12">
+            <el-form-item label="是否到期" prop="is_expire">
+              <el-radio-group v-model="form.is_expire">
+                <el-radio :label="0" size="large">在租期中</el-radio>
+                <el-radio :label="1" size="large">到期未续</el-radio>
+                <el-radio :label="2" size="large">明日到期</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="12">
+            <el-form-item label="是否下架" prop="is_off_shelf">
+              <el-switch v-model="form.is_off_shelf" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="20">
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="form.remark"
+                type="textarea"
+                :rows="4"
+                style="width: 500px"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button size="small" @click="closeDialog">取 消</el-button>
+          <el-button size="small" type="primary" @click="enterDialog"
+            >确 定</el-button
+          >
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "computer",
+};
+</script>
+
+<script setup>
+import {
+  getRentComputerList,
+  getRentComputerNum,
+  listRentComputerShopList,
+  listRentSetMealList,
+  getRentComputerById,
+  addRentComputer,
+  editRentComputer,
+  deleteRentComputerById,
+} from "@/api/rentComputer";
+import { useUserStore } from "@/pinia/modules/user";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { formatDate } from "@/utils/format";
+import { downloadTemplate } from "@/api/excel";
+
+const apis = ref([]);
+const form = ref({
+  id: 0,
+  pc_num: "",
+  pc_name: "",
+  shop_id: null,
+  set_meal_id: null,
+  todesk_id: "",
+  todesk_password: "",
+  sunflower_id: "",
+  sunflower_password: "",
+  rent_start: new Date(),
+  rent_duration: 0,
+  rent_end: new Date(),
+  remark: "",
+  is_expire: -1,
+  is_off_shelf: -1,
+});
+const rules = ref({
+  pc_num: [{ required: true, message: "请输入电脑编号", trigger: "blur" }],
+  pc_name: [{ required: true, message: "请输入电脑名称", trigger: "blur" }],
+  shop_id: [{ required: true, message: "请选择供应商", trigger: "blur" }],
+  set_meal_id: [{ required: true, message: "请选择套餐", trigger: "blur" }],
+  rent_start: [{ required: true, message: "请选择起租日期", trigger: "blur" }],
+  rent_duration: [
+    { required: true, message: "请输入租赁天数", trigger: "blur" },
+  ],
+  is_expire: [{ required: true, message: "请选择是否到期", trigger: "blur" }],
+  is_off_shelf: [
+    { required: true, message: "请选择是否下架", trigger: "blur" },
+  ],
+});
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(20);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+const computerNum = ref("");
+const shopOptions = ref();
+const setMealOptions = ref();
+const defaultTime = ref(new Date(2000, 1, 1, 12, 0, 0));
+const path = ref(import.meta.env.VITE_BASE_API);
+const userStore = useUserStore();
+
+const downloadExcelTemplate = () => {
+  downloadTemplate("RentComputerTemplate.xlsx");
+};
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  // console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+const onReset = () => {
+  searchInfo.value = {};
+};
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 搜索
+const onSubmit = () => {
+  page.value = 1;
+  pageSize.value = 10;
+
+  if (typeof searchInfo.value.set_meal_id != "undefined") {
+    searchInfo.value.set_meal_id = Number(searchInfo.value.set_meal_id);
+  }
+  if (typeof searchInfo.value.is_expire != "undefined") {
+    searchInfo.value.is_expire = Number(searchInfo.value.is_expire);
+  }
+  if (typeof searchInfo.value.is_off_shelf != "undefined") {
+    searchInfo.value.is_off_shelf = Number(searchInfo.value.is_off_shelf);
+  }
+
+  console.log(searchInfo);
+
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await getRentComputerList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+    getComputerNum();
+    getSelectList();
+  }
+};
+
+//获取下拉框list
+const getSelectList = async () => {
+  //listRentComputerShopList
+  const rentComputerShop = await listRentComputerShopList({
+    page: 1,
+    pageSize: 999,
+  });
+  let rentComputerShopList = [];
+  const data = rentComputerShop.data.list;
+  data.forEach((e) => {
+    rentComputerShopList.push({ value: e.id, label: e.name });
+  });
+  shopOptions.value = rentComputerShopList;
+  //listRentSetMealList
+  const setMealShop = await listRentSetMealList({
+    page: 1,
+    pageSize: 999,
+  });
+  let setMealList = [];
+  const data2 = setMealShop.data.list;
+  data2.forEach((e) => {
+    var priceStr = "";
+    if (e.price_type == 0) {
+      priceStr = "天卡(" + e.rent_price + "元)";
+    } else if (e.price_type == 1) {
+      priceStr = "周卡(" + e.rent_price + "元)";
+    } else {
+      priceStr = "月卡(" + e.rent_price + "元)";
+    }
+    setMealList.push({
+      value: e.id,
+      label: e.shop_name + "-" + e.name + "-" + priceStr,
+    });
+  });
+  setMealOptions.value = setMealList;
+};
+
+// 计算租机到期时间
+const calculateRentDuration = async (scope) => {
+  scope.rent_end = new Date(
+    Date.parse(scope.rent_start) +
+      1 * 24 * 60 * 60 * 1000 * parseInt(scope.rent_duration)
+  );
+};
+
+// 查询
+const getComputerNum = async () => {
+  const table = await getRentComputerNum({ ...searchInfo.value });
+  if (table.code === 0) {
+    // console.log(table.data);
+    computerNum.value = table.data;
+  }
+};
+//拉起TD连接
+const linkTd = async (row) => {
+  let todesk_id = row.todesk_id;
+  let todesk_password = row.todesk_password;
+  todesk_id = todesk_id.replace(/\s*/g, "");
+  todesk_password = todesk_password.replace(/\s*/g, "");
+  console.log(todesk_id);
+  console.log(todesk_password);
+  if (todesk_id == "" || todesk_password == "") {
+    ElMessage({
+      type: "error",
+      message: "todesk账号密码不完整!",
+    });
+  } else {
+    window.location.href =
+      "ToDesk://connect&" + todesk_id + "&" + todesk_password;
+  }
+};
+getTableData();
+
+// 批量操作
+const handleSelectionChange = (val) => {
+  apis.value = val;
+};
+
+const dialogFormVisible = ref(false);
+// 弹窗相关
+const menuForm = ref(null);
+const checkFlag = ref(false);
+const initForm = () => {
+  checkFlag.value = false;
+  menuForm.value.resetFields();
+  form.value = {
+    id: 0,
+    coding: "",
+    describe: "",
+    parent_id: "",
+  };
+};
+const menuOption = ref([
+  {
+    id: "0",
+    title: "根编号",
+  },
+]);
+const setOptions = () => {
+  menuOption.value = [
+    {
+      id: "0",
+      title: "根目录",
+    },
+  ];
+  setMenuOptions(tableData.value, menuOption.value, false);
+};
+const setMenuOptions = (menuData, optionsData, disabled) => {
+  menuData &&
+    menuData.forEach((item) => {
+      if (item.children && item.children.length) {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+          children: [],
+        };
+        setMenuOptions(
+          item.children,
+          option.children,
+          disabled || item.id === form.value.id
+        );
+        optionsData.push(option);
+      } else {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+        };
+        optionsData.push(option);
+      }
+    });
+};
+
+const loadExcel = (res) => {
+  if (res.code === 0) {
+    ElMessage({
+      type: "success",
+      message: res.msg,
+    });
+  } else {
+    ElMessage({
+      type: "error",
+      message: res.msg,
+      showClose: true,
+    });
+  }
+  getTableData();
+};
+
+// 添加菜单方法,id为 0则为添加根菜单
+const isEdit = ref(false);
+const dialogTitle = ref("新增租机");
+const addMenu = async (id) => {
+  dialogTitle.value = "新增租机";
+  form.value.parent_id = String(id);
+  isEdit.value = false;
+  setOptions();
+  dialogFormVisible.value = true;
+  getSelectList();
+};
+// 修改菜单方法
+const editMenu = async (id) => {
+  dialogTitle.value = "编辑租机";
+  const res = await getRentComputerById({ id });
+  form.value = res.data;
+  if (form.value.is_off_shelf == 1) {
+    form.value.is_off_shelf = true;
+  } else {
+    form.value.is_off_shelf = false;
+  }
+  isEdit.value = true;
+  setOptions();
+  dialogFormVisible.value = true;
+  getSelectList();
+};
+
+const closeDialog = () => {
+  initForm();
+  dialogFormVisible.value = false;
+};
+// 删除菜单
+const deleteMenu = async (id) => {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      console.log(id);
+
+      const res = await deleteRentComputerById({ id });
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: "删除成功!",
+        });
+        getTableData();
+      }
+    })
+    .catch(() => {
+      ElMessage({
+        type: "info",
+        message: "已取消删除",
+      });
+    });
+};
+const enterDialog = async () => {
+  //   console.log(form.value);
+  menuForm.value.validate(async (valid) => {
+    if (valid) {
+      let res;
+      form.value.id = Number(form.value.id);
+      form.value.shop_id = Number(form.value.shop_id);
+      form.value.set_meal_id = Number(form.value.set_meal_id);
+      form.value.rent_duration = Number(form.value.rent_duration);
+      form.value.rent_start = formatDate(form.value.rent_start);
+      form.value.rent_end = formatDate(form.value.rent_end);
+      form.value.is_expire = Number(form.value.is_expire);
+      if (form.value.is_off_shelf == true) {
+        form.value.is_off_shelf = 1;
+      } else {
+        form.value.is_off_shelf = 0;
+      }
+      if (isEdit.value) {
+        res = await editRentComputer(form.value);
+      } else {
+        res = await addRentComputer(form.value);
+      }
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: isEdit.value ? "编辑成功" : "添加成功!",
+        });
+        getTableData();
+      } else {
+        ElMessage({
+          type: "error",
+          message: res.message,
+        });
+      }
+      initForm();
+      dialogFormVisible.value = false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>

+ 419 - 0
src/view/rentComputer/rent_computer_shop.vue

@@ -0,0 +1,419 @@
+<!--
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2022-11-16 17:16:17
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-01-12 17:17:58
+ * @FilePath: \log-server-web\src\view\logComputer\list_computer_distinct.vue
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+-->
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-button size="small" type="primary" icon="plus" @click="addMenu('0')"
+          >新增供应商</el-button
+        >
+      </div>
+    </div>
+    <div class="row center">
+      <el-tag size="large">当前供应商数量 : {{ computerNum }} </el-tag>
+    </div>
+    <div class="gva-table-box">
+      <el-scrollbar max-height="550px">
+        <el-table
+          :data="tableData"
+          @sort-change="sortChange"
+          @selection-change="handleSelectionChange"
+          border
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column
+            align="left"
+            label="供应商名"
+            min-width="150"
+            prop="name"
+            sortable="custom"
+          />
+          <el-table-column
+            align="center"
+            label="结算方式"
+            min-width="150"
+            prop="pay_method"
+          >
+            <template #default="scope">
+              <el-button
+                size="small"
+                :type="scope.row.pay_method == 0 ? 'primary' : 'success'"
+              >
+                {{ scope.row.pay_method == 0 ? "先付后用" : "先用后付" }}
+              </el-button>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="left"
+            label="描述说明"
+            min-width="150"
+            prop="description"
+          />
+          <el-table-column
+            align="left"
+            label="创建时间"
+            min-width="150"
+            prop="create_time"
+          />
+          <el-table-column
+            align="left"
+            label="更新时间"
+            min-width="150"
+            prop="update_time"
+          />
+          <el-table-column align="left" fixed="right" label="操作" width="300">
+            <template #default="scope">
+              <el-button
+                size="small"
+                type="primary"
+                link
+                icon="edit"
+                @click="editMenu(scope.row.id)"
+                >编辑</el-button
+              >
+              <el-button
+                size="small"
+                type="primary"
+                link
+                icon="delete"
+                @click="deleteMenu(scope.row.id)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-scrollbar>
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+
+    <el-dialog
+      v-model="dialogFormVisible"
+      :before-close="handleClose"
+      :title="dialogTitle"
+    >
+      <el-form
+        v-if="dialogFormVisible"
+        ref="menuForm"
+        :inline="true"
+        :model="form"
+        :rules="rules"
+        label-position="left"
+        label-width="85px"
+      >
+        <el-row :gutter="10">
+          <el-col :span="12">
+            <el-form-item label="供应商名" prop="name">
+              <el-input v-model="form.name" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="20">
+            <el-form-item label="描述说明" prop="description">
+              <el-input v-model="form.description" type="textarea" :rows="4" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="12">
+            <el-form-item label="结算方式" prop="pay_method">
+              <el-radio-group v-model="form.pay_method">
+                <el-radio :label="1" size="large">先用后付</el-radio>
+                <el-radio :label="0" size="large">先付后用</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button size="small" @click="closeDialog">取 消</el-button>
+          <el-button size="small" type="primary" @click="enterDialog"
+            >确 定</el-button
+          >
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "computer-shop",
+};
+</script>
+
+<script setup>
+import {
+  listRentComputerShopList,
+  getRentComputerShopNum,
+  getRentComputerShopById,
+  addRentComputerShop,
+  editRentComputerShop,
+  deleteRentComputerShopById,
+} from "@/api/rentComputer";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+const apis = ref([]);
+const form = ref({
+  id: 0,
+  name: "",
+  description: "",
+  pay_method: 0,
+  create_time: "",
+});
+
+const rules = ref({
+  name: [{ required: true, message: "请输入供应商名称", trigger: "blur" }],
+  description: [{ required: true, message: "请输入描述", trigger: "blur" }],
+  pay_method: [{ required: true, message: "请选择", trigger: "blur" }],
+});
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(20);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await listRentComputerShopList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+    // console.log(table);
+    getComputerShopNum();
+  }
+};
+
+const computerNum = ref("");
+// 查询
+const getComputerShopNum = async () => {
+  // console.log("getRentComputerShopNum");
+  const table = await getRentComputerShopNum({ ...searchInfo.value });
+  console.log(table);
+  if (table.code === 0) {
+    console.log(table.data);
+    computerNum.value = table.data;
+  }
+};
+getTableData();
+
+// 批量操作
+const handleSelectionChange = (val) => {
+  apis.value = val;
+};
+
+const dialogFormVisible = ref(false);
+// 弹窗相关
+const menuForm = ref(null);
+const checkFlag = ref(false);
+const initForm = () => {
+  checkFlag.value = false;
+  menuForm.value.resetFields();
+  form.value = {
+    id: 0,
+    coding: "",
+    describe: "",
+    parent_id: "",
+  };
+};
+const menuOption = ref([
+  {
+    id: "0",
+    title: "根编号",
+  },
+]);
+const setOptions = () => {
+  menuOption.value = [
+    {
+      id: "0",
+      title: "根目录",
+    },
+  ];
+  setMenuOptions(tableData.value, menuOption.value, false);
+};
+const setMenuOptions = (menuData, optionsData, disabled) => {
+  menuData &&
+    menuData.forEach((item) => {
+      if (item.children && item.children.length) {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+          children: [],
+        };
+        setMenuOptions(
+          item.children,
+          option.children,
+          disabled || item.id === form.value.id
+        );
+        optionsData.push(option);
+      } else {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+        };
+        optionsData.push(option);
+      }
+    });
+};
+// 添加菜单方法,id为 0则为添加根菜单
+const isEdit = ref(false);
+const dialogTitle = ref("新增编号");
+const addMenu = (id) => {
+  dialogTitle.value = "新增编号";
+  form.value.parent_id = String(id);
+  isEdit.value = false;
+  setOptions();
+  dialogFormVisible.value = true;
+};
+// 修改菜单方法
+const editMenu = async (id) => {
+  dialogTitle.value = "编辑编号";
+  const res = await getRentComputerShopById({ id });
+  form.value = res.data;
+  isEdit.value = true;
+  setOptions();
+  dialogFormVisible.value = true;
+};
+
+const closeDialog = () => {
+  initForm();
+  dialogFormVisible.value = false;
+};
+// 删除菜单
+const deleteMenu = async (id) => {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      console.log(id);
+
+      const res = await deleteRentComputerShopById({ id });
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: "删除成功!",
+        });
+        getTableData();
+      }
+    })
+    .catch(() => {
+      ElMessage({
+        type: "info",
+        message: "已取消删除",
+      });
+    });
+};
+const enterDialog = async () => {
+  //   console.log(form.value);
+  menuForm.value.validate(async (valid) => {
+    if (valid) {
+      let res;
+      if (isEdit.value) {
+        form.value.id = Number(form.value.id);
+        // form.value.parent_id = Number(form.value.parent_id);
+        res = await editRentComputerShop(form.value);
+      } else {
+        // console.log(form.value.coding);
+        form.value.id = Number(form.value.id);
+        // form.value.parent_id = Number(form.value.parent_id);
+        res = await addRentComputerShop(form.value);
+      }
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: isEdit.value ? "编辑成功" : "添加成功!",
+        });
+        getTableData();
+      }
+      initForm();
+      dialogFormVisible.value = false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>

+ 508 - 0
src/view/rentComputer/rent_set_meal.vue

@@ -0,0 +1,508 @@
+<!--
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2022-11-16 17:16:17
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-01-12 10:03:44
+ * @FilePath: \log-server-web\src\view\logComputer\list_computer_distinct.vue
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+-->
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-button size="small" type="primary" icon="plus" @click="addMenu('0')"
+          >新增套餐</el-button
+        >
+      </div>
+    </div>
+    <div class="row center">
+      <el-tag size="large">当前套餐数量 : {{ computerNum }} </el-tag>
+    </div>
+    <div class="gva-table-box">
+      <el-scrollbar max-height="550px">
+        <el-table
+          :data="tableData"
+          @sort-change="sortChange"
+          @selection-change="handleSelectionChange"
+          border
+        >
+          <el-table-column type="selection" width="55" />
+          <el-table-column
+            align="left"
+            label="套餐名称"
+            min-width="150"
+            prop="name"
+            sortable="custom"
+          />
+          <el-table-column
+            align="left"
+            label="供应商"
+            min-width="150"
+            prop="shop_name"
+            sortable="custom"
+          />
+          <el-table-column
+            align="left"
+            label="套餐价格"
+            min-width="150"
+            prop="rent_price"
+            sortable="custom"
+          />
+
+          <el-table-column
+            align="center"
+            label="套餐类型"
+            min-width="150"
+            prop="price_type"
+          >
+            <template #default="scope">
+              <el-button
+                v-if="scope.row.price_type == 0"
+                size="small"
+                type="primary"
+                plain
+                >天卡</el-button
+              >
+              <el-button
+                v-else-if="scope.row.price_type == 1"
+                size="small"
+                type="warning"
+                plain
+                >周卡</el-button
+              >
+              <el-button v-else size="small" type="success" plain
+                >月卡</el-button
+              >
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="left"
+            label="折算天租金"
+            min-width="150"
+            prop="rent_price_day"
+          />
+          <el-table-column
+            align="left"
+            label="备注"
+            min-width="150"
+            prop="remark"
+          />
+          <el-table-column
+            align="left"
+            label="创建时间"
+            min-width="180"
+            prop="create_time"
+          />
+          <el-table-column
+            align="left"
+            label="更新时间"
+            min-width="180"
+            prop="update_time"
+          />
+          <el-table-column align="left" fixed="right" label="操作" width="180">
+            <template #default="scope">
+              <el-button
+                size="small"
+                type="primary"
+                link
+                icon="edit"
+                @click="editMenu(scope.row.id)"
+                >编辑</el-button
+              >
+              <el-button
+                size="small"
+                type="primary"
+                link
+                icon="delete"
+                @click="deleteMenu(scope.row.id)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-scrollbar>
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+
+    <el-dialog
+      v-model="dialogFormVisible"
+      :before-close="handleClose"
+      :title="dialogTitle"
+    >
+      <el-form
+        v-if="dialogFormVisible"
+        ref="menuForm"
+        :inline="true"
+        :model="form"
+        :rules="rules"
+        label-position="left"
+        label-width="85px"
+      >
+        <el-row :gutter="10">
+          <el-col :span="8">
+            <el-form-item label="套餐名称" prop="name">
+              <el-input v-model="form.name" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="供应商" prop="shop_id">
+              <el-select v-model="form.shop_id">
+                <el-option
+                  v-for="item in shopIdOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="8">
+            <el-form-item label="套餐价格" prop="rent_price">
+              <el-input v-model="form.rent_price" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="套餐类型" prop="price_type">
+              <el-select v-model="form.price_type" placeholder="请选择">
+                <el-option
+                  v-for="item in priceTypeOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="15">
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="form.remark"
+                :rows="4"
+                type="textarea"
+                show-word-limit
+                clearable
+                :autosize="{ minRows: 2, maxRows: 6 }"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button size="small" @click="closeDialog">取 消</el-button>
+          <el-button size="small" type="primary" @click="enterDialog"
+            >确 定</el-button
+          >
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "computer-shop",
+};
+</script>
+
+<script setup>
+import {
+  listRentSetMealList,
+  listRentComputerShopList,
+  getRentSetMealNum,
+  getRentSetMealById,
+  addRentSetMeal,
+  editRentSetMeal,
+  deleteRentSetMealById,
+} from "@/api/rentComputer";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+const apis = ref([]);
+const form = ref({
+  id: 0,
+  name: "",
+  rent_price: "",
+  price_type: null,
+  shop_id: null,
+  create_time: "",
+});
+
+const rules = ref({
+  name: [{ required: true, message: "请输入", trigger: "blur" }],
+  rent_price: [{ required: true, message: "请输入", trigger: "blur" }],
+  price_type: [{ required: true, message: "请选择", trigger: "blur" }],
+  shop_id: [{ required: true, message: "请选择", trigger: "blur" }],
+});
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(20);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await listRentSetMealList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+    getComputerNum();
+  }
+};
+
+const computerNum = ref("");
+const priceTypeOptions = ref([
+  { value: 0, label: "天卡" },
+  { value: 1, label: "周卡" },
+  { value: 2, label: "月卡" },
+]);
+const shopIdOptions = ref();
+
+// 查询
+const getComputerNum = async () => {
+  const table = await getRentSetMealNum({ ...searchInfo.value });
+  if (table.code === 0) {
+    // console.log(table.data);
+    computerNum.value = table.data;
+  }
+};
+getTableData();
+
+// 批量操作
+const handleSelectionChange = (val) => {
+  apis.value = val;
+};
+
+const dialogFormVisible = ref(false);
+// 弹窗相关
+const menuForm = ref(null);
+const checkFlag = ref(false);
+const initForm = () => {
+  checkFlag.value = false;
+  menuForm.value.resetFields();
+  form.value = {
+    id: 0,
+    coding: "",
+    describe: "",
+    parent_id: "",
+  };
+};
+const menuOption = ref([
+  {
+    id: "0",
+    title: "根编号",
+  },
+]);
+const setOptions = () => {
+  menuOption.value = [
+    {
+      id: "0",
+      title: "根目录",
+    },
+  ];
+  setMenuOptions(tableData.value, menuOption.value, false);
+};
+const setMenuOptions = (menuData, optionsData, disabled) => {
+  menuData &&
+    menuData.forEach((item) => {
+      if (item.children && item.children.length) {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+          children: [],
+        };
+        setMenuOptions(
+          item.children,
+          option.children,
+          disabled || item.id === form.value.id
+        );
+        optionsData.push(option);
+      } else {
+        const option = {
+          ID: String(item.id),
+          disabled: disabled || item.id === form.value.id,
+        };
+        optionsData.push(option);
+      }
+    });
+};
+// 添加菜单方法,id为 0则为添加根菜单
+const isEdit = ref(false);
+const dialogTitle = ref("新增编号");
+const addMenu = async (id) => {
+  dialogTitle.value = "新增编号";
+  form.value.parent_id = String(id);
+  isEdit.value = false;
+  setOptions();
+  dialogFormVisible.value = true;
+  const rentComputerShop = await listRentComputerShopList({
+    page: 1,
+    pageSize: 999,
+  });
+  let rentComputerShopList = [];
+  const data = rentComputerShop.data.list;
+  data.forEach((e) => {
+    rentComputerShopList.push({ value: e.id, label: e.name });
+  });
+  shopIdOptions.value = rentComputerShopList;
+};
+// 修改菜单方法
+const editMenu = async (id) => {
+  dialogTitle.value = "编辑编号";
+  const res = await getRentSetMealById({ id });
+  form.value = res.data;
+  isEdit.value = true;
+  setOptions();
+  dialogFormVisible.value = true;
+  const rentComputerShop = await listRentComputerShopList({
+    page: 1,
+    pageSize: 999,
+  });
+  let rentComputerShopList = [];
+  const data = rentComputerShop.data.list;
+  data.forEach((e) => {
+    rentComputerShopList.push({ value: e.id, label: e.name });
+  });
+  shopIdOptions.value = rentComputerShopList;
+};
+
+const closeDialog = () => {
+  initForm();
+  dialogFormVisible.value = false;
+};
+// 删除菜单
+const deleteMenu = async (id) => {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  })
+    .then(async () => {
+      console.log(id);
+
+      const res = await deleteRentSetMealById({ id });
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: "删除成功!",
+        });
+        getTableData();
+      }
+    })
+    .catch(() => {
+      ElMessage({
+        type: "info",
+        message: "已取消删除",
+      });
+    });
+};
+const enterDialog = async () => {
+  //   console.log(form.value);
+  menuForm.value.validate(async (valid) => {
+    if (valid) {
+      let res;
+      if (isEdit.value) {
+        form.value.id = Number(form.value.id);
+        form.value.shop_id = Number(form.value.shop_id);
+        form.value.rent_price = parseFloat(form.value.rent_price);
+        res = await editRentSetMeal(form.value);
+      } else {
+        // console.log(form.value.coding);
+        form.value.id = Number(form.value.id);
+        form.value.shop_id = Number(form.value.shop_id);
+        form.value.rent_price = parseFloat(form.value.rent_price);
+        res = await addRentSetMeal(form.value);
+      }
+      if (res.code === 0) {
+        ElMessage({
+          type: "success",
+          message: isEdit.value ? "编辑成功" : "添加成功!",
+        });
+        getTableData();
+      }
+      initForm();
+      dialogFormVisible.value = false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>