Browse Source

客户中心调整

master
肖正 4 weeks ago
parent
commit
8726d9f50d
  1. 1
      package.json
  2. 2
      public/config.js
  3. 10
      src/api/api.ts
  4. 16
      src/api/equipment.ts
  5. BIN
      src/assets/M9_01.png
  6. BIN
      src/assets/M9_02.png
  7. BIN
      src/assets/star.png
  8. 4
      src/views/HealthLayout/area.vue
  9. 2
      src/views/HealthLayout/cityPostion.js
  10. 80
      src/views/HealthLayout/index.vue
  11. 11
      src/views/customer/edit.vue
  12. 6
      src/views/customer/editGenetic.vue
  13. 1
      src/views/customer/index.vue
  14. 21
      src/views/customer/info.vue
  15. 114
      src/views/pages/regulatory/index.vue

1
package.json

@ -10,6 +10,7 @@
"build-api": "cd api_build/ && build.bat"
},
"dependencies": {
"@antv/x6": "^2.18.1",
"@element-plus/icons-vue": "^2.3.1",
"@microsoft/signalr": "^8.0.0",
"@vue-flow/additional-components": "^1.3.3",

2
public/config.js

@ -3,5 +3,5 @@ window.__env__ = {
"VITE_OPEN": "false",
"VITE_OPEN_CDN": "false",
"VITE_PUBLIC_PATH": "",
"VITE_API_URL": ""
"VITE_API_URL": "http://cloud.bodk.com.cn"
}

10
src/api/api.ts

@ -33,6 +33,8 @@ export function getTumor(code) {
method: 'get',
});
}
// 新增基因报告
export function addGeneReport(data) {
return request({
url: `/api/geneReport/report`,
@ -40,9 +42,17 @@ export function addGeneReport(data) {
data,
});
}
// 获取基因报告
export function getGeneReport(customerId) {
return request({
url: `/api/geneReport/list/${customerId}`,
method: 'get',
});
}
// 获取存下的细胞列表
export function getCellList() {
return request({
url: `/api/support/getCellList`,
method: 'post',
});
}

16
src/api/equipment.ts

@ -1,11 +1,10 @@
import request from '/@/utils/request';
// import type { ResultData } from './common';
export function getEquipmentList(data?: object) {
return request({
url: '/api/sysEquipment/equipmentList',
data,
data,
method: 'post',
});
}
@ -13,7 +12,7 @@ export function getEquipmentList(data?: object) {
export function add(data?: object) {
return request({
url: '/api/sysEquipment/add',
data,
data,
method: 'post',
});
}
@ -21,7 +20,7 @@ export function add(data?: object) {
export function update(data?: object) {
return request({
url: '/api/sysEquipment/update',
data,
data,
method: 'post',
});
}
@ -29,7 +28,14 @@ export function update(data?: object) {
export function del(data?: object) {
return request({
url: '/api/sysEquipment/delete',
data,
data,
method: 'post',
});
}
export function list(data?: object) {
return request({
url: '/api/device/list',
data,
method: 'post',
});
}

BIN
src/assets/M9_01.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 KiB

After

Width:  |  Height:  |  Size: 898 KiB

BIN
src/assets/M9_02.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

BIN
src/assets/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

4
src/views/HealthLayout/area.vue

@ -22,7 +22,9 @@
<div class="content" style="margin-left: 0;">{{val.city}}基地</div>
</template>
<!-- <div class="content-left">{{val.city}}</div> -->
<div class="content" v-for="(city, k) in val.list" :key="k">{{city.name}}</div>
<div class="content" v-for="(city, k) in val.list" :key="k">
<a :href="city.url" style="color: #fff;" target="_blank">{{city.name}}</a>
</div>
</el-collapse-item>
</div>
</div>

2
src/views/HealthLayout/cityPostion.js

@ -224,7 +224,7 @@ export const mockData2 = [
{ name: '西湖健康中心', value: 245223 },
],
},
{ city: '南昌', list: [{ name: '南昌健康中心', value: 245223 }] },
{ city: '江西', list: [{ name: '湖口健康中心', value: 245223, url: 'http://hukou.bodk.com.cn/#/' }] },
{ city: '厦门', list: [{ name: '厦门健康中心', value: 245223 }] },
{ city: '宁波', list: [{ name: '宁波健康中心', value: 245223 }] },
{ city: '合肥', list: [{ name: '合肥健康中心', value: 245223 }] },

80
src/views/HealthLayout/index.vue

@ -27,16 +27,16 @@ let height = ref(0);
import * as echarts from 'echarts';
import Area from './area.vue';
import { getCityPositionByName, } from './cityPostion'
import { useRouter } from 'vue-router';
const router = useRouter();
// import { useRouter } from 'vue-router';
// const router = useRouter();
// 10
let mockData = [
{ name: '北京', value: 11500 },
{ name: '天津', value: 1200 },
{ name: '河南', value: 2300 },
{ name: '广西', value: 1300 },
{ name: '广东', value: 9300 },
{ name: '北', value: 5300 },
// { name: '', value: '' },
// { name: '', value: 1200 },
// { name: '', value: 2300 },
{ name: '西', value: '湖口' },
{ name: '广东', value: '松山湖' },
{ name: '北', value: '宜昌' },
];
const state = reactive({
loading: false,
@ -69,7 +69,7 @@ const init = async () => {
// })
// })
// console.log(88888, data);
// echarts.graphic.registerSymbol('star', 'path://M25.6 0L33 9.4l10-1.2c0.9-0.1 1.3 1.1 0.6 1.7l-7.5 6.9 1.8 10c0.1 0.9-0.8 1.6-1.6 1.2L25 25.6l-9.3 4.6c-0.8 0.4-1.7-0.3-1.6-1.2l1.8-10-7.5-6.9c-0.7-0.6-0.3-1.8 0.6-1.7l10 1.2L22.4 0c0.6-0.9 1.8-0.9 2.4 0z')
let initMap = echarts.init(document.querySelector('#mapDom'))
initMap.on('click', mapClick);
initMap.setOption({
@ -121,8 +121,8 @@ const init = async () => {
disabled: true,
},
itemStyle: {
areaColor: '#00000000',
borderColor: '#00000000',
areaColor: '#000',
borderColor: '#000',
},
}],
z: 1,
@ -170,6 +170,57 @@ const init = async () => {
z: 2,
// data: data,
},
//
{
type: "effectScatter",
coordinateSystem: "geo",
data:data,//
symbolSize: 6,//
showEffectOn: "render",
//
rippleEffect: {
brushType: "stroke",
color: "#fcdd6e",
period: 10,//
scale: 5//
},
hoverAnimation: true,//
//
itemStyle: {
color: "#fcdd6e",
shadowBlur: 2,
shadowColor: "#333"
},
//
tooltip: {
show: false,
triggerOn:"click",
formatter: function(data1) {
console.log(data1)
let data2 = data1.data;
return `<b>${data2.value[2]}<b>`
}
},
zlevel: 1
},
{
type: "scatter",
coordinateSystem: "geo",
data:[
{name: '北京', value: ['116.3979471', '39.9081726'] }
],//
symbol: 'path://M512 40.36l73.41 202.59h211.8l-171.18 124.37 66.18 202.59-171.21-124.39-171.21 124.39 66.18-202.59-171.18-124.37h211.8z',
symbolSize: 20,//
//
itemStyle: {
color: '#ffde00',
borderColor: '#ff6700',
borderWidth: 2,
shadowBlur: 10,
shadowColor: '#333'
},
zlevel: 1
}
// {
// type: 'scatter',
// coordinateSystem: 'geo',
@ -192,7 +243,12 @@ const init = async () => {
})
}
const mapClick = (item) => {
router.push({name: 'home', query: {name: item.name}});
if (!item.value) return;
const a = document.createElement('a');
a.setAttribute('href', 'http://hukou.bodk.com.cn/#/');
a.setAttribute('target', '_blank');
a.click();
// router.push({name: 'home', query: {name: item.name}});
}
</script>
<style>

11
src/views/customer/edit.vue

@ -22,8 +22,8 @@
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="性别" prop="isMale" :rules="[{ required: true, message: '性别不能为空', trigger: 'blur' }]">
<el-radio-group v-model="state.ruleForm.isMale">
<el-radio :value="false"></el-radio>
<el-radio :value="true"></el-radio>
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -104,6 +104,13 @@ const state = reactive({
const openDialog = (row: any) => {
state.ruleForm = JSON.parse(JSON.stringify(row));
fileList.value = [];
if (row.voiceUrl) {
let arr = row.voiceUrl.split('/');
fileList.value = [{
name: arr[arr.length - 1],
url: row.voiceUrl
}];
}
state.isShowDialog = true;
ruleFormRef.value?.resetFields();
};

6
src/views/customer/editGenetic.vue

@ -125,6 +125,12 @@
</el-select>
</el-form-item>
</el-col>
<el-col :xs="12" :sm="8" :md="8" :lg="8" :xl="8" class="mb20">
<el-form-item>
<el-button type="danger" v-if="state.ruleForm.tumors.length>1"
@click="state.ruleForm.tumors.splice(i, 1)">删除当前类型</el-button>
</el-form-item>
</el-col>
</el-row>
<div><el-button type="primary" @click="state.ruleForm.tumors.push({})">新增检测类型</el-button></div>
</el-form>

1
src/views/customer/index.vue

@ -23,6 +23,7 @@
<el-card class="full-table" shadow="hover" style="margin-top: 5px">
<el-table :data="state.tableData" v-loading="state.loading" row-key="id" border>
<el-table-column type="index" label="序号" align="center" show-overflow-tooltip />
<el-table-column prop="name" label="客户名称" align="center" show-overflow-tooltip />
<el-table-column label="形象" width="150" align="center" show-overflow-tooltip>
<template #default="scope">

21
src/views/customer/info.vue

@ -15,7 +15,7 @@
<h1 class="heading">{{state.ruleForm.name}}的生命数据库</h1>
<p class="pera-title">Obviously I'm a Web Designer. Web Developer with over 3 years of experience. Experienced with all stages of the development</p>
<div class="hero-btn">
<el-button type="primary" size="default" @click="scrollTo('medical-report')">体检报告</el-button>
<el-button type="primary" size="default" @click="scrollTo('medical-report')">查看体检报告</el-button>
<el-button size="default" @click="scrollTo('cell-message')">细胞储存信息</el-button>
</div>
</div>
@ -39,7 +39,9 @@
<div class="container-title">
<h2>体检报告</h2>
<p class="pera-title">体检时间{{item?.submissionTime.split(' ')[0]}}报告时间{{item.reportTime.split(' ')[0]}}
样本类型{{item.sampleType}}检测项目{{item.testingType}}检测技术{{item.testingMethod}}</p>
样本类型{{item.sampleType}}检测项目{{item.testingType}}检测技术{{item.testingMethod}}
<el-button type="primary" size="default" text @click="downloadFile(item)">下载体检报告
</el-button></p>
</div>
<div class="content-box">
<div class="content-item" v-for="(tumor, i) in item.tumors" :key="i" @click="tumorShow(tumor)">
@ -50,7 +52,7 @@
</div>
<h3>{{tumor.tumorName}}</h3>
<p class="text-light-muted after">中国人群{{ tumor.tumorName }}平均遗传风险为 <span class="risk-score">{{tumor.avaRiskScore}}</span>;</p>
<p class="text-light-muted after">您的遗传风险值为 <span class="risk-score">{{ tumor.riskScore }}</span>
<p class="text-light-muted after">您的遗传风险值为 <span class="risk-score">{{ tumor.riskScore.toFixed(2) }}</span>
是平均遗传风险的<span class="risk-score">{{ (tumor.riskScore/tumor.avaRiskScore).toFixed(2) }}</span>
处于<span class="risk-score" :style="tumor.riskScore/tumor.avaRiskScore>=1.1?'color:red':''"
>{{ getRiskLevel(tumor) }} </span>风险<span class="risk-score">{{ tumor.riskLevel }} </span> </p>
@ -148,7 +150,6 @@
</template>
<script lang="ts" setup name="customerInfo">
import { ref, reactive, computed } from 'vue'
// import { ElMessageBox, } from 'element-plus'
import { CloseBold } from '@element-plus/icons-vue'
import type { DrawerProps } from 'element-plus'
import { getGeneReport } from '/@/api/api';
@ -191,8 +192,7 @@ const audioClick = () => {
audioRef.value.play();
}
const tumorShow = (item) => {
// state.lociData = item.loci || [];
state.lociObj = item
state.lociObj = item;
dialogTableVisible.value = true;
}
const scrollTo = (id) => {
@ -216,7 +216,12 @@ const openDrawer = async (row: any) => {
let res = await getGeneReport(row.id);
state.geneticList = res.data?.result || [];
};
const downloadFile =(item: any) => {
const a = document.createElement('a');
a.setAttribute('href', item.pdfUrl);
a.setAttribute('download', state.ruleForm.name+'的体检报告');
a.click();
};
//
const closeDrawer = () => {
// emits('handleQuery');
@ -386,7 +391,7 @@ defineExpose({ openDrawer });
}
.section {
padding-top: 100px;
padding-bottom: 100px;
padding-bottom: 30px;
position: relative;
}
.content-box {

114
src/views/pages/regulatory/index.vue

@ -30,17 +30,14 @@
<div class="box-header">
<el-icon style="cursor: pointer;" @click="fitView" size="18"><Aim /></el-icon>
</div>
<div class="fx-content">
<div class="fx-content" id="container" ref="nodeBox">
<!-- <div class="no-widget-hint" v-if="!state.taskChainList.length">请从左侧列表中选择组件.</div> -->
<VueFlow fit-view-on-init class="my-flow" v-model="elements" @nodeClick="nodeClickHandler" disable>
<!-- <VueFlow fit-view-on-init class="my-flow" v-model="elements" @nodeClick="nodeClickHandler" disable>
<Background />
<!-- <Panel :position="PanelPosition.TopRight"></Panel> -->
<!-- <Controls /> -->
<template #node-custom="props">
<CustomNode :node="props" />
</template>
</VueFlow>
</VueFlow> -->
</div>
</div>
<div class="fx-east">
@ -66,20 +63,21 @@
</template>
<script lang="ts" setup name="sysMenu">
import '@vue-flow/core/dist/style.css';
// import '@vue-flow/core/dist/style.css';
/* import the default theme (optional) */
import '@vue-flow/core/dist/theme-default.css';
// import '@vue-flow/core/dist/theme-default.css';
import { Background, Panel, Controls } from '@vue-flow/additional-components'
import { VueFlow, useVueFlow } from '@vue-flow/core'
// import { Background, Panel, Controls } from '@vue-flow/additional-components'
// import { VueFlow, useVueFlow } from '@vue-flow/core'
import { onMounted, reactive, ref } from 'vue';
import { Calendar, Grid, Aim } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus';
import CustomNode from './customNode.vue'
import { getEquipmentList, del } from '/@/api/equipment';
import { Session } from '/@/utils/storage';
import { Graph } from '@antv/x6'
const { nodes, addNodes, updateEdge, removeEdges, getElements, getNode, addEdges, fitView, updateNode, edges } = useVueFlow()
// const { nodes, addNodes, updateEdge, removeEdges, getElements, getNode, addEdges, fitView, updateNode, edges } = useVueFlow()
const data = [
// { id: '1', type: 'process', label: 'Node 1', position: { x: 250, y: 5 }, background: '#42B983' },
// { id: '2', label: 'Node 2', position: { x: 100, y: 100 } },
@ -92,7 +90,48 @@ const data = [
// { id: 'e1-3', source: '1', target: '3', type: 'edgeType' },
// { id: 'e1-4', source: '5', target: '6', type: 'edgeType' },
]
Graph.registerNode(
'custom-node',
{
inherit: 'rect', // rect
width: 100,
height: 40,
markup: [
{
tagName: 'rect', //
selector: 'body', //
},
{
tagName: 'image',
selector: 'img',
},
{
tagName: 'text',
selector: 'label',
},
],
attrs: {
body: {
stroke: '#8f8f8f',
strokeWidth: 1,
fill: '#fff',
rx: 6,
ry: 6,
},
img: {
'xlink:href':
'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
width: 16,
height: 16,
x: 12,
y: 12,
},
},
},
true,
)
let elements = ref(data)
let nodeBox = ref(null);
const collapseActiveNames = ref<string[]>(['1', '2', '3']);
const isAwait = ref(false);
// const addEquipmentRef = ref<InstanceType<typeof AddEquipment>>();
@ -120,12 +159,63 @@ const state = reactive({
onMounted(async () => {
state.orgData = Session.get('orgList') ?? [];
state.queryParams.position = state.orgData[0]?.code || '';
handleQuery();
// handleQuery();
setTimeout(() => {
initGraph();
}, 100)
});
const nodeClickHandler = () => {
console.log(nodes.value, edges.value)
}
const initGraph = () => {
const graph = new Graph({
container: nodeBox.value,
background: {
// color: '#F2F7FA',
},
grid: {
visible: true,
type: 'doubleMesh',
args: [
{
color: '#eee', // 线
thickness: 1, // 线
},
{
color: '#ddd', // 线
thickness: 1, // 线
factor: 4, // 线
},
],
},
})
const source = graph.addNode({
shape: 'custom-node', // 使 shape
x: 40,
y: 40,
label: 'hello',
})
const target = graph.addNode({
shape: 'custom-node',
x: 160,
y: 180,
label: 'world',
})
graph.addEdge({
source,
target,
attrs: {
line: {
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})
graph.centerContent()
}
// await
const changeSwitch = () => {
var node = nodes.value.find((el) => el.selected);

Loading…
Cancel
Save