瀏覽代碼

中医智能辅助与优势病种决策

cc12458 10 月之前
父節點
當前提交
92b4ddaf33

+ 149 - 0
public/database/jsjk-bar.json

@@ -0,0 +1,149 @@
+{
+  "Data": {
+    "2024-08": {
+      "精神不振": 63,
+      "情绪低落": 34,
+      "急躁易怒": 20,
+      "善悲易哭": 13,
+      "神神抑郁": 218,
+      "神神紧张": 15,
+      "胆怯易惊": 99,
+      "咽喉异物感": 3,
+      "精神良好": 0
+    },
+    "2024-09": {
+      "精神不振": 230,
+      "情绪低落": 78,
+      "急躁易怒": 57,
+      "善悲易哭": 11,
+      "神神抑郁": 438,
+      "神神紧张": 21,
+      "胆怯易惊": 242,
+      "咽喉异物感": 15,
+      "精神良好": 0
+    },
+    "2024-10": {
+      "精神不振": 291,
+      "情绪低落": 141,
+      "急躁易怒": 126,
+      "善悲易哭": 85,
+      "神神抑郁": 629,
+      "神神紧张": 27,
+      "胆怯易惊": 168,
+      "咽喉异物感": 9,
+      "精神良好": 0
+    },
+    "2024-11": {
+      "精神不振": 346,
+      "情绪低落": 170,
+      "急躁易怒": 161,
+      "善悲易哭": 65,
+      "神神抑郁": 614,
+      "神神紧张": 109,
+      "胆怯易惊": 295,
+      "咽喉异物感": 5,
+      "精神良好": 0
+    },
+    "2024-12": {
+      "精神不振": 521,
+      "情绪低落": 224,
+      "急躁易怒": 181,
+      "善悲易哭": 186,
+      "神神抑郁": 1392,
+      "神神紧张": 137,
+      "胆怯易惊": 736,
+      "咽喉异物感": 10,
+      "精神良好": 0
+    },
+    "2025-01": {
+      "精神不振": 387,
+      "情绪低落": 133,
+      "急躁易怒": 125,
+      "善悲易哭": 223,
+      "神神抑郁": 772,
+      "神神紧张": 59,
+      "胆怯易惊": 263,
+      "咽喉异物感": 1,
+      "精神良好": 0
+    },
+    "2025-02": {
+      "精神不振": 273,
+      "情绪低落": 71,
+      "急躁易怒": 61,
+      "善悲易哭": 188,
+      "神神抑郁": 337,
+      "神神紧张": 59,
+      "胆怯易惊": 164,
+      "咽喉异物感": 0,
+      "精神良好": 0
+    },
+    "2025-03": {
+      "精神不振": 51,
+      "情绪低落": 10,
+      "急躁易怒": 0,
+      "善悲易哭": 47,
+      "神神抑郁": 96,
+      "神神紧张": 55,
+      "胆怯易惊": 152,
+      "咽喉异物感": 1,
+      "精神良好": 0
+    },
+    "2025-04": {
+      "精神不振": 45,
+      "情绪低落": 13,
+      "急躁易怒": 0,
+      "善悲易哭": 14,
+      "神神抑郁": 44,
+      "神神紧张": 22,
+      "胆怯易惊": 59,
+      "咽喉异物感": 0,
+      "精神良好": 0
+    },
+    "2025-05": {
+      "精神不振": 51,
+      "情绪低落": 23,
+      "急躁易怒": 0,
+      "善悲易哭": 258,
+      "神神抑郁": 372,
+      "神神紧张": 41,
+      "胆怯易惊": 110,
+      "咽喉异物感": 3,
+      "精神良好": 0
+    },
+    "2025-06": {
+      "精神不振": 68,
+      "情绪低落": 21,
+      "急躁易怒": 0,
+      "善悲易哭": 23,
+      "神神抑郁": 408,
+      "神神紧张": 71,
+      "胆怯易惊": 524,
+      "咽喉异物感": 0,
+      "精神良好": 0
+    },
+    "2025-07": {
+      "精神不振": 33,
+      "情绪低落": 10,
+      "急躁易怒": 0,
+      "善悲易哭": 5,
+      "神神抑郁": 75,
+      "神神紧张": 14,
+      "胆怯易惊": 125,
+      "咽喉异物感": 1,
+      "精神良好": 0
+    },
+    "2025-08": {
+      "精神不振": 1,
+      "情绪低落": 0,
+      "急躁易怒": 0,
+      "善悲易哭": 0,
+      "神神抑郁": 0,
+      "神神紧张": 0,
+      "胆怯易惊": 0,
+      "咽喉异物感": 0,
+      "精神良好": 0
+    }
+  },
+  "ResultInfo": "操作成功",
+  "ResultCode": 0
+}

+ 54 - 0
public/database/jsjk-pie.json

@@ -0,0 +1,54 @@
+{
+  "Data": {
+    "气郁质": {
+      "精神不振": 40,
+      "情绪低落": 10,
+      "急躁易怒": 10,
+      "善悲易哭": 10,
+      "神神抑郁": 10,
+      "神神紧张": 10,
+      "胆怯易惊": 10
+    },
+    "气虚质": {
+      "精神不振": 70,
+      "情绪低落": 15,
+      "急躁易怒": 15
+    },
+    "血瘀质": {
+      "精神不振": 20,
+      "情绪低落": 20,
+      "急躁易怒": 40,
+      "善悲易哭": 20
+    },
+    "湿热质": {
+      "精神不振": 70,
+      "情绪低落": 30
+    },
+    "特禀质": {
+      "精神不振": 35,
+      "情绪低落": 32,
+      "急躁易怒": 33
+    },
+    "痰湿质": {
+      "精神不振": 70,
+      "情绪低落": 15,
+      "急躁易怒": 15
+    },
+    "阴虚质": {
+      "精神不振": 100
+    },
+    "平和质": {
+      "精神不振": 45,
+      "情绪低落": 14,
+      "急躁易怒": 14,
+      "善悲易哭": 14,
+      "神神抑郁": 13
+    },
+    "阳虚质": {
+      "精神不振": 70,
+      "情绪低落": 30
+    }
+  },
+  "ResultInfo": "操作成功",
+  "ResultCode": 0
+}

+ 144 - 0
public/database/yp-trend.json

@@ -0,0 +1,144 @@
+{
+  "Data": {
+    "2025-01月": {
+      "人参": 77,
+      "枸杞": 0,
+      "当归": 77,
+      "党参": 77,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-02月": {
+      "人参": 48,
+      "枸杞": 0,
+      "当归": 48,
+      "党参": 48,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-03月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-04月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-05月": {
+      "人参": 4,
+      "枸杞": 0,
+      "当归": 4,
+      "党参": 4,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-06月": {
+      "人参": 15,
+      "枸杞": 0,
+      "当归": 8,
+      "党参": 8,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 8
+    },
+    "2025-07月": {
+      "人参": 18,
+      "枸杞": 0,
+      "当归": 10,
+      "党参": 10,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 8
+    },
+    "2025-08月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-09月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-10月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-11月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    },
+    "2025-12月": {
+      "人参": 0,
+      "枸杞": 0,
+      "当归": 0,
+      "党参": 0,
+      "黄芪": 0,
+      "五味子": 0,
+      "五灵脂": 0,
+      "甘草": 0,
+      "藏红花": 0,
+      "玄参": 0
+    }
+  },
+  "ResultInfo": "操作成功",
+  "ResultCode": 0
+}

+ 50 - 1
src/api/dataAnalysis.js

@@ -86,4 +86,53 @@ export function exportCure(data) {
         method: 'post',
         data
     })
-};
+};
+
+const mockRequestUrl = location.href.replace(location.search, '').replace(location.hash, '').split('index.html')[0];
+
+// 精神健康柱状图
+export function getJSJK_BarChartData(data) {
+    return request({
+        url: `${mockRequestUrl}database/jsjk-bar.json`,
+        method: 'get',
+        params: {
+            ...data,
+            t: Date.now()
+        }
+    }).then(res => res.Data);
+}
+export function getJSJK_PieChartData(data) {
+    return request({
+        url: `${mockRequestUrl}database/jsjk-pie.json`,
+        method: 'get',
+        params: {
+            ...data,
+            t: Date.now()
+        }
+    }).then(res => res.Data);
+}
+// 饮片趋势分析
+export function getYPTrendData(data) {
+    return request({
+        url: `${mockRequestUrl}database/yp-trend.json`,
+        method: 'get',
+        params: {
+            ...data,
+            t: Date.now()
+        }
+    }).then(res => res.Data);
+}
+export function exportYPTrendChart(data) {
+    const link = document.createElement('a');
+    document.body.appendChild(link);
+    link.href = `${mockRequestUrl}database/yp-trend.json`;
+    link.download = 'yp-trend.json';
+    link.click();
+
+    return new Promise(resolve => {
+        setTimeout(() => {
+            document.body.removeChild(link);
+            resolve({name});
+        }, 20)
+    })
+}

+ 21 - 0
src/api/system.js

@@ -232,6 +232,27 @@ export function getMenuPermiss(data) {
         url: '/Admin/getMenu',
         method: 'post',
         data
+    }).then(res => {
+        try {
+            const menu = res.Data.find(menu => menu.title === '监管分析');
+            if (!menu.list.find(item => item.jump === '/index/YP-trend')) {
+                menu.list.push({
+                    name: 'JSJK-chart',
+                    id: 'JSJK-chart',
+                    title: '精神健康分析',
+                    type: 'page',
+                    jump: '/index/JSJK-chart',
+                });
+                menu.list.push({
+                    name: 'YP-trend',
+                    id: 'YP-trend',
+                    title: '饮片趋势分析',
+                    type: 'page',
+                    jump: '/index/YP-trend',
+                });
+            }
+        } catch (e) {}
+        return res;
     })
 };
 

+ 29 - 0
src/components/UiNotice.vue

@@ -0,0 +1,29 @@
+<script>
+export default {
+  name: 'UiNotice',
+  props: {
+    /* add edit remove */
+    type: {required: true},
+  },
+  data() {
+    return {
+      centerDialogVisible: false,
+    };
+  },
+  methods: {
+    onClick() {
+      try { this.$confirm('此操作有风险,确定继续吗?', { center: true }); } catch (e) {}
+    },
+  },
+};
+</script>
+
+<template>
+  <div @click="onClick()">
+    <slot></slot>
+  </div>
+</template>
+
+<style scoped lang="scss">
+
+</style>

+ 18 - 0
src/router/dataAnalysis.js

@@ -73,4 +73,22 @@ export default [{
         pftitle: '数据分析'
     }
 },
+    {
+        path: 'YP-trend',
+        name: 'YP-trend',
+        component: () => import('@/views/dataAnalysis/YP-trend.vue'),
+        meta: {
+            title: '饮片趋势分析',
+            pftitle: '数据分析'
+        }
+    },
+    {
+        path: 'JSJK-chart',
+        name: 'JSJK-chart',
+        component: () => import('@/views/dataAnalysis/JSJK-Chart.vue'),
+        meta: {
+            title: '精神健康分析',
+            pftitle: '数据分析'
+        }
+    },
 ] // 

+ 7 - 2
src/views/business/MedicalContol.vue

@@ -91,10 +91,13 @@
           <el-table-column prop="idcard" label="身份证号"></el-table-column>
           <el-table-column prop="namemedicine" label="中医病名"></el-table-column>
           <el-table-column prop="syndrometypes" label="中医病名"></el-table-column>
-          <el-table-column prop="syndrometypes" label="操作" width="80">
+          <el-table-column prop="syndrometypes" label="操作" width="132">
             <template slot-scope="scope">
-              <div>
+              <div style="display: flex;">
                 <el-button size="mini" type="primary" @click="toDetail(scope)">查看</el-button>
+                <ui-notice type="remove" style="margin-left: 10px;">
+                  <el-button size="mini" type="danger">删除</el-button>
+                </ui-notice>
               </div>
             </template>
           </el-table-column>
@@ -135,8 +138,10 @@ import medcalPad from "@/components/ui/outpatientRecords";
 import proup from "@/components/Propup";
 import { mapGetters } from "vuex";
 import {formatPicture} from "@/utils/picture";
+import UiNotice from '@/components/UiNotice.vue';
 export default {
   components: {
+    UiNotice,
     proup,
     medcalPad
   },

+ 429 - 0
src/views/dataAnalysis/JSJK-Chart.vue

@@ -0,0 +1,429 @@
+<template>
+  <div class="druglist">
+    <!-- 顶部筛选 -->
+    <div class="screening">
+      <div class="screening-title flex-vertical-center-l">
+        <img src="~@/assets/filters.png" alt/>
+      </div>
+      <div class="screening-form flex-vertical-center-l flex-wrap">
+        <div class="screening-item flex-vertical-center-l">
+          <div class="input" style="display: flex;">
+            <el-date-picker size="mini" v-model="start" type="month" placeholder="起始年月"
+                            :picker-options="startPickerOptions" format="yyyy-MM" :clearable="false"></el-date-picker>
+            <el-date-picker size="mini" v-model="end" type="month" placeholder="结束年月"
+                            :picker-options="endPickerOptions" format="yyyy-MM"></el-date-picker>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <span>医疗机构名称:</span>
+          <div class="input">
+            <el-select
+                size="mini"
+                v-model="cascader[1]"
+                placeholder="请选择"
+                @change="getCascaderC($event)"
+            >
+              <el-option
+                  :label="item.name"
+                  :value="item.pid"
+                  v-for="(item) in cascaderBOptions"
+                  :key="item.pid"
+              ></el-option>
+            </el-select>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <span>科室名称:</span>
+          <div class="input">
+            <el-select size="mini" v-model="cascader[2]" placeholder="请选择" multiple collapse-tags clearable
+                       @change="getCascaderD('')">
+              <el-option
+                  :label="item.name"
+                  :value="item.pid"
+                  v-for="(item) in cascaderCOptions"
+                  :key="item.pid"
+              ></el-option>
+            </el-select>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <div class="input flex-vertical-center-l">
+            <el-checkbox v-model="checked">是否包含下级</el-checkbox>
+          </div>
+        </div>
+
+        <el-button type="primary" size="mini" @click="search()">搜索</el-button>
+        <el-button type="warning" size="mini" @click="clearFilter()">清空</el-button>
+        <!--<el-button type="primary" size="mini" @click="exportDow()">导出</el-button>-->
+      </div>
+    </div>
+
+    <!-- 展示数据层 -->
+    <div class="showData">
+      <!-- 展示两种数据 -->
+      <div class="showEcharts">
+        <div id="myChart" :style="{width: '100%'}" class="myCharts"></div>
+        <div class="e-format" style="margin-bottom:20px;">
+          格式:量级维度-时间:数量
+          <span style="margin-left:30px;"></span> X轴:时间 Y轴:单位(次)
+        </div>
+      </div>
+      <div class="showEcharts">
+        <div style="font-size: 18px;font-weight: 700;text-align: center;">体质与精神状态分布图</div>
+        <div class="pie-wrapper">
+          <div class="pie-container" v-for="(pie) in pieSeries">
+            <div class="pie-chart" :data-name="pie.name"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import {getDepartSelect, getDoctorSelect} from "@/api/system.js";
+import {medicalInstitution} from "@/api/city";
+import {getJSJK_BarChartData, getJSJK_PieChartData} from '@/api/dataAnalysis';
+import {formatMonth, subtractMonths} from "@/utils/format";
+import {mapGetters} from "vuex";
+import dayjs from 'dayjs';
+
+export default {
+  data() {
+    return {
+      loadDoctorSelect: false,
+      cascaderAOptions: [],
+      cascaderBOptions: [],
+      cascaderCOptions: [],
+      cascaderDOptions: [],
+      cascader: [],
+      checked: false,
+      start: subtractMonths(-12),
+      end: new Date(),
+
+      xAxisData: [],
+      series: [],
+      pieSeries: [],
+
+      page: 1,
+      limit: 10,
+      total: 0,
+
+
+      startPickerOptions: {
+        disabledDate: (date) => {
+          const value = date.getTime();
+          return this.end && value > this.end.getTime() || value > Date.now()
+        }
+      },
+      endPickerOptions: {
+        disabledDate: (date) => {
+          const value = date.getTime();
+          return this.start && value < this.start.getTime() || value > Date.now()
+        }
+      }
+    };
+  },
+  created() {
+    this.getCascaderB(this.getuserinfo.organizationid);
+  },
+  mounted() {
+    this.load();
+  },
+  methods: {
+    search() {
+      this.load();
+    },
+    clearFilter() {
+      this.getCascaderB(this.getuserinfo.organizationid)
+      this.orderType = void 0;
+      this.start = subtractMonths(-12);
+      this.end = new Date();
+
+      this.search();
+    },
+    exportDow() {},
+    // 获取医疗机构选择器
+    async getCascaderB(id) {
+      this.cascader = [id, '', [], []];
+      this.cascaderBOptions = []
+      this.cascaderCOptions = []
+      this.cascaderDOptions = []
+      let res = await medicalInstitution({organizationId: id});
+      if (res.ResultCode == 0) { this.cascaderBOptions = res.Data; }
+    },
+    // 获取医疗机构下的科室
+    async getCascaderC(id) {
+      this.cascader = [this.cascader[0], id, [], []];
+      let res = await getDepartSelect({institutionId: id});
+      if (res.ResultCode == 0) { this.cascaderCOptions = res.Data; }
+
+      await this.getCascaderD().catch();
+    },
+    async getCascaderD(keyword) {
+      if (!this.cascader[1]) return;
+      this.loadDoctorSelect = true;
+      const res = await getDoctorSelect({
+        keyword,
+        organizationid: this.cascader[0] || '',
+        sititutionid: this.cascader[1] || '',
+        departmentsIds: this.cascader[2] || [],
+      })
+      if (res.ResultCode == 0) {
+        this.cascaderDOptions = res.Data.Items;
+      }
+      this.loadDoctorSelect = false;
+    },
+    // 获取列表
+    async load() {
+      let params = {
+        startMon: formatMonth(this.start),
+        endMon: formatMonth(this.end),
+        orgId: this.cascader[0] || '',
+        stiId: this.cascader[1] || '',
+        deptId: '',
+        deptIds: this.cascader[2] || [],
+        doctorIds: this.cascader[3] || [],
+      };
+      this.load2(params);
+
+      const length = dayjs(params.endMon).diff(params.startMon, 'month');
+      this.xAxisData = Array.from({length: length + 1}, (_, i) => dayjs(params.startMon).add(i, 'month').format('YYYY-MM'));
+      let data = await getJSJK_BarChartData(params);
+      const series = new Map();
+      this.xAxisData.forEach((key, index) => {
+        try {
+          for (const [name, value] of Object.entries(data[key])) {
+            if (!series.has(name)) series.set(name, {name, type: 'bar', data: []});
+            series.get(name).data.push(value);
+          }
+        } catch (e) {}
+      });
+      this.series = [...series.values()];
+      this.list = data;
+
+      this.drawLine();
+    },
+    async load2(params) {
+      this.pieSeries = [];
+      const data = await getJSJK_PieChartData(params);
+      for (const [name, value] of Object.entries(data)) {
+        this.pieSeries.push({name: name, value: value});
+        this.$nextTick(() => {
+          const el = document.querySelector(`[data-name="${name}"].pie-chart`);
+          const chart = this.$echarts.init(el);
+          chart.setOption({
+            title: {text: name, bottom: '10%', left: 'center'},
+            tooltip: {trigger: 'item'},
+            series: [
+              {
+                name: name,
+                type: 'pie',
+                radius: '60%',
+                data: Object.entries(value).map(([name, value]) => ({name, value})),
+                emphasis: {
+                  itemStyle: {
+                    shadowBlur: 10,
+                    shadowOffsetX: 0,
+                    shadowColor: 'rgba(0, 0, 0, 0.5)',
+                  },
+                },
+              },
+            ],
+          });
+          console.log(el);
+        });
+        // let chart = this.$echarts.init();
+      }
+      console.log(this.pieSeries);
+    },
+    drawLine() {
+      // 基于准备好的dom,初始化echarts实例
+      let myChart = this.$echarts.init(document.getElementById("myChart"));
+      // 绘制图表
+      myChart.setOption({
+        grid: {
+          left: "1%",
+          right: "1%",
+          bottom: "3%",
+          containLabel: true
+        },
+        title: {
+          text: `精神健康柱状图`,
+          left: 'center',
+        },
+        legend: {
+          top: '32px',
+        },
+        tooltip: {trigger: 'axis'},
+        xAxis: {type: "category", data: this.xAxisData},
+        yAxis: {type: "value"},
+        series: this.series,
+      });
+    }
+  },
+  computed: {
+    ...mapGetters(["getuserinfo"])
+  }
+};
+</script>
+<style lang="scss" scoped>
+.pie-wrapper {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-evenly;
+  .pie-container {
+    $size: 500px;
+    margin: 10px 0;
+    width: 30vw;
+    height: 30vw;
+    max-width: 500px;
+    max-height: 400px;
+  }
+  .pie-chart {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>
+<style lang="scss" scoped>
+@import "../../style/common.scss";
+@import "../../style/base.scss";
+
+.showData {
+  background: #fff;
+  border-radius: 10px;
+  margin-top: 5px;
+  padding: 10px;
+  height: 71vh;
+  overflow: auto;
+
+  .top-change {
+    margin-bottom: 20px;
+    width: 100px;
+    height: 34px;
+    border-radius: 8px;
+    cursor: pointer;
+    border: 1px solid #dcdfe6;
+    font-size: 14px;
+
+    div:first-child {
+      border-radius: 8px 0 0 8px;
+    }
+
+    div:last-child {
+      border-radius: 0 8px 8px 0;
+    }
+
+    div {
+      height: 34px;
+      width: 50px;
+      box-sizing: border-box;
+      line-height: 34px;
+      text-align: center;
+    }
+
+    .choosed {
+      background: #9F643A;
+      color: #fff;
+    }
+  }
+
+  .bg-yellow {
+    border-radius: 8px;
+    background: #ffae45;
+    color: #fff;
+    width: 74px;
+    height: 34px;
+    margin-bottom: 20px;
+    cursor: pointer;
+    margin-left: 20px;
+  }
+
+  .showEcharts {
+    width: 100%;
+
+    .myCharts {
+      height: 360px;
+    }
+  }
+
+  .showList {
+    width: 100%;
+
+    ul {
+      li {
+        padding: 15px;
+        border-bottom: 1px solid #dcdfe6;
+      }
+
+      li:hover {
+        background: #dcdfe6;
+        cursor: default;
+      }
+
+      .title {
+        font-weight: bold;
+        color: #9F643A;
+        width: 90px;
+      }
+    }
+  }
+}
+</style>
+<style lang="scss" scoped>
+@media screen and (min-width: 1681px) and (max-width: 1920px) {
+  .showData {
+    height: 81vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 500px;
+      }
+    }
+  }
+}
+
+@media screen and (min-width: 1601px) and (max-width: 1680px) {
+  .showData {
+    height: 80vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 500px;
+      }
+    }
+  }
+}
+
+@media screen and (min-width: 1361px) and (max-width: 1600px) {
+  .showData {
+    height: 73vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 410px;
+      }
+    }
+  }
+}
+
+@media screen and(min-width: 1281px) and (max-width: 1360px) {
+  .showData {
+    height: 73vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 410px;
+      }
+    }
+  }
+}
+</style>

+ 465 - 0
src/views/dataAnalysis/YP-trend.vue

@@ -0,0 +1,465 @@
+<template>
+  <div class="doctorWork">
+    <!-- 顶部筛选 -->
+    <div class="screening">
+      <div class="screening-title flex-vertical-center-l">
+        <span></span>
+        <div>筛选</div>
+      </div>
+      <div class="screening-form flex-vertical-center-l flex-wrap">
+        <div class="screening-item flex-vertical-center-l">
+          <span>年度:</span>
+          <div class="input">
+            <el-date-picker
+              size="mini"
+              @change="yearBlur"
+              v-model="form.year"
+              type="year"
+              placeholder="选择年"
+              :clearable="false"
+            ></el-date-picker>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <span>月度:</span>
+          <div class="input">
+            <el-date-picker
+              size="mini"
+              v-model="form.month"
+              format="MM"
+              type="month"
+              placeholder="选择月"
+            ></el-date-picker>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <span>机构名称:</span>
+          <div class="input">
+            <el-select size="mini" v-model="form.medName" placeholder="请选择">
+              <el-option
+                :label="item.name"
+                :value="item.pid"
+                v-for="(item,index) in medSelectList"
+                :key="index"
+              ></el-option>
+            </el-select>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l">
+          <div class="input flex-vertical-center-l">
+            <el-checkbox v-model="form.checked">是否包含下级</el-checkbox>
+          </div>
+        </div>
+        <div class="screening-item flex-vertical-center-l" v-if="false">
+          <div class="input">
+            <el-select size="mini" v-model="form.depart" placeholder="请选择">
+              <el-option label="全部科室" :value="1"></el-option>
+              <el-option label="中医内科" :value="2"></el-option>
+              <el-option label="康复科" :value="3"></el-option>
+            </el-select>
+          </div>
+        </div>
+        <ui-notice type="add" style="margin-right: 10px;">
+          <el-button size="mini">下发</el-button>
+        </ui-notice>
+        <el-button size="mini" type="primary" @click="search">搜索</el-button>
+        <el-button size="mini" type="warning" @click="clearFilter">清空</el-button>
+      </div>
+    </div>
+    <!-- 展示数据层 -->
+    <div class="showData" style="position: relative;">
+      <div style="display: flex; position: absolute; right: 24px;">
+        <ui-notice type="add" style="margin-left: 10px;">
+          <el-button size="mini" type="success">新增</el-button>
+        </ui-notice>
+        <ui-notice type="edit" style="margin-left: 10px;">
+          <el-button size="mini" type="warning">修改</el-button>
+        </ui-notice>
+        <ui-notice type="remove" style="margin-left: 10px;">
+          <el-button size="mini" type="danger">删除</el-button>
+        </ui-notice>
+      </div>
+      <!-- 展示两种数据 -->
+      <div class="showEcharts" v-if="isEcharts==0">
+        <div id="myChart" :style="{width: '100%'}" class="myCharts"></div>
+        <div class="e-format">
+          格式:时间:数量
+          <span style="margin-left:30px;"></span> X轴:时间 Y轴:单位(个)
+        </div>
+      </div>
+      <!-- 列表展示 -->
+      <div class="showList" v-if="isEcharts==1">
+        <ul>
+          <li class="flex-vertical-between" v-for="(item,index) in list" :key="index">
+            <div class="title">{{index}}</div>
+            <div v-for="(value, name) in item" :key="name">
+              {{name}}:{{value}}
+            </div>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
+import { medicalInstitution } from "@/api/city.js";
+import {getHospitalWork, exportDow, getYPTrendData, exportYPTrendChart} from '@/api/dataAnalysis.js';
+import UiNotice from '@/components/UiNotice.vue';
+export default {
+  components: {UiNotice},
+  data() {
+    return {
+      // 筛选数据
+      form: {
+        medName: "",
+        year: "",
+        month: "",
+        checked: false,
+        depart: 1
+      },
+      isFinish: 1, // 上一段函数 是否完成
+      // 医疗机构
+      medSelectList: [],
+      // 是否是图表
+      isEcharts: 0, // 0 图表 1 列表
+
+      list: [], // 列表
+
+      xAxisData: [], // 图表 横向坐标
+      series: [], // 图表 系列
+    };
+  },
+  created() {},
+  mounted() {
+    let date = new Date();
+    this.form.year = date.getFullYear().toString();
+
+    this.medicalInstitution();
+    this.getYPTrend();
+  },
+  filters: {
+    formMatD(value) {
+      let date = new Date(value);
+      let year = date.getFullYear();
+      let month = date.getMonth() + 1;
+
+      return year;
+    }
+  },
+  methods: {
+    // 年份失去焦点
+    yearBlur(e) {
+      if (!e || e.length > 4 || e.length < 4) {
+        let date = new Date();
+        this.form.year = date.getFullYear().toString();
+      }
+    },
+    // 顶部列表更改
+    topChange(type) {
+      this.isEcharts = type;
+      if (type == 0) {
+        setTimeout(() => {
+          this.drawLine();
+          // this.drawLine2()
+        }, 200);
+      }
+    },
+    // 绘制 图表
+    drawLine() {
+      // 基于准备好的dom,初始化echarts实例
+      let myChart = this.$echarts.init(document.getElementById("myChart"));
+      // 绘制图表
+      myChart.setOption({
+        grid: {
+          left: "1%",
+          right: "1%",
+          bottom: "3%",
+          containLabel: true
+        },
+        title: {
+          text: `排名前${Math.max(10, this.series.length)}的药品`,
+        },
+        legend: {},
+        color: [
+          "#5FA0FA",
+          "#FFB703",
+          "#1bb2d8",
+          "#FD2446",
+          "#51CEC6",
+          "#5470c6",
+          "#FB925A",
+          "#9a60b4",
+          "#ea7ccc",
+          "#91cc75",
+        ],
+        tooltip: {},
+        xAxis: {
+          type: "category",
+          data: this.xAxisData,
+          name: "时间",
+          nameLocation: "end"
+        },
+        yAxis: {
+          type: "value"
+          // name: "单位(个)"
+        },
+        series: this.series,
+      });
+    },
+    search() {
+      this.xAxisData = []; // 图表 横向坐标
+      this.series = []; // 图表 横向坐标
+      this.getYPTrend();
+    },
+    clearFilter() {
+      let date = new Date();
+
+      this.form = {
+        medName: "",
+        year: date.getFullYear().toString(),
+        month: "",
+        checked: false,
+        depart: 1
+      };
+      this.xAxisData = []; // 图表 横向坐标
+
+      if (this.isFinish == 0) return;
+      this.getYPTrend();
+    },
+    // 处理选择器 时间数据
+    forMatDate(type, data) {
+      if (!data) return "";
+      // type : 0 year 1 month
+      let date = new Date(data);
+      let year = date.getFullYear();
+      let month = date.getMonth() + 1;
+      if (type == 0) {
+        return year;
+      } else if (type == 1) {
+        return month.toString().padStart(2, "0");
+      }
+    },
+    // 获取医疗机构选择器
+    async medicalInstitution() {
+      let params = {
+        organizationId: this.getuserinfo.organizationid
+      };
+      let res = await medicalInstitution(params);
+      if (res.ResultCode == 0) {
+        this.medSelectList = res.Data;
+      }
+    },
+    // 获取饮片趋势分析数据
+    async getYPTrend() {
+      if (!this.form.month) {
+        for (let i = 1; i <= 12; i++) {
+          let xAxis = this.forMatDate(0, this.form.year) + "-" + i.toString().padStart(2, "0") + "月";
+          this.xAxisData.push(xAxis);
+        }
+      } else {
+        this.xAxisData = [
+          this.forMatDate(0, this.form.year) +
+          "-" +
+          this.forMatDate(1, this.form.month) +
+          "月"
+        ];
+      }
+      
+      this.isFinish = 0; //
+      let params = {
+        month: this.forMatDate(1, this.form.month),
+        stiId: this.form.medName,
+        type: this.form.checked ? "0" : "1",
+        year: this.forMatDate(0, this.form.year)
+      };
+      let data = await getYPTrendData(params);
+      const series = new Map();
+      this.xAxisData.forEach((key, index) => {
+        try {
+          for (const [name, value] of Object.entries(data[key])) {
+            if (!series.has(name)) series.set(name, {name, type: 'bar', data: []});
+            series.get(name).data.push(value);
+          }
+        } catch (e) {}
+      });
+      this.series = [...series.values()];
+      this.list = data;
+      setTimeout(() => {
+        this.isFinish = 1;
+        this.drawLine();
+      }, 200);
+    },
+    // 表导出
+    async exportYPTrend() {
+      let params = {
+        month: this.forMatDate(1, this.form.month),
+        stiId: this.form.medName,
+        type: this.form.checked ? "0" : "1",
+        year: this.forMatDate(0, this.form.year)
+      };
+      const loading = this.$loading({
+        lock: true,
+        text: "正在导出,请稍后",
+        spinner: "el-icon-loading",
+        background: "rgba(0, 0, 0, 0.7)"
+      });
+      try {
+        await exportYPTrendChart(params);
+        this.$message({
+          type: "success",
+          message: "导出成功",
+          showClose: true
+        });
+      } catch (e) { }
+      loading.close();
+    }
+  },
+  computed: {
+    ...mapGetters(["getuserinfo"])
+  }
+};
+</script>
+<style lang="scss" scoped>
+@import "../../style/common.scss";
+@import "../../style/base.scss";
+
+.showData {
+  background: #fff;
+  border-radius: 10px;
+  margin-top: 5px;
+  padding: 10px;
+  height: 71vh;
+  overflow: auto;
+
+  .top-change {
+    margin-bottom: 10px;
+    width: 100px;
+    height: 34px;
+    border-radius: 8px;
+    cursor: pointer;
+    border: 1px solid #dcdfe6;
+    font-size: 14px;
+
+    div:first-child {
+      border-radius: 8px 0 0 8px;
+    }
+
+    div:last-child {
+      border-radius: 0 8px 8px 0;
+    }
+
+    div {
+      height: 34px;
+      width: 50px;
+      box-sizing: border-box;
+      line-height: 34px;
+      text-align: center;
+    }
+
+    .choosed {
+      background: #9F643A;
+      color: #fff;
+    }
+  }
+
+  .bg-yellow {
+    border-radius: 8px;
+    background: #ffae45;
+    color: #fff;
+    width: 74px;
+    height: 34px;
+    margin-bottom: 20px;
+    cursor: pointer;
+    margin-left: 20px;
+  }
+
+  .showEcharts {
+    width: 100%;
+
+    .myCharts {
+      height: 340px;
+    }
+  }
+
+  .showList {
+    width: 100%;
+
+    ul {
+      li {
+        padding: 15px;
+        border-bottom: 1px solid #dcdfe6;
+      }
+
+      li:hover {
+        background: #dcdfe6;
+        cursor: default;
+      }
+
+      .title {
+        font-weight: bold;
+        color: #9F643A;
+        width: 90px;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss" scoped>
+@media screen and (min-width: 1681px) and (max-width: 1920px) {
+  .showData {
+    height: 81vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 400px;
+      }
+    }
+  }
+}
+
+@media screen and (min-width: 1601px) and (max-width: 1680px) {
+  .showData {
+    height: 80vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 400px;
+      }
+    }
+  }
+}
+
+@media screen and (min-width: 1361px) and (max-width: 1600px) {
+  .showData {
+    height: 73vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 360px;
+      }
+    }
+  }
+}
+
+@media screen and(min-width:1281px) and (max-width: 1360px) {
+  .showData {
+    height: 73vh;
+
+    .showEcharts {
+      width: 100%;
+
+      .myCharts {
+        height: 360px;
+      }
+    }
+  }
+}
+</style>

+ 5 - 1
src/views/knowledge/Disease.vue

@@ -22,7 +22,9 @@
                 </div> -->
                 <el-button size="mini" type="primary" @click="search">搜索</el-button>
                 <el-button size="mini" type="warning" @click="clearFilter">清空</el-button>
-
+                <ui-notice type="add" style="margin-left: 10px;">
+                  <el-button size="mini" type="success">新增</el-button>
+                </ui-notice>
             </div>
             <!-- <div class="total">
                 共 <span>123</span>味药
@@ -58,7 +60,9 @@
         getDiseaseList,
         getDiseaseClass
     } from '@/api/knowledge.js'
+    import UiNotice from '@/components/UiNotice.vue';
     export default {
+        components: {UiNotice},
         data() {
             return {
                 form: {

+ 9 - 1
src/views/knowledge/DiseaseD.vue

@@ -1,8 +1,14 @@
 <template>
   <div class="recipeAuditD flex-plane-center-top">
     <div class="recipe-left">
-      <div style="margin-bottom:10px;">
+      <div style="margin-bottom:10px; display: flex;">
         <el-button size="small" type="primary" @click="$router.back()">返回</el-button>
+        <ui-notice type="edit" style="margin-left: 10px;">
+          <el-button size="small" type="warning">修改</el-button>
+        </ui-notice>
+        <ui-notice type="remove" style="margin-left: 10px;">
+          <el-button size="small" type="danger">删除</el-button>
+        </ui-notice>
       </div>
       <div class="msg">
         <div class="msg-item flex-plane-center-l">
@@ -60,7 +66,9 @@
 </template>
 <script>
 import { getDiseasetDetail } from "@/api/knowledge.js";
+import UiNotice from '@/components/UiNotice.vue';
 export default {
+  components: {UiNotice},
   data() {
     return {
       info: {},

+ 13 - 2
src/views/knowledge/DoctorCase.vue

@@ -29,6 +29,9 @@
         <el-button size="mini" type="primary" @click="search">搜索</el-button>
         <el-button size="mini" type="warning" @click="clearFilter">清空</el-button>
         <el-button size="mini" type="warning" @click="$router.back()">返回</el-button>
+        <ui-notice type="add" style="margin-left: 10px;">
+          <el-button size="mini" type="success">新增</el-button>
+        </ui-notice>
 
         <!-- <div class="screen-btn flex-center" @click="search">
                     <img src="../../assets/search.png" alt="">
@@ -50,13 +53,19 @@
           <el-table-column prop="therapy" label="治法" align="center"></el-table-column>
           <el-table-column prop="attendingexpert" label="专家" width="80" align="center"></el-table-column>
           <el-table-column prop="book" label="出处"></el-table-column>
-          <el-table-column label="操作" width="80" align="center">
+          <el-table-column label="操作" width="220" align="center">
             <template slot-scope="scope">
-              <div class="operation">
+              <div class="operation" style="display: flex">
+                <ui-notice type="add" style="background-color: #e6a23c;">
+                  <span>编辑</span>
+                </ui-notice>
                 <div
                   class="flex-center"
                   @click="$router.push({path:'/index/doctorcased?verifyid='+scope.row.verifyid})"
                 >查看</div>
+                <ui-notice type="remove" style="background-color: #f56c6c;">
+                  <span>删除</span>
+                </ui-notice>
               </div>
             </template>
           </el-table-column>
@@ -76,8 +85,10 @@
 </template>
 <script>
 import { getDoctorCaseL } from "@/api/knowledge.js";
+import UiNotice from '@/components/UiNotice.vue';
 
 export default {
+  components: {UiNotice},
   data() {
     return {
       form: {

+ 6 - 1
src/views/patients/PatiensList.vue

@@ -73,11 +73,14 @@
                             {{scope.row.province}}{{scope.row.city}}{{scope.row.district}}{{scope.row.detailadress}}
             </template>-->
           </el-table-column>
-          <el-table-column prop="state" label="操作" width="140">
+          <el-table-column prop="state" label="操作" width="200">
             <template slot-scope="scope">
               <div class="flex-center flex-wrap">
                 <div class="find-detail find-fill" v-if="showJiuzhen" @click="seeDoctors(scope)">挂号</div>
                 <div class="find-detail" @click="edit(scope.row.pid)" v-if="showEdit">编辑</div>
+                <ui-notice type="remove" class="find-detail" style="background-color: #f56c6c; border-color: #f56c6c">
+                  <span>删除</span>
+                </ui-notice>
               </div>
             </template>
           </el-table-column>
@@ -271,8 +274,10 @@ import {
   registration
 } from "@/api/patients.js";
 import { getDepartSelect } from "@/api/system";
+import UiNotice from '@/components/UiNotice.vue';
 export default {
   components: {
+    UiNotice,
     pagePropup
   },
   data() {

+ 12 - 2
src/views/system/insurance.vue

@@ -22,9 +22,17 @@
           </el-table-column>
           <el-table-column prop="updateTime" label="修改时间" width="180" align="center"></el-table-column>
           <el-table-column prop="name" label="修改人" width="180" align="center"></el-table-column>
-          <el-table-column prop="updateUser" label="操作" width="180" align="center">
+          <el-table-column prop="updateUser" label="操作" width="200" align="center">
             <template slot-scope="scope">
-              <el-button type="primary" size="mini" @click="editItem(scope.row)">修改</el-button>
+              <div style="display: flex; justify-content: center;">
+                <ui-notice v-if="scope.row.key === 'rational_safe'" type="add" style="margin-right: 10px;">
+                  <el-button size="mini" type="success">新增</el-button>
+                </ui-notice>
+                <el-button type="primary" size="mini" @click="editItem(scope.row)">修改</el-button>
+                <ui-notice type="remove" style="margin-left: 10px;">
+                  <el-button size="mini" type="danger">删除</el-button>
+                </ui-notice>
+              </div>
             </template>
           </el-table-column>
         </el-table>
@@ -70,8 +78,10 @@
 <script>
 import { getInsuranceList, editInsurance } from "@/api/system";
 import popup from "@/components/Propup.vue";
+import UiNotice from '@/components/UiNotice.vue';
 export default {
   components: {
+    UiNotice,
     popup
   },
   data() {