浏览代码

机构注册

szw 1 年之前
父节点
当前提交
285849860e

+ 7 - 0
src/api/system/area.js

@@ -8,6 +8,13 @@ export function getAreaTree() {
   })
 }
 
+export function getTreeForRegister() {
+  return request({
+    url: '/system/area/treeForRegister',
+    method: 'get'
+  })
+}
+
 // 获得 IP 对应的地区名
 export function getAreaByIp(ip) {
   return request({

+ 61 - 0
src/api/system/industry.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 创建行业配置
+export function createIndustry(data) {
+  return request({
+    url: '/system/industry/create',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新行业配置
+export function updateIndustry(data) {
+  return request({
+    url: '/system/industry/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除行业配置
+export function deleteIndustry(id) {
+  return request({
+    url: '/system/industry/delete?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 获得行业配置
+export function getIndustry(id) {
+  return request({
+    url: '/system/industry/get?id=' + id,
+    method: 'get'
+  })
+}
+
+export function getAllIndustry(id) {
+  return request({
+    url: '/system/industry/getAllIndustry',
+    method: 'get'
+  })
+}
+
+// 获得行业配置分页
+export function getIndustryPage(query) {
+  return request({
+    url: '/system/industry/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出行业配置 Excel
+export function exportIndustryExcel(query) {
+  return request({
+    url: '/system/industry/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}

+ 15 - 0
src/api/system/tenant.js

@@ -29,6 +29,14 @@ export function createTenant(data) {
   })
 }
 
+export function tenantRegister(data) {
+  return request({
+    url: '/system/tenant/tenantRegister',
+    method: 'post',
+    data: data
+  })
+}
+
 // 更新机构
 export function updateTenant(data) {
   return request({
@@ -94,4 +102,11 @@ export function getAllTenantListByPhone(phone) {
     url: '/system/tenant/getAllTenantListByPhone?phone=' + phone,
     method: 'get',
   })
+}
+
+export function tenantPackageForRegister() {
+  return request({
+    url: '/system/tenant-package/tenantPackageForRegister',
+    method: 'get',
+  })
 }

+ 31 - 45
src/views/components/register/accountInfo.vue

@@ -62,9 +62,9 @@
         >
           <el-option
             v-for="item in options1"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
+            :key="item.id"
+            :label="item.industryName"
+            :value="item.id"
           >
           </el-option>
         </el-select>
@@ -159,6 +159,8 @@
 </template>
 
 <script>
+import { getTreeForRegister } from "@/api/system/area";
+import { getAllIndustry } from "@/api/system/industry";
 export default {
   name: "accountInfo",
   props: {
@@ -196,38 +198,8 @@ export default {
       }
     };
     return {
-      options1: [
-        {
-          value: "1",
-          label: "行业一",
-        },
-        {
-          value: "2",
-          label: "行业二",
-        },
-      ],
-      options: [
-        {
-          value: "jiangsu",
-          label: "江苏",
-          children: [
-            {
-              value: "nantong",
-              label: "南通",
-              children: [
-                {
-                  value: "haian",
-                  label: "海安",
-                },
-                {
-                  value: "rudong",
-                  label: "如东",
-                },
-              ],
-            },
-          ],
-        },
-      ],
+      options1: [],
+      options: [],
       rules: {
         registrationTypeList: [
           {
@@ -278,8 +250,22 @@ export default {
       },
     };
   },
+  created() {
+    this.getAreaList();
+    this.getIndustry();
+  },
   mounted() {},
   methods: {
+    getIndustry() {
+      getAllIndustry().then((res) => {
+        this.options1 = res.data;
+      });
+    },
+    getAreaList() {
+      getTreeForRegister().then((response) => {
+        this.options = response.data;
+      });
+    },
     //上一步
     previousStep() {
       this.changeComponents("registration-terms");
@@ -287,17 +273,17 @@ export default {
     },
     //下一步
     nextStep() {
-      this.changeComponents("entry-information");
-      this.next();
+      // this.changeComponents("entry-information");
+      // this.next();
       /** 需要校验使用下方事务 */
-      // this.$refs["form"].validate((valid) => {
-      //   if (valid) {
-      //     this.next();
-      //     this.changeComponents("entry-information");
-      //   } else {
-      //     return false;
-      //   }
-      // });
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          this.next();
+          this.changeComponents("entry-information");
+        } else {
+          return false;
+        }
+      });
     },
   },
 };

+ 81 - 24
src/views/components/register/entryInformation.vue

@@ -56,65 +56,81 @@
       </el-form-item>
       <el-form-item label="法人证件附件" prop="legalRepresentativeFile">
         <el-upload
-          action="https://jsonplaceholder.typicode.com/posts/"
+          limit="1"
+          :action="upload.url"
           list-type="picture-card"
-          :on-preview="handlePictureCardPreview"
+          :on-preview="handlePictureCardPreview1"
           :on-remove="handleRemove"
+          :on-success="handleSuccess1"
         >
           <i class="el-icon-plus"></i>
         </el-upload>
+        <span style="font-size: 12px; color: #b2b2b2">限制上传1份附件</span>
         <el-dialog :visible.sync="dialogVisible">
           <img width="100%" :src="dialogImageUrl" alt="" />
         </el-dialog>
       </el-form-item>
       <el-form-item label="营业执照附件" prop="businessLicenseFile">
         <el-upload
-          action="https://jsonplaceholder.typicode.com/posts/"
+          limit="1"
+          :action="upload.url"
           list-type="picture-card"
-          :on-preview="handlePictureCardPreview"
+          :on-preview="handlePictureCardPreview2"
           :on-remove="handleRemove"
+          :on-success="handleSuccess2"
         >
           <i class="el-icon-plus"></i>
         </el-upload>
+        <span style="font-size: 12px; color: #b2b2b2">限制上传1份附件</span>
+
         <el-dialog :visible.sync="dialogVisible">
           <img width="100%" :src="dialogImageUrl" alt="" />
         </el-dialog>
       </el-form-item>
       <el-form-item label="生产许可证附件" prop="productionLicenseFile">
         <el-upload
-          action="https://jsonplaceholder.typicode.com/posts/"
+          limit="1"
+          :action="upload.url"
           list-type="picture-card"
-          :on-preview="handlePictureCardPreview"
+          :on-preview="handlePictureCardPreview3"
           :on-remove="handleRemove"
+          :on-success="handleSuccess3"
         >
           <i class="el-icon-plus"></i>
         </el-upload>
+        <span style="font-size: 12px; color: #b2b2b2">限制上传1份附件</span>
         <el-dialog :visible.sync="dialogVisible">
           <img width="100%" :src="dialogImageUrl" alt="" />
         </el-dialog>
       </el-form-item>
       <el-form-item label="流通许可证附件" prop="circulationLicense">
         <el-upload
-          action="https://jsonplaceholder.typicode.com/posts/"
+          limit="1"
+          :action="upload.url"
           list-type="picture-card"
-          :on-preview="handlePictureCardPreview"
+          :on-preview="handlePictureCardPreview4"
           :on-remove="handleRemove"
+          :on-success="handleSuccess4"
         >
           <i class="el-icon-plus"></i>
         </el-upload>
+        <span style="font-size: 12px; color: #b2b2b2">限制上传1份附件</span>
         <el-dialog :visible.sync="dialogVisible">
           <img width="100%" :src="dialogImageUrl" alt="" />
         </el-dialog>
       </el-form-item>
       <el-form-item label="其他资质附件" prop="otherQualifications">
         <el-upload
-          action="https://jsonplaceholder.typicode.com/posts/"
+          limit="1"
+          :action="upload.url"
           list-type="picture-card"
-          :on-preview="handlePictureCardPreview"
+          :on-preview="handlePictureCardPreview5"
           :on-remove="handleRemove"
+          :on-success="handleSuccess5"
         >
           <i class="el-icon-plus"></i>
         </el-upload>
+        <span style="font-size: 12px; color: #b2b2b2">限制上传1份附件</span>
         <el-dialog :visible.sync="dialogVisible">
           <img width="100%" :src="dialogImageUrl" alt="" />
         </el-dialog>
@@ -135,6 +151,7 @@
 </template>
 
 <script>
+import { getAccessToken } from "@/utils/auth";
 export default {
   name: "entryInformation",
   props: {
@@ -153,14 +170,22 @@ export default {
   },
   data() {
     return {
+      upload: {
+        open: false, // 是否显示弹出层
+        title: "", // 弹出层标题
+        isUploading: false, // 是否禁用上传
+        url: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址
+        headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
+        data: {}, // 上传的额外数据,用于文件名
+      },
       options: [
         {
           value: "1",
-          label: "证件类型一",
+          label: "身份证",
         },
         {
           value: "2",
-          label: "证件类型二",
+          label: "驾驶证",
         },
       ],
       rules: {
@@ -231,23 +256,55 @@ export default {
     },
     //下一步
     nextStep() {
-      this.changeComponents("registration-package");
-      this.next();
+      // this.changeComponents("registration-package");
+      // this.next();
       /** 需要校验使用下方事务 */
-      // this.$refs["form"].validate((valid) => {
-      //   if (valid) {
-      //     this.next();
-      //     this.changeComponents("registration-package");
-      //   } else {
-      //     return false;
-      //   }
-      // });
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          this.next();
+          this.changeComponents("registration-package");
+        } else {
+          return false;
+        }
+      });
     },
     handleRemove(file, fileList) {
       console.log(file, fileList);
     },
-    handlePictureCardPreview(file) {
-      this.dialogImageUrl = file.url;
+
+    handlePictureCardPreview1(file) {
+      this.form.legalRepresentativeFile = file.url;
+      this.dialogVisible = true;
+    },
+    handleSuccess1(response, file, fileList) {
+      this.form.legalRepresentativeFile = response.data.replace("Blob:", "");
+    },
+    handleSuccess2(response, file, fileList) {
+      this.form.businessLicenseFile = response.data.replace("Blob:", "");
+    },
+    handleSuccess3(response, file, fileList) {
+      this.form.productionLicenseFile = response.data.replace("Blob:", "");
+    },
+    handleSuccess4(response, file, fileList) {
+      this.form.circulationLicense = response.data.replace("Blob:", "");
+    },
+    handleSuccess5(response, file, fileList) {
+      this.form.otherQualifications = response.data.replace("Blob:", "");
+    },
+    handlePictureCardPreview2(file) {
+      this.form.businessLicenseFile = file.url;
+      this.dialogVisible = true;
+    },
+    handlePictureCardPreview3(file) {
+      this.form.productionLicenseFile = file.url;
+      this.dialogVisible = true;
+    },
+    handlePictureCardPreview4(file) {
+      this.form.circulationLicense = file.url;
+      this.dialogVisible = true;
+    },
+    handlePictureCardPreview5(file) {
+      this.form.otherQualifications = file.url;
       this.dialogVisible = true;
     },
   },

+ 36 - 13
src/views/components/register/package.vue

@@ -7,16 +7,18 @@
     @click="mouseClick()"
   >
     <div class="topSty">
-      <div class="packageName" :style="`color:` + color">试用版</div>
-      <div class="discription">体验全新XXX服务</div>
+      <div class="packageName" :style="`color:` + color">
+        {{ pack.name }}
+      </div>
+      <div class="discription">{{ pack.description }}</div>
       <div class="price">
-        <span class="yuan">¥</span><span class="num">10000.00</span
+        <span class="yuan">¥</span><span class="num">{{ pack.price }}</span
         ><span class="nian">/年 起</span>
       </div>
-      <div class="memberCount">仅限5人</div>
+      <div class="memberCount">仅限{{ pack.numDesc }}人</div>
 
       <div class="ktBtn">
-        <el-button class="btnSty">开通</el-button>
+        <el-button class="btnSty" @click="mouseClick()">开通</el-button>
       </div>
     </div>
     <div class="middleSty">
@@ -24,11 +26,16 @@
 
       <div class="mid">
         <el-tree
-          :data="data1"
+          class="tree-border"
+          :data="getData1()"
+          ref="menu"
+          node-key="id"
+          :check-strictly="true"
+          empty-text="加载中,请稍后"
           :props="defaultProps"
-          :default-expand-all="true"
         ></el-tree>
       </div>
+
       <div class="mid">
         <el-tag size="mini" type="success" style="width: 100%"
           >小程序端应用</el-tag
@@ -36,9 +43,13 @@
       </div>
       <div class="mid">
         <el-tree
-          :data="data2"
-          :props="defaultProps"
-          :default-expand-all="true"
+          class="tree-border"
+          :data="pack.appMenuDOList"
+          ref="appmenu"
+          node-key="id"
+          :check-strictly="true"
+          empty-text="加载中,请稍后"
+          :props="defaultProps2"
         ></el-tree>
       </div>
     </div>
@@ -46,7 +57,7 @@
       <div style="display: block">
         <div class="fuwuSty">使用培训:√</div>
         <div class="fuwuSty">疑问解答:√</div>
-        <div class="fuwuSty">业务咨询:×</div>
+        <div class="fuwuSty">业务咨询:</div>
       </div>
     </div>
   </div>
@@ -56,6 +67,9 @@
 export default {
   name: "package-module",
   props: {
+    pack: {
+      type: null,
+    },
     color: {
       type: String,
       default: "#000000",
@@ -187,19 +201,28 @@ export default {
         },
       ],
       defaultProps: {
+        label: "name",
+        children: "children",
+      },
+      defaultProps2: {
+        label: "menuName",
         children: "children",
-        label: "label",
       },
     };
   },
   mounted() {},
   methods: {
+    getData1() {
+      const menuOptions = [];
+      menuOptions.push(...this.handleTree(this.pack.menuDOList, "id"));
+      return menuOptions;
+    },
     changeStyFlag(flag) {
       this.styFlag = flag;
       if (!flag) this.mouseLeave();
     },
     mouseClick() {
-      this.changeSty(this.packName);
+      this.changeSty(this.packName,this.pack.id,this.pack.numDesc,this.pack.price);
     },
     mouseOver() {
       this.borderSty = "border:3px " + this.color + " solid";

+ 48 - 4
src/views/components/register/registrationPackage.vue

@@ -6,6 +6,7 @@
         :key="index"
         :color="item"
         :packName="packageList[index].packageName"
+        :pack="packList[index]"
         :changeSty="changeSty"
         ref="packageRef"
       ></package-module>
@@ -37,6 +38,8 @@
               v-model="form.accountNum"
               :step="5"
               :precision="0"
+              :max="form.accountNum"
+              disabled
               style="width: 90%"
             ></el-input-number>
             &nbsp;&nbsp;人
@@ -200,6 +203,7 @@
 
 <script>
 import packageModule from "./package.vue";
+import { tenantRegister, tenantPackageForRegister } from "@/api/system/tenant";
 export default {
   name: "registrationPackage",
   components: {
@@ -222,6 +226,7 @@ export default {
   data() {
     return {
       colorList: ["#FFD43C", "#0FA9DE", "#BD7AFF", "#FF9A0D", "#09D640"],
+      packList: [],
       packageList: [
         { packageName: "pack1" },
         { packageName: "pack2" },
@@ -252,11 +257,27 @@ export default {
       options3: [
         {
           value: "1",
-          label: "中国建设银行",
+          label: "中国工商银行",
         },
         {
           value: "2",
-          label: "中国工商银行",
+          label: "中国银行",
+        },
+        {
+          value: "3",
+          label: "中国建设银行",
+        },
+        {
+          value: "4",
+          label: "中国农业银行",
+        },
+        {
+          value: "5",
+          label: "中国交通银行",
+        },
+        {
+          value: "6",
+          label: "中国邮政银行",
         },
       ],
       rules: {
@@ -296,9 +317,15 @@ export default {
       },
     };
   },
+  created() {
+    tenantPackageForRegister().then((res) => {
+      let data = res.data;
+      this.packList = data;
+    });
+  },
   mounted() {},
   methods: {
-    changeSty(packageName) {
+    changeSty(packageName, id, numDesc, price) {
       var comps = this.$refs.packageRef;
       for (let i = 0; i < comps.length; i++) {
         if (comps[i].packName === packageName) {
@@ -307,6 +334,10 @@ export default {
           comps[i].changeStyFlag(false);
         }
       }
+      this.form.accountNum = numDesc;
+      // this.form.totalPrice = numDesc * 10 + price;
+      this.form.totalPrice = price;
+      this.form.packageId = id;
     },
     //上一步
     previousStep() {
@@ -314,7 +345,20 @@ export default {
       this.previous();
     },
     submitAll() {
-      console.log(this.form);
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          console.log("======================", this.form);
+          tenantRegister(this.form).then((res) => {
+            this.$modal.msgSuccess("新增成功");
+          });
+        } else {
+          return false;
+        }
+      });
+      // console.log("======================", this.form);
+      // tenantRegister(this.form).then((res) => {
+      //   this.$modal.msgSuccess("新增成功");
+      // });
     },
   },
 };

+ 3 - 2
src/views/register.vue

@@ -50,6 +50,7 @@ export default {
 
       form: {
         isAgreeTerms: false, //是否同意注册条款
+        packageId: "",
         //===============================================
         registrationTypeList: [], //注册类型
         applyAddress: "", //应用地址
@@ -72,7 +73,7 @@ export default {
         //===============================================
         supplyTypeList: [], //供应类型
         legalRepresentativeName: "", //法人姓名
-        identificationType: "", //证件类型
+        identificationType: "1", //证件类型
         identificationNum: "", //证件号码
         businessLicense: "", //营业执照
         validityDeadline: "", //证件有效截止日期
@@ -84,7 +85,7 @@ export default {
         //===============================================
         purchaseDuration: 1, //购买时长
         accountNum: 5, //账号数量
-        totalPrice: 0.0, //总价
+        totalPrice: 0.00, //总价
         invoiceType: "1", //发票类型
         invoiceHeader: "1", //发票抬头:默认单位不可修改
         USICForInvoice: "", //统一社会识别码(发票)

+ 415 - 0
src/views/system/industry/index.vue

@@ -0,0 +1,415 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索工作栏 -->
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in optionsStatus"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          >
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="['00:00:00', '23:59:59']"
+        />
+      </el-form-item>
+      <el-form-item label="行业名称" prop="industryName">
+        <el-input
+          v-model="queryParams.industryName"
+          placeholder="请输入行业名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          >新增</el-button
+        >
+        <!-- v-hasPermi="['system:industry:create']" -->
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          :loading="exportLoading"
+          >导出</el-button
+        >
+        <!-- v-hasPermi="['system:industry:export']" -->
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getList"
+      ></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <!-- <el-table-column label="序号" align="center" prop="id" /> -->
+      <el-table-column
+        type="index"
+        label="序号"
+        width="50"
+        :index="indexMethod"
+      >
+      </el-table-column>
+      <el-table-column label="行业名称" align="center" prop="industryName" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.status === 1" type="primary">启用</el-tag>
+          <el-tag v-else type="danger"> 禁用 </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime">
+        <template v-slot="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template v-slot="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleSyncPro(scope.row)"
+            >同步流程</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleSyncData(scope.row)"
+            >同步字典</el-button
+          ></template
+        ></el-table-column
+      >
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template v-slot="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="maintainProcess(scope.row)"
+            >维护流程</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="maintainDictionary(scope.row)"
+            >维护字典</el-button
+          >
+          <br />
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            >修改</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNo"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog
+      :title="title"
+      :visible.sync="open"
+      width="500px"
+      v-dialogDrag
+      append-to-body
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="行业名称" prop="industryName">
+          <el-input v-model="form.industryName" placeholder="请输入行业名称" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            type="textarea"
+            v-model="form.remark"
+            placeholder="请输入备注"
+            maxlength="200"
+            show-word-limit
+          />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio label="1">启用</el-radio>
+            <el-radio label="2">禁用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  createIndustry,
+  updateIndustry,
+  deleteIndustry,
+  getIndustry,
+  getIndustryPage,
+  exportIndustryExcel,
+} from "@/api/system/industry";
+
+export default {
+  name: "Industry",
+  components: {},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 行业配置列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        status: null,
+        createTime: [],
+        industryName: null,
+        remark: null,
+      },
+      optionsStatus: [
+        {
+          value: "1",
+          label: "启用",
+        },
+        {
+          value: "2",
+          label: "禁用",
+        },
+      ],
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
+        industryName: [
+          { required: true, message: "行业名称不能为空", trigger: "blur" },
+        ],
+      },
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    //维护字典
+    maintainDictionary() {
+      this.$router.push({
+        path: "/system/syncDictionary/index",
+        // query: { id: row.id },
+      });
+    },
+    //维护流程
+    maintainProcess() {
+      this.$router.push({
+        path: "/system/syncProcess/index",
+        // query: { id: row.id },
+      });
+    },
+    //处理同步流程
+    handleSyncPro() {},
+    //处理同步字典
+    handleSyncData() {},
+    indexMethod(index) {
+      return index + 1;
+    },
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 执行查询
+      getIndustryPage(this.queryParams).then((response) => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        status: undefined,
+        industryName: undefined,
+        remark: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加行业配置";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getIndustry(id).then((response) => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改行业配置";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate((valid) => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateIndustry(this.form).then((response) => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createIndustry(this.form).then((response) => {
+          this.$modal.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal
+        .confirm('是否确认删除行业配置编号为"' + id + '"的数据项?')
+        .then(function () {
+          return deleteIndustry(id);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      // 处理查询参数
+      let params = { ...this.queryParams };
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      this.$modal
+        .confirm("是否确认导出所有行业配置数据项?")
+        .then(() => {
+          this.exportLoading = true;
+          return exportIndustryExcel(params);
+        })
+        .then((response) => {
+          this.$download.excel(response, "行业配置.xls");
+          this.exportLoading = false;
+        })
+        .catch(() => {});
+    },
+  },
+};
+</script>

+ 464 - 0
src/views/system/tenant/index.vue

@@ -0,0 +1,464 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="机构名" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入机构名" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <!-- <el-form-item label="联系人" prop="contactName">
+        <el-input v-model="queryParams.contactName" placeholder="请输入联系人" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="联系手机" prop="contactMobile">
+        <el-input v-model="queryParams.contactMobile" placeholder="请输入联系手机" clearable
+          @keyup.enter.native="handleQuery" />
+      </el-form-item> -->
+      <el-form-item label="机构状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择机构状态" clearable>
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :label="dict.label"
+            :value="dict.value" />
+        </el-select>
+      </el-form-item>
+      <!-- <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss"
+          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+          :default-time="['00:00:00', '23:59:59']" />
+      </el-form-item> -->
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
+          v-hasPermi="['system:tenant:create']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
+          :loading="exportLoading" v-hasPermi="['system:tenant:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="序号" align="center" prop="id" />
+      <el-table-column label="机构编号" align="center" prop="tenantDocCode" />
+      <el-table-column label="机构名" align="center" prop="name" />
+      <el-table-column label="机构地址" align="center" prop="location" />
+      <el-table-column label="机构套餐" align="center" prop="packageId">
+        <template v-slot="scope">
+          <el-tag v-if="scope.row.packageId === 0" type="danger">系统机构</el-tag>
+          <el-tag v-else> {{ getPackageName(scope.row.packageId) }} </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="联系人" align="center" prop="contactName" />
+      <el-table-column label="联系手机" align="center" prop="contactMobile" />
+      <el-table-column label="账号数量" align="center" prop="accountCount">
+
+        <template v-slot="scope">
+          <el-tag> {{ scope.row.accountCount }} </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="过期时间" align="center" prop="expireTime" width="150">
+
+        <template v-slot="scope">
+          <span>{{ parseTime(scope.row.expireTime, "{y}-{m}-{d}") }}</span>
+        </template>
+      </el-table-column>
+      <!-- <el-table-column label="绑定域名" align="center" prop="domain" width="180" /> -->
+      <el-table-column label="管理手机" align="center" prop="managePhone" />
+      <el-table-column label="管理密码" align="center">
+
+        <template v-slot="scope">
+          <el-button type="text" @click="showManagePwd(scope.row)" size="mini">查看密码</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="机构状态" align="center" prop="status">
+
+        <template v-slot="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+
+        <template v-slot="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="120">
+
+        <template v-slot="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:tenant:update']">修改</el-button>
+          <el-button size="mini" type="text" plain icon="el-icon-plus" @click="aaaaaaa(scope.row)">初始化机构</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+            v-hasPermi="['system:tenant:delete']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+      @pagination="getList" />
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body v-loading="loadingCreate">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <!-- <el-form-item label="机构编号" prop="tenantDocCode">
+          <el-input v-model="form.tenantDocCode" placeholder="请输入机构编号" />
+        </el-form-item> -->
+        <el-form-item label="机构名" prop="name">
+          <el-input v-model="form.name" placeholder="请输入机构名" />
+        </el-form-item>
+        <el-form-item label="机构地址" prop="location">
+          <el-cascader v-model="form.location" :options="locations" :show-all-levels="false" :props="{
+      label: 'name', value: 'id',
+      children: 'children'
+    }" />
+        </el-form-item>
+        <el-form-item label="机构套餐" prop="packageId">
+          <el-select v-model="form.packageId" placeholder="请选择机构套餐" clearable size="small">
+            <el-option v-for="item in packageList" :key="item.id" :label="item.name" :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="联系人" prop="contactName">
+          <el-input v-model="form.contactName" placeholder="请输入联系人" />
+        </el-form-item>
+        <el-form-item label="联系手机" prop="contactMobile">
+          <el-input v-model="form.contactMobile" placeholder="请输入联系手机" />
+        </el-form-item>
+        <!-- <el-form-item v-if="form.id === undefined" label="用户名称" prop="username">
+          <el-input v-model="form.username" placeholder="请输入用户名称" />
+        </el-form-item> -->
+        <el-form-item v-if="form.id === undefined" label="用户密码" prop="password">
+          <el-input v-model="form.password" placeholder="请输入用户密码" type="password" show-password />
+        </el-form-item>
+        <el-form-item label="账号数量" prop="accountCount">
+          <el-input-number v-model="form.accountCount" placeholder="请输入账号数量" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="过期时间" prop="expireTime">
+          <el-date-picker clearable size="small" v-model="form.expireTime" type="date" value-format="timestamp"
+            placeholder="请选择过期时间" />
+        </el-form-item>
+
+        <el-form-item label="提醒时间" prop="reminderTime">
+          <el-input-number v-model="form.reminderTime" placeholder="请输入提醒时间" controls-position="right" :precision="0"
+            :step="1" :min="1" />
+        </el-form-item>
+        <el-form-item label="绑定域名" prop="domain">
+          <el-input v-model="form.domain" placeholder="请输入绑定域名" />
+        </el-form-item>
+        <el-form-item label="机构状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" :key="dict.value"
+              :label="parseInt(dict.value)">{{ dict.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  createTenant,
+  updateTenant,
+  deleteTenant,
+  getTenant,
+  getTenantPage,
+  exportTenantExcel,
+  getUserManageDetail,
+} from "@/api/system/tenant";
+import { CommonStatusEnum } from "@/utils/constants";
+import { getTenantPackageList } from "@/api/system/tenantPackage";
+import { getAreaByIp, getAreaTree, getAreaTreePart } from "@/api/system/area";
+
+export default {
+  name: "Tenant",
+  components: {},
+  data() {
+    var validateMobile = (rule, value, callback) => {
+      var phoneReg = /(^1\d{10}$)|(^[0-9]\d{7}$)/;
+      // if (!phoneReg.test(value)) {
+      //   callback(new Error("手机号码格式错误!"));
+      // } else {
+      //   //  else if (this.form.contactMobile == "") {
+      //   //   callback(new Error("手机号不能为空!"));
+      //   // }
+      //   callback();
+      // }
+      if (this.form.contactMobile == "") {
+        callback(new Error("手机号码不能为空!"));
+      } else {
+        if (!phoneReg.test(value)) {
+          callback(new Error("手机号码格式错误!"));
+        }
+        callback();
+      }
+    };
+
+    var validatePass = (rule, value, callback) => {
+      var passReg = /(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[\W_]).{8,}/;
+      if (this.form.password == "") {
+        callback(new Error("密码不能为空!"));
+      } else {
+        if (!passReg.test(value)) {
+          callback(
+            new Error("密码必须由至少8位的大小写字母数字及特殊字符组成")
+          );
+        }
+        callback();
+      }
+    };
+    return {
+      locations: [],
+      // 遮罩层
+      loading: true,
+      loadingCreate: false,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 机构列表
+      list: [],
+      // 机构套餐列表
+      packageList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+        contactName: null,
+        contactMobile: null,
+        status: undefined,
+        createTime: [],
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        // tenantDocCode: [
+        //   { required: true, message: "机构编号不能为空", trigger: "blur" },
+        // ],
+        location: [
+          { required: true, message: "机构地址不能为空", trigger: "blur" },
+        ],
+        password: [
+          {
+            // validator: validatePass,
+            required: true,
+            message: "用户密码不能为空",
+            trigger: "blur",
+          },
+        ],
+        contactMobile: [
+          {
+            validator: validateMobile,
+            required: true,
+            // message: "联系手机格式错误",
+            trigger: "blur",
+          },
+        ],
+        name: [{ required: true, message: "机构名不能为空", trigger: "blur" }],
+        packageId: [
+          { required: true, message: "机构套餐不能为空", trigger: "blur" },
+        ],
+        contactName: [
+          { required: true, message: "联系人不能为空", trigger: "blur" },
+        ],
+
+        status: [
+          { required: true, message: "机构状态不能为空", trigger: "blur" },
+        ],
+        accountCount: [
+          { required: true, message: "账号数量不能为空", trigger: "blur" },
+        ],
+        expireTime: [
+          { required: true, message: "过期时间不能为空", trigger: "blur" },
+        ],
+        reminderTime: [
+          { required: true, message: "提醒时间不能为空", trigger: "blur" },
+        ],
+        // domain: [
+        //   { required: true, message: "绑定域名不能为空", trigger: "blur" },
+        // ],
+      },
+    };
+  },
+  created() {
+    this.getList();
+    // 获得机构套餐列表
+    getTenantPackageList().then((response) => {
+      this.packageList = response.data;
+    });
+    getAreaTreePart().then(response => {
+      this.locations = response.data;
+    })
+  },
+  methods: {
+    showManagePwd(row) {
+      getUserManageDetail(row.managePhone).then(res => {
+        this.$alert(res.data, row.managePhone + '的管理密码', {
+          confirmButtonText: '确定',
+        });
+      })
+
+    },
+    aaaaaaa(row) {
+      // console.log(row)
+      this.$router.push({
+        path: "/system/initialize/dataAndRule",
+        query: { tenantId: row.id },
+      });
+    },
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 执行查询
+      getTenantPage(this.queryParams).then((response) => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        name: undefined,
+        packageId: undefined,
+        contactName: undefined,
+        contactMobile: undefined,
+        accountCount: undefined,
+        expireTime: undefined,
+        domain: undefined,
+        status: CommonStatusEnum.ENABLE,
+        location: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加机构";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getTenant(id).then((response) => {
+        this.form = response.data;
+        this.form.location = parseInt(this.form.location)
+        this.open = true;
+        this.title = "修改机构";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.loadingCreate = true;
+      if (this.form.location != null && this.form.location != "" && this.form.location instanceof Array) {
+        this.form.location = this.form.location[this.form.location.length - 1];
+      }
+      this.$refs["form"].validate((valid) => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateTenant(this.form).then((response) => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.loadingCreate = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createTenant(this.form).then((response) => {
+          this.$modal
+            .confirm(
+              '机构创建成功,请使用账号"' +
+              response.data +
+              '"登录新的机构管理员账号'
+            )
+            .then(() => {
+              this.open = false;
+              this.loadingCreate = false;
+              this.getList();
+            });
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal
+        .confirm('是否确认删除机构编号为"' + id + '"的数据项?')
+        .then(function () {
+          return deleteTenant(id);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      // 处理查询参数
+      let params = { ...this.queryParams };
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      // 执行导出
+      this.$modal
+        .confirm("是否确认导出所有机构数据项?")
+        .then(() => {
+          this.exportLoading = true;
+          return exportTenantExcel(params);
+        })
+        .then((response) => {
+          this.$download.excel(response, "机构.xlsx");
+          this.exportLoading = false;
+        })
+        .catch(() => { });
+    },
+    /** 套餐名格式化 */
+    getPackageName(packageId) {
+      for (const item of this.packageList) {
+        if (item.id === packageId) {
+          return item.name;
+        }
+      }
+      return "未知套餐";
+    },
+  },
+};
+</script>

+ 578 - 0
src/views/system/tenantPackage/index.vue

@@ -0,0 +1,578 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索工作栏 -->
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="套餐名" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入套餐名"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+        >
+          <el-option
+            v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="['00:00:00', '23:59:59']"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery"
+          >搜索
+        </el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:tenant-package:create']"
+          >新增
+        </el-button>
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getList"
+      ></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="套餐编号" align="center" prop="id" width="120" />
+      <el-table-column label="套餐名" align="center" prop="name" />
+      <el-table-column label="状态" align="center" prop="status" width="100">
+        <template v-slot="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="是否可供选购"
+        align="center"
+        prop="available"
+        width="100"
+      >
+        <template v-slot="scope">
+          <el-tag type="primary" v-if="scope.row.available == 1">可购 </el-tag>
+          <el-tag type="danger" v-else>紧购</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        width="180"
+      >
+        <template v-slot="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template v-slot="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:tenant-package:update']"
+            >修改
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:tenant-package:delete']"
+            >删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNo"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="套餐名" prop="name">
+          <el-input v-model="form.name" placeholder="请输入套餐名" />
+        </el-form-item>
+        <el-form-item label="菜单权限">
+          <el-checkbox
+            v-model="menuExpand"
+            @change="handleCheckedTreeExpand($event)"
+            >展开/折叠
+          </el-checkbox>
+          <el-checkbox
+            v-model="menuNodeAll"
+            @change="handleCheckedTreeNodeAll($event)"
+            >全选/全不选
+          </el-checkbox>
+          <el-tree
+            class="tree-border"
+            :data="menuOptions"
+            show-checkbox
+            ref="menu"
+            node-key="id"
+            :check-strictly="menuCheckStrictly"
+            empty-text="加载中,请稍后"
+            :props="defaultProps"
+          ></el-tree>
+        </el-form-item>
+        <el-form-item label="小程序权限">
+          <div
+            style="border: 1px solid #dcdfe6; padding: 10px; border-radius: 4px"
+          >
+            <el-checkbox
+              :indeterminate="isIndeterminate"
+              v-model="checkAll"
+              @change="handleCheckAllChange"
+              >全选
+            </el-checkbox>
+            <el-checkbox-group
+              v-model="checkedMenus"
+              @change="handleCheckedMenusChange"
+            >
+              <el-checkbox
+                v-for="appMenu in appMenus"
+                :label="appMenu.id"
+                :key="appMenu.id"
+                >{{ appMenu.menuName }}
+              </el-checkbox>
+            </el-checkbox-group>
+          </div>
+        </el-form-item>
+        <el-form-item label="食堂功能权限">
+          <div
+            style="border: 1px solid #dcdfe6; padding: 10px; border-radius: 4px"
+          >
+            <el-checkbox
+              :indeterminate="isIndeterminateCanteen"
+              v-model="checkCanteenAll"
+              @change="handleCanteenCheckAllChange"
+              >全选
+            </el-checkbox>
+            <div style="margin: 15px 0"></div>
+            <el-checkbox-group
+              v-model="checkedCanteenMenus"
+              @change="handleCanteenCheckedMenusChange"
+            >
+              <el-checkbox
+                v-for="item in canteenFunConfigs"
+                :label="item.id"
+                :key="item.id"
+              >
+                {{ item.funName }}
+              </el-checkbox>
+            </el-checkbox-group>
+          </div>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
+              :key="dict.value"
+              :label="parseInt(dict.value)"
+              >{{ dict.label }}
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="可购状态" prop="available" v-if="form.id != null">
+          <el-radio-group v-model="form.available">
+            <el-radio :label="1">可购</el-radio>
+            <el-radio :label="2">禁购</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item
+          label="套餐描述"
+          prop="description"
+          v-if="form.available === 1"
+        >
+          <el-input
+            v-model="form.description"
+            placeholder="请输入套餐描述"
+            maxlength="10"
+            show-word-limit
+          />
+        </el-form-item>
+        <el-form-item label="套餐价格" prop="price" v-if="form.available === 1">
+          <el-input-number
+            v-model="form.price"
+            :precision="2"
+            placeholder="请输入套餐价格"
+          ></el-input-number>
+        </el-form-item>
+        <el-form-item label="人数" prop="numDesc" v-if="form.available === 1">
+          <el-input-number
+            v-model="form.numDesc"
+            :precision="0"
+            placeholder="请输入套餐人数"
+          ></el-input-number>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  createTenantPackage,
+  updateTenantPackage,
+  deleteTenantPackage,
+  getTenantPackage,
+  getTenantPackagePage,
+} from "@/api/system/tenantPackage";
+import { getAllAppMenu } from "@/api/system/appMenu";
+import { getAllCanteenFunConfig } from "@/api/system/canteenFunConfig";
+import { CommonStatusEnum } from "@/utils/constants";
+import { listSimpleMenus } from "@/api/system/menu";
+
+const cityOptions = [
+  { menuName: "上海", id: 1 },
+  { menuName: "北京", id: 2 },
+  { menuName: "广州", id: 3 },
+  { menuName: "深圳", id: 4 },
+];
+export default {
+  name: "TenantPackage",
+  components: {},
+  data() {
+    return {
+      checkedMenus: [],
+      checkedCanteenMenus: [],
+      checkAll: false,
+      checkCanteenAll: false,
+      appMenus: [],
+      canteenFunConfigs: [],
+      isIndeterminate: true,
+      isIndeterminateCanteen: true,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 机构套餐列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+        status: null,
+        remark: null,
+        createTime: [],
+      },
+      // 表单参数
+      form: {},
+      menuExpand: false,
+      menuNodeAll: false,
+      menuCheckStrictly: true,
+      defaultProps: {
+        label: "name",
+        children: "children",
+      },
+      menuOptions: [], // 菜单列表
+      // 表单校验
+      rules: {
+        name: [{ required: true, message: "套餐名不能为空", trigger: "blur" }],
+        status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
+        menuIds: [
+          {
+            required: true,
+            message: "关联的菜单编号不能为空",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.getMenus();
+    this.getAllCanteenFunConfig();
+  },
+  methods: {
+    /** 全选操作 */
+    handleCheckAllChange(val) {
+      if (val) {
+        for (let i = 0; i < this.appMenus.length; i++) {
+          this.checkedMenus.push(this.appMenus[i].id);
+        }
+      } else {
+        this.checkedMenus = [];
+      }
+
+      this.isIndeterminate = false;
+    },
+    handleCanteenCheckAllChange(val) {
+      if (val) {
+        for (let i = 0; i < this.canteenFunConfigs.length; i++) {
+          this.checkedCanteenMenus.push(this.canteenFunConfigs[i].id);
+        }
+      } else {
+        this.checkedCanteenMenus = [];
+      }
+      this.isIndeterminateCanteen = false;
+    },
+    /** 选中反相操作全选 */
+    handleCheckedMenusChange(value) {
+      let checkedCount = value.length;
+      this.checkAll = checkedCount === this.appMenus.length;
+      this.isIndeterminate =
+        checkedCount > 0 && checkedCount < this.appMenus.length;
+    },
+    /** 选中反相操作全选 */
+    handleCanteenCheckedMenusChange(value) {
+      let checkedCount = value.length;
+      this.checkCanteenAll = checkedCount === this.canteenFunConfigs.length;
+      this.isIndeterminateCanteen =
+        checkedCount > 0 && checkedCount < this.canteenFunConfigs.length;
+    },
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 执行查询
+      getTenantPackagePage(this.queryParams).then((response) => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.checkedMenus = [];
+      this.checkedCanteenMenus = [];
+      // 菜单选择重置
+      if (this.$refs.menu !== undefined) {
+        this.$refs.menu.setCheckedKeys([]);
+      }
+      this.menuExpand = false;
+      this.menuNodeAll = false;
+      this.menuCheckStrictly = true;
+      // 表单重置
+      this.form = {
+        id: undefined,
+        name: undefined,
+        status: CommonStatusEnum.ENABLE,
+        remark: undefined,
+        menuIds: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      // 表单重置
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加机构套餐";
+      // 设置为非严格,继续使用半选中
+      this.menuCheckStrictly = false;
+      getAllAppMenu().then((response) => {
+        this.appMenus = response.data;
+      });
+      this.getAllCanteenFunConfig();
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      this.open = true;
+      this.title = "修改机构套餐";
+      getAllAppMenu().then((response) => {
+        this.appMenus = response.data;
+        // 获得菜单列表
+        getTenantPackage(id).then((response) => {
+          this.form = response.data;
+          // 设置菜单项
+          // 设置为严格,避免设置父节点自动选中子节点,解决半选中问题
+          this.menuCheckStrictly = true;
+          // 设置选中
+          this.$refs.menu.setCheckedKeys(response.data.menuIds);
+          // 设置为非严格,继续使用半选中
+          this.menuCheckStrictly = false;
+          // 设置小程序菜单选中项
+          this.checkedMenus =
+            this.form.appMenuIds == null ? [] : this.form.appMenuIds;
+          this.checkedCanteenMenus =
+            this.form.canteenFunIds == null ? [] : this.form.canteenFunIds;
+          if (
+            this.appMenus.length > 0 &&
+            this.checkedMenus.length == this.appMenus.length
+          ) {
+            this.checkAll = true;
+            this.isIndeterminate = false;
+          } else {
+            this.checkAll = false;
+            this.isIndeterminate = true;
+          }
+          if (
+            this.canteenFunConfigs.length > 0 &&
+            this.checkedCanteenMenus.length === this.canteenFunConfigs.length
+          ) {
+            this.checkCanteenAll = true;
+            this.isIndeterminateCanteen = false;
+          } else {
+            this.checkCanteenAll = false;
+            this.isIndeterminateCanteen = true;
+          }
+        });
+      });
+    },
+    /** 获得菜单 */
+    getMenus() {
+      listSimpleMenus().then((response) => {
+        // 处理 menuOptions 参数
+        this.menuOptions = [];
+        // 只需要配置
+        this.menuOptions.push(...this.handleTree(response.data, "id"));
+      });
+    },
+    /** 获得菜单 */
+    getAllCanteenFunConfig() {
+      getAllCanteenFunConfig().then((response) => {
+        // 处理 menuOptions 参数
+        this.canteenFunConfigs = response.data;
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate((valid) => {
+        if (!valid) {
+          return;
+        }
+        this.form.appMenuIds = this.checkedMenus;
+        this.form.canteenFunIds = this.checkedCanteenMenus;
+        // 修改的提交
+        if (this.form.id != null) {
+          updateTenantPackage({
+            ...this.form,
+            menuIds: [
+              ...this.$refs.menu.getCheckedKeys(),
+              ...this.$refs.menu.getHalfCheckedKeys(),
+            ],
+          }).then((response) => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createTenantPackage({
+          ...this.form,
+          menuIds: [
+            ...this.$refs.menu.getCheckedKeys(),
+            ...this.$refs.menu.getHalfCheckedKeys(),
+          ],
+        }).then((response) => {
+          this.$modal.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal
+        .confirm('是否确认删除机构套餐编号为"' + id + '"的数据项?')
+        .then(function () {
+          return deleteTenantPackage(id);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    // 树权限(展开/折叠)
+    handleCheckedTreeExpand(value, type) {
+      let treeList = this.menuOptions;
+      for (let i = 0; i < treeList.length; i++) {
+        this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value;
+      }
+    },
+    // 树权限(全选/全不选)
+    handleCheckedTreeNodeAll(value) {
+      this.$refs.menu.setCheckedNodes(value ? this.menuOptions : []);
+    },
+    // 树权限(父子联动)
+    handleCheckedTreeConnect(value) {
+      this.form.menuCheckStrictly = value;
+    },
+  },
+};
+</script>