Browse Source

peter

360view
newPeter7 2 years ago
parent
commit
f40dfa4556
  1. 234
      src/components/echarts/line-kpi-iop.vue
  2. 145
      src/components/ecrf/crf-data.vue
  3. 129
      src/components/ecrf/dialog-load.vue
  4. 88
      src/components/ecrf/ecrf-select.vue
  5. 177
      src/components/ecrf/follow-up-edit.vue
  6. 194
      src/components/ecrf/follow-up.vue
  7. 87
      src/components/hm-crf/del_load-crf-dialog.vue
  8. 49
      src/components/hm-crf/del_load_crf.vue
  9. 88
      src/components/hm-crf/del_preview-dialog.vue
  10. 100
      src/components/hm-crf/del_preview.vue
  11. 239
      src/components/hm-crf/index.vue
  12. 76
      src/components/hm-crf/load-content.vue
  13. 10
      src/components/hm-crf/tinymce/icons/icons.js
  14. 7
      src/components/hm-crf/tinymce/icons/index.js
  15. 7
      src/components/hm-crf/tinymce/plugins/hm_checkbox/index.js
  16. 234
      src/components/hm-crf/tinymce/plugins/hm_checkbox/plugin.js
  17. 7
      src/components/hm-crf/tinymce/plugins/hm_input/index.js
  18. 366
      src/components/hm-crf/tinymce/plugins/hm_input/plugin.js
  19. 7
      src/components/hm-crf/tinymce/plugins/hm_preview/index.js
  20. 143
      src/components/hm-crf/tinymce/plugins/hm_preview/plugin.js
  21. 7
      src/components/hm-crf/tinymce/plugins/hm_radio/index.js
  22. 235
      src/components/hm-crf/tinymce/plugins/hm_radio/plugin.js
  23. 304
      src/components/hm-crf/tinymce/plugins/hm_utils/index.js
  24. 56
      src/components/hm-crf/tinymce/plugins/letterspacing/index.js
  25. 7
      src/components/hm-crf/tinymce/themes/silver/index.js
  26. 32446
      src/components/hm-crf/tinymce/themes/silver/theme.js
  27. 2
      src/components/item-select/display.vue
  28. 12
      src/components/item-select/index.vue
  29. 16
      src/components/patient-search/index.vue
  30. 149
      src/components/patient-view/detail/_del_component.vue
  31. 150
      src/components/patient-view/detail/_mixin.js
  32. 75
      src/components/patient-view/detail/diagnose.vue
  33. 73
      src/components/patient-view/detail/ecrf.vue
  34. 83
      src/components/patient-view/detail/emr-treatments.vue
  35. 118
      src/components/patient-view/detail/exam-item.vue
  36. 57
      src/components/patient-view/detail/inhospital.vue
  37. 38
      src/components/patient-view/detail/iop.vue
  38. 113
      src/components/patient-view/detail/kpi.vue
  39. 99
      src/components/patient-view/detail/medication.vue
  40. 87
      src/components/patient-view/detail/operation.vue
  41. 55
      src/components/patient-view/detail/ref.vue
  42. 40
      src/components/patient-view/detail/va.vue
  43. 629
      src/components/patient-view/index.vue
  44. 134
      src/components/patient-view/set-followup.vue
  45. 16
      src/mixins/full-screen.js
  46. 13
      src/page-subspecialty/router/index.js
  47. 2
      src/page-subspecialty/views/modules/imgEditorFabric/img-editor/bgBar.vue
  48. 39
      src/page-subspecialty/views/modules/imgEditorFabric/index.vue
  49. 425
      src/page-subspecialty/views/modules/optometryManagement/seeDoctor/first-visit/index.vue
  50. 1
      src/page-subspecialty/views/modules/optometryManagement/seeDoctor/ok-lens-rgp/index.vue
  51. 3
      src/page-subspecialty/views/modules/optometryManagement/seeDoctor/ok-lens-rgp/left-right-eye.vue
  52. 286
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/doctor/index.vue
  53. 138
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/ecrf/add-or-update.vue
  54. 99
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/ecrf/index.vue
  55. 50
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/index.vue
  56. 103
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/log/index.vue
  57. 71
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/patient-search/index.vue
  58. 775
      src/page-subspecialty/views/modules/scientificManagement/subjectMgt/patient-subject/index.vue
  59. 10
      src/page-subspecialty/views/modules/scientificManagement/sys/project.vue
  60. 56
      src/page-subspecialty/views/pages/subjectManage/index.vue

234
src/components/echarts/line-kpi-iop.vue

@ -0,0 +1,234 @@
<template>
<div class="chart" :class="className" :style="{ height: height, width: width }" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
import cloneDeep from 'lodash/cloneDeep'
import { getAllDateMonthList, formatDate } from '@/utils'
export default {
mixins: [resize],
props: {
className: { type: String, default: '' },
width: { type: String, default: '100%' },
height: { type: String, default: '200px' },
chartData: { type: Array, default: () => [] },
title: { type: String, default: '眼压' }
},
data() {
return {
chart: null,
disabled: false,
data: []
}
},
watch: {
chartData: {
handler(newVal, oldVal) {
this.initChart()
},
deep: true
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) { return }
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el)
this.data = cloneDeep(this.chartData) || []
this.setOptions()
},
resize() {
this.$_resizeHandler()
},
setOptions() {
let xDateStart = null
let xDateEnd = null
let dateMonthList = []
let xArrayDataValue = []
if (this.data && this.data.length > 0) {
this.disabled = false
this.data.sort((a, b) => {
if (a && b && a.examTime && b.examTime) { return new Date(a.examTime) - new Date(b.examTime) }
})
this.data = this.data.map(item => {
return {
...item,
examDate: formatDate(item.examTime, 'yyyy-MM-dd')
}
})
xDateStart = this.data[0].examDate
xDateEnd = this.data[this.data.length - 1 || 0].examDate
dateMonthList = getAllDateMonthList(xDateStart, xDateEnd)
xArrayDataValue = [...new Set(this.data.map(item => item.examDate))]
} else {
this.disabled = true
}
const legendData = []
const seriesData = []
// const demo= {
// examTime: '',
// examDate: '',
// examType: '',
// examMemo: '',
// odIop: 1,
// osIop: 1,
// sodIop: null,
// sosIop: null,
// }
const itemObj = {
'OD': ['odIop', 'sodIop'],
'OS': ['osIop', 'sosIop']
}
const colors = ['#FF7F00', '#6A3D9A', '#6af1b0', '#4d9bf9']
let i = 0
for (const obj in itemObj) {
legendData.push(obj)
const objValueColName = itemObj[obj][0]
const objLabelColName = itemObj[obj][1]
const serieData = []
this.data.forEach(item => {
if (item[objValueColName] != null) {
serieData.push({
name: item.examDate,
value: [
item.examDate,
item[objValueColName],
item[objLabelColName]
]
})
}
})
seriesData.push({
name: obj,
type: 'line',
data: serieData,
showAllSymbol: true,
smooth: true,
itemStyle: { color: colors[i] },
symbolSize: 10
})
i++
}
const thatData = this.data
this.chart.setOption({
title: { text: this.title },
tooltip: {
trigger: 'axis',
className: 'test',
axisPointer: { type: 'line' },
formatter: function(params, ticket, callback) {
const thisDate = params[0].data.name
let result = `日期:${thisDate} <br/>`
const dateDataList = thatData.filter(item => {
return String(item.examDate) === String(thisDate)
})
// 1
// const styleCommon = `display:inline-block;width:60px;text-align:left;`
// result += `
// <div style='border-top:1px dashed #fff;border-bottom:1px dashed #fff;padding:2px 0;margin:5px 0;'>
// <span style="${styleCommon}margin-left:5px;">OD</span>
// <span style="${styleCommon}">OS</span>
// <span style="${styleCommon}width:100px;"></span>
// </div>`
// dateDataList.forEach(item => {
// result += `
// <span style="${styleCommon}margin-left:5px;">${item.odIop || '-'}</span>
// <span style="${styleCommon}">${item.osIop || '-'}</span>
// <span style="${styleCommon}">${formatDate(item.examTime, 'hh:mm:ss')}${item.iopType || '-'}</span>
// <br/>`
// })
// 2
const tabelBorderStyle = 'border-right:1px solid #fff;border-bottom:1px solid #fff;'
const tdStyle = 'border-left:1px solid #fff;border-top:1px solid #fff;width:60px;text-align:center;'
result += `<table border="0" cellspacing="0" cellpadding="0" style="${tabelBorderStyle}" >
<tr>
<td style="${tdStyle}">OD</td>
<td style="${tdStyle}">OS</td>
<td style="${tdStyle}">检查时间</td>
</tr>`
let trStr = ''
dateDataList.forEach(item => {
trStr += `<tr>
<td style="${tdStyle}">${item.odIop || '-'}</td>
<td style="${tdStyle}">${item.osIop || '-'}</td>
<td style="${tdStyle} width:100px;text-align:left;padding:0 5px;">
${formatDate(item.examTime, 'hh:mm:ss')} (${item.iopType || '-'})
</td>
</tr>`
})
result += `${trStr}</table>`
return result
}
},
legend: {
data: legendData,
icon: 'pin'
},
dataZoom: [{
type: 'inside',
disabled: this.disabled,
start: 0,
end: 100
}],
grid: {
top: 45,
left: 50,
right: 50,
bottom: 30,
containLabel: false
},
xAxis: [{
type: 'time',
min: xDateStart,
max: xDateEnd,
data: xArrayDataValue,
splitLine: { show: false },
axisLabel: { show: false },
axisTick: { show: false }
}, {
type: 'category',
position: 'bottom',
data: dateMonthList,
axisPointer: {
triggerTooltip: false,
show: false
},
axisTick: { show: true }
}],
yAxis: { type: 'value' },
series: seriesData
})
}
}
}
</script>
<style scoped>
.chart{
padding: 0 20px;
}
</style>

145
src/components/ecrf/crf-data.vue

@ -0,0 +1,145 @@
<template>
<div class="component-container">
<div class="exam-info-container clearfix">
<div class="exam-title">{{ examName }}</div>
<div class="exam-date-time-list" />
</div>
<div class="dialog-container">
<el-table :data="activeObj.data" :span-method="arraySpanMethod" border style="width: 100%">
<el-table-column align="center" show-overflow-tooltip width="150px">
<template slot="header">
<el-select
ref="select"
v-model="activeRecId"
placeholder="请选择"
popper-class="c-el-select-popper"
:popper-append-to-body="false"
@visible-change="selectVisibleHandle"
>
<el-option
v-for="item in list"
:key="item.recId"
:label="item.time"
:value="item.recId"
@mouseover.native="preview(item)"
@mouseout.native="restore()"
/>
</el-select>
</template>
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column align="center" show-overflow-tooltip label="OD">
<template slot-scope="scope">
<span>{{ (scope.row.both||scope.row.od)|f_null }}</span>
</template>
</el-table-column>
<el-table-column align="center" show-overflow-tooltip label="OS">
<template slot-scope="scope">
<span>{{ (scope.row.both||scope.row.os)|f_null }}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
filters: {
f_null(val) {
if ((!val) || val === 'null') { return '' } else { return val }
}
},
props: {
examName: { type: String, default: '' },
list: { type: Array, default: () => [] },
value: { type: Object, default: () => {} }
},
data() {
return {
activeRecId: '',
activeObj: {
type: '',
time: null,
recId: '',
data: []
}
}
},
watch: {
activeRecId(val) {
this.activeObj = this.list.find((item, index, array) => item.recId === val)
this.$emit('input', this.activeObj)
},
list(val) {
this.init()
}
},
mounted() {
if (this.list.length > 0) { this.init() }
},
methods: {
init() {
this.activeRecId = this.list[0].recId
},
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
if (row.both && column.property !== 'name') {
// od1,os2.(odos)
if (columnIndex === 1) {
return [1, 2]
} else if (columnIndex === 2) {
return [0, 0]
}
}
},
preview(item) {
this.activeObj = item
},
restore() {
this.activeObj = this.list.find((item, index, array) => item.recId === this.activeRecId)
},
selectVisibleHandle(val) {
if (val && this.list.length > 0) {
const selectInputDom = this.$refs.select.$el
//
const width = selectInputDom.offsetWidth
const selectPoper = selectInputDom.getElementsByClassName('c-el-select-popper')[0]
const arrowDom = selectInputDom.getElementsByClassName('popper__arrow')[0]
this.$nextTick(function() {
const left = parseInt(selectPoper.style.left)
//
// arrowDom.style.left = '10px'
// selectPoper.style.left = (left + width - 25) + 'px'
//
arrowDom.style.left = (width + 20) + 'px'
selectPoper.style.left = (left - width - 10) + 'px'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.component-container{
margin-bottom: 5px;
}
.exam-info-container {
margin-bottom: 5px;
.exam-title {
float: left;
margin-top: 5px;
font-size: 16px;
font-weight: 600;
}
.exam-date-time-list {
float: right;
}
}
</style>

129
src/components/ecrf/dialog-load.vue

@ -0,0 +1,129 @@
<template>
<el-dialog title="查看" :visible.sync="visible" append-to-body class="dialog-crf" top="4vh" width="280mm">
<hm-preview v-if="content" ref="ecrf" :value="content" class="hmPreview" />
<!-- 工具 -->
<div class="tool-bar">
<el-button v-if="print" icon="el-icon-printer" circle title="打印" @click="btnPrintClick" />
<el-button v-if="edit" icon="el-icon-edit-outline" circle title="编辑" @click="btnEditClick" />
<el-button v-if="remove" icon="el-icon-delete" circle title="删除" @click="btnDeleteClick" />
</div>
</el-dialog>
</template>
<script>
import hmPreview from '@/components/hm-crf/load-content'
const Base64 = require('js-base64').Base64
export default {
components: { hmPreview },
props: {
height: { type: String, default: '100%' },
type: { type: String, default: 'load' },
print: { type: Boolean, default: false },
edit: { type: Boolean, default: false },
remove: { type: Boolean, default: false }
},
data() {
return {
visible: false,
id: '',
content: ''
}
},
watch: {
id(val) { console.log(val) }
},
mounted() { },
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.content = ''
this.getInfo()
})
},
//
getInfo() {
if (this.type === 'load') {
//
this.$http.get('/crf/form', { params: { id: this.id }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
}
})
} else {
//
this.$http.get('/crf/template', { params: { crfId: this.id }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
}
})
}
},
btnPrintClick() {
this.$refs.ecrf.print()
},
btnEditClick() {
this.$emit('edit', this.id)
},
btnDeleteClick() {
this.$confirm(this.$t('prompt.info', { handle: this.$t('delete') }), this.$t('prompt.title'), {
confirmButtonText: this.$t('confirm'),
cancelButtonText: this.$t('cancel'),
type: 'warning'
}).then(() => {
this.$http.delete('/crf/form/' + this.id).then(({ data: res }) => {
this.$message.success('删除成功!')
this.visible = false
this.$emit('remove', this.id)
})
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-crf {
::v-deep .el-dialog {
margin-bottom: 10px;
.el-dialog__header {
padding: 10px 20px;
.el-dialog__headerbtn {
top: 10px;
font-size: 20px;
.el-dialog__close {
font-weight: bolder;
}
}
}
.el-dialog__body {
padding: 10px 0;
text-align: center;
background: #606266;
height: calc(96vh - 55px);
.hmPreview {
background: #fff;
height: 100%;
}
}
}
}
.tool-bar {
position: absolute;
width: 50px;
bottom: 20px;
right: 5px;
.el-button + .el-button {
margin-left: 0;
margin-top: 10px;
}
}
</style>

88
src/components/ecrf/ecrf-select.vue

@ -0,0 +1,88 @@
<template>
<el-dialog title="选择表单" :visible.sync="visible" append-to-body>
<el-table v-loading="dataListLoading" :data="dataList" row-key="id" border style="width: 100%;">
<!-- 名称 -->
<el-table-column prop="name" :label="'名称'" />
<!-- 操作 -->
<el-table-column prop="operation" :label="$t('handle')" fixed="right" width="150">
<template slot-scope="scope">
<el-button type="text" size="small" @click="preview(scope.row)">{{ '预览' }}</el-button>
<el-button type="text" size="small" @click="followUp(scope.row)">{{ '填写' }}</el-button>
</template>
</el-table-column>
</el-table>
<template slot="footer">
<el-button @click="visible = false">{{ $t('close') }}</el-button>
</template>
<!-- 预览 -->
<preview v-if="previewVisible" ref="preview" :type="'preview'" />
<!-- 填写 -->
<follow-up v-if="followUpVisible" ref="followUp" v-on="$listeners" />
</el-dialog>
</template>
<script>
import preview from '@/components/ecrf/dialog-load'
import followUp from './follow-up.vue'
export default {
components: { preview, followUp },
props: {
patientIdNumber: { type: String, required: true }
},
data() {
return {
visible: false,
previewVisible: false,
followUpVisible: false,
dataListLoading: false,
dataList: []
}
},
mounted() {
},
methods: {
init() {
this.visible = true
this.dataListLoading = true
this.$nextTick(() => {
this.$http.get('/crf/page', {
params: {
projectId: window.SITE_CONFIG['projectId'],
order: '',
orderField: '',
page: 1,
limit: 1000
}
}).then(({ data: res }) => {
this.dataList = res.data.list
this.dataListLoading = false
}).catch(() => { this.dataListLoading = false })
})
},
preview(row) {
this.previewVisible = true
this.$nextTick(() => {
this.$refs.preview.id = row.id
this.$refs.preview.init()
})
},
followUp(row) {
this.followUpVisible = true
this.$nextTick(() => {
this.$refs.followUp.crfId = row.id
this.$refs.followUp.patientIdNumber = this.patientIdNumber
this.$refs.followUp.init()
})
}
}
}
</script>
<style>
</style>

177
src/components/ecrf/follow-up-edit.vue

@ -0,0 +1,177 @@
<template>
<el-dialog
title="填写表单"
top="1vh"
width="calc(220mm + 600px)"
:visible.sync="visible"
append-to-body
>
<div class="dialog-container">
<!-- 表单内容 -->
<div class="crf-container" style="width: 220mm;">
<hm-crf v-if="crfVisible" ref="hmCrf" :value="content" class="hmPreview" :js-arr="jsArr" />
</div>
<!-- 填充数据 -->
<div class="crf-data" style="width: calc(100% - 220mm);">
<template v-if="examData.length>0">
<div v-for="(item,index) in examData" :key="index">
<crf-data
v-if="crfDataVisible&&item.exams.length>0"
v-model="item.value"
:exam-name="item.name"
:list="item.exams"
/>
</div>
</template>
<template v-else>
<el-empty description="没有可用的填充数据" />
</template>
</div>
</div>
<template slot="footer">
<!-- <el-button @click="visible = false">{{ $t('cancel') }}</el-button> -->
<el-button type="primary" @click="fillCrf">{{ '一键填充' }}</el-button>
<el-button type="primary" @click="submit">{{ '保存' }}</el-button>
</template>
</el-dialog>
</template>
<script>
const Base64 = require('js-base64').Base64
import hmCrf from '../hm-crf/load-content.vue'
import crfData from './crf-data.vue'
import { formatDate } from '@/utils/index.js'
export default {
components: { hmCrf, crfData },
data() {
return {
visible: false,
crfVisible: false,
crfDataVisible: false,
jsArr: [],
inputDate: formatDate(new Date(), 'yyyy-MM-dd'),
id: '',
crfId: '',
patientIdNumber: '',
// CRF
content: '',
// item.valuev-modeliframe
examData: []
}
},
mounted() { },
methods: {
init() {
this.visible = true
this.crfVisible = false
this.crfDataVisible = false
this.$nextTick(() => {
//
this.$http.get('/crf/form', { params: { id: this.id }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
this.crfVisible = true
}
})
//
this.$http.get('/crf/fillData', {
params: {
crfId: this.crfId,
idNumber: this.patientIdNumber
}
}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
this.examData = res.data
this.crfDataVisible = true
}
}).catch(() => { })
})
},
fillCrf() {
//
const dataSelect = []
let fillItemList = []
this.examData.forEach(item => {
if (item.value) {
dataSelect.push(item.value)
if (item.value.data) {
const examItemList = item.value.data.map((obj, index, arr) => {
obj.recId = item.value.recId
obj.time = item.value.time
return obj
})
fillItemList = fillItemList.concat(examItemList)
}
}
})
const ifr = this.$refs.hmCrf.$el
const ifrWin = ifr.contentWindow
ifrWin.dataFill(fillItemList)
},
submit() {
const ifr = this.$refs.hmCrf.$el
const ifrDoc = ifr.contentWindow.document || ifr.contentDocument
const body = ifrDoc.getElementsByTagName('body')[0]
const crfContent = body.innerHTML
this.$http.put('/crf/form', {
formId: this.id,
dataContent: Base64.encode(crfContent)
}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshData')
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-container {
height: calc(100vh - 1vh - 54px - 70px);
//
.crf-container {
display: inline-block;
vertical-align: top;
height: 100%;
// border: 1px solid;
padding: 10px 0;
text-align: center;
background: #606266;
.hmPreview {
background: #fff;
height: 100%;
}
}
//
.crf-data {
display: inline-block;
vertical-align: top;
height: 100%;
overflow: auto;
padding: 0 20px 0 20px;
}
}
// .btn-fill {
// margin-right: calc(100% - 960px - 160px);
// }
</style>

194
src/components/ecrf/follow-up.vue

@ -0,0 +1,194 @@
<template>
<el-dialog
title="填写表单"
top="1vh"
width="calc(220mm + 600px)"
:visible.sync="visible"
append-to-body
>
<div class="dialog-container">
<!-- 表单内容 -->
<div class="crf-container" style="width: 220mm;">
<hm-crf v-if="crfVisible" ref="hmCrf" :value="content" class="hmPreview" :js-arr="jsArr" />
</div>
<!-- 填充数据 -->
<div class="crf-data" style="width: calc(100% - 220mm);">
<template v-if="examData.length>0">
<div v-for="(item,index) in examData" :key="index">
<crf-data
v-if="crfDataVisible&&item.exams.length>0"
v-model="item.value"
:exam-name="item.name"
:list="item.exams"
/>
</div>
</template>
<template v-else>
<el-empty description="没有可用的填充数据" />
</template>
</div>
</div>
<template slot="footer">
<el-button type="primary" @click="fillCrf">{{ '一键填充' }}</el-button>
<!-- <el-button @click="visible = false">{{ $t('cancel') }}</el-button> -->
<el-button type="primary" @click="submit">{{ '保存' }}</el-button>
</template>
</el-dialog>
</template>
<script>
const Base64 = require('js-base64').Base64
import hmCrf from '../hm-crf/load-content.vue'
import crfData from './crf-data.vue'
import { formatDate } from '@/utils/index.js'
export default {
components: { hmCrf, crfData },
data() {
return {
visible: false,
crfVisible: false,
crfDataVisible: false,
jsArr: [],
inputDate: formatDate(new Date(), 'yyyy-MM-dd'),
crfId: '',
patientIdNumber: '',
// CRF
content: '',
// item.valuev-modeliframe
examData: []
}
},
mounted() {
},
methods: {
init() {
this.visible = true
this.crfVisible = false
this.crfDataVisible = false
this.$nextTick(() => {
this.$http.get('/crf/template', { params: { crfId: this.crfId }}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
this.content = Base64.decode(res.data.content)
this.crfVisible = true
}
}).catch(() => { })
this.$http.get('/crf/fillData', {
params: {
crfId: this.crfId,
idNumber: this.patientIdNumber
}
}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
this.examData = res.data
this.crfDataVisible = true
}
}).catch(() => { })
})
},
fillCrf() {
//
const dataSelect = []
let fillItemList = []
this.examData.forEach(item => {
if (item.value) {
dataSelect.push(item.value)
if (item.value.data) {
const examItemList = item.value.data.map((obj, index, arr) => {
obj.recId = item.value.recId
obj.time = item.value.time
return obj
})
fillItemList = fillItemList.concat(examItemList)
}
}
})
const ifr = this.$refs.hmCrf.$el
const ifrWin = ifr.contentWindow
ifrWin.dataFill(fillItemList)
},
submit() {
const ifr = this.$refs.hmCrf.$el
const ifrDoc = ifr.contentWindow.document || ifr.contentDocument
const body = ifrDoc.getElementsByTagName('body')[0]
const crfContent = body.innerHTML
this.$http.post('/crf/form', {
crfId: this.crfId,
dataContent: Base64.encode(crfContent),
idNumber: this.patientIdNumber,
inputDate: this.inputDate,
projectId: window.SITE_CONFIG['projectId']
}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
// this.updateVisitPlan()
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshData')
}
})
})
}
// 20211014
// 访
// updateVisitPlan() {
// this.$http.post('/visit/list/updateVisitPlan', {
// patientIdNumber: this.patientIdNumber,
// projectId: window.SITE_CONFIG['projectId']
// }).then(({ data: res }) => {
// if (res.code !== 0) {
// return this.$message.error(res.msg)
// }
// })
// }
}
}
</script>
<style lang="scss" scoped>
.dialog-container {
height: calc(100vh - 1vh - 54px - 70px);
//
.crf-container {
display: inline-block;
vertical-align: top;
height: 100%;
// border: 1px solid;
padding: 10px 0;
text-align: center;
background: #606266;
.hmPreview {
background: #fff;
height: 100%;
}
}
//
.crf-data {
display: inline-block;
vertical-align: top;
height: 100%;
overflow: auto;
padding: 0 20px 0 20px;
}
}
// .btn-fill {
// margin-right: calc(100% - 960px - 160px);
// }
</style>

87
src/components/hm-crf/del_load-crf-dialog.vue

@ -0,0 +1,87 @@
<template>
<el-dialog
title="查看"
:visible.sync="visible"
append-to-body
class="dialog-crf"
top="4vh"
width="240mm"
>
<hm-preview v-if="content" :value="content" class="hmPreview" />
</el-dialog>
</template>
<script>
import hmPreview from './load-content'
const Base64 = require('js-base64').Base64
export default {
components: { hmPreview },
props: {
id: { type: String, required: true },
height: { type: String, default: '100%' }
},
data() {
return {
visible: false,
content: ''
}
},
watch: {
id(val) {
console.log(val)
}
},
mounted() { },
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.content = ''
this.getInfo()
})
},
//
getInfo() {
this.$http.get('/crf/form', { params: { id: '1435810703477837825' }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-crf {
::v-deep .el-dialog {
margin-bottom: 10px;
.el-dialog__header {
padding: 10px 20px;
.el-dialog__headerbtn {
top: 10px;
font-size: 20px;
.el-dialog__close {
font-weight: bolder;
}
}
}
.el-dialog__body {
padding: 10px 0;
text-align: center;
background: #606266;
height: calc(96vh - 55px);
.hmPreview {
background: #fff;
height: 100%;
}
}
}
}
</style>

49
src/components/hm-crf/del_load_crf.vue

@ -0,0 +1,49 @@
<template>
<hm-preview v-if="content" :value="content" />
</template>
<script>
import hmPreview from './load-content'
const Base64 = require('js-base64').Base64
export default {
components: { hmPreview },
props: {
id: {
type: String,
required: true
},
height: {
type: String,
default: '100%'
}
},
data() {
return {
content: ''
}
},
watch: {
id(val) {
console.log(val)
}
},
mounted() {
this.getInfo()
},
methods: {
init() {
this.content = ''
this.getInfo()
},
//
getInfo() {
this.$http.get('/crf/form', { params: { id: this.id }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
}
})
}
}
}
</script>

88
src/components/hm-crf/del_preview-dialog.vue

@ -0,0 +1,88 @@
<template>
<el-dialog
title="查看"
:visible.sync="visible"
append-to-body
class="dialog-crf"
top="4vh"
width="240mm"
>
<hm-preview v-if="content" :value="content" class="hmPreview" />
</el-dialog>
</template>
<script>
import hmPreview from './load-content'
const Base64 = require('js-base64').Base64
export default {
components: { hmPreview },
props: {
// id: { type: String, required: true },
height: { type: String, default: '100%' }
},
data() {
return {
visible: false,
id: '',
content: ''
}
},
watch: {
id(val) {
console.log(val)
}
},
mounted() { },
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.content = ''
this.getInfo()
})
},
//
getInfo() {
this.$http.get('/crf/template', { params: { crfId: this.id }}).then(({ data: res }) => {
if (res.data) {
this.content = Base64.decode(res.data.content)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-crf {
::v-deep .el-dialog {
margin-bottom: 10px;
.el-dialog__header {
padding: 10px 20px;
.el-dialog__headerbtn {
top: 10px;
font-size: 20px;
.el-dialog__close {
font-weight: bolder;
}
}
}
.el-dialog__body {
padding: 10px 0;
text-align: center;
background: #606266;
height: calc(96vh - 55px);
.hmPreview {
background: #fff;
height: 100%;
}
}
}
}
</style>

100
src/components/hm-crf/del_preview.vue

@ -0,0 +1,100 @@
<template>
<el-dialog
width="90%"
top="2vh"
:visible.sync="visible"
:title="'预览'"
:close-on-click-modal="false"
:close-on-press-escape="false"
append-to-body
>
<iframe
ref="ifrCRF"
style="margin: 0;padding: 0;width: 100%;border: 1px solid #000;"
:style="{ height: height }"
/>
<template slot="footer">
<el-button @click="visible = false">{{ $t('cancel') }}</el-button>
</template>
</el-dialog>
</template>
<script>
const Base64 = require('js-base64').Base64
export default {
data() {
return {
visible: false,
height: 'calc(100vh - 200px)',
dataForm: {
id: '',
projectId: '',
name: '',
description: '',
content: ''
}
}
},
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.dataForm.projectId = window.SITE_CONFIG['projectId']
this.getInfo()
})
},
//
getInfo() {
this.$http.get('/crf/template', { params: { crfId: this.dataForm.id }}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
this.dataForm.content = Base64.decode(res.data.content)
this.dataForm = { ...this.dataForm }
this.render()
}
}).catch(() => {})
},
render() {
const baseUrl = window.location.origin
// const ifr = document.getElementById('crfPreview')
const ifr = this.$refs.ifrCRF
const doc = ifr.contentWindow.document || ifr.contentDocument
const head = doc.getElementsByTagName('head')[0]
const body = doc.getElementsByTagName('body')[0]
const cssArr = ['skins-tinymce/ui/oxide/content.min.css', 'hmcrf.css']
const jsHeadArr = ['jquery-3.5.1/jquery.min.js', 'laydate/laydate.js']
cssArr.forEach(href => {
const css = document.createElement('link')
css.type = 'text/css'
css.rel = 'stylesheet'
css.href = baseUrl + '/static/css/' + href
head.appendChild(css)
})
jsHeadArr.forEach(src => {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
head.appendChild(script)
})
body.innerHTML = this.dataForm.content
setTimeout(() => {
const jsBodyArr = ['hmcrf.js']
jsBodyArr.forEach(src => {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
body.appendChild(script)
})
}, 500)
}
}
}
</script>

239
src/components/hm-crf/index.vue

@ -0,0 +1,239 @@
<template>
<div id="tinymceContainer" class="tinymce-editor">
<editor id="myEditor" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick" />
</div>
</template>
<script>
// import Cookies from 'js-cookie'
import tinymce from 'tinymce'
import Editor from '@tinymce/tinymce-vue'
// import 'tinymce/skins/content/default/content.min.css'
import 'tinymce/icons/default/icons'
import 'tinymce/plugins/image'
import 'tinymce/plugins/media'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/contextmenu'
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/textcolor'
import 'tinymce/plugins/code'
import 'tinymce/plugins/print'
import 'tinymce/plugins/quickbars'
import 'tinymce/plugins/hr'
import 'tinymce/plugins/pagebreak'
/**
* 自定义部分
*/
import './tinymce/themes/silver'
import './tinymce/icons'
import './tinymce/plugins/letterspacing'
import './tinymce/plugins/hm_preview'
import './tinymce/plugins/hm_input'
import './tinymce/plugins/hm_checkbox'
import './tinymce/plugins/hm_radio'
import { isInclude } from './tinymce/plugins/hm_utils'
const tinyID = 'myEditor'
export default {
components: {
Editor
},
props: {
value: {
type: String,
default: ''
},
height: {
type: String,
default: '500px'
},
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default: 'hminput hmcheckbox hmradio quickbars print hmpreview lists image media table code letterspacing hr pagebreak'// paste contextmenu colorpicker textcolor
},
toolbar: {
type: [String, Array],
default:
`hminput hmcheckbox hmradio |
image table |
formatselect | fontselect fontsizeselect | hr pagebreak |
bold italic forecolor backcolor |
hmpreview print |
alignleft aligncenter alignright alignjustify |
bullist numlist outdent indent | letterspacing lineheight`
// media removeformat
// code |
},
contextmenu: {
type: [String, Array],
default: 'hminput hmcheckbox hmradio image imagetools table spellchecker lists'
}
},
data() {
return {
init: {
selector: '#' + tinyID,
icons: 'custom',
language_url: '/static/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/static/tinymce/skins/ui/oxide', // oxide-dark',//
theme: 'silver', //
height: this.height, // '100vh',
statusbar: false, //
// --------------------------------------------------------------
menubar: false,
// --------------------------------------------------------------
contextmenu_never_use_native: true,
contextmenu: this.contextmenu,
// --------------------------------------------------------------
plugins: this.plugins,
// --------------------------------------------------------------
toolbar_mode: 'wrap', // : floating/sliding/scrolling/wrap
toolbar: this.toolbar, //
// --------------------------------------------------------------
quickbars_selection_toolbar: false,
// quickbars_selection_toolbar: 'bold italic underline strikethrough | code fontsizeselect ',
paste_data_images: true,
// images_upload_url: "/demo/eUpload.php",
images_upload_base_path: '', // "/demo/"
images_upload_handler: function(blobInfo, succFun, failFun) {
//
// blobInfo: blob
// succFun(url|string)
// failFun(string)
var file = blobInfo.blob()
var reader = new FileReader()
reader.onload = function(e) {
succFun(e.target.result)
}
reader.readAsDataURL(file)
},
content_css: '/static/css/hmcrf.css',
setup: (editor) => {
// editor.hmBaseCss = ['/static/css/hmcrf.css'];
editor.hmBaseScripts = [
'/static/js/jquery-3.5.1/jquery.min.js',
'/static/js/hmcrf.js'
]
},
init_instance_callback: (editor) => {
},
init: () => {
},
font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;'
},
myValue: this.value
}
},
watch: {
value(newValue) {
this.myValue = newValue
},
myValue(newValue) {
this.$emit('input', newValue)
}
},
mounted() {
// Cookies.set('token', '9def6f4db676363e9f01990d56e62929')
//
this.$http.get('/table/dict/optionsColumn', { params: { type: 3 }}).then(({ data: res }) => {
const data = res.data
window.sessionStorage.setItem('dictField', JSON.stringify(data))
})
// this.$http.get(`/table/dict/getTableDictTreeForCRF`).then(({ data: res }) => {
// if (res.code === 0) {
// const data = res.data
// window.sessionStorage.setItem('dictField', JSON.stringify(data))
// }
// })
this.$nextTick(() => {
})
},
methods: {
// => https://github.com/tinymce/tinymce-vue => All available events
onClick(e) {
this.$emit('onClick', e, tinymce)
},
clear() {
this.myValue = ''
},
setReadOnly() {
tinymce.editors[tinyID].setMode('readonly')
},
setDesign() {
tinymce.editors[tinyID].setMode('design')
},
exportHtml() {
this.fileDown(tinymce.editors[tinyID].getDoc().documentElement.outerHTML, '文件.html')
},
fileDown(content, filename) {
const eleLink = document.createElement('a')
eleLink.download = filename
eleLink.style.display = 'none'
const blob = new Blob([content])
eleLink.href = URL.createObjectURL(blob)
document.body.appendChild(eleLink)
eleLink.click()
document.body.removeChild(eleLink)
},
//
renderContent() {
const baseUrl = window.location.origin
const ifr = document.getElementsByClassName('tox-edit-area__iframe')[0]
const doc = ifr.contentWindow.document
const head = doc.getElementsByTagName('head')[0]
const jsHeadArr = ['jquery-3.5.1/jquery.min.js']
jsHeadArr.forEach(src => {
if (!isInclude(src, doc)) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
head.appendChild(script)
}
})
// appendjsjQuery
setTimeout(() => {
const jsHeadArr2 = ['hmcrf.js']
jsHeadArr2.forEach(src => {
if (!isInclude(src, doc)) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
head.appendChild(script)
}
})
}, 1000)
}
}
}
</script>
<style>
/*没有申请key的话会出现一个弹窗要去申请key,在这里把那个弹窗隐藏,当然也可以自己申请key再使用 */
.tox-notifications-container {
display: none;
}
/* 在页面正常使用时不用加这个样式,在弹窗使用时,要加这个样式,因为使用弹窗,z-index层数比较低,工具栏的一些工具不能使用,要将z-index层数提高。 */
.tox-tinymce-aux {
z-index: 5000 !important;
}
button {
margin: 0px 5px 5px 0px;
}
/* 弹窗微调 */
.tox-dialog-wrap .tox-dialog .tox-dialog__header {
padding: 0 16px;
}
</style>

76
src/components/hm-crf/load-content.vue

@ -0,0 +1,76 @@
<template>
<iframe
ref="ifrCRF"
style="margin: 0;padding:0px;width: 210mm;"
:style="{ height: height,border:border }"
scrolling="auto"
frameborder="0"
/>
</template>
<script>
export default {
name: 'IfrCRF',
props: {
value: { type: String, required: true },
height: { type: String, default: '100%' },
border: { type: String, default: 'none' },
jsArr: { type: Array, default: () => [] }
},
data() {
return {
// content: ''
}
},
mounted() {
this.init()
},
methods: {
init() {
const baseUrl = window.location.origin
// const ifr = document.getElementById('ifrCRF') => this.$refs.ifrCRF
const ifr = this.$refs.ifrCRF
const doc = ifr.contentWindow.document || ifr.contentDocument
const head = doc.getElementsByTagName('head')[0]
const body = doc.getElementsByTagName('body')[0]
const cssArr = ['skins-tinymce/ui/oxide/content.min.css', 'hmcrf.css']
const jsHeadArr = ['jquery-3.5.1/jquery.min.js', 'laydate/laydate.js']
cssArr.forEach(href => {
const css = document.createElement('link')
css.type = 'text/css'
css.rel = 'stylesheet'
css.href = baseUrl + '/static/css/' + href
head.appendChild(css)
})
jsHeadArr.forEach(src => {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
head.appendChild(script)
})
body.innerHTML = this.value
setTimeout(() => {
const jsArr = ['hmcrf.js', ...this.jsArr]
jsArr.forEach(src => {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = baseUrl + '/static/js/' + src
head.appendChild(script)
})
}, 500)
},
print() {
const ifr = this.$refs.ifrCRF
ifr.contentWindow.print()
}
}
}
</script>
<style lang="scss" scoped>
</style>

10
src/components/hm-crf/tinymce/icons/icons.js

@ -0,0 +1,10 @@
// eslint-disable-next-line no-undef
tinymce.IconManager.add('custom', {
icons: {
'input-date': '<svg t="1623053598045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="839" width="32" height="32"><path d="M950.4 182.4H73.6C32 182.4 0 214.4 0 256v512c0 41.6 32 73.6 73.6 73.6h876.8c41.6 0 73.6-32 73.6-73.6V256c0-41.6-32-73.6-73.6-73.6z m0 550.4c0 22.4-16 35.2-35.2 35.2H108.8c-22.4 0-35.2-16-35.2-35.2V291.2c0-19.2 12.8-35.2 35.2-35.2h803.2c22.4 0 35.2 16 35.2 35.2v441.6h3.2z" p-id="840"></path><path d="M771.2 320h44.8v70.4h-44.8zM588.8 320h44.8v70.4h-44.8z" p-id="841"></path><path d="M860.8 364.8h-22.4v44.8h-89.6v-44.8h-89.6v44.8h-89.6v-44.8H544c-12.8 0-22.4 9.6-22.4 22.4v294.4c0 12.8 9.6 22.4 22.4 22.4h316.8c12.8 0 22.4-9.6 22.4-22.4v-294.4c0-12.8-9.6-22.4-22.4-22.4z m-230.4 249.6h-44.8v-44.8h44.8v44.8z m0-89.6h-44.8V480h44.8v44.8z m92.8 89.6h-44.8v-44.8h44.8v44.8z m0-89.6h-44.8V480h44.8v44.8z m89.6 89.6H768v-44.8h44.8v44.8z m0-89.6H768V480h44.8v44.8zM230.4 352h-64c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32h64c19.2 0 32-12.8 32-32v-256c0-16-12.8-32-32-32z" p-id="842"></path></svg>',
'input': '<svg t="1623053714556" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5638" width="32" height="32"><path d="M73.142857 731.428571h877.714286V292.571429H73.142857v438.857142z m0-512h877.714286c43.885714 0 73.142857 29.257143 73.142857 73.142858v438.857142c0 43.885714-29.257143 73.142857-73.142857 73.142858H73.142857c-43.885714 0-73.142857-29.257143-73.142857-73.142858V292.571429c0-43.885714 29.257143-73.142857 73.142857-73.142858z m131.657143 146.285715h73.142857v292.571428h-73.142857V365.714286z" p-id="5639"></path></svg>',
'radio': '<svg t="1623292373056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5458" width="16" height="16"><path d="M512 256c-143.36 0-256 112.64-256 256S368.64 768 512 768 768 655.36 768 512 655.36 256 512 256zM512 0C230.4 0 0 230.4 0 512s230.4 512 512 512 512-230.4 512-512S793.6 0 512 0z m0 921.6c-225.28 0-409.6-184.32-409.6-409.6S286.72 102.4 512 102.4s409.6 184.32 409.6 409.6-184.32 409.6-409.6 409.6z" p-id="5459"></path></svg>',
'checkbox': '<svg t="1623292420789" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" width="16" height="16"><path d="M278.755556 403.911111l-79.644445 79.644445L455.111111 739.555556l568.888889-568.888889-79.644444-79.644445L455.111111 580.266667l-176.355555-176.355556zM910.222222 910.222222H113.777778V113.777778h568.888889V0H113.777778C51.2 0 0 51.2 0 113.777778v796.444444c0 62.577778 51.2 113.777778 113.777778 113.777778h796.444444c62.577778 0 113.777778-51.2 113.777778-113.777778V455.111111h-113.777778v455.111111z" p-id="5718"></path></svg>',
'textarea': '<svg t="1623773458085" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4996" width="40" height="24"><path d="M29.866667 85.333333v853.333334h968.533333V85.333333H29.866667z m883.2 597.333334L768 827.733333H110.933333V196.266667h802.133334V682.666667z" p-id="4997"></path><path d="M196.266667 337.066667c8.533333-29.866667 8.533333-29.866667 42.666666-29.866667V469.333333h-38.4v46.933334h136.533334V469.333333H298.666667V307.2h12.8c21.333333 0 25.6 0 29.866666 29.866667v17.066666l42.666667-8.533333v-25.6c0-17.066667-4.266667-38.4 0-51.2v-21.333333h-38.4L341.333333 256H196.266667l-4.266667-8.533333h-38.4v21.333333c0 17.066667 0 38.4-4.266667 59.733333v21.333334h42.666667l4.266667-12.8z m473.6 409.6l179.2-179.2 29.866666 29.866666-179.2 179.2-29.866666-29.866666z" p-id="4998"></path></svg>'
}
})

7
src/components/hm-crf/tinymce/icons/index.js

@ -0,0 +1,7 @@
// Exports the "default" icons for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/icons/default')
// ES2015:
// import 'tinymce/icons/default'
require('./icons.js')

7
src/components/hm-crf/tinymce/plugins/hm_checkbox/index.js

@ -0,0 +1,7 @@
// Exports the "anchor" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/anchor')
// ES2015:
// import 'tinymce/plugins/anchor'
require('./plugin.js')

234
src/components/hm-crf/tinymce/plugins/hm_checkbox/plugin.js

@ -0,0 +1,234 @@
import {
loadJS_ifrEditArea,
loadCSS_ifrEditArea,
isPlugin,
// updateElm,
updateAttrib,
getIdByClassName,
__assign,
isElm
// dataFormToElmPartStr,
// elmToDataForm,
// hasElm
}
from '../hm_utils/index'
(function() {
'use strict'
const pluginOptions = {
jsArr: [],
cssArr: [],
name: 'hmcheckbox',
className: 'hmcheckbox', // 判断依据,建议和name值一致
cmdName: 'cmdhmcheckbox',
editName: 'hmcheckbox_edit',
dataForm: {
'data-hm_id': '',
'data-hm_type': 'checkbox',
'label': '',
'value': ''
}
}
const global = tinymce.util.Tools.resolve('tinymce.PluginManager')
// 初始设置
const setup = function(editor) {
// 编辑器初始化后执行
editor.on('init', function() {
loadJS_ifrEditArea(editor, pluginOptions.jsArr)
loadCSS_ifrEditArea(editor, pluginOptions.cssArr)
})
// 右键菜单,选定目标
editor.on('contextmenu', function(evt) {
const elm = evt.target
editor.selection.select(elm)
}, true)
}
const open = function(editor) {
editor.windowManager.open({
title: '新增',
size: 'normal', // 'normal', 'medium' or 'large'
body: {
type: 'panel',
items: [
{
type: 'input',
name: 'data-hm_id',
label: '组号',
placeholder: '分组编号'
},
{
type: 'input',
name: 'label',
label: '选项名'
},
{
type: 'input',
name: 'value',
label: '选项值'
}
]
},
initialData: elmToDataForm(editor, pluginOptions.dataForm, pluginOptions.className),
buttons: [
{
type: 'cancel',
name: 'cancel',
text: '取消'
},
{
type: 'submit',
name: 'save',
text: '确定',
primary: true
}
],
onSubmit: function(api) {
const dataForm = api.getData()
dataForm['data-hm_type'] = pluginOptions.dataForm['data-hm_type']
const hmType = dataForm['data-hm_type']
const className = pluginOptions.className
const elm = editor.selection.getNode()
let elm_input, elm_label
if (elm.className.indexOf(className + '-label') >= 0) {
elm_input = isElm(elm.previousElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
elm_label = elm
} else if (elm.className.indexOf(className) >= 0 && isElm(elm, 'data-hm_type', hmType)) {
elm_input = elm
elm_label = isElm(elm.nextElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
}
if (elm && isPlugin(elm, className)) {
// 更新
updateElm(editor, elm_input, elm_label, dataForm, changeHandler)
api.close()
} else {
// 插入
insertElm(editor, dataForm)
api.close()
}
}
})
}
const elmToDataForm = function(editor, initDataForm, pluginClassName) {
const elm = editor.selection.getNode()
const dataForm = __assign({}, initDataForm)
const hmType = initDataForm['data-hm_type']
if (isPlugin(elm, pluginClassName)) {
let elm_input, elm_label
if (elm.className.indexOf(pluginClassName + '-label') >= 0) {
elm_input = isElm(elm.previousElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
elm_label = elm
} else if (elm.className.indexOf(pluginClassName) >= 0 && isElm(elm, 'data-hm_type', hmType)) {
elm_input = elm
elm_label = isElm(elm.nextElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
}
dataForm['data-hm_id'] = elm_input.getAttribute('data-hm_id')
dataForm['label'] = elm_label.innerText
dataForm['value'] = elm_input.getAttribute('value')
}
return dataForm
}
const insertElm = function(editor, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const className = pluginOptions.className
const id = getIdByClassName(doc, className)
const name = dataForm['data-hm_id']
const hmType = dataForm['data-hm_type']
const label = dataForm['label']
const value = dataForm['value'] || label
const win = editor.contentWindow
const domStr_input = `<input type="checkbox" id="${id}" class="${className}" name="${name}" value="${value}" data-hm_id="${name}" data-hm_type="${hmType}">`
const domStr_label = `<label class="${className}-label" for="${id}">${label}</label></input>`
editor.insertContent(domStr_input + domStr_label)
// 渲染控件
renderElm(doc, win, id, dataForm['data-hm_type'])
}
const updateElm = function(editor, elm_input, elm_label, dataForm, changeHandler) {
const name = dataForm['data-hm_id']
const label = dataForm['label']
const value = dataForm['value'] || label
if (elm_input) {
updateAttrib(elm_input, 'name', name)
updateAttrib(elm_input, 'value', value)
updateAttrib(elm_input, 'data-hm_id', name)
}
if (elm_label) {
elm_label.innerText = label
}
}
// 编辑控件状态后,触发处理逻辑
const changeHandler = function(editor, elm, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const win = editor.contentWindow
const id = editor.dom.getAttrib(elm, 'id')
renderElm(doc, win, id, dataForm['data-hm_type'])
}
const renderElm = function(doc, win, id, type) {
}
const register = function(editor) {
editor.addCommand(pluginOptions.cmdName, function() {
open(editor)
})
}
const register$1 = function(editor) {
// 工具栏
editor.ui.registry.addButton(pluginOptions.name, {
icon: 'checkbox',
title: '复选框',
tooltip: '复选框',
onAction: function() {
open(editor)
},
onSetup: function(buttonApi) {
}
})
// 菜单栏
editor.ui.registry.addMenuItem(pluginOptions.name, {
icon: 'checkbox',
text: '复选框',
onAction: function() {
open(editor)
}
})
// 菜单栏(编辑)
editor.ui.registry.addMenuItem(pluginOptions.editName, {
icon: 'checkbox',
text: '编辑',
onAction: function() {
open(editor)
}
})
editor.ui.registry.addContextMenu(pluginOptions.name, {
update: function(elm) {
return isPlugin(elm, pluginOptions.className) ? [pluginOptions.editName] : []
}
})
}
function Plugin() {
global.add(pluginOptions.name, function(editor) {
setup(editor)
register(editor)
register$1(editor)
})
}
Plugin()
}())

7
src/components/hm-crf/tinymce/plugins/hm_input/index.js

@ -0,0 +1,7 @@
// Exports the "anchor" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/anchor')
// ES2015:
// import 'tinymce/plugins/anchor'
require('./plugin.js')

366
src/components/hm-crf/tinymce/plugins/hm_input/plugin.js

@ -0,0 +1,366 @@
/* eslint-disable no-useless-escape */
/* eslint-disable no-undef */
/* eslint-disable no-unused-vars */
import {
loadJS_ifrEditArea,
loadCSS_ifrEditArea,
isPlugin,
updateElm,
dataFormToElmPartStr,
elmToDataForm,
getIdByClassName,
getListbox_Field,
hasElm,
__assign
}
from '../hm_utils/index'
(function() {
'use strict'
const pluginOptions = {
jsArr: ['/static/js/laydate/laydate.js'],
cssArr: [], // '/static/css/hmcrf.css'
name: 'hminput',
className: 'hminput', // 判断依据,建议和name值一致
cmdName: 'cmdhminput',
editName: 'hminput_edit',
dataForm: {
'data-hm_id': '',
'data-hm_type': '',
'data-hm_required': 'false',
'data-hm_bd_eye_type': '',
'data-hm_bd_id': '',
'placeholder': '',
'title': '',
'class.border': '',
'style.width': '120',
'style.height': '18',
'style.text-align': 'center',
'style.background-color': ''
}
}
const global = tinymce.util.Tools.resolve('tinymce.PluginManager')
// 初始设置
const setup = function(editor) {
// 编辑器初始化后执行
editor.on('init', function() {
loadJS_ifrEditArea(editor, pluginOptions.jsArr)
loadCSS_ifrEditArea(editor, pluginOptions.cssArr)
})
// 右键菜单,选定目标
editor.on('contextmenu', function(evt) {
console.log(evt)
const target = evt.target
editor.selection.select(target)
}, true)
}
const dialogBody = function() {
return {
type: 'panel',
items: [
{
type: 'grid',
columns: 2,
items: [
{
type: 'input',
name: 'data-hm_id',
label: '编号 (ID)',
// other: 't1',
placeholder: '唯一编号'
},
{
type: 'selectbox',
name: 'data-hm_type',
label: '类型',
size: 1,
disabled: false,
items: [
{ value: 'text', text: '文本' },
{ value: 'textarea', text: '文本域', hmto: 'textarea' },
{ value: 'number', text: '数字' },
{ value: 'date', text: '日期' },
{ value: 'datetime', text: '日期时间' },
{ value: 'time', text: '时间' }
]
},
// --------
{
type: 'input',
name: 'style.width',
label: '宽度 (px或%)'
},
{
type: 'input',
name: 'style.height',
label: '高度 (px或%)'
},
// --------
{
type: 'selectbox',
name: 'style.text-align',
label: '对齐方式',
size: 1,
items: [
{ value: 'left', text: '居左' },
{ value: 'center', text: '居中' },
{ value: 'right', text: '居右' }
]
},
{
type: 'selectbox',
name: 'class.border',
label: '边框',
size: 1,
items: [
// 必须是class.X的【X-】形式命名选项值
{ value: 'border-1', text: '下划线' },
{ value: 'border-2', text: '可见' },
{ value: 'border-3', text: '不可见' }
]
},
// --------
{
type: 'colorinput',
name: 'style.background-color',
label: '背景色'
},
{
type: 'selectbox',
name: 'data-hm_required',
label: '必填',
size: 1,
items: [
{ value: 'false', text: '否' },
{ value: 'true', text: '是' }
]
},
// --------
{
type: 'listbox',
name: 'data-hm_bd_id',
label: '绑定字段',
items: getListbox_Field()
},
{
type: 'selectbox',
name: 'data-hm_bd_eye_type',
label: '绑定眼别',
size: 1,
items: [
{ value: '', text: '----无----' },
{ value: 'os', text: '左眼(OS)' },
{ value: 'od', text: '右眼(OD)' }
]
},
// --------
{
type: 'input',
name: 'placeholder',
label: '背景文字'
},
{
type: 'input',
name: 'title',
label: '提示'
}
]
}
]
}
}
const open = function(editor) {
editor.windowManager.open({
title: '新增',
size: 'medium', // 'normal', 'medium' or 'large'
// height:500,
body: dialogBody(),
initialData: elmToDataForm(editor, pluginOptions.dataForm, pluginOptions.className, init),
buttons: [
{
type: 'cancel',
name: 'cancel',
text: '取消'
},
{
type: 'submit',
name: 'save',
text: '确定',
primary: true
}
],
onChange: function(api, details) {
// const dataForm = api.getData()
// console.log(details, dataForm[details.name])
},
onSubmit: function(api) {
const dataForm = api.getData()
const doc = editor.contentDocument || editor.contentWindow.document
const className = pluginOptions.className
const hmType = dataForm['data-hm_type']
const elm = editor.selection.getNode()
if (dataForm['data-hm_id'].length === 0) {
tinymce.activeEditor.windowManager.alert('请填写编号')
} else {
if (elm && isPlugin(elm, className)) {
const elmHmType = editor.dom.getAttrib(elm, 'data-hm_type')
if (elmHmType !== hmType) {
// 先插后删
insertElm(editor, dataForm)
elm.remove()
} else {
// 更新
updateElm(editor, elm, className, dataForm, changeHandler)
}
api.close()
} else {
// 判读是否存在相同编号ID的控件
if (hasElm(doc, 'data-hm_id', dataForm['data-hm_id'])) {
tinymce.activeEditor.windowManager.confirm('已存在,确定使用该ID吗?', function(s) {
// tinymce.activeEditor.windowManager.alert("Ok");
if (s) {
// 插入
insertElm(editor, dataForm)
api.close()
} else {
return
}
})
} else {
// 插入
insertElm(editor, dataForm)
api.close()
}
}
}
}
})
}
const init = function(editor, dataForm) {
// const elm = editor.selection.getNode()
// const hmType = editor.dom.getAttrib(elm, 'data-hm_type')
// if (hmType === 'number' || hmType === 'textarea') {
// dataForm['data-hm_type']
// }
// const tempDataForm = JSON.parse(window.sessionStorage.getItem('crfInputOptions'))
// if (tempDataForm) {
// dataForm = __assign({}, dataForm, tempDataForm)
// return dataForm
// }
}
const insertElm = function(editor, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const className = pluginOptions.className
const id = getIdByClassName(doc, className)
const name = dataForm['data-hm_id']
const win = editor.contentWindow
let domStr = ''
switch (dataForm['data-hm_type']) {
case 'number':
domStr = `<input type="number" name="${name}" id="${id}" ${dataFormToElmPartStr(dataForm, className)}
autocomplete="off"
onkeypress="return(/[\d]/.test(String.fromCharCode(event.keyCode) ) )"
onkeyup="this.value=this.value.replace(/[^\d]/g,'');"/>`
break
case 'textarea':
domStr = `<textarea name="${name}" id="${id}" autocomplete="off" ${dataFormToElmPartStr(dataForm, className)} ></textarea>`
break
default:
domStr = `<input type="text" name="${name}" id="${id}" autocomplete="off" ${dataFormToElmPartStr(dataForm, className)}/>`
break
}
// console.log(domStr)
editor.insertContent(domStr)
// const ifr = document.getElementsByClassName('tox-edit-area__iframe')[0]
// 【ifr.contentDocument = ifr.contentWindow.document】
// 【editor.contentDocument = editor.contentWindow.document】
// 渲染控件
initElm(doc, win, id, dataForm['data-hm_type'])
// // 记录此次配置,方便下次新增
// window.sessionStorage.setItem('crfInputOptions', JSON.stringify(dataForm))
}
// 编辑控件状态后,触发处理逻辑
const changeHandler = function(editor, elm, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const win = editor.contentWindow
const id = editor.dom.getAttrib(elm, 'id')
// 二次渲染重置处理,【失败】,暂时保留BUG // elm.removeAttribute('lay-key');
initElm(doc, win, id, dataForm['data-hm_type'])
}
const initElm = function(doc, win, id, type) {
if (type === 'date' || type === 'datetime' || type === 'time') {
win.laydate.render({
elem: '#' + id,
type: type
})
}
}
const register = function(editor) {
editor.addCommand(pluginOptions.cmdName, function() {
open(editor)
})
}
const register$1 = function(editor) {
// 工具栏
editor.ui.registry.addButton(pluginOptions.name, {
icon: 'input',
title: '输入框',
tooltip: '输入框',
onAction: function() {
open(editor)
},
onSetup: function(buttonApi) {
}
})
// 菜单栏
editor.ui.registry.addMenuItem(pluginOptions.name, {
icon: 'duplicate-row',
text: '属性',
onAction: function() {
open(editor)
}
})
// 菜单栏(编辑)
editor.ui.registry.addMenuItem(pluginOptions.editName, {
icon: 'duplicate-row',
text: '编辑',
onAction: function() {
open(editor)
}
})
editor.ui.registry.addContextMenu(pluginOptions.name, {
update: function(element) {
return isPlugin(element, pluginOptions.className) ? [pluginOptions.editName] : []
}
})
}
function Plugin() {
global.add(pluginOptions.name, function(editor) {
setup(editor)
register(editor)
register$1(editor)
})
}
Plugin()
}())

7
src/components/hm-crf/tinymce/plugins/hm_preview/index.js

@ -0,0 +1,7 @@
// Exports the "preview" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/preview')
// ES2015:
// import 'tinymce/plugins/preview'
require('./plugin.js')

143
src/components/hm-crf/tinymce/plugins/hm_preview/plugin.js

@ -0,0 +1,143 @@
/* eslint-disable no-undef */
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*
* Version: 5.7.0 (2021-02-10)
*/
(function() {
'use strict'
var global = tinymce.util.Tools.resolve('tinymce.PluginManager')
var global$1 = tinymce.util.Tools.resolve('tinymce.Env')
var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools')
var getContentStyle = function(editor) {
return editor.getParam('content_style', '', 'string')
}
var shouldUseContentCssCors = function(editor) {
return editor.getParam('content_css_cors', false, 'boolean')
}
var getBodyClassByHash = function(editor) {
var bodyClass = editor.getParam('body_class', '', 'hash')
return bodyClass[editor.id] || ''
}
var getBodyClass = function(editor) {
var bodyClass = editor.getParam('body_class', '', 'string')
if (bodyClass.indexOf('=') === -1) {
return bodyClass
} else {
return getBodyClassByHash(editor)
}
}
var getBodyIdByHash = function(editor) {
var bodyId = editor.getParam('body_id', '', 'hash')
return bodyId[editor.id] || bodyId
}
var getBodyId = function(editor) {
var bodyId = editor.getParam('body_id', 'tinymce', 'string')
if (bodyId.indexOf('=') === -1) {
return bodyId
} else {
return getBodyIdByHash(editor)
}
}
var getPreviewHtml = function(editor) {
console.log(editor)
var headHtml = ''
var encode = editor.dom.encode
var contentStyle = getContentStyle(editor)
headHtml += '<base href="' + encode(editor.documentBaseURI.getURI()) + '">'
var cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : ''
global$2.each(editor.contentCSS, function(url) {
headHtml += '<link type="text/css" rel="stylesheet" href="' + encode(editor.documentBaseURI.toAbsolute(url)) + '"' + cors + '>'
})
if (contentStyle) {
headHtml += '<style type="text/css">' + contentStyle + '</style>'
}
// ----------------------------------
global$2.each(editor.hmPluginCss, function(url) {
headHtml += `<link type="text/css" rel="stylesheet" href="${encode(editor.documentBaseURI.toAbsolute(url))}" ${cors}/>`
})
global$2.each(editor.hmBaseScripts, function(src) {
headHtml += `<script src="${encode(editor.documentBaseURI.toAbsolute(src))}" ${cors}></script>`
})
global$2.each(editor.hmPluginScript, function(src) {
headHtml += `<script src="${encode(editor.documentBaseURI.toAbsolute(src))}" ${cors}></script>`
})
var bodyId = getBodyId(editor)
var bodyClass = getBodyClass(editor)
var isMetaKeyPressed = global$1.mac ? 'e.metaKey' : 'e.ctrlKey && !e.altKey'
var preventClicksOnLinksScript = '<script>' + 'document.addEventListener && document.addEventListener("click", function(e) {' + 'for (var elm = e.target; elm; elm = elm.parentNode) {' + 'if (elm.nodeName === "A" && !(' + isMetaKeyPressed + ')) {' + 'e.preventDefault();' + '}' + '}' + '}, false);' + '</script> '
var directionality = editor.getBody().dir
var dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : ''
var previewHtml = '<!DOCTYPE html>' + '<html>' + '<head>' + headHtml + '</head>' + '<body id="' + encode(bodyId) + '" class="mce-content-body ' + encode(bodyClass) + '"' + dirAttr + '>' + editor.getContent() + preventClicksOnLinksScript + '</body>' + '</html>'
return previewHtml
}
var open = function(editor) {
var content = getPreviewHtml(editor)
var dataApi = editor.windowManager.open({
title: 'Preview',
size: 'large',
body: {
type: 'panel',
items: [{
name: 'preview',
type: 'iframe',
sandboxed: true
}]
},
buttons: [{
type: 'cancel',
name: 'close',
text: 'Close',
primary: true
}],
initialData: { preview: content }
})
dataApi.focus('close')
}
var register = function(editor) {
editor.addCommand('cmdhmpreview', function() {
open(editor)
})
}
var register$1 = function(editor) {
editor.ui.registry.addButton('hmpreview', {
icon: 'preview',
tooltip: 'Preview',
onAction: function() {
return editor.execCommand('cmdhmpreview')
}
})
editor.ui.registry.addMenuItem('hmpreview', {
icon: 'preview',
text: 'Preview',
onAction: function() {
return editor.execCommand('cmdhmpreview')
}
})
}
function Plugin() {
global.add('hmpreview', function(editor) {
register(editor)
register$1(editor)
})
}
Plugin()
}())

7
src/components/hm-crf/tinymce/plugins/hm_radio/index.js

@ -0,0 +1,7 @@
// Exports the "anchor" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/anchor')
// ES2015:
// import 'tinymce/plugins/anchor'
require('./plugin.js')

235
src/components/hm-crf/tinymce/plugins/hm_radio/plugin.js

@ -0,0 +1,235 @@
import {
loadJS_ifrEditArea,
loadCSS_ifrEditArea,
isPlugin,
// updateElm,
updateAttrib,
getIdByClassName,
__assign,
isElm
// dataFormToElmPartStr,
// elmToDataForm,
// hasElm
}
from '../hm_utils/index'
(function() {
'use strict'
const pluginOptions = {
jsArr: [],
cssArr: [],
name: 'hmradio',
className: 'hmradio', // 判断依据,建议和name值一致
cmdName: 'cmdhmradio',
editName: 'hmradio_edit',
dataForm: {
'data-hm_id': '',
'data-hm_type': 'radio',
'label': '',
'value': ''
}
}
const global = tinymce.util.Tools.resolve('tinymce.PluginManager')
// 初始设置
const setup = function(editor) {
// 编辑器初始化后执行
editor.on('init', function() {
loadJS_ifrEditArea(editor, pluginOptions.jsArr)
loadCSS_ifrEditArea(editor, pluginOptions.cssArr)
})
// 右键菜单,选定目标
editor.on('contextmenu', function(evt) {
const elm = evt.target
editor.selection.select(elm)
}, true)
}
const open = function(editor) {
editor.windowManager.open({
title: '新增',
size: 'normal', // 'normal', 'medium' or 'large'
body: {
type: 'panel',
items: [
{
type: 'input',
name: 'data-hm_id',
label: '组号',
placeholder: '分组编号'
},
{
type: 'input',
name: 'label',
label: '选项名'
},
{
type: 'input',
name: 'value',
label: '选项值'
}
]
},
initialData: elmToDataForm(editor, pluginOptions.dataForm, pluginOptions.className),
buttons: [
{
type: 'cancel',
name: 'cancel',
text: '取消'
},
{
type: 'submit',
name: 'save',
text: '确定',
primary: true
}
],
onSubmit: function(api) {
const dataForm = api.getData()
dataForm['data-hm_type'] = pluginOptions.dataForm['data-hm_type']
const hmType = dataForm['data-hm_type']
const className = pluginOptions.className
const elm = editor.selection.getNode()
let elm_input, elm_label
if (elm.className.indexOf(className + '-label') >= 0) {
elm_input = isElm(elm.previousElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
elm_label = elm
} else if (elm.className.indexOf(className) >= 0 && isElm(elm, 'data-hm_type', hmType)) {
elm_input = elm
elm_label = isElm(elm.nextElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
}
if (elm && isPlugin(elm, className)) {
// 更新
updateElm(editor, elm_input, elm_label, dataForm, changeHandler)
api.close()
} else {
// 插入
insertElm(editor, dataForm)
api.close()
}
}
})
}
const elmToDataForm = function(editor, initDataForm, pluginClassName) {
const elm = editor.selection.getNode()
const dataForm = __assign({}, initDataForm)
const hmType = initDataForm['data-hm_type']
if (isPlugin(elm, pluginClassName)) {
let elm_input, elm_label
if (elm.className.indexOf(pluginClassName + '-label') >= 0) {
elm_input = isElm(elm.previousElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
elm_label = elm
} else if (elm.className.indexOf(pluginClassName) >= 0 && isElm(elm, 'data-hm_type', hmType)) {
elm_input = elm
elm_label = isElm(elm.nextElementSibling, 'data-hm_type', hmType) ? elm.previousElementSibling : undefined
}
dataForm['data-hm_id'] = elm_input.getAttribute('data-hm_id')
dataForm['label'] = elm_label.innerText
dataForm['value'] = elm_input.getAttribute('value')
}
return dataForm
}
const insertElm = function(editor, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const className = pluginOptions.className
const id = getIdByClassName(doc, className)
const name = dataForm['data-hm_id']
const hmType = dataForm['data-hm_type']
const label = dataForm['label']
const value = dataForm['value'] || label
const win = editor.contentWindow
const domStr_input = `<input type="radio" id="${id}" class="${className}" name="${name}" value="${value}" data-hm_id="${name}" data-hm_type="${hmType}">`
const domStr_label = `<label class="${className}-label" for="${id}">${label}</label></input>`
editor.insertContent(domStr_input + domStr_label)
// 渲染控件
renderElm(doc, win, id, dataForm['data-hm_type'])
}
const updateElm = function(editor, elm_input, elm_label, dataForm, changeHandler) {
const name = dataForm['data-hm_id']
const label = dataForm['label']
const value = dataForm['value'] || label
if (elm_input) {
updateAttrib(elm_input, 'name', name)
updateAttrib(elm_input, 'value', value)
updateAttrib(elm_input, 'data-hm_id', name)
}
if (elm_label) {
elm_label.innerText = label
}
}
// 编辑控件状态后,触发处理逻辑
const changeHandler = function(editor, elm, dataForm) {
const doc = editor.contentDocument || editor.contentWindow.document
const win = editor.contentWindow
const id = editor.dom.getAttrib(elm, 'id')
renderElm(doc, win, id, dataForm['data-hm_type'])
}
const renderElm = function(doc, win, id, type) {
}
const register = function(editor) {
editor.addCommand(pluginOptions.cmdName, function() {
open(editor)
})
}
const register$1 = function(editor) {
// 工具栏
editor.ui.registry.addButton(pluginOptions.name, {
icon: 'radio',
title: '复选框',
tooltip: '复选框',
onAction: function() {
open(editor)
},
onSetup: function(buttonApi) {
}
})
// 菜单栏
editor.ui.registry.addMenuItem(pluginOptions.name, {
icon: 'radio',
text: '复选框',
onAction: function() {
open(editor)
}
})
// 菜单栏(编辑)
editor.ui.registry.addMenuItem(pluginOptions.editName, {
icon: 'radio',
text: '编辑',
onAction: function() {
open(editor)
}
})
editor.ui.registry.addContextMenu(pluginOptions.name, {
update: function(elm) {
return isPlugin(elm, pluginOptions.className) ? [pluginOptions.editName] : []
}
})
}
function Plugin() {
global.add(pluginOptions.name, function(editor) {
setup(editor)
register(editor)
register$1(editor)
})
}
Plugin()
}())

304
src/components/hm-crf/tinymce/plugins/hm_utils/index.js

@ -0,0 +1,304 @@
// 判断是否已引用
export const isInclude = function(name, doc) {
doc = doc || document
var js = /js$/i.test(name)
var es = doc.getElementsByTagName(js ? 'script' : 'link')
for (var i = 0; i < es.length; i++) { if (es[i][js ? 'src' : 'href'].indexOf(name) !== -1) return true }
return false
}
// 加载插件所需js
export const loadJS_ifrEditArea = function(editor, jsArr) {
if (jsArr.length > 0) {
const nodeList = document.getElementsByClassName('tox-edit-area__iframe')
nodeList.forEach(node => {
const ifr = node.contentWindow.document
const head = ifr.getElementsByTagName('head')[0]
jsArr.forEach(src => {
if (!isInclude(src, ifr)) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = editor.dom.encode(editor.documentBaseURI.toAbsolute(src))
head.appendChild(script)
}
})
})
editor.hmPluginScript = (editor.hmPluginScript || []).concat(jsArr)
}
}
// 加载插件所需css
export const loadCSS_ifrEditArea = function(editor, cssArr) {
if (cssArr.length > 0) {
const nodeList = document.getElementsByClassName('tox-edit-area__iframe')
nodeList.forEach(node => {
const ifr = node.contentWindow.document
const head = ifr.getElementsByTagName('head')[0]
cssArr.forEach(href => {
if (!isInclude(href, ifr)) {
const css = document.createElement('link')
css.type = 'text/css'
css.rel = 'stylesheet'
css.href = editor.dom.encode(editor.documentBaseURI.toAbsolute(href))
head.appendChild(css)
}
})
})
editor.hmPluginCss = (editor.hmPluginCss || []).concat(cssArr)
}
}
/**
* 生成dom对象id取最大值+1
* @param {*} doc document对象
* @param {*} className 样式名(插件名)
* @returns
*/
export const getIdByClassName = function(doc, className) {
let i = 0
doc.querySelectorAll('.' + className).forEach(elm => {
const j = Number(elm.id && elm.id.replace(className, '') || 0)
if (i <= j) {
i = j
}
})
return className + (i + 1)
}
/**
* 判断是否已存在相应的dom对象
* @param {*} doc document对象
* @param {*} attrName 属性名
* @param {*} attrValue 属性值
* @returns
*/
export const hasElm = function(doc, attrName, attrValue) {
return attrValue !== '' && (doc.querySelectorAll(`[${attrName}='${attrValue}']`).length > 0)
}
/**
* 判断element对象
* @param {*} elm element对象
* @param {*} attrName 属性名
* @param {*} attrValue 属性值
* @returns
*/
export const isElm = function(elm, attrName, attrValue) {
return elm.hasAttribute(attrName) && elm.getAttribute(attrName) === attrValue
}
/**
* 判断插件(根据样式)
* @param {*} element dom对象
* @param {*} pluginClassName 插件名
* @returns
*/
export const isPlugin = function(elm, pluginClassName) {
if (elm.className && elm.className.indexOf(pluginClassName) >= 0) {
return true
}
return false
}
/**
* 字典表样式单位匹配
*/
export const styleUnitMap = {
width: 'px',
height: 'px'
}
/**
* 属性更新
* @param {*} elm dom节点
* @param {*} name 属性名
* @param {*} value 属性值
*/
export const updateAttrib = function(elm, name, value) {
if (value === '') {
elm.removeAttribute(name)
} else {
elm.setAttribute(name, value)
}
}
/**
* 更新dom对象
* @param {*} editor 编辑器
* @param {*} elm dom对象
* @param {*} dataForm 新数据集合对象
* @param {*} initHandler 初始化执行函数
*/
export const updateElm = function(editor, elm, className, dataForm, initHandler) {
const styleObj = {}
let classes = className + ' '
for (const key of Object.keys(dataForm)) {
if (key.indexOf('style.') >= 0) {
const styleName = key.replace('style.', '')
let styleValue = dataForm[key]
if (styleName === 'width' || styleName === 'height') {
if (dataForm[key].indexOf('%') > 0 || dataForm[key].indexOf('px') > 0) {
styleValue = dataForm[key]
} else {
styleValue = dataForm[key] + 'px'
}
}
styleObj[styleName] = styleValue
} else if (key.indexOf('class.') >= 0) {
if (dataForm[key] !== '') {
classes += dataForm[key] + ' '
}
} else {
if (dataForm[key] !== editor.dom.getAttrib(elm, key)) {
updateAttrib(elm, key, dataForm[key])
}
}
}
editor.dom.setStyles(elm, styleObj)
elm.className = classes
// 初始化控件
if (initHandler) { initHandler(editor, elm, dataForm) }
}
/**
* 根据数据集合对象转换成dom对象代码片段
* @param {*} dataForm 数据集合对象
* @returns dom对象代码片段
*/
export const dataFormToElmPartStr = function(dataForm, className) {
let attributes = ''
let styles = ''
let classes = className + ' '
for (const key of Object.keys(dataForm)) {
if (key.indexOf('style.') === 0) {
if (dataForm[key] !== '') {
const styleName = key.replace('style.', '')
let styleValue = dataForm[key]
if (styleName === 'width' || styleName === 'height') {
if (dataForm[key].indexOf('%') > 0 || dataForm[key].indexOf('px') > 0) {
styleValue = dataForm[key]
} else {
styleValue = dataForm[key] + 'px'
}
}
styles += `${styleName}:${styleValue};`
}
} else if (key.indexOf('class.') === 0) {
if (dataForm[key] !== '') {
classes += dataForm[key] + ' '
}
} else {
attributes += `${key}="${dataForm[key]}" `
}
}
return `class="${classes}" style="${styles} font-family: inherit;font-size: inherit;" ${attributes}`
}
/**
* dom对象提取数据集合对象
* @param {*} editor 编辑器
* @param {*} initDataForm 原始数据对象
* @param {*} pluginClassName 插件名
* @returns 数据集合对象
*/
export const elmToDataForm = function(editor, initDataForm, pluginClassName, customHandle) {
const elm = editor.selection.getNode()
const dataForm = __assign({}, initDataForm)
if (isPlugin(elm, pluginClassName)) {
for (const key of Object.keys(dataForm)) {
if (key.indexOf('style.') >= 0) {
const styleName = key.replace('style.', '')
dataForm[key] = editor.dom.getStyle(elm, styleName).replace(styleUnitMap[styleName] || '', '')
} else if (key.indexOf('class.') >= 0) {
dataForm[key] = classMap(elm.className, key) || ''
} else {
dataForm[key] = editor.dom.getAttrib(elm, key)
}
}
}
customHandle ? customHandle(editor, dataForm) : null
return dataForm
}
/**
* 根据id获取选项具体信息
* @param {*} id 匹配字段对应listbox中的value
* @returns 对象
*/
export const getItemInfo_Field = function(id) {
if (window.sessionStorage.getItem('dictField')) {
const dict = Array.from(JSON.parse(window.sessionStorage.getItem('dictField')))
dict.forEach(item => {
if (item.id && item.id === id) {
return item
} else {
item.childrenList.forEach(item2 => {
if (item2.id && item2.id === id) {
return id
}
})
}
})
}
return null
}
/**
* 获取字段字典表的listbox格式的数据
* @returns listbox数组
*/
export const getListbox_Field = function() {
const selectbox = [{ text: '----无----', value: '' }]
if (window.sessionStorage.getItem('dictField')) {
const dict = Array.from(JSON.parse(window.sessionStorage.getItem('dictField')))
dict.forEach(examItem => {
const obj = {
text: '',
items: []
}
obj.text = examItem.label
if (examItem.children && examItem.children.length > 0) {
examItem.children.forEach(field => {
obj.items.push({
text: field.label,
value: field.value
})
})
}
selectbox.push(obj)
})
}
return selectbox
}
/**
* 根据dom的className匹配属性选项值
* className中的XXX-1 => dataForm["class.XXX"]=XXX-1
* @param {*} className dom元素的className
* @param {*} dataFormKey 需要匹配的属性
* @returns
*/
export const classMap = function(className, dataFormKey) {
const classList = className.split(' ')
const temp = dataFormKey.replace('class.', '')
for (let i = 0; i < classList.length; i++) {
if (classList[i].indexOf(temp + '-') === 0) {
return classList[i]
}
}
}
// 浅拷贝
export let __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i]
for (var p in s) {
if (Object.prototype.hasOwnProperty.call(s, p)) { t[p] = s[p] }
}
}
return t
}
return __assign.apply(this, arguments)
}

56
src/components/hm-crf/tinymce/plugins/letterspacing/index.js

@ -0,0 +1,56 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
tinymce.PluginManager.add('letterspacing', function(editor, url) {
var pluginName = '字间距'
var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools')
var letterspacing_val = editor.getParam('letterspacing_val', '1px 2px 3px 4px 5px')
editor.on('init', function() {
editor.formatter.register({
letterspacing: { inline: 'span', styles: { 'letter-spacing': '%value' }}
})
})
var doAct = function(value) {
editor.formatter.apply('letterspacing', { value: value })
editor.fire('change', {})
}
editor.ui.registry.addMenuButton('letterspacing', {
text: '<svg t="1570979572631" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12244" width="20" height="20" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M33.450667 3.413333h102.4v956.8256H33.450667V3.413333z m887.330133 1.8432h102.4v957.713067h-102.4V5.188267z m-425.301333 200.704h108.9536l223.6416 584.977067h-102.4l-53.248-146.6368H427.485867l-53.248 146.6368h-102.4l223.6416-584.9088z m-39.3216 359.697067H643.754667L552.004267 309.248h-3.2768L456.157867 565.6576z" fill="#2c2c2c" p-id="12245"></path></svg>',
tooltip: pluginName,
fetch: function(callback) {
var dom = editor.dom
var blocks = editor.selection.getSelectedBlocks()
var lhv = 0
global$1.each(blocks, function(block) {
if (lhv === 0) {
lhv = dom.getStyle(block, 'letterspacing') ? dom.getStyle(block, 'letterspacing') : 0
}
})
var items = letterspacing_val.split(' ').map(function(item) {
var text = item
var value = item
return {
type: 'togglemenuitem',
text: text,
active: lhv === value,
onAction: function() {
doAct(value)
}
}
})
callback(items)
}
})
return {
getMetadata: function() {
return {
name: pluginName,
url: 'http://tinymce.ax-z.cn/more-plugins/lineheight.php'
}
}
}
})

7
src/components/hm-crf/tinymce/themes/silver/index.js

@ -0,0 +1,7 @@
// Exports the "silver" theme for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/themes/silver')
// ES2015:
// import 'tinymce/themes/silver'
require('./theme.js')

32446
src/components/hm-crf/tinymce/themes/silver/theme.js

File diff suppressed because it is too large

2
src/components/item-select/display.vue

@ -124,7 +124,7 @@ export default {
this.options_kpi = window.SITE_CONFIG['dict_colSearch']
} else {
//
const { data: res } = await this.$http.get('/sys/table/dict/getList', { params: { type: 1 }})
const { data: res } = await this.$http.get('/table/dict/optionsColumn', { params: { type: 1 }})
this.options_kpi = res.data
}
}

12
src/components/item-select/index.vue

@ -182,13 +182,9 @@ export default {
// dataList
this.dataList = arrayData.map(item => {
if (this.options_kpi.length === 0) { this.getOptionsKPI() }
const valueList = findPathArray(this.options_kpi, item.id, 'value', 'children')
const itemParentInfo = this.getItem(valueList[(valueList.length - 2) || 0])
console.log(1,valueList)
const itemInfo = this.getItem(valueList[(valueList.length - 1) || 0])
// console.log(item, itemInfo, itemParentInfo)
//
if (item.id.indexOf('DEVICE_ID') >= 0) {
const dict = cloneDeep(window.SITE_CONFIG['dict_device_item'])
@ -196,13 +192,12 @@ export default {
const obj = dict.find(item2 => item2.value === itemId)
this.options_device = obj ? obj.children : []
}
return {
recId: item.recId,
itemName: itemParentInfo.label,
itemName: item.itemName,
kpiId: item.id,
kpiName: item.label,
kpiType: item.type,
kpiName: item.kpiName,
kpiType: item.kpiType,
queryType: item.queryType, //
// queryTypeName: options_matchType.find((item2) => item2.value === item.queryType).label,
queryLogic: item.queryLogic, // queryValue=queryLogic
@ -227,7 +222,6 @@ export default {
const item = this.getItem(value)
const oldValType = this.dataForm.kpiType
console.log(item)
this.dataForm.itemName = parentItem.label
this.dataForm.kpiId = item.id
this.dataForm.kpiName = item.label

16
src/components/patient-search/index.vue

@ -67,14 +67,14 @@
</div>
</el-card>
<!-- 底部全选反选 -->
<checked-footer ref="checkfooter" table-ref="multipleTable" :current-table-list="currentTableList" :data-list="dataList">
<div class="batch_button">
<div class="batch_button">
<el-button type="primary" size="small" :disabled="currentTableList.length > 0 ? false :true">加入分组
</el-button>
</div>
</div>
</checked-footer>
<!-- <checked-footer ref="checkfooter" table-ref="multipleTable" :current-table-list="currentTableList" :data-list="dataList">-->
<!-- <div class="batch_button">-->
<!-- <div class="batch_button">-->
<!-- <el-button type="primary" size="small" :disabled="currentTableList.length > 0 ? false :true">加入分组-->
<!-- </el-button>-->
<!-- </div>-->
<!-- </div>-->
<!-- </checked-footer>-->
</div>
<detail-view v-if="detailViewVisible" ref="viewRef" :only-read="onlyRead" :is-search="'1'" :patient-id="patientId" @detailViewVisible="detailViewVisible=false" />
</div>

149
src/components/patient-view/detail/_del_component.vue

@ -0,0 +1,149 @@
<template>
<el-input
v-model="searchKeyWord"
class="header-search"
size="mini"
placeholder="关键词"
@keyup.enter.native="searchNext"
>
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
export default {
props: {
value: { type: Array, default: () => [] }
},
data() {
return {
dataList: [],
dataListTemp: [],
searchKeyWord: '',
searchIndex: -1,
searchResult: []
}
},
watch: {
searchKeyWord(val) {
if (val) {
this.searchHandle()
}
},
value(val) {
// this.dataListTemp = val
}
},
methods: {
searchLast() {
if (this.searchResult.length > 0) {
if (this.searchIndex > 0) {
this.searchIndex--
} else {
this.searchIndex = this.searchResult.length - 1
}
this.searchIndexDisplay()
} else {
this.searchIndex = -1
}
},
searchNext() {
if (this.searchResult.length > 0) {
if (this.searchIndex + 1 < this.searchResult.length) {
this.searchIndex++
} else if (this.searchIndex + 1 >= this.searchResult.length) {
this.searchIndex = 0
}
this.searchIndexDisplay()
} else {
this.searchIndex = -1
}
},
searchReset() {
this.searchIndex = -1
this.searchKeyWord = ''
this.searchResult = []
this.dataList = cloneDeep(this.dataListTemp)
},
searchIndexDisplay() {
if (this.searchIndex >= 0 && this.searchResult.length > 0) {
const index = this.searchResult[this.searchIndex]
// this.$refs.dataList.toggleRowExpansion(this.dataList[index], true)
// this.setCurrentRow(index)
this.$emit('focusResult', index)
}
},
searchHandle() {
if (!this.searchKeyWord) { return false }
this.searchIndex = -1
this.searchResult = []
this.dataList = cloneDeep(this.dataListTemp)
const regex = new RegExp(this.searchKeyWord, 'g')
let rowCount = 0
this.dataList.forEach((item1, rowIndex1) => {
const data = item1.data
let isFlag = false
if (data && data.length > 0) {
data.forEach((item2, rowIndex2) => {
//
Object.keys(item2).forEach(key => {
if (item2[key] && item2[key].toString().includes(this.searchKeyWord)) {
isFlag = true
//
item2[key] = item2[key].toString().replace(regex, `<span style='color:red;'>${this.searchKeyWord}</span>`)
}
})
})
}
if (isFlag) {
//
this.searchResult[rowCount] = rowIndex1
rowCount++
}
})
this.$emit('input', this.dataList)
// this.$emit('update:queryItem', queryItem)
}
}
}
</script>
<style lang="scss" scoped>
.header-search {
width: 300px;
}
::v-deep .el-input__suffix {
display: flex;
align-items: center;
.el-input__suffix-inner {
.search-result {
display: inline-block;
padding: 0 10px;
border-right: 1px solid #c0c4cc;
}
.el-input__icon {
cursor: pointer;
width: 20px;
border-radius: 20px;
line-height: 20px;
margin: 4px 2px;
}
.el-input__icon:hover {
background: #c0c4cc;
color: #fff;
}
}
}
</style>

150
src/components/patient-view/detail/_mixin.js

@ -0,0 +1,150 @@
import cloneDeep from 'lodash/cloneDeep'
export default {
props: {
patientIdNumber: { type: String, required: true },
projectId: { type: String, default: '' }
},
data() {
return {
dataListLoading: false,
dataList: [],
dataListTemp: [],
type: '',
searchKeyWord: '',
searchIndex: -1,
searchResult: [],
searchColumn: []
}
},
watch: {
searchKeyWord(val) {
if (val) {
this.searchHandle()
} else {
this.searchReset()
}
}
},
created() { this.getDataList() },
methods: {
refreshData() { this.getDataList() },
getDataList() {
this.dataListLoading = true
this.$http.get('/patient/view/examData', {
params: {
patientIdNumber: this.patientIdNumber,
projectId: this.projectId ? this.projectId : null,
type: this.type
}
}).then(({ data: res }) => {
this.dataList = cloneDeep(res.data)
this.dataListTemp = cloneDeep(res.data)
this.dataListLoading = false
}).catch(() => { this.dataListLoading = false })
},
setIndexDate(date) {
if (date) {
const rowIndex = this.dataList.findIndex(item => {
return (item.opDate && item.opDate === date) ||
(item.examTime && item.examTime.indexOf(date) >= 0) ||
(item.EXAM_TIME && item.EXAM_TIME.indexOf(date) >= 0)
})
if (rowIndex >= 0) {
setTimeout(() => {
this.setCurrentRow(rowIndex)
}, 100)
}
}
},
setCurrentRow(i) {
if (this.$refs.dataList) {
this.$refs.dataList.setCurrentRow(this.dataList[i])
// this.$refs.dataList.toggleRowExpansion(this.dataList[i], true)
const targetTop = this.$refs.dataList.$el.querySelectorAll('.el-table__body .row-1')[i].getBoundingClientRect().top
const containerTop = this.$refs.dataList.$el.querySelector('.el-table__body').getBoundingClientRect().top
const scrollParent = this.$refs.dataList.$el.querySelector('.el-table__body-wrapper')
// console.log(this.$refs.dataList.$el, scrollParent, targetTop, containerTop)
// const el = this.$refs.dataList.$el.querySelectorAll('.el-table__body .row-1')[i]
// console.log(el, el.getClientRects(), el.getBoundingClientRect())
scrollParent.scrollTop = targetTop - containerTop
}
},
searchLast() {
if (this.searchResult.length > 0) {
if (this.searchIndex > 0) {
this.searchIndex--
} else {
this.searchIndex = this.searchResult.length - 1
}
this.searchIndexDisplay()
} else {
this.searchIndex = -1
}
},
searchNext() {
if (this.searchResult.length > 0) {
if (this.searchIndex + 1 < this.searchResult.length) {
this.searchIndex++
} else if (this.searchIndex + 1 >= this.searchResult.length) {
this.searchIndex = 0
}
this.searchIndexDisplay()
} else {
this.searchIndex = -1
}
},
searchReset() {
this.searchIndex = -1
this.searchKeyWord = ''
this.searchResult = []
this.dataList = cloneDeep(this.dataListTemp)
},
searchIndexDisplay() {
if (this.searchIndex >= 0 && this.searchResult.length > 0) {
const index = this.searchResult[this.searchIndex]
this.$refs.dataList.toggleRowExpansion(this.dataList[index], true)
this.setCurrentRow(index)
}
},
searchHandle() {
if (!this.searchKeyWord) { return false }
this.searchIndex = -1
this.searchResult = []
this.dataList = cloneDeep(this.dataListTemp)
const regex = new RegExp(this.searchKeyWord, 'g')
let rowCount = 0
this.dataList.forEach((item1, rowIndex1) => {
const data = item1.data
let isFlag = false
if (data && data.length > 0) {
// data子集匹配
data.forEach((item2, rowIndex2) => {
// 遍历行对象
// Object.keys(item2).forEach(key => {
this.searchColumn.forEach(key => {
if (item2[key] && item2[key].toString().includes(this.searchKeyWord)) {
isFlag = true
item2[key] = item2[key].toString().replace(regex, `<span style='color:red;'>${this.searchKeyWord}</span>`)
}
})
})
} else {
// 无data子集,自匹配
this.searchColumn.forEach(key => {
if (item1[key] && item1[key].toString().includes(this.searchKeyWord)) {
isFlag = true
item1[key] = item1[key].toString().replace(regex, `<span style='color:red;'>${this.searchKeyWord}</span>`)
}
})
}
if (isFlag) {
// 记录数据位置
this.searchResult[rowCount] = rowIndex1
rowCount++
}
})
}
}
}

75
src/components/patient-view/detail/diagnose.vue

@ -0,0 +1,75 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column type="expand" :label="'展开'" width="50px">
<template slot-scope="scope">
<el-table :data="scope.row.data">
<el-table-column prop="OP_TIME" :label="'诊断时间'" width="155px">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_TIME" />
</template>
</el-table-column>
<el-table-column prop="DIAG_ICD" :label="'诊断编码'">
<template slot-scope="scope2">
<div v-html="scope2.row.DIAG_ICD" />
</template>
</el-table-column>
<el-table-column prop="DIAG_NAME" :label="'诊断内容'" show-overflow-tooltip>
<template slot-scope="scope2">
<div v-html="scope2.row.DIAG_NAME" />
</template>
</el-table-column>
<el-table-column prop="DIAG_ICD_ATTACH" :label="'附加'">
<template slot-scope="scope2">
<div v-html="scope2.row.DIAG_ICD_ATTACH" />
</template>
</el-table-column>
<el-table-column prop="OP_USER_NAME" :label="'诊断医生'">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_USER_NAME" />
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column prop="opDate" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="opContent" show-overflow-tooltip>
<template slot="header" slot-scope="{}">
<div class="header-wrapper">
<span>主要内容诊断</span>
<el-input v-model="searchKeyWord" class="header-search" size="mini" placeholder="关键词" @keyup.enter.native="searchNext">
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '诊断',
searchColumn: ['OP_TIME', 'DIAG_ICD', 'DIAG_NAME', 'DIAG_ICD_ATTACH', 'OP_USER_NAME']
}
}
}
</script>

73
src/components/patient-view/detail/ecrf.vue

@ -0,0 +1,73 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column prop="INPUT_DATE" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="CRF_NAME" :label="'表单'" show-overflow-tooltip />
<el-table-column label="操作" header-align="center" align="center" width="120">
<template slot-scope="scope">
<el-button type="text" size="small" @click="btnEcrfViewClick(scope.row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<ecrf-view v-if="visible" ref="ecrfView" :type="'load'" print edit remove @remove="remove" @edit="edit" />
<!-- 填写 -->
<follow-up-edit v-if="followUpVisible" ref="followUpEdit" @refreshData="refreshData" />
</div>
</template>
<script>
import myMixin from './_mixin'
import ecrfView from '@/components/ecrf/dialog-load.vue'
import followUpEdit from '@/components/ecrf/follow-up-edit.vue'
export default {
components: { ecrfView, followUpEdit },
mixins: [myMixin],
data() {
return {
visible: false,
followUpVisible: false,
ecrfId: '',
type: '表单'
}
},
methods: {
btnEcrfViewClick(row) {
this.visible = true
this.$nextTick(() => {
this.$refs.ecrfView.id = String(row.ID)
this.$refs.ecrfView.init()
})
},
remove(id) {
this.$emit('refresh')
},
edit(id) {
const obj = this.dataList.find(item => item.ID === id)
console.log(this.dataList, obj, id)
if (obj) {
this.visible = false
this.$nextTick(() => {
this.followUpVisible = true
this.$nextTick(() => {
this.$refs.followUpEdit.id = String(obj.ID)
this.$refs.followUpEdit.crfId = String(obj.CRF_ID)
this.$refs.followUpEdit.patientIdNumber = obj.PATIENT_ID_NUMBER
this.$refs.followUpEdit.init()
})
})
}
}
}
}
</script>

83
src/components/patient-view/detail/emr-treatments.vue

@ -0,0 +1,83 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column type="expand" :label="'展开'" width="50px">
<template slot-scope="scope">
<el-form label-width="120px" class="expand-form">
<el-form-item :label="'就诊时间'">
<div v-html="scope.row.TREAT_TIME" />
</el-form-item>
<el-form-item :label="'主诉'">
<div v-html="scope.row.COMP_CONTENT" />
</el-form-item>
<el-form-item :label="'现病史'">
<div v-html="scope.row.ILLN_CONTENT" />
</el-form-item>
<el-form-item :label="'既往史'">
<div v-html="scope.row.HIS_ILLN_CONTENT" />
</el-form-item>
<el-form-item :label="'诊断'">
<div v-html="scope.row.DIAG_NAME" />
</el-form-item>
<el-form-item :label="'处理意见'">
<div v-html="scope.row.EMR_TREA_SUGGESTION" />
</el-form-item>
<el-form-item :label="'专科检查文本'">
<div v-html="scope.row.EMR_SPEC_TEXT" />
</el-form-item>
<el-form-item :label="'医生姓名'">
<div v-html="scope.row.DOCTOR_NAME" />
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column prop="OP_DATE" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="DIAG_NAME" :label="'主要内容(诊断)'" show-overflow-tooltip>
<template slot="header" slot-scope="{}">
<div class="header-wrapper">
<span>主要内容诊断</span>
<el-input v-model="searchKeyWord" class="header-search" size="mini" placeholder="关键词" @keyup.enter.native="searchNext">
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '门诊',
searchColumn: [
'TREAT_TIME',
'COMP_CONTENT',
'ILLN_CONTENT',
'HIS_ILLN_CONTENT',
'DIAG_NAME',
'EMR_TREA_SUGGESTION',
'EMR_SPEC_TEXT',
'DOCTOR_NAME'
]
}
}
}
</script>

118
src/components/patient-view/detail/exam-item.vue

@ -0,0 +1,118 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column type="expand" :label="'展开'" width="50px">
<template slot-scope="scope">
<el-table :data="scope.row.data">
<el-table-column prop="EXAM_TIME" :label="'检查时间'" width="155px">
<template slot-scope="scope2">
<div v-html="scope2.row.EXAM_TIME" />
</template>
</el-table-column>
<el-table-column prop="EXAMINE_ITEM" :label="'检查项目'">
<template slot-scope="scope2">
<div v-html="scope2.row.ITEM_NAME || scope2.row.EXAMINE_ITEM" />
</template>
</el-table-column>
<el-table-column :label="'检查报告'">
<template slot-scope="scope2">
<el-button type="text" @click="showReport(scope2.row)">当次报告</el-button>
<el-button type="text" @click="showReportAll(scope2.row)">所有报告</el-button>
</template>
</el-table-column>
</el-table>
<!-- EXAM_NO EXAMINE_CODE ITEM_ID ITEM_NAME -->
</template>
</el-table-column>
<el-table-column prop="opDate" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="opContent" :label="'主要内容(检查项目)'" show-overflow-tooltip>
<template slot="header" slot-scope="{}">
<div class="header-wrapper">
<span>主要内容检查项目</span>
<el-input v-model="searchKeyWord" class="header-search" size="mini" placeholder="关键词" @keyup.enter.native="searchNext">
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</div>
</template>
</el-table-column>
</el-table>
<el-dialog
width="95%"
top="5vh"
class="dialog-iframe"
:title="examItemName||''"
:visible.sync="dialogVisible"
append-to-body
>
<iframe :src="src" width="100%" height="100%" frameborder="0" scrolling="yes" />
</el-dialog>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
dialogVisible: false,
examItemName: '',
src: '',
type: '检查',
searchColumn: [
'EXAM_TIME',
'ITEM_NAME'
]
}
},
methods: {
showReport(scopeRow) {
// scopeRow.examTime = this.$options.filters['dateFilterThree'](scopeRow.examTime)
this.dialogVisible = true
this.examItemName = scopeRow.EXAMINE_ITEM
this.src = `${window.SITE_CONFIG['pacsWeb2URL']}/file/default1.asp?pid=${scopeRow.PATIENT_ID}&examdate=(''${this.$options.filters['dateFilterThree'](scopeRow.EXAM_DATE)}${scopeRow.EXAMINE_CODE}'')&itemcode=x&language=zh-CN&risNo=${scopeRow.RIS_NO}&examNo=${scopeRow.EXAM_NO}`
},
showReportAll(scopeRow) {
// scopeRow.examTime = this.$options.filters['dateFilterThree'](scopeRow.examTime)
this.dialogVisible = true
this.examItemName = scopeRow.EXAMINE_ITEM
this.src = `${window.SITE_CONFIG['pacsWeb2URL']}/file/default1.asp?pid=${scopeRow.PATIENT_ID}&itemcode=''${scopeRow.EXAMINE_CODE}''`
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
.dialog-iframe {
::v-deep .el-dialog__header{
padding: 5px 20px;
.el-dialog__headerbtn{
top: 10px;
}
}
::v-deep .el-dialog__body{
height: calc(90vh - 70px);
}
}
</style>

57
src/components/patient-view/detail/inhospital.vue

@ -0,0 +1,57 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column prop="IN_DATE" :label="'住院时间'" width="160px" />
<el-table-column prop="OUT_DATE" :label="'出院时间'" width="160px" />
<el-table-column prop="DIAG_NAME" :label="'住院诊断'" show-overflow-tooltip />
<el-table-column prop="DIAG_ID" :label="'诊断编号'" />
<el-table-column prop="DEPT_NAME" :label="'部门'" />
<el-table-column prop="WARD_NAME" :label="'病区'" />
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
props: {
dateType: { type: String, default: 'in' }
},
data() {
return {
type: '住院'
}
},
methods: {
setIndexDate(date) {
// console.log(date, this.dateType)
if (date) {
const rowIndex = this.dataList.findIndex(item => {
return (this.dateType === 'in' && item.IN_DATE && item.IN_DATE.indexOf(date) >= 0) ||
(this.dateType === 'out' && item.OUT_DATE && item.OUT_DATE.indexOf(date) >= 0)
})
setTimeout(() => {
this.setCurrentRow(rowIndex)
}, 200)
}
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
</style>

38
src/components/patient-view/detail/iop.vue

@ -0,0 +1,38 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column prop="EXAM_TIME" :label="'检查时间'" width="155px" />
<el-table-column prop="IOP_TYPE" :label="'检查类型'" width="155px" />
<el-table-column prop="S_OD_IOP" :label="'OD'" />
<el-table-column prop="S_OS_IOP" :label="'OS'" />
<el-table-column prop="EXAM_MEMO" :label="'备注'" />
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '眼压'
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
</style>

113
src/components/patient-view/detail/kpi.vue

@ -0,0 +1,113 @@
<template>
<div class="component-container">
<div>
<kpi-select v-model="kpiIdList" class="kpi-select" :type="2" @change="kpiChangeHandle" />
</div>
<div>
<echarts-line-kpi-iop ref="chartIOP" class="echart-kpi" :chart-data="dataVaIop.yanya" :title="'眼压'" />
<echarts-line-kpi-va ref="chartVA" class="echart-kpi" :chart-data="dataVaIop.shili" />
<!-- 指标选择 -->
<echarts-line-kpi
v-for="(item,index) in kpiValEchartsList"
ref="chartKPI"
:key="index"
class="echart-kpi"
:chart-data="item.data"
:title="item.label"
/>
</div>
</div>
</template>
<script>
import kpiSelect from '@/components/kpi-select'
import echartsLineKpi from '@/components/echarts/line-kpi'
import echartsLineKpiVa from '@/components/echarts/line-kpi-va'
import echartsLineKpiIop from '@/components/echarts/line-kpi-iop'
export default {
components: { echartsLineKpi, echartsLineKpiVa, echartsLineKpiIop, kpiSelect },
props: {
patientIdNumber: { type: String, required: true },
indexDate: { type: String, default: '' },
projectId: { type: String, default: '' }
},
data() {
return {
dataVaIop: [],
kpiIdList: [],
kpiValEchartsList: [], // echarts
kpiSelectItemList: []
}
},
watch: {
kpiSelectItemList: {
handler(newVal, oldVal) {
//
const arrAdd = newVal.filter(x => oldVal.every(y => y.value !== x.value))
//
const arrDel = oldVal.filter(x => newVal.every(y => y.value !== x.value))
arrAdd.forEach(item => {
this.getKPIValue(item)
})
arrDel.forEach(item => {
const index = this.kpiValEchartsList.findIndex(item2 => item2.id === item.value)
if (index >= 0) { this.kpiValEchartsList.splice(index, 1) }
})
},
deep: true
}
},
created() { this.getDataVaIop() },
mounted() { },
methods: {
getDataVaIop() {
this.$http.get('/patient/view/getShiLiAndYanyaData', { params: { patientIdNumber: this.patientIdNumber }})
.then(({ data: res }) => {
this.dataVaIop = res.data
})
},
kpiChangeHandle(itemList) {
this.kpiSelectItemList = itemList
},
getKPIValue(item) {
this.$http.get('/patient/view/kpiData', {
params: {
kpiId: item.value,
patientIdNumber: this.patientIdNumber
}
}).then(({ data: res }) => {
this.kpiValEchartsList.push({
id: item.value,
label: item.label,
data: res.data
})
})
},
resize() {
this.$refs.chartIOP.resize()
this.$refs.chartVA.resize()
if (Array.isArray(this.$refs.chartKPI)) {
this.$refs.chartKPI.forEach(el => {
el.resize()
})
}
}
}
}
</script>
<style lang="scss" scoped>
.kpi-select {
width: calc(100% - 40px);
padding-left: 20px;
}
.echart-kpi {
width: 100%;
margin-top: 10px;
}
</style>

99
src/components/patient-view/detail/medication.vue

@ -0,0 +1,99 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column type="expand" :label="'展开'" width="50px">
<template slot-scope="scope">
<el-table :data="scope.row.data">
<el-table-column prop="OP_TIME" :label="'开药时间'" width="155px">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_TIME" />
</template>
</el-table-column>
<el-table-column prop="MED_NAME" :label="'药品(商品名)'">
<template slot-scope="scope2">
<div v-html="scope2.row.MED_NAME" />
</template>
</el-table-column>
<el-table-column prop="SOC_NAME" :label="'药品(通用名)'" show-overflow-tooltip>
<template slot-scope="scope2">
<div v-html="scope2.row.SOC_NAME" />
</template>
</el-table-column>
<el-table-column prop="NUMBER_USE" :label="'用药数量'">
<template slot-scope="scope2">
<div v-html="scope2.row.NUMBER_USE" />
</template>
</el-table-column>
<el-table-column prop="SITE" :label="'用药部位'">
<template slot-scope="scope2">
<div v-html="scope2.row.SITE" />
</template>
</el-table-column>
<el-table-column prop="FREQUENCY" :label="'给药频率'">
<template slot-scope="scope2">
<div v-html="scope2.row.FREQUENCY" />
</template>
</el-table-column>
<el-table-column prop="ITEM_TYPE" :label="'门诊/住院'">
<template slot-scope="scope2">
<div v-html="scope2.row.ITEM_TYPE" />
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column prop="opDate" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="opContent" :label="'主要内容(商品名)'" show-overflow-tooltip>
<template slot="header" slot-scope="{}">
<div class="header-wrapper">
<span>主要内容商品名</span>
<el-input v-model="searchKeyWord" class="header-search" size="mini" placeholder="关键词" @keyup.enter.native="searchNext">
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '用药',
searchColumn: [
'OP_TIME',
'MED_NAME',
'SOC_NAME',
'NUMBER_USE',
'SITE',
'FREQUENCY',
'ITEM_TYPE'
]
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
</style>

87
src/components/patient-view/detail/operation.vue

@ -0,0 +1,87 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column type="expand" :label="'展开'" width="50px">
<template slot-scope="scope">
<el-table :data="scope.row.data">
<el-table-column prop="OP_TIME" :label="'手术时间'" width="155px">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_TIME" />
</template>
</el-table-column>
<el-table-column prop="OP_NAME" :label="'手术名称'">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_NAME" />
</template>
</el-table-column>
<el-table-column prop="OP_PART_NAME" :label="'手术部位'">
<template slot-scope="scope2">
<div v-html="scope2.row.OP_PART_NAME" />
</template>
</el-table-column>
<el-table-column prop="MAIN_DR_NAME" :label="'主刀医生'">
<template slot-scope="scope2">
<div v-html="scope2.row.MAIN_DR_NAME" />
</template>
</el-table-column>
<el-table-column prop="DEPT_NAME" :label="'部门'">
<template slot-scope="scope2">
<div v-html="scope2.row.DEPT_NAME" />
</template>
</el-table-column>
<el-table-column prop="WARD_NAME" :label="'病区'">
<template slot-scope="scope2">
<div v-html="scope2.row.WARD_NAME" />
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column prop="opDate" :label="'日期'" width="120px" header-align="center" align="center" />
<el-table-column prop="opContent" :label="'主要内容(手术)'" show-overflow-tooltip>
<template slot="header" slot-scope="{}">
<div class="header-wrapper">
<span>主要内容手术</span>
<el-input v-model="searchKeyWord" class="header-search" size="mini" placeholder="关键词" @keyup.enter.native="searchNext">
<span slot="suffix" class="search-result">
{{ ((searchIndex==-1)?0:(searchIndex+1))+'/'+searchResult.length }}
</span>
<i slot="suffix" class="el-input__icon el-icon-arrow-down" title="下一个" @click="searchNext" />
<i slot="suffix" class="el-input__icon el-icon-arrow-up" title="上一个" @click="searchLast" />
<i slot="suffix" class="el-input__icon el-icon-refresh" title="重置" @click="searchReset" />
</el-input>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '手术',
searchColumn: [
'OP_TIME',
'OP_NAME',
'OP_PART_NAME',
'MAIN_DR_NAME',
'DEPT_NAME',
'WARD_NAME'
]
}
}
}
</script>

55
src/components/patient-view/detail/ref.vue

@ -0,0 +1,55 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column prop="EXAM_TIME" :label="'检查时间'" width="160px" />
<el-table-column prop="EXAM_TYPE" :label="'验光类型'" width="120px" header-align="center" align="center" />
<el-table-column :label="'OD'" header-align="center">
<el-table-column prop="OD_SPH" label="球镜" header-align="center" align="center" />
<el-table-column prop="OD_CYL" label="柱镜" header-align="center" align="center" />
<el-table-column prop="OD_AX" label="轴向" header-align="center" align="center" />
<el-table-column prop="OD_SE" label="等效球镜" header-align="center" align="center" />
<el-table-column prop="OD_VA" label="矫正视力" header-align="center" align="center" />
<el-table-column prop="OD_VD" label="顶点距" header-align="center" align="center" />
<el-table-column prop="OD_PS" label="瞳孔大小" header-align="center" align="center" />
<el-table-column prop="S_OD_MEMO" label="备注" />
</el-table-column>
<el-table-column :label="'OS'" header-align="center">
<el-table-column prop="OS_SPH" label="球镜" header-align="center" align="center" />
<el-table-column prop="OS_CYL" label="柱镜" header-align="center" align="center" />
<el-table-column prop="OS_AX" label="轴向" header-align="center" align="center" />
<el-table-column prop="OS_SE" label="等效球镜" header-align="center" align="center" />
<el-table-column prop="OS_VA" label="矫正视力" header-align="center" align="center" />
<el-table-column prop="OS_VD" label="顶点距" header-align="center" align="center" />
<el-table-column prop="OS_PS" label="瞳孔大小" header-align="center" align="center" />
<el-table-column prop="S_OS_MEMO" label="备注" />
</el-table-column>
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '验光'
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
</style>

40
src/components/patient-view/detail/va.vue

@ -0,0 +1,40 @@
<template>
<div class="component-wrapper">
<el-table
ref="dataList"
v-loading="dataListLoading"
highlight-current-row
height="100%"
:data="dataList"
border
:row-class-name="'row-1'"
>
<el-table-column prop="EXAM_TIME" :label="'检查时间'" width="155px" />
<el-table-column prop="EXAM_TYPE" :label="'数据来源'" width="150px" />
<el-table-column prop="S_OD_VAN" :label="'OD(裸眼)'" />
<el-table-column prop="S_OS_VAN" :label="'OS(裸眼)'" />
<el-table-column prop="S_OD_VAG" :label="'OD(矫正)'" />
<el-table-column prop="S_OS_VAG" :label="'OS(矫正)'" />
<el-table-column prop="EXAM_MEMO" :label="'备注'" show-overflow-tooltip />
</el-table>
</div>
</template>
<script>
import myMixin from './_mixin'
export default {
mixins: [myMixin],
data() {
return {
type: '视力'
}
}
}
</script>
<style lang="scss" scoped>
// .component-wrapper{
// height: auto !important;
// }
</style>

629
src/components/patient-view/index.vue

@ -0,0 +1,629 @@
<template>
<el-container class="component-wrapper">
<!-- 时间轴 -->
<el-aside class="time-line-wrapper" width="250px">
<!-- 检索 -->
<div class="toolbar-wrapper">
<el-input v-model="filterText" size="mini" placeholder="快速检索" class="filter-input" />
<el-dropdown size="medium" class="tree-set">
<i class="el-icon-set-up icon-dropdown" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="expandAll(true)">全部展开</el-dropdown-item>
<el-dropdown-item @click.native="expandAll(false)">全部折叠</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div v-loading="treeLoading" class="tree-wrapper">
<el-tree
ref="tree"
class="filter-tree"
:data="treeData"
:props="treeSet"
:expand-on-click-node="true"
default-expand-all
:filter-node-method="filterNode"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<!-- 日期节点 -->
<template v-if="data.children">
<span>{{ data.label }}</span>
</template>
<!-- 叶子节点 -->
<template v-else>
<template v-if="data.opContent">
<el-tooltip effect="dark" :content="data.opContent" placement="bottom-end">
<el-tag size="mini" @click="treeNodeTagClickHandle(data)">{{ data.label }}</el-tag>
</el-tooltip>
</template>
<template v-else>
<el-tag size="mini" @click="treeNodeTagClickHandle(data)">{{ data.label }}</el-tag>
</template>
</template>
</span>
</el-tree>
</div>
</el-aside>
<el-container class="info-wrapper">
<!-- 信息 -->
<el-header class="patient-info-wrapper" :height="isSubject&&patientInfo.visitInfo?'200px':'145px'">
<el-descriptions v-loading="infoLoading" :title="patientInfo.patientName||''" :column="3" border>
<template slot="title">
{{ patientInfo.patientName||'' }}
<i :class="sexClass" class="icon-sex" />
<!-- <el-button size="mini" icon="el-icon-refresh" title="刷新" @click="refresh" />
<el-button size="mini" icon="el-icon-refresh" title="刷新" @click="refresh" /> -->
</template>
<template slot="extra">
<!-- 收藏 -->
<el-button
size="mini"
:icon="isCollected?'el-icon-star-on':'el-icon-star-off'"
:title="isCollected?'已收藏':'收藏'"
:class="[isCollected?'isCollected':'']"
@click="collect"
/>
<!-- 全屏 -->
<el-button size="mini" icon="el-icon-full-screen" title="全屏切换" @click="fullscreenHandle" />
<!-- 刷新 -->
<el-button size="mini" icon="el-icon-refresh" title="刷新" @click="refresh" />
<!-- 其他按钮 -->
<template v-if="isSubject&&projectId">
<el-button type="primary" size="mini" icon="el-icon-edit" @click="btnEcrfClick">表单</el-button>
<el-button type="primary" size="mini" icon="el-icon-setting" @click="btnFollowUpClick">随访</el-button>
</template>
</template>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-user" />
身份证号
</template>
{{ patientInfo.patientIdNumber | f_desensitize_idNumber }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<svg-icon icon-class="icon-birthday" />
当前年龄
</template>
{{ patientInfo.birthday | f_getAge }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone" />
联系电话
</template>
<span style="display: inline-block;width: 100px;">{{ patientTel }} </span>
<template v-if="isSubject">
<svg-icon :icon-class="viewTel?'icon-visible':'icon-disvisible'" @click="viewTel = !viewTel" />
</template>
</el-descriptions-item>
<!-- 随访信息 -->
<template v-if="isSubject&&patientInfo.visitInfo">
<el-descriptions-item>
<template slot="label">
<i class="el-icon-tickets" />
随访方案
</template>
{{ patientInfo.visitInfo.visitName }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-time" />
最近到访
</template>
{{ patientInfo.visitInfo.lastDate | dateFilterTwo }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-time" />
下次到访
</template>
{{ patientInfo.visitInfo.planDate | dateFilterTwo }}
</el-descriptions-item>
</template>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building" />
联系地址
</template>
{{ patientInfo.address | f_desensitize_address }}
</el-descriptions-item>
</el-descriptions>
</el-header>
<!-- 展示面板 -->
<el-main class="view-wrapper">
<el-tabs ref="tabs" v-model="tabActiveName" class="tabs-wrapper" type="border-card" @tab-click="tabClickHandle">
<el-tab-pane label="诊断" name="诊断">
<diagnose ref="diagnose" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="手术" name="手术">
<operation ref="operation" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="用药" name="用药">
<medication ref="medication" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="检查项目" name="检查项目">
<exam-item ref="examItem" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="门诊" name="门诊">
<emr-treatments ref="emrTreatments" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="住院" name="住院">
<inhospital
ref="inhospital"
:style="{height:tabBodyHeight}"
:date-type="inhospitalType"
:patient-id-number="patientIdNumber"
/>
</el-tab-pane>
<el-tab-pane label="视力" name="视力">
<va ref="va" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="眼压" name="眼压">
<iop ref="iop" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane label="验光" name="验光">
<ref ref="ref" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
<el-tab-pane v-if="projectId" label="表单" name="表单">
<ecrf
ref="ecrf"
:style="{height:tabBodyHeight}"
:patient-id-number="patientIdNumber"
:project-id="projectId"
@refresh="refreshDataEcrf"
/>
</el-tab-pane>
<el-tab-pane label="单项数据" name="单项数据">
<kpi ref="kpi" :style="{height:tabBodyHeight}" :patient-id-number="patientIdNumber" />
</el-tab-pane>
</el-tabs>
</el-main>
</el-container>
<!-- 弹窗--随访表单 -->
<ecrf-select
v-if="crfSelectVisible"
ref="goCrfSelect"
:patient-id-number="patientIdNumber"
@refreshData="refreshDataEcrf"
/>
<set-followup
v-if="setFollowUpVisible"
ref="goFollowUp"
:patient-id-number="patientIdNumber"
@refreshData="refreshInfo"
/>
</el-container>
</template>
<script>
import fullscreen from '@/mixins/full-screen'
import { isMobile } from '@/utils/validate.js'
import { groupBy } from '@/utils/tree.js'
import diagnose from './detail/diagnose.vue'
import operation from './detail/operation.vue'
import medication from './detail/medication.vue'
import examItem from './detail/exam-item.vue'
import inhospital from './detail/inhospital.vue'
import va from './detail/va.vue'
import iop from './detail/iop.vue'
import ref from './detail/ref.vue'
import ecrf from './detail/ecrf.vue'
import kpi from './detail/kpi.vue'
import emrTreatments from './detail/emr-treatments.vue'
import ecrfSelect from '@/components/ecrf/ecrf-select.vue'
import setFollowup from './set-followup.vue'
export default {
components: {
diagnose,
operation,
medication,
examItem,
inhospital,
emrTreatments,
va,
iop,
ref,
kpi,
ecrf,
ecrfSelect,
setFollowup
},
mixins: [fullscreen],
props: {
patientIdNumber: { type: String, required: true },
projectId: { type: String, default: '' },
isSubject: { type: Boolean, default: false }
},
data() {
return {
isCollected: false,
treeLoading: false,
infoLoading: false,
treeSet: {
children: 'children',
label: 'label'
},
timeLineData: [],
filterText: '',
treeData: [],
patientInfo: {},
tabActiveName: '诊断',
tabBodyHeight: '500px',
inhospitalType: 'in',
crfSelectVisible: false,
setFollowUpVisible: false,
viewTel: false
}
},
computed: {
sexClass() {
if (this.patientInfo.sex) {
return {
'el-icon-female female': this.patientInfo.sex.indexOf('女') >= 0,
'el-icon-male male': this.patientInfo.sex.indexOf('男') >= 0
}
} else {
return { 'el-icon-user': true }
}
},
patientTel() {
if (this.viewTel) {
return this.patientInfo.tel
}
if (this.patientInfo.tel && isMobile(this.patientInfo.tel)) {
return this.$options.filters['f_desensitize_phone'](this.patientInfo.tel)
} else { return this.patientInfo.tel }
}
},
watch: {
filterText(val) {
this.$refs.tree.filter(val)
}
},
created() {
this.getPatientInfo()
this.getTimeLine()
},
mounted() {
const elTabsBody = this.$refs.tabs.$el.querySelector('.el-tabs__content')
this.tabBodyHeight = (elTabsBody.clientHeight - 30) + 'px'
},
methods: {
hasCollected() {
this.$http.get('/collect/patient/judgeExist', { params: { patientIdNumber: this.patientIdNumber }}).then(({ data: res }) => {
// eslint-disable-next-line no-eval
this.isCollected = eval(res.data)
})
},
collect() {
if (!this.isCollected) {
//
this.$http.post('/collect/patient', { patientIdNumber: this.patientIdNumber }).then(({ data: res }) => {
this.isCollected = true
})
} else {
//
this.$http.delete('/collect/patient', { data: [this.patientIdNumber] }).then(({ data: res }) => {
this.isCollected = false
})
}
},
refreshInfo() {
this.getPatientInfo()
this.getTimeLine()
},
refreshDataEcrf() {
this.crfSelectVisible = false
this.tabActiveName = '表单'
this.$refs.ecrf.getDataList('表单')
this.getTimeLine()
},
refresh() {
this.getPatientInfo()
this.getTimeLine()
this.tabActiveName = '诊断'
this.$refs.diagnose.refreshData()
this.$refs.operation.refreshData()
this.$refs.medication.refreshData()
this.$refs.examItem.refreshData()
this.$refs.emrTreatments.refreshData()
this.$refs.inhospital.refreshData()
this.$refs.va.refreshData()
this.$refs.iop.refreshData()
this.$refs.ref.refreshData()
if (this.$refs.ecrf) { this.$refs.ecrf.refreshData() }
},
getPatientInfo() {
this.infoLoading = true
this.$http.get('/patient/view/patInfo', {
params: {
patientIdNumber: this.patientIdNumber,
projectId: this.projectId ? this.projectId : null
}
}).then(({ data: res }) => {
this.patientInfo = res.data || {}
this.infoLoading = false
}).catch(() => { this.infoLoading = false })
this.hasCollected()
},
getTimeLine() {
this.treeLoading = true
this.$http.get('/patient/view/timeline', {
params: {
patientIdNumber: this.patientIdNumber,
projectId: this.projectId ? this.projectId : null
}
}).then(({ data: res }) => {
this.timeLineData = res.data
this.treeData = groupBy(this.timeLineData, 'opDate', 'groupName')
// this.$nextTick(() => {console.log(this.$refs.tree.$children) })
this.treeLoading = false
}).catch(() => { this.treeLoading = false })
},
filterNode(value, data, node) {
// value-
// data -
// node -
if (!value) return true
this.expandAll(true)
value = value.toUpperCase()
return data.label.toUpperCase().indexOf(value) !== -1 || (data.opContent && data.opContent.toUpperCase().indexOf(value) !== -1)
},
expandAll(isExpandAll) {
this.$refs.tree.$children.forEach(item => {
item.expanded = isExpandAll
})
},
tabClickHandle(tab, event) {
if (tab.name === '单项数据') {
this.$refs.kpi.resize()
}
},
treeNodeTagClickHandle(nodeData) {
switch (nodeData.label) {
case '诊断':
this.tabActiveName = '诊断'
this.$refs.diagnose.setIndexDate(nodeData.opDate)
break
case '手术':
this.tabActiveName = '手术'
this.$refs.operation.setIndexDate(nodeData.opDate)
break
case '用药':
this.tabActiveName = '用药'
this.$refs.medication.setIndexDate(nodeData.opDate)
break
case '检查':
this.tabActiveName = '检查项目'
this.$refs.examItem.setIndexDate(nodeData.opDate)
break
case '门诊':
this.tabActiveName = '门诊'
this.$refs.emrTreatments.setIndexDate(nodeData.opDate)
break
case '住院':
this.tabActiveName = '住院'
this.inhospitalType = 'in'
this.$refs.inhospital.setIndexDate(nodeData.opDate)
break
case '出院':
this.tabActiveName = '住院'
this.inhospitalType = 'out'
this.$refs.inhospital.setIndexDate(nodeData.opDate)
break
case '视力':
this.tabActiveName = '视力'
this.$refs.va.setIndexDate(nodeData.opDate)
break
case '眼压':
this.tabActiveName = '眼压'
this.$refs.iop.setIndexDate(nodeData.opDate)
break
case '验光':
this.tabActiveName = '验光'
this.$refs.ref.setIndexDate(nodeData.opDate)
break
case '表单':
this.tabActiveName = '表单'
this.$refs.ecrf.setIndexDate(nodeData.opDate)
break
default:
this.tabActiveName = '诊断'
this.$refs.diagnose.setIndexDate(nodeData.opDate)
break
}
},
//
btnEcrfClick() {
this.crfSelectVisible = true
this.$nextTick(() => {
this.$refs.goCrfSelect.init()
})
},
// 访
btnFollowUpClick() {
this.setFollowUpVisible = true
this.$nextTick(() => {
this.$refs.goFollowUp.init()
})
}
}
}
</script>
<style lang="scss" scoped>
.component-wrapper {
width: 100%;
height: calc(100vh - 65px);
}
//
.time-line-wrapper {
.toolbar-wrapper {
height: 40px;
.filter-input {
padding: 5px;
width: 200px;
}
.tree-set {
vertical-align: middle;
.icon-dropdown {
margin-left: 10px;
font-size: 20px;
}
}
}
//
.tree-wrapper {
height: calc(100% - 40px);
padding-top: 5px;
overflow: auto;
border: 1px solid #ebeef5;
background: #fff;
}
}
//
.info-wrapper {
padding-left: 10px;
//
.patient-info-wrapper {
padding: 5px 0 0;
.icon-sex {
font-size: 16px;
}
.female {
color: #f8667f;
}
.male {
color: #4550f3;
}
::v-deep .el-descriptions__header {
margin-bottom: 8px;
// margin-top: 5px;
padding-left: 5px;
.el-descriptions__title {
font-size: 20px;
font-weight: bolder;
color: #767a82;
}
}
}
//
.view-wrapper {
// background: #c4e93f;
padding: 0;
.tabs-wrapper {
height: 100%;
overflow: hidden;
// ::v-deep .el-tabs__header{
// height: 39px;
// }
::v-deep .el-tabs__content {
height: calc(100% - 39px);
overflow: auto;
}
}
}
}
.filter-tree {
padding-right: 20px;
//
> ::v-deep .el-tree-node > .el-tree-node__content {
font-weight: 700;
}
// children
> ::v-deep .el-tree-node > .el-tree-node__children {
white-space: normal;
padding-left: 20px;
// ()
> .el-tree-node {
display: inline-block;
//
.el-tree-node__content {
padding-left: 5px !important;
.is-leaf {
display: none;
}
}
}
}
}
.isCollected {
padding: 2px 12px 5px 12px;
color: #f1a33c;
font-size: 18px;
}
</style>
<style lang='scss'>
.header-wrapper {
display: flex;
justify-content: space-between;
.header-search {
width: 300px;
}
.el-input__suffix {
display: flex;
align-items: center;
.el-input__suffix-inner {
.search-result {
display: inline-block;
padding: 0 10px;
border-right: 1px solid #c0c4cc;
}
.el-input__icon {
cursor: pointer;
width: 20px;
border-radius: 20px;
line-height: 20px;
margin: 4px 2px;
}
.el-input__icon:hover {
background: #c0c4cc;
color: #fff;
}
}
}
}
</style>

134
src/components/patient-view/set-followup.vue

@ -0,0 +1,134 @@
<template>
<el-dialog title="设置随访方案" :visible.sync="visible" append-to-body>
<el-form
ref="dataForm"
v-loading="loading"
:model="dataForm"
:rules="dataRule"
label-width="120px"
@submit.native.prevent
@keyup.enter.native="dataFormSubmitHandle()"
>
<el-form-item label="上次到访日期" prop="lastVisitDate">
<el-date-picker
v-model="dataForm.lastVisitDate"
type="date"
placeholder="请选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width:300px;"
/>
</el-form-item>
<el-form-item label="选择随访方案" prop="visitId">
<el-select v-model="dataForm.visitId" placeholder="请选择随访方案" style="width:300px;">
<el-option v-for="item in options_visit" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="备注信息" prop="remark">
<el-input v-model="dataForm.remark" type="textarea" placeholder="请输入变更随访方案的原因" />
</el-form-item>
</el-form>
<template slot="footer">
<el-button @click="visible = false">{{ $t('cancel') }}</el-button>
<el-button type="primary" @click="dataFormSubmitHandle()">{{ $t('confirm') }}</el-button>
</template>
</el-dialog>
</template>
<script>
import debounce from 'lodash/debounce'
export default {
props: {
patientIdNumber: { type: String, required: true }
},
data() {
return {
loading: false,
visible: false,
options_visit: [],
dataForm: {
lastVisitDate: '',
visitId: '',
remark: ''
}
}
},
computed: {
dataRule() {
// const validate_planList = (rule, value, callback) => {
// return (value && value.length > 0) ? callback() : callback(new Error('访'))
// }
// return {
// name: [{ required: true, message: this.$t('validate.required'), trigger: 'blur' }],
// planList: [{ required: true, validator: validate_planList, trigger: 'blur' }]
// }
return {}
}
},
created() { this.getFollowList() },
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.resetDataForm()
this.getInfo()
})
},
resetDataForm() {
this.$refs.dataForm.resetFields()
},
// 访
getFollowList() {
this.$http.get('/visit/page', { params: {
limit: 1000,
page: 1,
projectId: window.SITE_CONFIG['projectId'] }
}).then(({ data: res }) => {
if (res.data) { this.options_visit = res.data.list || [] }
})
},
//
getInfo() {
this.loading = true
this.$http.get('/visit/pat', {
params: {
patientIdNumber: this.patientIdNumber,
projectId: window.SITE_CONFIG['projectId']
}
}).then(({ data: res }) => {
console.log(res.data)
this.dataForm = { ...this.dataForm, ...res.data }
this.loading = false
}).catch(() => { this.loading = false })
},
//
dataFormSubmitHandle: debounce(function() {
this.$refs.dataForm.validate((valid) => {
if (!valid) { return false }
this.$http.post('/visit/bindPat',
{ ...this.dataForm,
lastDate: this.dataForm.lastVisitDate,
projectId: window.SITE_CONFIG['projectId'],
patientIdNumber: this.patientIdNumber
}).then(({ data: res }) => {
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshData')
}
})
})
})
}, 1000, { leading: true, trailing: false })
}
}
</script>
<style>
</style>

16
src/mixins/full-screen.js

@ -0,0 +1,16 @@
import screenfull from 'screenfull'
export default {
methods: {
fullscreenHandle() {
if (!screenfull.enabled) {
return this.$message({
message: this.$t('fullscreen.prompt'),
type: 'warning',
duration: 500
})
}
screenfull.toggle()
}
}
}

13
src/page-subspecialty/router/index.js

@ -47,14 +47,7 @@ export const pageRoutes = [
component: () => import('@/page-subspecialty/views/pages/pacs/index'),
name: 'pacs',
meta: { title: 'pacs浏览器', isTab: true }
},
{
path: '/subjectMgt',
component: () => import('@/page-subspecialty/views/pages/subjectManage/index'),
name: 'subjectMgt',
meta: { title: '课题管理', isTab: true }
}
]
// 模块路由(基于主入口布局页面)*8
@ -78,6 +71,12 @@ export const moduleRoutes = {
meta: { title: '详情', isTab: true },
component: () => import('@/page-subspecialty/views/modules/optometryManagement/seeDoctor/index')
},
{
path: '/subjectMgt',
name: 'subjectMgt',
meta: { title: '样本库', isTab: true },
component: () => import('@/page-subspecialty/views/modules/scientificManagement/subjectMgt/index')
},
{
path: '/iframe',
component: null,

2
src/page-subspecialty/views/modules/imgEditorFabric/img-editor/bgBar.vue

@ -60,7 +60,7 @@ export default {
// console.log(imgEl)
imgEl.onload = () => {
//
const imgInstance = new this.fabric.Image(imgEl, { crossOrigin: 'anonymous' })
const imgInstance = new this.fabric.Image(imgEl, { crossOrigin: 'anonymous', erasable: false })
// console.log(imgInstance)
//
this.canvas.c.setBackgroundImage(imgInstance, this.canvas.c.renderAll.bind(this.canvas.c), {

39
src/page-subspecialty/views/modules/imgEditorFabric/index.vue

@ -39,7 +39,6 @@
<el-option :value="'钻石'">钻石</el-option>
</el-select>
</div>
<div class="drawing_item">
<div for="drawing-line-width">线条宽度:<span class="info">{{ lineWidth }}</span></div>
<el-slider v-model="lineWidth" :min="0" :max="150" @change="changeLineWidth" />
@ -50,12 +49,15 @@
<div for="drawing-color">线条颜色:</div>
<el-input id="drawing-color" class="toolStyle" type="color" value="#FF0000" />
</div>
<!-- <div class="drawing_item" style="display: flex;align-items: center">-->
<!-- <div>橡皮擦:</div>-->
<!-- <el-button @click="setEarser">橡皮擦</el-button>-->
<!-- </div>-->
<div class="drawing_item" id="eraser-btn" style="display: flex;align-items: center">
<div>橡皮擦: </div>
<el-button size="mini" @click="setEarser" type="text" style="font-size: 16px;margin-left: 4px">橡皮擦</el-button>
<!-- <span @click="setUndoErasing">恢复擦拭</span>-->
</div>
<div class="drawing_item" style="display: flex;align-items: center">
<div>画笔: </div>
<el-button size="mini" @click="changeModel('钻石')" type="text" style="font-size: 16px;margin-left: 4px">画笔</el-button>
</div>
</div>
</div>
</div>
@ -101,7 +103,6 @@ import 'fabric/src/mixins/eraser_brush.mixin'
import initAligningGuidelines from '@/core/initAligningGuidelines'
import initHotkeys from '@/core/initHotKeys'
import initControls from '@/core/initControls'
const event = new EventHandle()
const canvas = {}
export default {
@ -262,14 +263,20 @@ export default {
brush.width = parseInt(this.lineWidth, 10) || 1
}
},
// setEarser() {
// // canvas.isDrawingMode = true //
//
// //
// canvas.freeDrawingBrush = new fabric.PencilBrush(canvas)
// canvas.freeDrawingBrush.color = 'rgba(0,0,0,0)' //
// canvas.freeDrawingBrush.width = 20 //
// },
setEarser() {
this.canvas.isDrawingMode = true //
//
this.canvas.freeDrawingBrush = new fabric.EraserBrush(this.canvas)
this.canvas.freeDrawingBrush.color = 'rgba(0,0,0,0)' //
this.canvas.freeDrawingBrush.width = 30 //
},
setUndoErasing() {
this.canvas.isDrawingMode = true
this.canvas.freeDrawingBrush = new fabric.EraserBrush(this.canvas)
this.canvas.freeDrawingBrush.width = 10
this.canvas.freeDrawingBrush.inverted = true //
},
//
changeDrawing() {
this.canvas.isDrawingMode = !this.canvas.isDrawingMode

425
src/page-subspecialty/views/modules/optometryManagement/seeDoctor/first-visit/index.vue

@ -1,98 +1,385 @@
<template>
<div class="first-visit">
<!-- 首诊记录头部 -->
<head-template head-left="首诊记录">
<el-tooltip class="item" effect="dark" content="首诊单模板有新版本可点击更新" placement="top">
<el-button v-if="dataForm.isNew==2" type="danger" size="small" @click="updateHandle">更新</el-button>
</el-tooltip>
<!-- <el-button type="primary" size="small" @click="addOrUpdateHandle">填写</el-button>-->
<!-- <button v-print="'#printMe'" class="printer">打印</button> -->
<button class="printer" @click="printerHandle">打印</button>
<head-template>
<el-button type="primary" size="small" @click="saveCheckData()">保存</el-button>
<el-button v-print="'cornealPrint'" size="small">打印</el-button>
</head-template>
<p class="tips">如需补充患者首诊记录信息请点击填写按钮</p>
<!-- 首诊内容 -->
<div class="first-visit-content">
<div class="notice-content">
<div class="notice-box">
<div id="cornealPrint" class="notice_tip" style="page-break-after:always">
<h2 style="text-align: center;margin-bottom: 32px;">
验配流程
</h2>
<div style="float: right">
<span style="word-break: keep-all;font-size: 18px">验配日期</span>
<el-date-picker
style="width: 220px"
v-model="formData.patientCheckDate"
type="date"
/>
</div>
<table class="cornealTable">
<tr>
<td colspan="1"><div class="tdItem">姓名 <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div></td>
<td colspan="1"><div class="tdItem">姓别 <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div></td>
<td colspan="1">
<div class="tdItem">
<span style="word-break: keep-all">检查日期</span>
<el-date-picker
v-model="formData.patientCheckDate"
type="date"
/>
</div>
</td>
<td colspan="1"><div class="tdItem">联系电话 <el-input v-model="formData.patientWearTime" style="flex: 1" placeholder="" /></div></td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">家庭住址 <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">近视家族史 <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">裸眼视力: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">眼压: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="4">
<div class="tdItem">电脑验光:
R<el-input v-model="formData.patientName" style="flex: 1" placeholder="" />
L<el-input v-model="formData.patientName" style="flex: 1" placeholder="" />
</div>
</td>
</tr>
<tr>
<td colspan="4">
<div class="tdItem">主觉验光:
R<el-input v-model="formData.patientName" style="flex: 1" placeholder="" />
L<el-input v-model="formData.patientName" style="flex: 1" placeholder="" />
</div>
</td>
</tr>
<tr>
<td colspan="2">右眼</td>
<td colspan="2">左眼</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">H: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">H: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">V: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">V: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">E值: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">E值: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">直径: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">直径: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">眼轴: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">眼轴: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">厚度: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">厚度: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">内皮: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">内皮: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">BUT: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">BUT: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="4">试戴参数:</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">R: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">L: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">R: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">L: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">R: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">L: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
<tr>
<td colspan="4">订片参数:</td>
</tr>
<tr>
<td colspan="2">
<div class="tdItem">R: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
<td colspan="2">
<div class="tdItem">L: <el-input v-model="formData.patientName" style="flex: 1" placeholder="" /></div>
</td>
</tr>
</table>
</div>
</div>
</div>
<!-- 弹窗, 新增 / 修改 -->
<!-- <follow-up v-if="followUpVisible" ref="followUp" is-first="1" :title="drgsName + '首诊'" @refreshDataList="init()" />-->
</div>
</template>
<script>
import headTemplate from '@/components/head'
const Base64 = require('js-base64').Base64
export default {
inject: ['refresh'],
name: 'CornealReview',
components: {
headTemplate
// followUp
},
mixins: [],
props: {
patientId: {
type: String,
default: ''
}
},
data() {
return {
height: 'calc(100vh - 200px)',
dataForm: {
name: '',
description: '',
content: ''
},
crfVisible: false,
followUpVisible: false,
// item.valuev-modeliframe
examData: [],
jsArr: [],
addOrUpdateVisible: false,
bodyStyleShow: false,
clearTimeOut: null,
realVisitType: '首诊单', //
isFirst: 1
formData: {
patientName: '',
patientCheckDate: '',
patientWearTime: '',
checkList: [
{
name: '正常',
isSelect: false
}, {
name: '重影',
isSelect: false
}, {
name: '视力波动',
isSelect: false
}, {
name: '异物感',
isSelect: false
}, {
name: '镜片难摘',
isSelect: false
}, {
name: '眼红',
isSelect: false
}, {
name: '眼痛',
isSelect: false
}, {
name: '眩光',
isSelect: false
}, {
name: '视力不佳',
isSelect: false
}, {
name: '其他',
isSelect: false
}
],
projectList: [
{
name: '视力',
os: '',
od: ''
}, {
name: '眼压',
os: '',
od: ''
}, {
name: '角膜地形图',
os: '',
od: ''
}, {
name: '眼轴',
os: '',
od: ''
}, {
name: '眼表',
os: '',
od: '',
areaList: [
{
name: '角膜',
os: '',
od: ''
}, {
name: '结膜',
os: '',
od: ''
}, {
name: '其他',
os: '',
od: ''
}
]
}, {
name: '镜片',
os: '',
od: '',
osList: [
{
name: '正常',
isSelect: false
}, {
name: '划痕',
isSelect: false
}, {
name: '污染',
isSelect: false
}, {
name: '破损',
isSelect: false
}
],
odList: [
{
name: '正常',
isSelect: false
}, {
name: '划痕',
isSelect: false
}, {
name: '污染',
isSelect: false
}, {
name: '破损',
isSelect: false
}
]
}
],
remark: '',
patientSign: '',
docSign: ''
}
}
},
created() {
},
// beforeDestroy() {
// clearInterval(this.clearTimeOut)
// this.clearTimeOut = null
// },
methods: {
//
printerHandle() {
this.$refs.crfComponent.$el.contentWindow.print()
saveCheckData() {
console.log(this.formData)
}
}
}
</script>
<style lang="scss" scoped>
.first-visit {
.head {
padding-bottom: 0px;
}
.printer {
.first-visit{
height: 100%;
}
input{
-webkit-appearance: checkbox !important;
margin-right: 5px;
}
::v-deep .el-input__inner {
border: none !important;
text-align: center;
border-radius: 0;
padding: 0;
font-size: 16px;
}
::v-deep .el-input__prefix {
display: none;
}
.el-date-editor.el-input, .el-date-editor.el-input__inner{
width: 100%;
}
.cornealTable{
width: 100%;
tr td{
border: 1px solid #ccc;
width: 56px;
height: 32px;
border-radius: 3px;
margin: 0;
margin-left: 10px;
cursor: pointer;
font-size: 18px;
padding: 5px 10px;
::v-deep .el-input__inner {
border: none !important;
text-align: center;
border-radius: 0;
padding: 0;
}
::v-deep .el-textarea__inner{
border: none;
}
.tdItem{
display: flex !important;
align-items: center;
}
.checkItem{
cursor: pointer;
user-select: none;
word-break: keep-all;
margin-right: 20px;
}
}
.tips {
color: #ff4d4f;
margin-bottom: 6px;
}
.corneal{
width: 100%;
height: 100%;
display:flex;
flex-direction: column;
}
.notice-content{
width: 100%;
height: calc(100% - 50px);
flex:1;
//overflow-y: auto;
.notice-box{
width: 100%;
height: 100%;
}
.first-visit-content {
min-width: 960px;
height: calc(100vh - 50px - 32px - 42px - 54px - 32px);
padding: 16px;
background: #ededed;
text-align: center;
.notice_tip{
height: 100%;
overflow-y: auto;
border: 1px solid #000;
padding: 64px 32px;
margin-right: 16px;
}
}
</style>

1
src/page-subspecialty/views/modules/optometryManagement/seeDoctor/ok-lens-rgp/index.vue

@ -13,7 +13,6 @@
</el-button>
<el-button type="primary" size="small" icon="el-icon-plus" @click="addOrUpdateHandle('','','新增')">新增</el-button>
</head-template>
<!-- ok镜内容 -->
<!-- 1:定片未到货2:到货未通知3:通知未取镜4:取镜/离焦软镜5:放弃取镜6:换片 7:补录8:借片100:退货 -->
<el-table ref="multipleTable" :data="dataList" tooltip-effect="dark" style="width: 100%" :height="`calc(100vh - 217px)`" :row-class-name="getRowClass">

3
src/page-subspecialty/views/modules/optometryManagement/seeDoctor/ok-lens-rgp/left-right-eye.vue

@ -12,7 +12,7 @@
</el-select>
</el-form-item>
<el-form-item label="品 牌:" :label-width="title=='新增' ? '60px' : '95px'" prop="brandId">
<el-select v-model="dataForm.brandId" placeholder="请选择品牌" clearable>
<el-select v-model="dataForm.brandId" placeholder="请选择品牌" clearable multiple filterable allow-create>
<el-option v-for="(item,index) in brandList " :key="index" :value="item.id" :label="item.brand" @click.native="selectOptionBrandHandle(item)" />
</el-select>
</el-form-item>
@ -172,7 +172,6 @@ export default {
this.$nextTick(() => {
this.ISCRTForm = '0'
this.$refs.dataForm.resetFields() //
console.log(this.eyeType)
this.dataForm.eyeType = this.title === '新增' || this.title === '借片' || this.title === '换片' || this.title === '补录' ? this.eyeType : ''
this.dataForm.status = this.tabTitle === 'LJRJ' ? 4 : ''
if (this.title === '换片') {

286
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/doctor/index.vue

@ -0,0 +1,286 @@
<template>
<el-card shadow="never" class="aui-card--fill">
<div class="doctor-management">
<el-form
:inline="true"
@submit.native.prevent
>
<el-form-item>
<el-button
type="primary"
style="margin-left:12px;"
icon="el-icon-plus"
@click="assignPeopleClick()"
>分配人员
</el-button>
</el-form-item>
</el-form>
<el-table :data="doctorList">
<el-table-column prop="userName" label="用户名" header-align="center" align="center" />
<el-table-column prop="realName" label="真实姓名" header-align="center" align="center" />
<el-table-column prop="gender" label="性别" header-align="center" align="center">
<template slot-scope="scope">
<span>{{ scope.row.gender=='0' ? '男': (scope.row.gender=='1' ? '女':'保密') }}</span>
</template>
</el-table-column>
<el-table-column prop="mobile" label="手机号" header-align="center" align="center" />
<el-table-column prop="roleNameList" label="角色" header-align="center" align="center">
<template slot-scope="scope">
<div v-if="scope.row.roleNameList.length>0">
<p v-for="(item,index) in scope.row.roleNameList" :key="index" style="margin:0">{{ item }}
</p>
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" header-align="center" align="center">
<template slot-scope="scope">
<span
:class="scope.row.status=='1' ? 'state-circle state-circle-green' :'state-circle state-circle-red'"
/>
<span>{{ scope.row.status == '1' ? '正常':'停用' }}</span>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" header-align="center" align="center">
<template slot-scope="scope">
<span v-if="opPermission(scope.row)">
<el-dropdown trigger="click" @command="handleRoleCommand(scope.row,$event)">
<span class="el-dropdown-link" style="padding-right:8px;cursor: pointer;">更改角色</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item in roleList" :key="item.roleId" :command="item.id">{{ item.name }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span
style="color:#FF4D4F"
class="operation-delete"
@click="deleteClick(scope.row)"
>移出</span>
</span>
</template>
</el-table-column>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:total="total"
@current-change="pageCurrentChangeHandle"
/>
</div>
<!-- 弹框 -->
<el-dialog title="分配人员" :visible.sync="dialogFormVisible" width="650px">
<div style="text-align: center">
<el-transfer
v-model="rightValue"
style="text-align: left; display: inline-block"
:render-content="renderFunc"
:format="{noChecked: '${total}',hasChecked: '${checked}/${total}'}"
:titles="['未加入', '已加入课题']"
:props="{key: 'userId', label: 'realName'}"
:data="AllJoinedPeopleList"
@change="handleChange"
/>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="sureJoinedPeopleClick"> </el-button>
</span>
</el-dialog>
</el-card>
</template>
<script>
import { confirm } from '@/utils/confirm'
export default {
inject: ['refresh'],
data() {
const generateData = _ => {
const transferData = []
for (let i = 1; i <= 15; i++) {
transferData.push({
key: i,
label: `备选项 ${i}`,
disabled: i % 4 === 0
})
}
return transferData
}
return {
inputSearchValue: '',
transferData: generateData(),
renderFunc(h, option) {
return <span>{option.realName}</span>
},
dialogFormVisible: false,
projectId: '',
doctorList: [],
roleList: [],
limit: 10,
currentPage: 1,
total: 0,
searchTime: '',
JoinedPeopleList: [],
notJoinedPeopleList: [],
AllJoinedPeopleList: [],
rightValue: [],
joinedListUserId: []
}
},
created() {
this.projectId = window.SITE_CONFIG['projectId']
this.getDoctorList()
this.getProjectUser()
this.getRoleList()
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(() => {
this.isRouterAlive = true
})
},
opPermission(rowObj) {
return rowObj.userId !== this.$store.state.user.id
},
//
assignPeopleClick() {
this.dialogFormVisible = true
},
//
getProjectUser() {
this.$http.get(`/projectUser/getUserList/${this.projectId}`)
.then(({ data: res }) => {
this.JoinedPeopleList = res.data.joinedList
this.notJoinedPeopleList = res.data.notJoined
//
if (res.data.joinedList.length > 0) {
res.data.joinedList.forEach(item => {
this.rightValue.push(item.userId)
if (item.isAdmin === 1) {
item.disabled = true
}
})
}
//
if (res.data.notJoined.length > 0) {
res.data.notJoined.forEach(item => {
if (item.isAdmin === 1) {
item.disabled = true
}
})
}
this.AllJoinedPeopleList = [...res.data.joinedList, ...res.data.notJoined]
})
},
//
handleChange(value) {
this.joinedListUserId = value
},
//
sureJoinedPeopleClick() {
this.dialogFormVisible = false
this.$http.post('/projectUser', {
projectId: this.projectId,
userIdList: this.joinedListUserId
}).then(({ data: res }) => {
this.$message.success('分配成功')
this.refresh()
})
},
//
getRoleList(scopeRow) {
this.$http.get('/sys/role/getProjectRoleList', {
params: {
deptId: this.$store.state.user.deptId || window.SITE_CONFIG['projectInfo'].deptId
}
}).then(({ data: res }) => {
this.roleList = res.data
})
},
//
handleRoleCommand(scopeRow, e) {
this.$http.post('projectUser/saveOrUpdateUserRoleForProject', {
projectId: this.projectId,
roleIdList: [e],
userId: scopeRow.userId
}).then(({ data: res }) => {
this.$message.success('更改角色成功!')
this.refresh()
})
},
//
getDoctorList(e) {
this.$http.get('/projectUser/page', {
params: {
limit: this.limit,
page: this.currentPage,
projectId: this.projectId,
realName: ''
}
}).then(({ data: res }) => {
this.doctorList = res.data.list
this.total = res.data.total
})
},
//
pageCurrentChangeHandle(e) {
this.currentPage = e
this.getDoctorList()
},
//
deleteClick(scopeRow) {
confirm('').then(async() => {
this.$http({
method: 'delete',
url: '/projectUser',
data: [scopeRow.id]
}).then(({ data: res }) => {
this.$message.success('删除成功!')
this.refresh()
})
})
}
}
}
</script>
<style lang='scss' scoped>
.state-circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
}
.state-circle-green {
background-color: #52c41a;
}
.state-circle-red {
background-color: #ff4d4f;
}
.operation-details,
.operation-delete,
.el-dropdown-link {
cursor: pointer;
}
.el-dropdown-link {
color:#1890FF;
padding-right: 8px;
}
</style>
<style lang="scss">
.el-transfer__button:first-child {
margin-bottom: 4px;
}
.el-transfer__buttons {
.el-button {
display: block;
padding: 0;
width: 24px;
height: 24px;
}
.el-button:nth-child(2) {
margin-left: 0;
}
}
</style>

138
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/ecrf/add-or-update.vue

@ -0,0 +1,138 @@
<template>
<el-dialog
width="calc(210mm + 90px + 100px)"
top="2vh"
:visible.sync="visible"
:title="dataForm.title||(!dataForm.id ? $t('add') : $t('update'))"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form
ref="dataForm"
:model="dataForm"
:rules="dataRule"
label-width="auto"
@submit.native.prevent
@keyup.enter.native="initBaseInfo()"
>
<el-form-item prop="name" :label="'名称'">
<el-input
v-model="dataForm.name"
:placeholder="'请填写表单名称'"
/>
</el-form-item>
<el-form-item prop="content" :label="'表单'">
<crf-editor ref="crf" v-model="dataForm.content" :height="height" />
</el-form-item>
<el-form-item prop="description" :label="'描述'">
<el-input
v-model="dataForm.description"
type="textarea"
:rows="1"
:placeholder="'相关描述'"
/>
</el-form-item>
</el-form>
<template slot="footer">
<el-button @click="visible = false">{{ $t('cancel') }}</el-button>
<el-button type="primary" @click="dataFormSubmitHandle()">{{ $t('confirm') }}</el-button>
</template>
</el-dialog>
</template>
<script>
import debounce from 'lodash/debounce'
import crfEditor from '@/components/hm-crf'
const Base64 = require('js-base64').Base64
export default {
components: { crfEditor },
data() {
return {
visible: false,
height: 'calc(100vh - 300px)',
dataForm: {
id: '',
projectId: '',
name: '',
description: '',
content: ''
}
}
},
computed: {
dataRule() {
var validate_content = (rule, value, callback) => {
if (this.dataForm.content === '') {
return callback(new Error('请设计表单内容'))
}
callback()
}
return {
name: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
content: [
{ required: true, validator: validate_content, trigger: 'change' }
]
}
}
},
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.$refs.dataForm.resetFields()
this.dataForm.projectId = window.SITE_CONFIG['projectId']
if (this.dataForm.id) {
this.getInfo()
} else {
this.dataForm = { ...this.dataForm }
}
})
},
//
getInfo() {
this.$http.get('/crf/template', { params: { crfId: this.dataForm.id }}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
this.dataForm.name = res.data.name
this.dataForm.content = Base64.decode(res.data.content)
this.dataForm.description = res.data.description
this.$refs['crf'].renderContent()
}
}).catch(() => {})
},
//
dataFormSubmitHandle: debounce(function() {
this.$refs.dataForm.validate((valid) => {
if (!valid) {
return false
}
this.$http[!this.dataForm.id ? 'post' : 'put']('/crf/template', { ...this.dataForm, content: Base64.encode(this.dataForm.content) }).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
}).catch(() => {})
})
}, 1000, { leading: true, trailing: false })
}
}
</script>
<style lang="scss">
</style>

99
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/ecrf/index.vue

@ -0,0 +1,99 @@
<template>
<el-card shadow="never" class="aui-card--fill">
<el-form
:inline="true"
:model="dataForm"
@submit.native.prevent
@keyup.enter.native="getDataList()"
>
<el-form-item>
<el-button type="primary" @click="addOrUpdateHandle(null,null,'新增表单')">{{ $t('add') }}</el-button>
</el-form-item>
</el-form>
<el-table v-loading="dataListLoading" :data="dataList" row-key="id" border style="width: 100%;">
<!-- 名称 -->
<el-table-column prop="name" :label="'名称'" />
<!-- 描述 -->
<el-table-column prop="description" :label="'描述'" />
<!-- 创建时间 -->
<el-table-column prop="createDate" :label="'创建时间'" />
<!-- 操作 -->
<el-table-column prop="operation" :label="$t('handle')">
<template slot-scope="scope">
<!-- <el-button type="text" size="small" @click="testClick1(scope.row.id,...scope.row)">{{ '测试1' }}</el-button> -->
<!-- <el-button type="text" size="small" @click="testClick2(scope.row.id,...scope.row)">{{ '测试2' }}</el-button> -->
<el-button
type="text"
size="small"
@click="preview(scope.row.id,...scope.row)"
>{{ $t('preview') }}</el-button>
<el-button
type="text"
size="small"
@click="addOrUpdateHandle(scope.row.id,...scope.row)"
>{{ $t('update') }}</el-button>
<el-button
type="text"
size="small"
style="color:red"
@click="deleteHandle(scope.row.id)"
>{{ $t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加分页组件 -->
<el-pagination
background
layout="prev, pager, next"
:total="total"
@current-change="pageCurrentChangeHandle"
/>
<!-- <el-pagination
:current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="limit"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="pageSizeChangeHandle"
@current-change="pageCurrentChangeHandle"
/> -->
<!-- 弹窗, 新增 / 修改 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList" />
<!-- 弹窗, 预览 -->
<preview v-if="previewVisible" ref="preview" :type="'preview'" />
</el-card>
</template>
<script>
import mixinViewModule from '@/mixins/view-module'
import AddOrUpdate from './add-or-update'
import preview from '@/components/ecrf/dialog-load'
export default {
components: { AddOrUpdate, preview },
mixins: [mixinViewModule],
data() {
return {
previewVisible: false,
mixinViewModuleOptions: {
getDataListURL: '/crf/page',
getDataListIsPage: true,
deleteURL: '/crf'
},
dataForm: {
projectId: window.SITE_CONFIG['projectId']
}
}
},
methods: {
preview(id, params, title) {
this.previewVisible = true
this.$nextTick(() => {
this.$refs.preview.id = id
this.$refs.preview.init()
})
}
}
}
</script>

50
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/index.vue

@ -0,0 +1,50 @@
<template>
<div class="template-container">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="样本库" name="first">
<search />
</el-tab-pane>
<el-tab-pane label="医生管理" name="second">
<doctor />
</el-tab-pane>
<el-tab-pane label="eCRF管理" name="third">
<eCrf></eCrf>
</el-tab-pane>
<el-tab-pane label="受试者管理" name="fourth">
<patientSubject></patientSubject>
</el-tab-pane>
<el-tab-pane label="日志" name="five">
<operateLog></operateLog>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import search from './patient-search/index'
import doctor from './doctor/index'
import eCrf from './ecrf/index'
import patientSubject from './patient-subject/index'
import operateLog from './log/index'
export default {
components: { doctor, search, eCrf, patientSubject, operateLog },
data() {
return {
activeName: 'first'
}
},
mounted() {
},
methods: {
handleClick() {
}
}
}
</script>
<style lang='scss' scoped>
.template-container {
}
</style>

103
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/log/index.vue

@ -0,0 +1,103 @@
<template>
<el-card shadow="never" class="aui-card--fill">
<div class="filter-wrapper">
<el-form :inline="true" :model="dataForm" @submit.native.prevent @keyup.enter.native="getDataList()">
<el-form-item>
<el-input v-model="input" placeholder="关键词" class="input-with-select" clearable>
<el-select slot="prepend" v-model="select" placeholder="请选择">
<el-option label="用户名" value="username" />
<el-option label="用户姓名" value="realName" />
<el-option label="用户操作" value="action" />
<el-option label="IP地址" value="ip" />
</el-select>
<el-button slot="append" icon="el-icon-search" @click="getDataList()">{{ $t('query') }}</el-button>
</el-input>
</el-form-item>
</el-form>
<el-table
v-loading="dataListLoading"
:data="dataList"
border
style="width: 100%;"
@sort-change="dataListSortChangeHandle"
>
<el-table-column prop="creatorName" :label="'账号'" header-align="center" align="center" width="120" />
<el-table-column prop="realName" :label="'用户姓名'" header-align="center" align="center" width="120" />
<el-table-column prop="operation" :label="'用户操作'" />
<!-- <el-table-column prop="projectName" :label="'课题'" header-align="center" align="center" show-overflow-tooltip /> -->
<el-table-column prop="ip" :label="'操作IP'" width="125" header-align="center" />
<el-table-column prop="createDate" :label="'操作时间'" header-align="center" sortable="custom" width="160" />
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="limit"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="pageSizeChangeHandle"
@current-change="pageCurrentChangeHandle"
/>
</div>
</el-card>
</template>
<script>
import mixinViewModule from '@/mixins/view-module'
export default {
mixins: [mixinViewModule],
data() {
return {
mixinViewModuleOptions: {
getDataListURL: '/sys/log/operation/page4User',
getDataListIsPage: true
},
select: 'action',
input: '',
dataForm: {
username: '',
realName: '',
action: '',
ip: ''
}
}
},
watch: {
select(val) { this.dataFormHandle() },
input(val) { this.dataFormHandle() }
},
methods: {
dataFormHandle() {
const inputValue = !(this.input) ? null : this.input
switch (this.select) {
case 'realName':
this.dataForm.realName = inputValue
break
case 'action':
this.dataForm.action = inputValue
break
case 'ip':
this.dataForm.ip = inputValue
break
}
}
}
}
</script>
<style lang="scss" scoped>
.input-with-select {
width: 500px;
::v-deep .el-select .el-input {
width: 120px;
}
::v-deep .el-input-group__prepend {
background-color: #fff;
}
}
</style>

71
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/patient-search/index.vue

@ -0,0 +1,71 @@
<!-- 样本库 -->
<template>
<div class="search">
<patient-search
ref="patientSearch"
:enable-select="enableSelect"
:project-id="projectId"
:select-disable-id-list="selectDisableIdList"
:query-item.sync="queryItem"
:size="'small'"
@vmSelectIdList="vmSelectIdList"
>
<template slot="btn">
<el-button type="primary" size="small" @click="btnPullInSubjectClick">引入受试者</el-button>
</template>
</patient-search>
</div>
</template>
<script>
import patientSearch from '@/components/patient-search'
export default {
components: { patientSearch },
data() {
return {
enableSelect: true,
projectId: window.SITE_CONFIG['projectId'],
selectIdList: [],
selectDisableIdList: [],
queryItem: {}
}
},
created() {
this.getSubjectIdNumberList()
},
mounted() {
},
methods: {
vmSelectIdList(data) {
this.selectIdList = data
},
//
btnPullInSubjectClick() {
if (this.selectIdList.length === 0) {
return this.$message.error('请勾选需要导出的患者!')
}
this.$refs.patientSearch.clearSelect()
this.getSubjectIdNumberList()
this.$http.post('/project/patient', {
projectId: this.projectId,
hospitalCode: '52618662',
idNumberList: this.selectIdList
}).then(({ data: res }) => {
this.$message.success('引入成功!')
// 1:2:3:
this.$http.put('/project/status', { projectId: this.projectId, status: 2 })
this.getSubjectIdNumberList()
})
},
getSubjectIdNumberList() {
this.$http.get('/project/patient/patIdNumberList', { params: { projectId: this.projectId }})
.then(({ data: res }) => {
this.selectDisableIdList = res.data
})
}
}
}
</script>

775
src/page-subspecialty/views/modules/scientificManagement/subjectMgt/patient-subject/index.vue

@ -0,0 +1,775 @@
<template>
<div class="subject-management">
<div class="subject-left">
<el-scrollbar style="height: 100%">
<div class="photo-groups">
<span>受试者分组</span>
<i class="el-icon-circle-plus" @click="addGroupClick" />
</div>
<div
v-for="(item, index) in groupList"
:key="item.id"
class="group-list"
:class="currentIndex == index ? 'group-list-active' : ''"
@click="grouplistClick(item.id, index)"
>
<span>{{ item.name }}</span>
<span v-if="item.name == '全部'" style="margin-right:20px;">{{ groupListAll.total }}</span>
<span v-else-if="item.name == '未分组'" style="margin-right:20px;">{{ groupListAll.noInGroup }}</span>
<div v-else class="dropdown-right">
<span class="number">{{ item.groupTotal }}</span>
<el-dropdown trigger="click" @command="handleDropdownCommand(item.id, $event)">
<i class="el-icon-more" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="1">修改</el-dropdown-item>
<el-dropdown-item command="2">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</el-scrollbar>
</div>
<div class="subject-right">
<div class="input-search">
<el-input
v-model="inputSearchValue"
placeholder="姓名"
class="input-with-select"
clearable
@clear="getDataList()"
@change="getDataList()"
>
<el-button slot="append" icon="el-icon-search" @click="getDataList()" />
</el-input>
</div>
<div class="people-list">
<!-- <div class="title">人员列表</div> -->
<el-table
ref="multipleTable"
v-loading="tabelLoading"
:data="dataList"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column type="index" width="55" label="序号" header-align="center" align="center" />
<el-table-column prop="patientName" label="姓名" header-align="center" align="center" />
<el-table-column prop="age" label="年龄" header-align="center" align="center" />
<el-table-column prop="patientSex" label="性别" header-align="center" align="center" />
<el-table-column prop="suggest" label="纳排建议" header-align="center" align="center">
<template slot-scope="scope">
<span
v-if="scope.row.suggest"
:class="scope.row.suggest == '1' ? 'suggest-circle suggest-circle-green' : 'suggest-circle suggest-circle-red'"
/>
<span>{{ scope.row.suggest==1 ? '符合': (scope.row.suggest==0 ? '不符合' : '无') }}</span>
</template>
</el-table-column>
<el-table-column label="分组信息" header-align="center" align="center">
<template slot-scope="scope">
<div v-show="scope.row.groupList.length > 0">
<span v-for="item in scope.row.groupList" :key="item.id">{{ item.name }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="200">
<template slot-scope="scope">
<span
style="color: #1890ff; padding-right: 8px"
class="operation-details"
@click="showDetail(scope.row)"
>详情</span>
<span
style="color: #ff4d4f"
class="operation-delete"
@click="deleteSubjectClick(scope.row.id)"
>移出课题</span>
<span
v-show="groupId!==0 && groupId!=='' ? true:false"
style="color: #ff4d4f;padding-left:10px;"
class="operation-delete"
@click="deleteGroupClick(scope.row)"
>移出分组</span>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="limit"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="pageSizeChangeHandle"
@current-change="pageCurrentChangeHandle"
/>
<!-- 底部全选反选 -->
<checked-footer
ref="checkfooter"
table-ref="multipleTable"
:current-table-list="currentTableList"
:data-list="dataList"
>
<div class="batch_button">
<!-- <el-button
size="small"
:disabled="(groupId==0 || groupId=='') && currentTableList.length > 0 ? false:true"
@click="batchDeleteSubjectClick"
>批量移出课题</el-button>
<el-button
size="small"
:disabled="groupId!==0 && groupId!==''&& currentTableList.length > 0 ? false:true"
@click="batchDeleteGroupClick"
>批量移出分组</el-button>
<el-button size="small" @click="btnExportClick">{{ currentTableList.length > 0 ?"导出":"全部导出" }}</el-button>
<el-dropdown @command="handleGroupCommand($event)">
<el-button type="primary" size="small" :disabled="currentTableList.length > 0 ? false :true">分组
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in groupList"
:key="item.id"
:command="item.id"
:disabled="item.name=='全部' || item.name=='未分组'"
>{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<!-- 批量 -->
<el-dropdown @command="handleCommandChecked">
<el-button split-button size="small" type="primary" :disabled="currentTableList.length === 0">
<span class="el-dropdown-link">
批量操作
</span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="export">导出</el-dropdown-item>
<el-dropdown-item command="remove">移除</el-dropdown-item>
<el-dropdown-item command="group">分组</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 全部 -->
<el-dropdown @command="handleCommandAll">
<el-button split-button size="small" type="primary">
<span class="el-dropdown-link">
全部操作
</span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="export">导出</el-dropdown-item>
<el-dropdown-item command="remove">移除</el-dropdown-item>
<el-dropdown-item command="group">分组</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</checked-footer>
</div>
</div>
<!-- 分组 -->
<el-dialog
title="提示"
:visible.sync="dialogVisible_group"
width="30%"
>
<div>
<el-select v-model="dialogGroup.groupSelect" placeholder="请选择">
<el-option
v-for="item in c_groupList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible_group = false"> </el-button>
<el-button type="primary" @click="handleGroup_OK"> </el-button>
</span>
</el-dialog>
<!-- 详情页 -->
<el-dialog
class="dialog-360"
:visible.sync="dialogVisible"
:title="'患者360'"
:close-on-click-modal="false"
:close-on-press-escape="false"
:fullscreen="true"
append-to-body
>
<patient-view
v-if="dialogVisible"
ref="detailView"
:patient-id-number="patient.patientIdNumber"
:project-id="patient.projectId"
:is-subject="true"
/>
</el-dialog>
<!-- 添加分组弹框 -->
<el-dialog title="添加分组" :visible.sync="dialogFormVisible" @close="CloseDialog">
<el-form ref="addGroupRuleForm" :model="formGroup" :rules="addGroupRules" @submit.native.prevent>
<el-form-item label="分组名称" label-width="120px" prop="name">
<el-input v-model="formGroup.name" />
</el-form-item>
<el-form-item label="分组描述" label-width="120px">
<el-input v-model="formGroup.description" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button v-if="sureShow == true" type="primary" @click="sureSubjectGroupClick(1)"> </el-button>
<el-button v-else type="primary" @click="sureSubjectGroupClick(2)"> </el-button>
</div>
</el-dialog>
<!-- 导出数据指标 -->
<el-dialog title="导出数据" :visible.sync="dialogExportVisible" append-to-body>
<el-form>
<el-form-item label="指标">
<kpi-select v-if="dialogExportVisible" v-model="kpiList" style="width:100%" :type="4" />
</el-form-item>
<el-form-item label="设备过滤">
<device-select
v-if="dialogExportVisible"
v-model="deviceIdList"
style="width:100%"
:placeholder="'选择设备后,将过滤相关项目数据'"
@change="deviceChangeHandle"
/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogExportVisible = false"> </el-button>
<el-button type="primary" @click="exportOK()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import checked from '@/mixins/checked'
import patientView from '@/components/patient-view'
import checkedFooter from '@/components/checked-footer'
import kpiSelect from '@/components/kpi-select'
import deviceSelect from '@/components/device-select'
import { confirm } from '@/utils/confirm'
import { formatDate } from '@/utils/index.js'
export default {
components: { patientView, checkedFooter, kpiSelect, deviceSelect },
mixins: [checked],
data() {
return {
inputSearchValue: '',
dataList: [],
cheackAllFooter: false,
dialogVisible: false,
dialogVisible_group: false,
dialogGroup: {
groupSelect: '',
type: ''
},
dialogFormVisible: false,
dialogExportVisible: false,
tabelLoading: false,
currentTableList: [],
limit: 10,
page: 1,
projectId: window.SITE_CONFIG['projectId'],
total: 0,
groupList: [
// { name: '', id: '' },
// { name: '', id: 0 }
],
groupListAll: {},
addGroupRules: {
name: [
{ required: true, message: '请输入分组名称', trigger: 'blur' }
]
},
formGroup: {
name: '',
description: '',
projectId: window.SITE_CONFIG['projectId'],
id: ''
},
sureShow: true,
currentIndex: 0,
groupId: '',
detailId: '',
patientIdNumber: '',
activeTab: '',
kpiList: [],
deviceIdList: [],
deviceSelectItemList: [],
checkList: [],
patient: {
patientIdNumber: '',
projectId: ''
}
}
},
computed: {
c_groupList() {
return this.groupList.filter(item => item.id !== '' && item.id !== 0)
}
},
activated() {
this.refresh()
},
created() {
this.getDataList()
this.getGroupList()
},
mounted() { },
methods: {
refresh() {
this.getGroupList()
this.grouplistClick(this.groupId, this.currentIndex)
},
//
showDetail(row) {
// console.log(row)
this.dialogVisible = true
this.patient.patientIdNumber = row.patientIdNumber
this.patient.projectId = this.projectId
},
//
grouplistClick(id, index) {
this.groupId = id
this.currentIndex = index
this.page = 1
this.getDataList()
},
//
getDataList() {
this.tabelLoading = true
this.$http.get('/project/patient/page', {
params: {
limit: this.limit,
page: this.page,
projectId: this.formGroup.projectId,
patientName: this.inputSearchValue, //
groupId: this.groupId // id
}
}).then(({ data: res }) => {
this.dataList = res.data.list
this.total = res.data.total
this.tabelLoading = false
}).catch(() => { this.tabelLoading = false })
},
//
deleteSubjectClick(id) {
this.deleteSubjectFun([id])
},
//
batchDeleteSubjectClick() {
this.deleteSubjectFun(this.currentTableList.map(item => item.id))
},
//
deleteSubjectFun(ids) {
confirm('您确定要移除此受试者吗?').then(async() => {
this.$http({
method: 'delete',
url: '/project/patient',
data: ids
}).then(({ data: res }) => {
this.$message.success('删除成功!')
this.refresh()
})
})
},
//
deleteSubjectAll() {
confirm('您确定要移除所有受试者吗?').then(async() => {
this.$http.delete('/project/patient/' + this.projectId).then(({ data: res }) => {
this.$message.success('删除成功!')
this.visible = false
this.refresh()
})
})
},
//
deleteGroupClick(scopeRow) {
const patientList = [{
hospitalCode: scopeRow.hospitalCode,
patientId: scopeRow.patientId
}]
this.deleteGroupFun(patientList)
},
//
batchDeleteGroupClick() {
this.deleteGroupFun(this.currentTableList)
},
//
deleteGroupFun(patientList) {
confirm('您确定要移除此分组吗').then(async() => {
this.$http.post('/patient/group/removeGroup', {
groupId: this.groupId,
patientList: patientList
}).then(({ data: res }) => {
this.$message.success('删除成功!')
this.refresh()
})
})
},
//
addGroupClick() {
this.dialogFormVisible = true
this.sureShow = true
},
//
getGroupList() {
this.$http.get('/group/getList', {
params: {
projectId: this.formGroup.projectId
}
}).then(({ data: res }) => {
this.groupList = [{ name: '全部', id: '' }, { name: '未分组', id: 0 }, ...res.data.list]
this.groupListAll = res.data
})
},
//
editGroup(id) {
this.dialogFormVisible = true
// id
this.$http.get('group', {
params: { id: id }
}).then(({ data: res }) => {
this.formGroup = res.data
})
},
//
deleteGroup(id) {
confirm('').then(async() => {
this.$http.delete('/group', {
params: { id: id }
}).then(({ data: res }) => {
this.$message.success('删除成功!')
this.refresh()
})
})
},
//
handleDropdownCommand(id, command) {
if (command === '1') {
this.sureShow = false
this.editGroup(id)
} else if (command === '2') {
this.deleteGroup(id)
}
},
handleCommandChecked(command) {
switch (command) {
case 'export':
this.handleExport()
break
case 'remove':
this.batchDeleteSubjectClick()
break
case 'group':
this.handleGroup('group')
break
}
},
handleCommandAll(command) {
switch (command) {
case 'export':
this.handleExport()
break
case 'remove':
this.deleteSubjectAll()
break
case 'group':
this.handleGroup('all')
break
}
},
//
handleGroup(type) {
this.dialogVisible_group = true
this.dialogGroup.type = type
},
handleGroup_OK() {
this.$http.post('/patient/group', {
groupId: this.dialogGroup.groupSelect,
patientList: this.dialogGroup.type === 'group' ? this.currentTableList : []
}).then(({ data: res }) => {
this.$message.success(this.dialogGroup.type === 'group' ? '批量分组成功!' : '全部分组成功!')
this.dialogVisible_group = false
this.dialogGroup.type = ''
this.refresh()
})
},
//
sureSubjectGroupClick(num) {
this.$refs.addGroupRuleForm.validate(async(valid) => {
if (valid) {
this.$http({
method: num === 1 ? 'post' : 'put',
url: '/group',
data: this.formGroup
}).then(({ data: res }) => {
this.$message.success('操作成功!')
this.dialogFormVisible = false
this.refresh()
})
} else {
console.log('error submit!!')
return false
}
})
},
btnExportClick() {
this.handleExport()
},
handleExport() {
this.dialogExportVisible = true
if (this.kpiList.length === 0 && window.SITE_CONFIG['projectInfo']) {
this.kpiList = window.SITE_CONFIG['projectInfo'].kpiList || []
}
},
//
exportOK() {
this.dialogExportVisible = false
this.exportExecl()
},
// execl
exportExecl() {
const patientIdNumbers = []
this.currentTableList.forEach(item => {
patientIdNumbers.push(item.patientIdNumber)
})
// if (patientIdNumbers.length === 0) {
// return this.$message.error('')
// }
if (this.kpiList.length === 0) {
return this.$message.error('请勾选需要导出的指标!')
}
const loading = this.$loading({
lock: true,
text: '导出数据生成中,请稍等...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)',
customClass: 'export-loading'
})
this.$http.post('/project/patient/exportPatient',
{
patientIdNumbers: patientIdNumbers,
tableDictIds: this.kpiList,
projectId: this.projectId,
deviceList: this.deviceSelectItemList.map(item => { return { dataSource: item.dataSource || item.datSource, deviceId: item.deviceId || item.value } })
},
{
responseType: 'blob',
timeout: 60000 * 10
}
).then(({ data: res }) => {
loading.close()
const link = document.createElement('a')
// type
const blob = new Blob([res], { type: 'application/zip' })
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download', `数据导出_${formatDate(new Date(), 'yyyy-MM-dd')}_${this.$store.state.user.realName}`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
this.checkList = []
// this.$refs.multipleTable.clearSelection()
}).catch((error) => {
this.$message.error(error)
loading.close()
})
},
// MessageBox
CloseDialog() {
this.formGroup.name = ''
this.formGroup.description = ''
},
// ,
pageCurrentChangeHandle(val) {
this.page = val
this.getDataList()
},
// ,
pageSizeChangeHandle(val) {
this.page = 1
this.limit = val
this.getDataList()
},
//
async handleGroupCommand(e) {
this.$http.post('/patient/group', {
groupId: e,
patientList: this.currentTableList
}).then(({ data: res }) => {
this.$message.success('分组成功!')
this.refresh()
})
},
deviceChangeHandle(val) {
this.deviceSelectItemList = val
}
}
}
</script>
<style lang='scss' scoped>
.subject-management {
display: flex;
.subject-left {
min-width: 240px;
background-color: #fff;
margin-right: 10px;
height: calc(calc(100vh - 50px - 38px - 80px));
.photo-groups,
.group-list {
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 24px;
padding-right: 16px;
color: #000;
}
.photo-groups {
height: 48px;
font-size: 16px;
font-weight: 700;
.el-icon-circle-plus {
cursor: pointer;
color: #1e79ff;
font-size: 24px;
}
}
.group-list {
height: 32px;
line-height: 32px;
font-size: 14px;
.el-icon-more {
transform: rotate(90deg);
}
.dropdown-right {
.number {
padding-right: 10px;
}
}
}
.group-list-active {
background-color: #1890ff;
color: #fff;
.el-icon-more {
color: #fff;
}
}
// .group-list:hover {
// background-color: #eee;
// }
}
.subject-right {
flex: 1;
background-color: #fff;
padding: 16px 10px;
}
.input-search {
display: flex;
}
.people-list {
padding-bottom: 10px;
margin-top: 10px;
margin-bottom: 50px;
}
.title {
height: 64px;
padding-left: 24px;
line-height: 64px;
font-size: 16px;
background-color: #fff;
box-shadow: inset 0px -1px 0px #f0f0f0;
border-radius: 2px 2px 0px 0px;
}
.suggest-circle {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
}
.suggest-circle-green {
background-color: #52c41a;
}
.suggest-circle-red {
background-color: #ff4d4f;
}
.operation-details,
.operation-delete {
cursor: pointer;
}
.scroll-father-head {
height: 150px;
}
}
.batch_button{
.el-dropdown {
margin-left: 15px;
}
}
</style>
<style lang="scss">
.input-search {
display: flex;
.el-icon-d-arrow-right {
transform: rotate(-90deg);
}
.el-dropdown {
vertical-align: top;
}
.el-dropdown {
margin-left: 15px;
}
.el-icon-arrow-down {
font-size: 12px;
}
}
.subject-management .detail-view {
.el-dialog {
background: #000;
overflow: hidden;
}
.el-dialog__header {
padding: 10px 20px 10px;
.el-dialog__title {
color: #fff;
padding: 10px;
}
.el-dialog__headerbtn {
top: 5px;
font-size: 30px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #fff;
}
}
.el-dialog__body {
height: calc(100vh - 60px);
padding: 0 10px;
}
}
</style>

10
src/page-subspecialty/views/modules/scientificManagement/sys/project.vue

@ -1,6 +1,5 @@
<template>
<!-- 科研课题管理 -->
<el-card shadow="never" class="aui-card--fill project-main">
<div class="mod-sys__role">
<el-form
@ -316,10 +315,11 @@ export default {
methods: {
windowOpen_project(projectId, deptId) {
// window.open(`project/home?id=${projectId}`)
const { href } = this.$router.resolve({
name: 'subjectMgt'
})
window.open(href, '_blank')
// const { href } = this.$router.resolve({
// name: 'subject'
// })
// window.open(href, '_blank')
this.$router.push('subjectMgt')
},
handleChange(value) {
this.joinedListUserId = value

56
src/page-subspecialty/views/pages/subjectManage/index.vue

@ -1,56 +0,0 @@
<template>
<div class="subjectManagement">
<el-container style="">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>王小虎</span>
</el-header>
<el-main>
<el-table :data="tableData">
<el-table-column prop="date" label="日期" width="140" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="address" label="地址" />
</el-table>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.subjectManagement{
width: 100%;
height: 100%;
}
</style>
Loading…
Cancel
Save