From b77e3962cc06407e7b32c78b466435ef9e62e427 Mon Sep 17 00:00:00 2001
From: heimawl <1785969728@qq.com>
Date: 星期三, 12 七月 2023 15:57:15 +0800
Subject: [PATCH] 11

---
 src/views/followvisit/tasklist/index.vue          |  892 ++++++++
 src/views/followvisit/outpatient/index.vue        |  897 ++++++++
 src/views/sfstatistics/Voicedetail/index.vue      |    2 
 src/views/sfstatistics/statement/index.vue        |    2 
 src/views/followvisit/satisfaction/index.vue      |  892 ++++++++
 src/views/followvisit/linem/index.vue             |  798 +++++++
 src/views/followvisit/record/index.vue            | 1092 ++++++++++
 src/views/sfstatistics/propaganda/index.vue       |    2 
 src/views/sfstatistics/review/index.vue           |    2 
 src/views/shortmessage/aoprojection/index.vue     |  230 ++
 src/views/sfstatistics/analyse/index.vue          |    2 
 src/views/followvisit/record/detailpage/index.vue |   91 
 src/views/sfstatistics/percentage/index.vue       |    2 
 package.json                                      |    1 
 src/views/shortmessage/aoconnect/index.vue        |    2 
 src/views/shortmessage/aovideo/index.vue          |  239 ++
 src/views/followvisit/discharge/index.vue         |  897 ++++++++
 17 files changed, 6,024 insertions(+), 19 deletions(-)

diff --git a/package.json b/package.json
index 5477964..de480a5 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
     "quill-image-resize-module": "^3.0.0",
     "sass": "^1.63.6",
     "screenfull": "5.0.2",
+    "socket.io": "^2.1.1",
     "sortablejs": "1.10.2",
     "style-loader": "^3.3.3",
     "stylus-loader": "^7.1.3",
diff --git a/src/views/followvisit/discharge/index.vue b/src/views/followvisit/discharge/index.vue
new file mode 100644
index 0000000..3b969de
--- /dev/null
+++ b/src/views/followvisit/discharge/index.vue
@@ -0,0 +1,897 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳浜�">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚绫诲瀷" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="妯$増" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="闂ㄨ瘖闅忚鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="medium"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:user:edit']"
+            >淇敼</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col>
+        <el-col :span="19">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-download"
+                size="medium"
+                @click="handleExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/鎵ц澶辫触</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-promotion"></i>寮�濮嬫墽琛�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟璇︽儏"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-xq"
+                ><i class="el-icon-s-data"></i>璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-order"></i>鎶ヨ〃</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍒犻櫎</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then((response) => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.addalteropen = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  color: #2ba05c;
+}
+.button-xq {
+  font-weight: 500;
+  color: #409eff;
+}
+.button-sc {
+  font-weight: 500;
+  color: #dd302a;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/linem/index.vue b/src/views/followvisit/linem/index.vue
new file mode 100644
index 0000000..a21e535
--- /dev/null
+++ b/src/views/followvisit/linem/index.vue
@@ -0,0 +1,798 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col>
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/鎵ц澶辫触</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-promotion"></i>寮�濮嬫墽琛�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟璇︽儏"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-xq"
+                ><i class="el-icon-s-data"></i>璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-order"></i>鎶ヨ〃</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍒犻櫎</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then((response) => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.addalteropen = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  color: #2ba05c;
+}
+.button-xq {
+  font-weight: 500;
+  color: #409eff;
+}
+.button-sc {
+  font-weight: 500;
+  color: #dd302a;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/outpatient/index.vue b/src/views/followvisit/outpatient/index.vue
new file mode 100644
index 0000000..3b969de
--- /dev/null
+++ b/src/views/followvisit/outpatient/index.vue
@@ -0,0 +1,897 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳浜�">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚绫诲瀷" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="妯$増" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="闂ㄨ瘖闅忚鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="medium"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:user:edit']"
+            >淇敼</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col>
+        <el-col :span="19">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-download"
+                size="medium"
+                @click="handleExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/鎵ц澶辫触</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-promotion"></i>寮�濮嬫墽琛�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟璇︽儏"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-xq"
+                ><i class="el-icon-s-data"></i>璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-order"></i>鎶ヨ〃</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍒犻櫎</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then((response) => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.addalteropen = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  color: #2ba05c;
+}
+.button-xq {
+  font-weight: 500;
+  color: #409eff;
+}
+.button-sc {
+  font-weight: 500;
+  color: #dd302a;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/record/detailpage/index.vue b/src/views/followvisit/record/detailpage/index.vue
new file mode 100644
index 0000000..ad484bd
--- /dev/null
+++ b/src/views/followvisit/record/detailpage/index.vue
@@ -0,0 +1,91 @@
+<template>
+  <div class="Followupdetailspage">
+    <div class="Followuserinfo">
+      <div class="userinfo-text">闅忚璇︽儏</div>
+      <div class="userinfo-value">
+        <span><i class="el-icon-user-solid"></i>鍚撮緳</span><span>鐢�</span
+        ><span><i class="el-icon-user-solid"></i>13803963330</span
+        ><span>鍑洪櫌鏃堕棿锛�:2023-03-29 08:57:57</span>
+      </div>
+      <div><el-button type="success">闅忚鍚庣煭淇�</el-button></div>
+    </div>
+    <div>
+      <el-tabs type="border-card">
+        <el-tab-pane>
+          <span class="mulsz" slot="label"
+            ><i class="el-icon-headset"></i> 璇煶璇︽儏1</span
+          >
+          <div class="borderdiv">璇煶璇︽儏1</div>
+        </el-tab-pane>
+        <el-tab-pane>
+          <span class="mulsz" slot="label"
+            ><i class="el-icon-headset"></i> 璇煶璇︽儏2</span
+          >
+          <div class="borderdiv">璇煶璇︽儏2</div>
+        </el-tab-pane>
+        <el-tab-pane>
+          <span class="mulsz" slot="label"
+            ><i class="el-icon-notebook-1"></i> 璇煶淇℃伅</span
+          >
+          <div class="borderdiv">璇煶淇℃伅</div>
+        </el-tab-pane>
+        <el-tab-pane>
+          <span class="mulsz" slot="label"
+            ><i class="el-icon-phone-outline"></i> 澶栧懠淇℃伅</span
+          >
+          <div class="borderdiv">澶栧懠淇℃伅</div>
+        </el-tab-pane>
+        <el-tab-pane>
+          <span class="mulsz" slot="label"
+            ><i class="el-icon-s-operation"></i> 鏍囩鐘舵��</span
+          >
+          <div class="borderdiv">
+            <el-radio v-model="radio" label="1">涓嶅鐞�</el-radio>
+            <el-radio v-model="radio" label="2">缁х画璺熻釜</el-radio
+            ><el-radio v-model="radio" label="3">閫氱煡鍖婚櫌灏辫瘖</el-radio>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      radio: "1",
+      userid: "",
+    };
+  },
+
+  created() {},
+
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped>
+.Followuserinfo {
+  margin: 20px 10px;
+  display: flex;
+  align-items: center;
+  .userinfo-text {
+    font-size: 20px;
+    margin-right: 20px;
+  }
+  .userinfo-value {
+    color: rgb(15, 139, 211);
+    span {
+      margin-right: 20px;
+    }
+  }
+}
+.borderdiv {
+  min-height: 60vh;
+}
+.mulsz {
+  font-size: 25px;
+  margin-top: 20px;
+}
+</style>
diff --git a/src/views/followvisit/record/index.vue b/src/views/followvisit/record/index.vue
new file mode 100644
index 0000000..0b922c4
--- /dev/null
+++ b/src/views/followvisit/record/index.vue
@@ -0,0 +1,1092 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳浜�">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚绫诲瀷" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="妯$増" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="闂ㄨ瘖闅忚鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <!-- <el-col :span="1.5">
+          <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="medium"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:user:edit']"
+            >淇敼</el-button
+          >
+        </el-col> -->
+        <!-- <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col> -->
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-upload2"
+                size="medium"
+                @click="handleExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="success"
+                plain
+                icon="el-icon-download"
+                size="medium"
+                @click="toleadExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎叆</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="info"
+                icon="el-icon-refresh"
+                size="medium"
+                @click="TaskReset"
+                v-hasPermi="['system:user:export']"
+                >浠诲姟閲嶇疆</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="success"
+                icon="el-icon-position"
+                size="medium"
+                @click="AllStarted"
+                v-hasPermi="['system:user:export']"
+                >鍏ㄩ儴寮�濮�</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                icon="el-icon-remove"
+                size="medium"
+                @click="AllStop"
+                v-hasPermi="['system:user:export']"
+                >鍏ㄩ儴鍋滄</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="1.5">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="primary"
+                icon="el-icon-remove"
+                size="medium"
+                @click="Sendtimesetting"
+                v-hasPermi="['system:user:export']"
+                >鍙戦�佹椂闂磋缃�</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/寰呭鏍�</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="followupvisit(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-promotion"></i>閲嶆柊闅忚</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handlestop(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍋滄</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="Seedetails(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-order"></i>鏌ョ湅璇︽儏</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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>
+    <!-- 淇敼鍙戦�佹椂闂村璇濇 -->
+    <el-dialog
+      title="鍙戦�佹椂闂磋缃�"
+      :visible.sync="modificationVisible"
+      width="45%"
+    >
+      <div style="margin-bottom: 20px; color: red">
+        缁熶竴淇敼褰撳ぉ鏈彂閫佺殑浠诲姟鏃堕棿
+      </div>
+
+      <el-form
+        :model="ruleForm"
+        :rules="rules"
+        ref="ruleForm"
+        label-width="120px"
+        class="demo-ruleForm"
+      >
+        <el-form-item label="鍙戦�佹棩鏈�">
+          <el-date-picker
+            v-model="ruleForm.value1"
+            type="date"
+            placeholder="閫夋嫨鏃ユ湡"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item label="鏃堕棿娈�" prop="type">
+          <el-checkbox-group v-model="ruleForm.type">
+            <el-checkbox label="涓婂崍" name="type"></el-checkbox>
+            <el-checkbox label="涓嬪崍" name="type"></el-checkbox>
+            <el-checkbox label="鏅氫笂" name="type"></el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="涓婂崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value2"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="涓嬪崍鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value3"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="鏅氫笂鏃堕棿鍖洪棿" required>
+          <el-time-picker
+            is-range
+            v-model="ruleForm.value4"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫椂闂�"
+            end-placeholder="缁撴潫鏃堕棿"
+            placeholder="閫夋嫨鏃堕棿鑼冨洿"
+          >
+          </el-time-picker>
+        </el-form-item>
+      </el-form>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="modificationVisible = false">鍙� 娑�</el-button>
+        <el-button type="primary" @click="modificationVisible = false"
+          >纭� 瀹�</el-button
+        >
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 淇敼鍙戦�佹椂闂村璇濇
+      modificationVisible: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      ruleForm: {
+        type: [],
+      },
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    // handleUpdate(row) {
+    //   this.reset();
+    //   const userId = row.userId || this.ids;
+    //   getUser(userId).then((response) => {
+    //     this.form = response.data;
+    //     this.postOptions = response.posts;
+    //     this.roleOptions = response.roles;
+    //     this.$set(this.form, "postIds", response.postIds);
+    //     this.$set(this.form, "roleIds", response.roleIds);
+    //     this.addalteropen = true;
+    //     this.title = "淇敼鐢ㄦ埛";
+    //     this.form.password = "";
+    //   });
+    // },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
+
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴鍋滄
+    AllStop() {
+      this.$modal
+        .confirm("鏄惁鍋滄鍏ㄩ儴浠诲姟锛�")
+        .then(function () {
+          return console.log("鍋滄鎴愬姛");
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgWarning("鍋滄鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 鍏ㄩ儴寮�濮�
+    AllStarted() {
+      this.$modal
+        .confirm("鏄惁寮�鍚叏閮ㄤ换鍔★紵")
+        .then(function () {
+          return console.log("寮�鍚垚鍔�");
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("寮�鍚垚鍔�");
+        })
+        .catch(() => {});
+    },
+    // 浠诲姟閲嶇疆
+    TaskReset() {
+      this.$modal
+        .confirm("鏄惁閲嶇疆閫変腑鐨勪换鍔¢」锛�")
+        .then(function () {
+          return console.log("閫変腑鎴愬姛");
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("閲嶇疆鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    // 璁剧疆鍙戦�佹椂闂�
+    Sendtimesetting() {
+      this.modificationVisible = true;
+    },
+    // 璺宠浆璇︽儏椤�
+    Seedetails() {
+      this.$router.push({
+        path: "/followvisit/record/detailpage/",
+        query: { id: "1" },
+      });
+    },
+    // 瀵煎叆鎸夐挳
+    toleadExport() {},
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  // width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  background-color: #2ba05c;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-xq {
+  font-weight: 500;
+  background-color: #409eff;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-sc {
+  font-weight: 500;
+  background-color: #dd302a;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+// 閫夐」瀛椾綋鏀惧ぇ
+// ::v-deep.el-checkbox-group {
+//   span {
+//     font-size: 24px;
+//   }
+// }
+</style>
diff --git a/src/views/followvisit/satisfaction/index.vue b/src/views/followvisit/satisfaction/index.vue
index e6b4411..3b969de 100644
--- a/src/views/followvisit/satisfaction/index.vue
+++ b/src/views/followvisit/satisfaction/index.vue
@@ -1,17 +1,897 @@
 <template>
-  <div>婊℃剰搴﹁皟鏌�</div>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳浜�">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚绫诲瀷" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="妯$増" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="闂ㄨ瘖闅忚鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="medium"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:user:edit']"
+            >淇敼</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col>
+        <el-col :span="19">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-download"
+                size="medium"
+                @click="handleExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/鎵ц澶辫触</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-promotion"></i>寮�濮嬫墽琛�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟璇︽儏"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-xq"
+                ><i class="el-icon-s-data"></i>璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-order"></i>鎶ヨ〃</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍒犻櫎</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
 export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
   data() {
-    return {};
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
   },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then((response) => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.addalteropen = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
 
-  created() {},
-
-  methods: {},
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
 };
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  color: #2ba05c;
+}
+.button-xq {
+  font-weight: 500;
+  color: #409eff;
+}
+.button-sc {
+  font-weight: 500;
+  color: #dd302a;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/followvisit/tasklist/index.vue b/src/views/followvisit/tasklist/index.vue
index 9ff8630..3b969de 100644
--- a/src/views/followvisit/tasklist/index.vue
+++ b/src/views/followvisit/tasklist/index.vue
@@ -1,17 +1,897 @@
 <template>
-  <div>浠诲姟鍒楄〃</div>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--鐢ㄦ埛鏁版嵁-->
+
+      <el-form
+        :model="topqueryParams"
+        ref="queryForm"
+        size="small"
+        :inline="true"
+        v-show="showSearch"
+        label-width="98px"
+      >
+        <el-form-item label="浠诲姟鍚嶇О">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳浜�">
+          <el-input v-model="topqueryParams.name"></el-input>
+        </el-form-item>
+        <el-form-item label="瀹℃牳鏃堕棿">
+          <el-date-picker
+            v-model="dateRange"
+            style="width: 240px"
+            value-format="yyyy-MM-dd"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="闅忚绫诲瀷" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="妯$増" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="闂ㄨ瘖闅忚鐘舵��" prop="status">
+          <el-select v-model="topqueryParams.topic" placeholder="璇烽�夋嫨">
+            <el-option
+              v-for="item in topicoptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="medium"
+            @click="handleQuery"
+            >鎼滅储</el-button
+          >
+          <el-button icon="el-icon-refresh" size="medium" @click="resetQuery"
+            >閲嶇疆</el-button
+          >
+        </el-form-item>
+      </el-form>
+      <el-divider></el-divider>
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="medium"
+            @click="handleAdd"
+            v-hasPermi="['system:user:add']"
+            >鏂板</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="medium"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:user:edit']"
+            >淇敼</el-button
+          >
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="medium"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:user:remove']"
+            >鍒犻櫎</el-button
+          >
+        </el-col>
+        <el-col :span="19">
+          <div class="documentf">
+            <div class="document">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-download"
+                size="medium"
+                @click="handleExport"
+                v-hasPermi="['system:user:export']"
+                >瀵煎嚭</el-button
+              >
+            </div>
+          </div>
+        </el-col>
+        <!-- <el-col :span="1.5"> </el-col> -->
+      </el-row>
+      <!-- <right-toolbar
+              :showSearch.sync="showSearch"
+              @queryTable="getList"
+              :columns="columns"
+            ></right-toolbar> -->
+      <el-table
+        v-loading="loading"
+        :data="userList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" align="center" />
+        <el-table-column
+          label="搴忓彿"
+          align="center"
+          key="userId"
+          prop="userId"
+        />
+
+        <el-table-column
+          label="浠诲姟鍚嶇О"
+          align="center"
+          sortable
+          key="userName"
+          prop="userName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="鏈嶅姟妯℃澘"
+          align="center"
+          key="types"
+          prop="types"
+        />
+        <el-table-column
+          label="鍒涘缓鏃ユ湡"
+          align="center"
+          key="nickName"
+          prop="nickName"
+        />
+        <el-table-column
+          label="寰呮墽琛�/鎬绘暟"
+          align="center"
+          key="phonenumber"
+          prop="phonenumber"
+          width="120"
+        >
+          <template slot-scope="scope">
+            <span style="margin-left: 10px"
+              >{{ scope.row.date }}/{{ scope.row.data }}</span
+            >
+          </template>
+        </el-table-column>
+
+        <el-table-column
+          label="鎵ц鐘舵��"
+          align="center"
+          key="topicnumber"
+          prop="topicnumber"
+          width="120"
+          :show-overflow-tooltip="true"
+        >
+          <template slot-scope="scope">
+            <div>鎵ц瀹屾垚/鎵ц澶辫触</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="瀹℃牳浜�"
+          align="center"
+          key="topicnumberaa"
+          prop="topicnumberaa"
+          sortable
+          width="120"
+          :show-overflow-tooltip="true"
+        />
+
+        <el-table-column
+          label="瀹℃牳鏃堕棿"
+          sortable
+          align="center"
+          prop="createTime"
+          width="160"
+        >
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="鎿嶄綔"
+          align="center"
+          width="120"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-zx"
+                ><i class="el-icon-s-promotion"></i>寮�濮嬫墽琛�</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="浠诲姟璇︽儏"
+          align="center"
+          width="200"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-xq"
+                ><i class="el-icon-s-data"></i>璇︽儏</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-bb"
+                ><i class="el-icon-s-order"></i>鎶ヨ〃</span
+              ></el-button
+            >
+            <el-button
+              size="medium"
+              type="text"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['system:user:edit']"
+              ><span class="button-sc"
+                ><i class="el-icon-delete"></i>鍒犻櫎</span
+              ></el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="topqueryParams.pageNum"
+        :limit.sync="topqueryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <!-- 娣诲姞鎴栦慨鏀归棬璇婇殢璁垮璇濇 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="addalteropen"
+      width="700px"
+      append-to-body
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-row :gutter="20">
+          <el-col :span="12"
+            ><el-form-item label="浠诲姟鍚嶇О">
+              <el-input v-model="form.name"></el-input> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="鎵�灞炵瀹�">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨绉戝">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item></el-col
+        ></el-row>
+        <el-row :gutter="20">
+          <el-col :span="24"
+            ><el-form-item label="闅忚绫诲瀷">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨闅忚绫诲瀷">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select> </el-form-item
+          ></el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="鏈嶅姟妯″潡">
+              <el-select v-model="form.region" placeholder="璇烽�夋嫨妯″潡">
+                <el-option label="鍖哄煙涓�" value="shanghai"></el-option>
+                <el-option label="鍖哄煙浜�" value="beijing"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="闂ㄨ瘖闅忚瑕佹眰">
+              <el-input type="textarea" v-model="form.desc"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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 {
+  listUser,
+  getUser,
+  delUser,
+  addUser,
+  updateUser,
+  resetUserPwd,
+  changeUserStatus,
+} from "@/api/system/user";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
 export default {
+  name: "User",
+  dicts: ["sys_normal_disable", "sys_user_sex"],
+  components: { Treeselect },
   data() {
-    return {};
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏂板闂ㄨ瘖闅忚",
+      // 鏄惁鏄剧ず淇敼銆佹坊鍔犲脊鍑哄眰
+      addalteropen: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      dynamicTags: ["閫夐」涓�", "閫夐」浜�", "閫夐」涓�"], //閫夐」
+      inputVisible: false,
+      inputValue: "",
+      previewVisible: false, //闂ㄨ瘖闅忚棰勮寮规
+      radio: "",
+      radios: [],
+      previewtype: 2, //棰勮闂ㄨ瘖闅忚绫诲瀷
+      total: 0, // 鎬绘潯鏁�
+      ImportQuantity: 999, //瀵奸棬璇婇殢璁挎暟閲�
+      //棰勮闂ㄨ瘖闅忚淇℃伅
+      previewvalue: {
+        username: "杩欎釜鍖荤敓瀵逛綘鎬庝箞鏍�",
+      },
+      value: [],
+      list: [],
+      loading: false,
+      states: [
+        "Alabama",
+        "Alaska",
+        "Arizona",
+        "Arkansas",
+        "California",
+        "Colorado",
+        "Connecticut",
+        "Delaware",
+        "Florida",
+        "Georgia",
+        "Hawaii",
+        "Idaho",
+        "Illinois",
+        "Indiana",
+        "Iowa",
+        "Kansas",
+        "Kentucky",
+        "Louisiana",
+        "Maine",
+        "Maryland",
+        "Massachusetts",
+        "Michigan",
+        "Minnesota",
+        "Mississippi",
+        "Missouri",
+        "Montana",
+        "Nebraska",
+        "Nevada",
+        "New Hampshire",
+        "New Jersey",
+        "New Mexico",
+        "New York",
+        "North Carolina",
+        "North Dakota",
+        "Ohio",
+        "Oklahoma",
+        "Oregon",
+        "Pennsylvania",
+        "Rhode Island",
+        "South Carolina",
+        "South Dakota",
+        "Tennessee",
+        "Texas",
+        "Utah",
+        "Vermont",
+        "Virginia",
+        "Washington",
+        "West Virginia",
+        "Wisconsin",
+        "Wyoming",
+      ],
+      pickerOptions: {
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+        shortcuts: [
+          {
+            text: "浠婂ぉ",
+            onClick(picker) {
+              picker.$emit("pick", new Date());
+            },
+          },
+          {
+            text: "鏄ㄥぉ",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24);
+              picker.$emit("pick", date);
+            },
+          },
+          {
+            text: "涓�鍛ㄥ墠",
+            onClick(picker) {
+              const date = new Date();
+              date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", date);
+            },
+          },
+        ],
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {
+        phonenumber: "",
+        totagid: "",
+        types: "",
+        nickName: "",
+        qystatus: "",
+        btstatus: "",
+      },
+      // 鏌ヨ鍙傛暟
+      topqueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        tagid: undefined,
+        topic: undefined,
+      },
+      propss: { multiple: true },
+      options: [],
+
+      topicoptions: [
+        {
+          value: 1,
+          label: "寰呭鏍�",
+        },
+        {
+          value: 2,
+          label: "鎵ц涓�",
+        },
+        {
+          value: 3,
+          label: "鎵ц瀹屾垚",
+        },
+        {
+          value: 4,
+          label: "宸插仠姝�",
+        },
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 20,
+            message: "鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 5,
+            max: 20,
+            message: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"],
+          },
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur",
+          },
+        ],
+        IDnumber: [
+          {
+            pattern:
+              /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/,
+            message: "璇疯緭鍏ユ纭殑韬唤璇佸彿鐮�",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
   },
+  watch: {},
+  created() {
+    this.getList();
+    this.getConfigKey("sys.user.initPassword").then((response) => {
+      this.initPassword = response.msg;
+    });
+  },
+  // 鎼滅储
+  mounted() {
+    this.list = this.states.map((item) => {
+      return { value: `value:${item}`, label: `label:${item}` };
+    });
+  },
+  methods: {
+    /** 鏌ヨ闂ㄨ瘖闅忚鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.topqueryParams, this.dateRange)).then(
+        (response) => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鏌ョ湅闂ㄨ瘖闅忚璇︽儏
+    Referencequestion(row) {
+      this.previewVisible = true;
+    },
+    // 娣诲姞寮规鎼滅储
+    remoteMethod(query) {
+      if (query !== "") {
+        this.loading = true;
+        setTimeout(() => {
+          this.loading = false;
+          this.options = this.list.filter((item) => {
+            return item.label.toLowerCase().indexOf(query.toLowerCase()) > -1;
+          });
+        }, 200);
+      } else {
+        this.options = [];
+      }
+    },
+    // 闂ㄨ瘖闅忚鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal
+        .confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵')
+        .then(function () {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.$modal.msgSuccess(text + "鎴愬姛");
+        })
+        .catch(function () {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.addalteropen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: [],
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.topqueryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.topqueryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    //鍒犻櫎閫夐」
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
+    },
+    //瑙﹀彂鏂板杈撳叆
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick((_) => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    //鑾峰彇澶卞幓鐒︾偣瑙﹀彂
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.dynamicTags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = "";
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.addalteropen = true;
+      // getUser().then((response) => {
+      //   this.postOptions = response.posts;
+      //   this.roleOptions = response.roles;
+      //   this.title = "鏂板闂ㄨ瘖闅忚";
+      //   this.form.password = this.initPassword;
+      // });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then((response) => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.addalteropen = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+      })
+        .then(({ value }) => {
+          resetUserPwd(row.userId, value).then((response) => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        })
+        .catch(() => {});
+    },
 
-  created() {},
-
-  methods: {},
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function () {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then((response) => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then((response) => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal
+        .confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�')
+        .then(function () {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        })
+        .catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download(
+        "system/user/export",
+        {
+          ...this.topqueryParams,
+        },
+        `user_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
 };
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.el-button--primary.is-plain {
+  color: #ffffff;
+  background: #409eff;
+  border-color: #4fabe9;
+}
+
+.document {
+  width: 100px;
+  height: 50px;
+}
+
+.documentf {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download {
+  text-align: center;
+
+  .el-upload__tip {
+    font-size: 23px;
+  }
+
+  .el-upload__text {
+    font-size: 23px;
+  }
+}
+
+.uploading {
+  margin-top: 20px;
+  margin: 20px;
+  padding: 30px;
+  background: #ffffff;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+.drexamine {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30px;
+  background: #daeaf5;
+
+  img {
+    width: 100px;
+    height: 100px;
+  }
+}
+
+.qrcode-dialo {
+  // text-align: center;
+  //   display: flex;
+  margin: 20px;
+  padding: 30px;
+  background: #edf1f7;
+  border: 1px solid #dcdfe6;
+  -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12),
+    0 0 6px 0 rgba(0, 0, 0, 0.04);
+
+  .topic-dev {
+    margin-bottom: 25px;
+    font-size: 20px !important;
+
+    .dev-text {
+      margin-bottom: 10px;
+    }
+  }
+}
+.button-bb {
+  font-weight: 500;
+  color: #2ba05c;
+}
+.button-xq {
+  font-weight: 500;
+  color: #409eff;
+}
+.button-sc {
+  font-weight: 500;
+  color: #dd302a;
+}
+.button-zx {
+  background: #4fabe9;
+  padding: 5px;
+  border-radius: 1px;
+  color: #ffffff;
+}
+
+::v-deep.el-radio-group {
+  span {
+    font-size: 24px;
+  }
+}
+
+::v-deep.el-checkbox-group {
+  span {
+    font-size: 24px;
+  }
+}
+</style>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/Voicedetail/index.vue
similarity index 85%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/sfstatistics/Voicedetail/index.vue
index 08f2014..df47fb3 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/Voicedetail/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>澶嶈瘖缁熻</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/analyse/index.vue
similarity index 85%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/sfstatistics/analyse/index.vue
index 08f2014..7972788 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/analyse/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>鎸囨爣鍒嗘瀽</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/percentage/index.vue
similarity index 85%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/sfstatistics/percentage/index.vue
index 08f2014..cab048c 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/percentage/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>闅忚缁熻</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/propaganda/index.vue
similarity index 85%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/sfstatistics/propaganda/index.vue
index 08f2014..c957b81 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/propaganda/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>瀹f暀缁熻</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/review/index.vue
similarity index 85%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/sfstatistics/review/index.vue
index 08f2014..7f55ecf 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/review/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>澶嶆煡閫氱煡</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/sfstatistics/statement/index.vue
similarity index 85%
rename from src/views/complaint/complaintmy/AddComplaint/index.vue
rename to src/views/sfstatistics/statement/index.vue
index 08f2014..6e46b0b 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/sfstatistics/statement/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>闂嵎缁熻</div>
 </template>
 
 <script>
diff --git a/src/views/complaint/complaintmy/AddComplaint/index.vue b/src/views/shortmessage/aoconnect/index.vue
similarity index 84%
copy from src/views/complaint/complaintmy/AddComplaint/index.vue
copy to src/views/shortmessage/aoconnect/index.vue
index 08f2014..574f966 100644
--- a/src/views/complaint/complaintmy/AddComplaint/index.vue
+++ b/src/views/shortmessage/aoconnect/index.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>tjiats</div>
+  <div>涓�瀵逛竴娴嬭瘯</div>
 </template>
 
 <script>
diff --git a/src/views/shortmessage/aoprojection/index.vue b/src/views/shortmessage/aoprojection/index.vue
new file mode 100644
index 0000000..5fbfa39
--- /dev/null
+++ b/src/views/shortmessage/aoprojection/index.vue
@@ -0,0 +1,230 @@
+<template>
+  <div class="container">
+    <div class="header">
+      <div>
+        鎴块棿鍙�:
+        <input type="text" id="room" />
+        <button @click="createRoom()">鍒涘缓鎴块棿</button>
+      </div>
+      <div>
+        瀵规柟鎴块棿鍙�
+        <input type="text" id="receive" />
+        <button @click="Connect()">杩炴帴</button>
+      </div>
+    </div>
+    <div style="margin-top: 20px">
+      <video
+        src=""
+        id="self"
+        autoplay
+        controls
+        muted
+        style="width: 500px; object-fit: cover; margin-right: 100px"
+      ></video>
+      <video
+        src=""
+        id="other"
+        autoplay
+        controls
+        muted
+        style="width: 500px; object-fit: cover"
+      ></video>
+    </div>
+  </div>
+</template>
+
+<script>
+let PeerConnection =
+  window.PeerConnection ||
+  window.webkitPeerConnection00 ||
+  window.webkitRTCPeerConnection ||
+  window.mozRTCPeerConnection;
+let nativeRTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
+let nativeRTCSessionDescription =
+  window.mozRTCSessionDescription || window.RTCSessionDescription;
+//ice鏈嶅姟鍣ㄥ湴鍧�
+const iceServer = {
+  iceServers: [
+    {
+      url: "turn:42.192.40.58:3478?transport=udp",
+      username: "ddssingsong",
+      credential: "123456",
+    },
+    {
+      url: "turn:42.192.40.58:3478?transport=tcp",
+      username: "ddssingsong",
+      credential: "123456",
+    },
+  ],
+};
+let socket = "";
+let receiver = "";
+let pc;
+
+export default {
+  data() {
+    return {};
+  },
+
+  created() {},
+
+  methods: {
+    createRoom() {
+      let room = document.getElementById("room");
+      if (!room.value) {
+        alert("璇疯緭鍏ユ埧闂村彿!!!");
+        return;
+      }
+      //寤虹珛websocket杩炴帴
+      socket = new WebSocket(`wss://127.0.0.1:3000/single?room=${room.value}`);
+      socket.onopen = async () => {
+        alert("杩炴帴鎴愬姛");
+        try {
+          //鑾峰彇褰撳墠璁惧鐨勮棰戞祦
+          let stream = await navigator.mediaDevices.getDisplayMedia({
+            video: true,
+            audio: false,
+          });
+          console.log(stream);
+          //鍒濆鍖朠C婧�
+          pc = this.initPC(stream);
+          console.log(pc);
+          //娣诲姞闊宠棰戞祦
+          pc.addStream(stream);
+          console.log(pc);
+          let video = document.getElementById("self");
+          video.srcObject = stream;
+          console.log(video);
+        } catch (error) {
+          console.log(error);
+          alert("鑾峰彇娴佸け璐�");
+        }
+      };
+      socket.onmessage = async (message) => {
+        let data = JSON.parse(message.data);
+        switch (data.name) {
+          //鎺ユ敹鍒伴個璇�
+          case "peer":
+            receiver = data.receiver;
+            this.acceptAudio();
+            break;
+          /**
+           * 1.閭�璇蜂汉灏嗗鏂圭殑闊宠棰戞祦閫氳繃setRemoteDescription鍑芥暟杩涜瀛樺偍
+           * 2.瀛樺偍瀹屽悗閭�璇蜂汉鍒涘缓answer鏉ヨ幏鍙栬嚜宸辩殑闊宠棰戞祦,閫氳繃setLocalDescription鍑芥暟瀛樺偍鑷繁鐨勯煶瑙嗛娴�,骞跺彂閫乤nswer鎸囦护(鎼哄甫鑷繁鐨勯煶瑙嗛)鍛婅瘔瀵规柟瑕佸瓨鍌ㄩ個璇蜂汉鐨勯煶瑙嗛
+           */
+          case "offer":
+            //褰撴敹鍒板鏂规帴鏀惰姹傚悗,璁剧疆闊抽婧�,骞跺彂閫乤nswer缁欏鏂�
+            pc.setRemoteDescription(
+              new nativeRTCSessionDescription(data.data.sdp)
+            );
+            pc.createAnswer(
+              (session_desc) => {
+                pc.setLocalDescription(session_desc);
+                socket.send(
+                  JSON.stringify({
+                    name: "answer",
+                    data: {
+                      sdp: session_desc,
+                    },
+                    receiver: receiver,
+                  })
+                );
+              },
+              (err) => {
+                console.log(err);
+              }
+            );
+            break;
+          case "answer":
+            //璁剧疆閭�璇蜂汉鍙戞潵鐨勯煶棰戞簮
+            pc.setRemoteDescription(
+              new nativeRTCSessionDescription(data.data.sdp)
+            );
+            break;
+          case "ice_candidate":
+            //娣诲姞ice婧�,杩欎竴姝ュ緢閲嶈,濡傛灉娌℃湁鎺ユ敹ice鍒欐煡鐪嬫槸鍚︽祦绋嬫湁闂
+            var candidate = new nativeRTCIceCandidate(data.data);
+            pc.addIceCandidate(candidate);
+            break;
+        }
+      };
+    },
+    //鍒濆鍖朠C婧�
+    initPC() {
+      let pc = new PeerConnection(iceServer);
+      pc.onicecandidate = (evt) => {
+        if (evt.candidate) {
+          socket.send(
+            JSON.stringify({
+              name: `ice_candidate`,
+              data: {
+                id: evt.candidate.sdpMid,
+                label: evt.candidate.sdpMLineIndex,
+                sdpMLineIndex: evt.candidate.sdpMLineIndex,
+                candidate: evt.candidate.candidate,
+              },
+              receiver: receiver,
+            })
+          );
+        }
+      };
+      pc.onaddstream = (evt) => {
+        let stream = evt.stream;
+        let video = document.getElementById("other");
+        video.srcObject = stream;
+      };
+      return pc;
+    },
+    //鍜屽鏂瑰缓绔嬭繛鎺�
+    Connect() {
+      receiver = document.getElementById("receive").value;
+      console.log(receiver);
+      if (!socket) {
+        alert("鍏堝垱寤鸿嚜宸辩殑鎴块棿鍙�!!");
+        return;
+      }
+      if (!receiver) {
+        alert("璇疯緭鍏ュ鏂规埧闂村彿");
+        return;
+      }
+      socket.send(JSON.stringify({ name: "createRoom", receiver: receiver }));
+      console.log("鎴愬姛");
+    },
+    //鎺ユ敹閭�璇�
+    async acceptAudio() {
+      /**
+       * 1.鐐瑰嚮鍚屾剰鍚�
+       * 2.鑾峰彇鑷繁鐨勮棰戞祦
+       * 3.鍒濆鍖朠C婧�
+       * 4.PC娣诲姞闊宠棰戞祦
+       * 5.鍒涘缓offer,鑾峰彇鑷繁鐨勯煶瑙嗛娴�,骞堕�氳繃setLocalDescription鍑芥暟瀛樺偍鑷繁鐨勯煶瑙嗛娴�
+       * 6.骞跺彂閫乸eer鎸囦护(鎼哄甫鑷繁鐨勯煶瑙嗛)鍛婅瘔閭�璇蜂汉瑕佸瓨鍌ㄨ嚜宸辩殑闊宠棰�
+       */
+      try {
+        pc.createOffer(
+          (session_desc) => {
+            pc.setLocalDescription(session_desc);
+            socket.send(
+              JSON.stringify({
+                name: "offer",
+                data: {
+                  sdp: session_desc,
+                },
+                receiver: receiver,
+              })
+            );
+          },
+          (err) => {
+            console.log(err);
+          }
+        );
+      } catch (error) {
+        alert("妫�娴嬪埌褰撳墠璁惧涓嶆敮鎸侀害鍏嬮,璇疯缃潈闄愬悗鍦ㄩ噸璇�");
+        this.socket.close();
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/shortmessage/aovideo/index.vue b/src/views/shortmessage/aovideo/index.vue
new file mode 100644
index 0000000..099f5d3
--- /dev/null
+++ b/src/views/shortmessage/aovideo/index.vue
@@ -0,0 +1,239 @@
+<template>
+  <div class="demo">
+    <div class="rtcBox">
+      <div>
+        <div class="video-box">
+          <video src="" id="rtcA" controls autoplay></video>
+          <h5>A</h5>
+        </div>
+        <div class="chat-box" v-show="!allowHangup && messageOpen">
+          <h5>鏀舵秷鎭�</h5>
+          <p>{{ receiveText }}</p>
+        </div>
+      </div>
+      <div>
+        <div class="video-box">
+          <video src="" id="rtcB" controls autoplay></video>
+          <h5>B</h5>
+          <button @click="call" :disabled="allowCall">鍙戣捣杩炴帴</button>
+          <button @click="hangup" :disabled="allowHangup">hangup</button>
+        </div>
+        <div class="chat-box" v-show="!allowHangup && messageOpen">
+          <h5>鍙戞秷鎭�</h5>
+          <textarea v-model="sendText"></textarea>
+          <br />
+          <button @click="send">鍙戦��</button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "local1",
+  data() {
+    return {
+      peerA: null,
+      peerB: null,
+      channelA: null,
+      channelB: null,
+      offerOption: {
+        offerToReceiveAudio: 1,
+        offerToReceiveVideo: 1,
+      },
+      allowCall: true,
+      allowHangup: true,
+      messageOpen: false,
+      sendText: "",
+      receiveText: "",
+    };
+  },
+  methods: {
+    send() {
+      this.channelB.send(JSON.stringify({ name: this.sendText }));
+      this.sendText = "";
+    },
+    start() {
+      this.state = "2";
+      this.newRecognition.start();
+    },
+    stop() {
+      this.state = "1";
+      this.newRecognition.stop();
+    },
+    async call() {
+      if (!this.peerA || !this.peerB) {
+        // 鍒ゆ柇鏄惁鏈夊搴斿疄渚嬶紝娌℃湁灏遍噸鏂板垱寤�
+        this.initPeer();
+      }
+      try {
+        let offer = await this.peerB.createOffer(this.offerOption); // 鍒涘缓 offer
+        await this.onCreateOffer(offer);
+      } catch (e) {
+        console.log("createOffer: ", e);
+      }
+
+      this.allowCall = true;
+      this.allowHangup = false;
+    },
+    hangup() {
+      this.peerA.close();
+      this.peerB.close();
+      this.channelA.close();
+      this.channelB.close();
+      this.peerA = null;
+      this.peerB = null;
+      this.channelA = null;
+      this.channelB = null;
+      this.sendText = "";
+      this.receiveText = "";
+      this.allowCall = false;
+      this.allowHangup = true;
+    },
+    async onCreateOffer(desc) {
+      try {
+        await this.peerB.setLocalDescription(desc); // 鍛煎彨绔缃湰鍦� offer 鎻忚堪
+      } catch (e) {
+        console.log("Offer-setLocalDescription: ", e);
+      }
+      try {
+        await this.peerA.setRemoteDescription(desc); // 鎺ユ敹绔缃繙绋� offer 鎻忚堪
+      } catch (e) {
+        console.log("Offer-setRemoteDescription: ", e);
+      }
+      try {
+        let answer = await this.peerA.createAnswer(); // 鎺ユ敹绔垱寤� answer
+        await this.onCreateAnswer(answer);
+      } catch (e) {
+        console.log("createAnswer: ", e);
+      }
+    },
+    async onCreateAnswer(desc) {
+      try {
+        await this.peerA.setLocalDescription(desc); // 鎺ユ敹绔缃湰鍦� answer 鎻忚堪
+      } catch (e) {
+        console.log("answer-setLocalDescription: ", e);
+      }
+      try {
+        await this.peerB.setRemoteDescription(desc); // 鍛煎彨绔缃繙绋� answer 鎻忚堪
+      } catch (e) {
+        console.log("answer-setRemoteDescription: ", e);
+      }
+    },
+    initPeer() {
+      // 鍒涘缓杈撳嚭绔� PeerConnection
+      let PeerConnection =
+        window.RTCPeerConnection ||
+        window.mozRTCPeerConnection ||
+        window.webkitRTCPeerConnection;
+      this.peerA = new PeerConnection();
+      this.peerA.addStream(this.localstream); // 娣诲姞鏈湴娴�
+      // 鐩戝惉 A 鐨処CE鍊欓�変俊鎭�
+      // 濡傛灉鏀堕泦鍒帮紝灏辨坊鍔犵粰 B
+      this.peerA.onicecandidate = (event) => {
+        if (event.candidate) {
+          this.peerB.addIceCandidate(event.candidate);
+        }
+      };
+      this.peerA.ondatachannel = (event) => {
+        console.log(event);
+        this.channelA = event.channel;
+        this.channelA.binaryType = "arraybuffer";
+        this.channelA.onopen = (e) => {
+          console.log("channelA onopen", e);
+        };
+        this.channelA.onclose = (e) => {
+          console.log("channelA onclose", e);
+        };
+        this.channelA.onmessage = (e) => {
+          this.receiveText = JSON.parse(e.data).name;
+          console.log("channelA onmessage", e.data);
+        };
+      };
+      //                this.channelA.send('Hi you!');
+      // 鍒涘缓鍛煎彨绔�
+      this.peerB = new PeerConnection();
+      this.peerB.onaddstream = (event) => {
+        // 鐩戝惉鏄惁鏈夊獟浣撴祦鎺ュ叆锛屽鏋滄湁灏辫祴鍊肩粰 rtcB 鐨� src
+        console.log("event-stream", event);
+        let video = document.querySelector("#rtcB");
+        video.srcObject = event.stream;
+      };
+      this.channelB = this.peerB.createDataChannel("messagechannel");
+      console.log("this.channelB", this.channelB);
+      this.channelB.binaryType = "arraybuffer";
+      this.channelB.onopen = (event) => {
+        console.log(1);
+        console.log("channelB onopen", event);
+        this.messageOpen = true;
+      };
+      this.channelB.onclose = function (event) {
+        console.log(1);
+        console.log("channelB onclose", event);
+      };
+      // 鐩戝惉 B 鐨処CE鍊欓�変俊鎭�
+      // 濡傛灉鏀堕泦鍒帮紝灏辨坊鍔犵粰 A
+      this.peerB.onicecandidate = (event) => {
+        if (event.candidate) {
+          this.peerA.addIceCandidate(event.candidate);
+        }
+      };
+      this.allowCall = false;
+    },
+    async createMedia() {
+      // 淇濆瓨鏈湴娴佸埌鍏ㄥ眬锛堣棰戦煶棰戦兘鏀寔锛�
+      this.localstream = await navigator.mediaDevices.getUserMedia({
+        audio: true,
+        video: true,
+      });
+      console.log(this.localstream);
+      console.log(
+        this.localstream.getVideoTracks(),
+        this.localstream.getAudioTracks()
+      );
+      let video = document.querySelector("#rtcA");
+      video.srcObject = this.localstream;
+      this.initPeer(); // 鑾峰彇鍒板獟浣撴祦鍚庯紝璋冪敤鍑芥暟鍒濆鍖� RTCPeerConnection
+    },
+  },
+  mounted() {
+    // 鑾峰彇鏈�鏂拌鍥惧悗鑾峰彇鏈湴娴�
+    this.$nextTick(() => {
+      // {mediaSource: 'screen'}
+      this.createMedia();
+    });
+  },
+};
+</script>
+
+<style lang="scss">
+.rtcBox {
+  display: flex;
+  justify-content: center;
+  .video-box {
+    height: 380px;
+    border-bottom: 1px solid #1fbeca;
+    margin-bottom: 10px;
+  }
+  video {
+    width: 400px;
+    height: 300px;
+    margin-left: 20px;
+    background-color: #ddd;
+  }
+  .chat-box {
+    text-align: center;
+    h5 {
+      margin-bottom: 10px;
+    }
+    p,
+    textarea {
+      width: 240px;
+      height: 60px;
+      border: 1px solid #000;
+      display: inline-block;
+    }
+  }
+}
+</style>

--
Gitblit v1.9.3