Browse Source

360view独立

360view
bianyaqi 2 years ago
parent
commit
b165e6208e
  1. 2
      .env.development
  2. 2
      .env.localhost
  3. 2
      .env.production
  4. 2
      .env.staging
  5. 23
      package.json
  6. 0
      src/components/.gitkeep
  7. 9
      src/components/360View/index.vue
  8. 72
      src/components/bread-crumb/index.vue
  9. 58
      src/components/checked-footer/index.vue
  10. 41
      src/components/dept-select/index.vue
  11. 40
      src/components/device-select/index.vue
  12. 145
      src/components/ecrf/crf-data.vue
  13. 129
      src/components/ecrf/dialog-load.vue
  14. 88
      src/components/ecrf/ecrf-select.vue
  15. 177
      src/components/ecrf/follow-up-edit.vue
  16. 194
      src/components/ecrf/follow-up.vue
  17. 40
      src/components/exam-item-select/index.vue
  18. 102
      src/components/files/index.vue
  19. 224
      src/components/filter/index.vue
  20. 61
      src/components/head/index.vue
  21. 87
      src/components/hm-crf/del_load-crf-dialog.vue
  22. 49
      src/components/hm-crf/del_load_crf.vue
  23. 88
      src/components/hm-crf/del_preview-dialog.vue
  24. 100
      src/components/hm-crf/del_preview.vue
  25. 239
      src/components/hm-crf/index.vue
  26. 76
      src/components/hm-crf/load-content.vue
  27. 10
      src/components/hm-crf/tinymce/icons/icons.js
  28. 7
      src/components/hm-crf/tinymce/icons/index.js
  29. 7
      src/components/hm-crf/tinymce/plugins/hm_checkbox/index.js
  30. 234
      src/components/hm-crf/tinymce/plugins/hm_checkbox/plugin.js
  31. 7
      src/components/hm-crf/tinymce/plugins/hm_input/index.js
  32. 366
      src/components/hm-crf/tinymce/plugins/hm_input/plugin.js
  33. 7
      src/components/hm-crf/tinymce/plugins/hm_preview/index.js
  34. 143
      src/components/hm-crf/tinymce/plugins/hm_preview/plugin.js
  35. 7
      src/components/hm-crf/tinymce/plugins/hm_radio/index.js
  36. 235
      src/components/hm-crf/tinymce/plugins/hm_radio/plugin.js
  37. 305
      src/components/hm-crf/tinymce/plugins/hm_utils/index.js
  38. 56
      src/components/hm-crf/tinymce/plugins/letterspacing/index.js
  39. 7
      src/components/hm-crf/tinymce/themes/silver/index.js
  40. 32446
      src/components/hm-crf/tinymce/themes/silver/theme.js
  41. 174
      src/components/input-select/display.vue
  42. 99
      src/components/input-select/index.vue
  43. 174
      src/components/item-select/display.vue
  44. 397
      src/components/item-select/index.vue
  45. 73
      src/components/kpi-select/display.vue
  46. 92
      src/components/kpi-select/index.vue
  47. 226
      src/components/patient-search/data-list.vue
  48. 276
      src/components/patient-search/index.vue
  49. 149
      src/components/patient-view/detail/_del_component.vue
  50. 150
      src/components/patient-view/detail/_mixin.js
  51. 75
      src/components/patient-view/detail/diagnose.vue
  52. 73
      src/components/patient-view/detail/ecrf.vue
  53. 83
      src/components/patient-view/detail/emr-treatments.vue
  54. 118
      src/components/patient-view/detail/exam-item.vue
  55. 57
      src/components/patient-view/detail/inhospital.vue
  56. 38
      src/components/patient-view/detail/iop.vue
  57. 113
      src/components/patient-view/detail/kpi.vue
  58. 99
      src/components/patient-view/detail/medication.vue
  59. 87
      src/components/patient-view/detail/operation.vue
  60. 55
      src/components/patient-view/detail/ref.vue
  61. 40
      src/components/patient-view/detail/va.vue
  62. 629
      src/components/patient-view/index.vue
  63. 134
      src/components/patient-view/set-followup.vue
  64. 52
      src/components/region-tree/index.vue
  65. 195
      src/components/time-line/index.vue
  66. 54
      src/components/user-select/index.vue
  67. 217
      src/core/initAligningGuidelines.js
  68. 60
      src/core/initControls.js
  69. 86
      src/core/initHotKeys.js
  70. 89
      src/core/initializeLineDrawing.js
  71. 46
      src/core/objects/Arrow.js
  72. 92
      src/filters/index.js
  73. 107
      src/mixins/IntelligentFill.js
  74. 88
      src/mixins/IntelligentFill.防止重复调取.js
  75. 37
      src/mixins/checked.js
  76. 16
      src/mixins/full-screen.js
  77. 35
      src/mixins/printModel.js
  78. 35
      src/mixins/qgyCRFData.js
  79. 80
      src/mixins/select.js
  80. 128
      src/mixins/sign-NSV.js
  81. 121
      src/mixins/styeFormSign.js
  82. 5
      src/page-subspecialty/router/index.js
  83. 100
      src/page-subspecialty/views/main-navbar-update-password.vue
  84. 132
      src/page-subspecialty/views/main-navbar.vue
  85. 135
      src/page-subspecialty/views/main-sidebar-sub-menu.vue
  86. 149
      src/page-subspecialty/views/main-sidebar.vue
  87. 19
      src/page-subspecialty/views/modules/TEMP.vue
  88. 18
      src/page-subspecialty/views/redirect.vue
  89. 122
      src/utils/LodopFuncs.js
  90. 33
      src/utils/eventHandler.js
  91. 113
      src/utils/tree.js
  92. 47
      src/utils/utils.js
  93. 16
      static/css/hmcrf-add.css
  94. 124
      static/css/hmcrf.css
  95. 714
      static/css/skins-tinymce/ui/oxide-dark/content.css
  96. 726
      static/css/skins-tinymce/ui/oxide-dark/content.inline.css
  97. 7
      static/css/skins-tinymce/ui/oxide-dark/content.inline.min.css
  98. 7
      static/css/skins-tinymce/ui/oxide-dark/content.min.css
  99. 29
      static/css/skins-tinymce/ui/oxide-dark/content.mobile.css
  100. 7
      static/css/skins-tinymce/ui/oxide-dark/content.mobile.min.css

2
.env.development

@ -1,2 +0,0 @@
NODE_ENV=development
VUE_APP_NODE_ENV=dev

2
.env.localhost

@ -1,2 +0,0 @@
NODE_ENV=localhost
VUE_APP_NODE_ENV=local

2
.env.production

@ -1,2 +0,0 @@
NODE_ENV=production
VUE_APP_NODE_ENV=prod

2
.env.staging

@ -1,2 +0,0 @@
NODE_ENV=production
VUE_APP_NODE_ENV=staging

23
package.json

@ -13,20 +13,6 @@
"et": "node_modules/.bin/et",
"et:init": "node_modules/.bin/et -i"
},
"browserslist": {
"development": [
"last 1 version"
],
"production": [
"> 1%",
"last 2 versions",
"not ie <= 10"
],
"modern": [
"last 1 chrome version",
"last 1 firefox version"
]
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@tinymce/tinymce-vue": "^3.2.8",
@ -54,7 +40,6 @@
"fontfaceobserver": "^2.1.0",
"hammerjs": "^2.0.8",
"hotkeys-js": "^3.8.8",
"jquery": "^3.6.0",
"js-audio-recorder": "^1.0.7",
"js-base64": "^3.6.1",
"js-cookie": "^2.2.1",
@ -76,8 +61,6 @@
"svg-sprite-loader": "^5.0.0",
"throttle-debounce": "^5.0.0",
"tinymce": "^5.8.1",
"tui-color-picker": "^2.2.8",
"tui-image-editor": "^3.15.3",
"uuid": "^9.0.0",
"v-tooltip": "^2.1.3",
"vue": "^2.6.11",
@ -120,12 +103,6 @@
"lamejs": "^1.2.0",
"lib-flexible": "^0.3.2",
"natives": "^1.1.6",
"postcss-plugin-px2rem": "^0.8.1",
"postcss-px-to-viewport": "https://github.com/evrone/postcss-px-to-viewport",
"postcss-pxtorem": "^5.1.1",
"pug": "^3.0.2",
"pug-html-loader": "^1.1.5",
"pug-plain-loader": "^1.1.0",
"sass": "1.26.8",
"sass-loader": "8.0.2",
"vue-loader": "^15.9.8",

0
src/components/.gitkeep

9
src/components/360View/index.vue

@ -42,6 +42,12 @@
<el-tab-pane name="特殊检查" label="特殊检查" style="height: 100%">
<special :patient-id="patientId||$route.query.patientId" :only-read="readOnly" />
</el-tab-pane>
<el-tab-pane name="收费记录" label="收费记录" style="height: 100%">
<div>收费记录</div>
</el-tab-pane>
<el-tab-pane name="用药记录" label="用药记录" style="height: 100%">
<div>用药记录</div>
</el-tab-pane>
<el-tab-pane name="诊断" label="诊断" style="height: 100%">
<el-table
:data="timeAxisNodeInfo"
@ -224,14 +230,13 @@ import drawer from '@/components/360View/drawer'
import overView from '@/components/360View/overView' //
import routine from '@/components/360View/routine' //
import special from '@/components/360View/special' //
import followUpRecord from '@/components/360View/followUpRecord'
import keyIndicators from './key-indicators'
import imgRecord from './img-reccrd.vue'
import pacsList from '@/components/360View/pacs/patientList'
import eventBus from '@/page-subspecialty/utils/eventBus'
export default {
name: '360view',
components: { timeLine, drawer, keyIndicators, shrink, imgRecord, overView, routine, special, followUpRecord, pacsList },
components: { timeLine, drawer, keyIndicators, shrink, imgRecord, overView, routine, special, pacsList },
mixins: [],
props: {
patientId: {

72
src/components/bread-crumb/index.vue

@ -1,72 +0,0 @@
<template>
<div class="bread">
<div class="example-container">
<el-breadcrumb separator="/">
<el-breadcrumb-item
v-for="(item,index) in breadList"
:key="index"
:to="item.name.includes('seeDoctor') ? item.path + '?info=' + queryList.info : item.path"
@click.native="breadcrumbClick(item)"
>{{ item.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
</template>
<script>
export default {
data() {
return {
breadList: [], // ,
userData: {},
queryList: {}
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
created() {
this.userData = window.sessionStorage.getItem('qg-userData')
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
const matched = this.$route.matched
// seeDoctor
if (this.$route.name === 'templateManagement') {
this.queryList = this.$route.query
}
matched.forEach((item, i) => {
if (item.meta.title === '首页' && item.redirect && item.redirect.name) {
item.name = 'outpatientManagement'
item.path = '/outpatientManagement-call'
item.meta.title = '首页'
}
})
this.breadList = matched
},
breadcrumbClick(item) {
console.log(item)
if (item.meta.title === '首页') {
this.$store.commit('activeIndexFun', window.SITE_CONFIG.menuList[0].children[0].id)
}
}
}
}
</script>
<style scoped>
.bread /deep/ .el-breadcrumb{
display: inline-block;
display: inline-block;
height: 50px;
vertical-align: top;
line-height: 50px;
}
.bread /deep/ .is-link{
font-weight: normal;
}
.bread{
float:left;
}
</style>

58
src/components/checked-footer/index.vue

@ -1,58 +0,0 @@
<template>
<div :class="['footer',{'footer-left':$store.state.sidebarFold}]">
<div class="footer-left">
<el-checkbox
v-model="cheackAllFooter"
label="全选"
@change="cheackAllChange(tableRef)"
/>
<el-link
:underline="true"
@click="cheackReverseClick(tableRef)"
>反选</el-link>
</div>
<div class="footer-right">
<div class="checkNum_cancel">
<span class="checked">
已选
<span class="number">{{ currentTableList.length }}</span>
</span>
<span class="cancel" @click="cancelClick(tableRef)">取消</span>
</div>
<div class="batch_button">
<slot />
</div>
</div>
</div>
</template>
<script>
import checked from '@/mixins/checked'
export default {
mixins: [checked],
props: {
dataList: {
type: Array,
default: () => []
},
currentTableList: {
type: Array,
default: () => []
},
tableRef: {
type: String,
default: ''
}
},
data() {
return {
cheackAllFooter: false
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

41
src/components/dept-select/index.vue

@ -1,41 +0,0 @@
<template>
<el-select
:value="value"
:placeholder="placeholder"
:multiple="multiple"
clearable
filterable
style="width:100%;"
@change="$emit('input', $event)"
>
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<script>
export default {
props: {
value: { type: String, default: '' },
multiple: { type: Boolean, default: false },
placeholder: { type: String, default: '请选择' }
},
data() {
return {
dataList: []
}
},
mounted() { this.getDataList() },
methods: {
getDataList(id) {
// /sys/user/getDeptList4AddUser
return this.$http.get('/sys/dept/list?type=1').then(({ data: res }) => {
if (res.code === 0) { this.dataList = res.data } else { this.$message.error(res.msg) }
}).catch(() => {})
}
}
}
</script>

40
src/components/device-select/index.vue

@ -1,40 +0,0 @@
<template>
<el-select
:value="value"
:placeholder="placeholder"
:multiple="multiple"
clearable
filterable
style="width:100%;"
@change="$emit('input', $event)"
>
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<script>
export default {
props: {
value: { type: Array, default: () => [] },
multiple: { type: Boolean, default: false },
placeholder: { type: String, default: '请选择' }
},
data() {
return {
dataList: []
}
},
mounted() { this.getDataList() },
methods: {
getDataList(id) {
return this.$http.get('/device/project/getList').then(({ data: res }) => {
if (res.code === 0) { this.dataList = res.data } else { this.$message.error(res.msg) }
}).catch(() => {})
}
}
}
</script>

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

@ -1,145 +0,0 @@
<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

@ -1,129 +0,0 @@
<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('/project/crf/template/' + 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: rgba(193, 193, 193, 0.2);
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

@ -1,88 +0,0 @@
<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

@ -1,177 +0,0 @@
<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

@ -1,194 +0,0 @@
<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>

40
src/components/exam-item-select/index.vue

@ -1,40 +0,0 @@
<template>
<el-select
:value="value"
:placeholder="placeholder"
:multiple="multiple"
clearable
filterable
style="width:100%;"
@change="$emit('input', $event)"
>
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<script>
export default {
props: {
value: { type: Array, default: () => [] },
multiple: { type: Boolean, default: false },
placeholder: { type: String, default: '请选择' }
},
data() {
return {
dataList: []
}
},
mounted() { this.getDataList() },
methods: {
getDataList(id) {
return this.$http.get('/checkItem/project/getList').then(({ data: res }) => {
if (res.code === 0) { this.dataList = res.data } else { this.$message.error(res.msg) }
}).catch(() => {})
}
}
}
</script>

102
src/components/files/index.vue

@ -1,102 +0,0 @@
<template>
<div class="flex-container">
<div class="file-list">
<el-table :data="fileList" style="width: 100%" highlight-current-row @row-click="rowClick">
<el-table-column label="文件列表">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.name|f_fileName }}</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="file-show">
<template v-if="isImg(activeFile.url)">
<el-image :fit="'fill'" :src="activeFile.url" />
</template>
<template v-if="isPdf(activeFile.url)">
<pdf :src="activeFile.url" />
</template>
</div>
</div>
</template>
<script>
import pdf from 'vue-pdf'
export default {
components: {
pdf
},
filters: {
f_fileName(val) {
return val.substring(0, val.lastIndexOf('-'))
},
f_url(val) {
return `${window.SITE_CONFIG['apiURL']}/upload/${val}`
}
},
props: {
fileList: { type: Array, required: true }
},
data() {
return {
activeFile: {}
}
},
watch: {
fileList: {
immediate: true,
handler(val) {
this.activeFile = this.fileList[0] || {}
}
}
},
mounted() {
this.$nextTick(() => {
})
},
methods: {
fileType(url) {
return url ? url.substring(url.lastIndexOf('.') + 1) : ''
},
isImg(url) {
const type = this.fileType(url)
return ['png', 'jpg', 'jpeg', 'bmp'].indexOf(type.toLowerCase()) >= 0
},
isPdf(url) {
const type = this.fileType(url)
return ['pdf'].indexOf(type.toLowerCase()) >= 0
},
rowClick(row) {
this.activeFile = row
}
}
}
</script>
<style lang="scss" scoped>
.flex-container {
display: flex;
width: 100%;
height: 100%;
// height: 500px;
}
.file-list{
// display:flex;
width: 200px;
height: 100%;
margin-right: 20px;
.file-item{
display: block;
}
}
.file-show{
// display:flex;
width: calc(100% - 220px);
height: 100%;
border:1px solid;
}
</style>

224
src/components/filter/index.vue

@ -1,224 +0,0 @@
<template>
<div class="component-container">
<span class="title">{{ title }}</span>
<div v-for="(queryItem,queryIndex) in queryItemList" :key="queryIndex" class="query-item-wrapper">
<!-- 关系() -->
<div :class="{disvisible:queryIndex==0}" class="query-item">
<el-select v-model="queryItem.connection" filterable placeholder="" style="width:80px">
<el-option
v-for="(itemRel,indexRel) in dictRel"
:key="indexRel"
:label="itemRel.name"
:value="itemRel.value"
/>
</el-select>
</div>
<!-- 查询字段 -->
<div class="query-item">
<el-select v-model="queryItem.fieldItem" filterable placeholder="检索字段" @change="clickHandle_fieldName(queryItem)">
<!-- axios获取列表 -->
<el-option-group
v-for="(groupItem,groupIndex) in dataListDemo"
:key="groupIndex"
:label="groupItem.tableDescription"
class="select-group"
>
<el-option
v-for="(fieldItem,fieldIndex) in groupItem.fieldList"
:key="fieldIndex"
:label="fieldItem.fieldDescription"
:value="fieldItem"
/>
</el-option-group>
</el-select>
</div>
<!-- 检索类型匹配精准匹配范围查询 -->
<div class="query-item">
<el-select v-model="queryItem.queryType" placeholder="" style="width:100px">
<el-option
v-for="(item,index) in dictQuery"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</div>
<!-- 查询内容 -->
<!-- 范围 -->
<div v-if="queryItem.queryType=='number'" class="query-item">
<!-- dictLogicValueGt -->
<el-select style="width:100px">
<el-option label=">" value="gt" />
<el-option label=">=" value="gte" />
</el-select>
<el-input-number v-model="queryItem.queryValue1" controls-position="right" />
<!-- dictLogicValueLt -->
<el-select style="width:100px">
<el-option label="<" value="lt" />
<el-option label="<=" value="lte" />
</el-select>
<el-input-number v-model="queryItem.queryValue2" controls-position="right" />
</div>
<!-- 日期 -->
<div v-else-if="queryItem.queryType=='date'" class="query-item">
<!-- dictLogicValueGt -->
<el-select style="width:100px">
<el-option label=">" value="gt" />
<el-option label=">=" value="gte" />
</el-select>
<el-date-picker v-model="queryItem.queryValue1" type="datetime" />
<!-- dictLogicValueLt -->
<el-select style="width:100px">
<el-option label="<" value="lt" />
<el-option label="<=" value="lte" />
</el-select>
<el-date-picker v-model="queryItem.queryValue2" type="datetime" />
</div>
<!-- -->
<div v-else class="query-item">
<!-- dictLogicValueEq -->
<el-select v-model="queryItem.queryLogic" style="width:80px">
<!-- <el-option
v-for="(item,index) in dictLogicValueEq"
:key="index"
:label="item.name"
:value="item.value"
/> -->
<el-option label="等于" value="eq" />
</el-select>
</div>
</div>
</div>
</template>
<script>
//
const dictRel = [
{ name: '并且', value: 'must' }, // and
{ name: '可以', value: 'should' }, // or
{ name: '排除', value: 'must_not' } // not
]
//
const dictLogicValue = [
{ name: '等于', value: 'eq' }, // =
{ name: '小于', value: 'lt' }, // <
{ name: '小于等于', value: 'lte' }, // <=
{ name: '大于', value: 'gt' }, // >
{ name: '大于等于', value: 'gte' } // >=
]
//
const dictQuery = [
{ name: '匹配', value: 'matchQuery' },
{ name: '精准匹配', value: 'termQuery' },
{ name: '范围查询', value: 'rangeQuery' }
]
const dataListDemo = [
{
tableDescription: '基础信息', //
tableName: 'REGISTER_PATIENT', //
type: '1', // 12
fieldList: [
{ fieldDescription: '登记号', fieldName: 'patientId', fieldType: 'string' },
{ fieldDescription: '年龄', fieldName: 'age', fieldType: 'number' },
{ fieldDescription: '出生日期', fieldName: 'birthday', fieldType: 'date' },
{ fieldDescription: '地址', fieldName: 'address', fieldType: 'string' }
]
},
{
tableDescription: '就诊信息',
tableName: 'REGISTER_EXAMINE',
type: '1',
fieldList: [
{ fieldDescription: '就诊日期', fieldName: 'registerTime', fieldType: 'date' },
{ fieldDescription: '主诉', fieldName: 'complain', fieldType: 'string' },
{ fieldDescription: '诊断', fieldName: 'diag', fieldType: 'string' }
]
}
]
export default {
props: {
title: { type: String, required: true },
isGroup: { type: Boolean, default: true },
dataList: { type: Array, required: true }
},
data() {
return {
dictRel: dictRel,
dictLogicValue: dictLogicValue,
dictQuery: dictQuery,
queryItemList: [{
connection: 'must',
tableName: '',
fieldName: '',
fieldItem: undefined,
queryType: 'matchQuery',
queryValue: {
eq: '',
lt: '',
gt: '',
lte: '',
gte: ''
},
queryLogic: 'eq', // eq,lt,gt,lte,gte
queryValue1: '',
queryValue2: ''
}, {
connection: 'must',
tableName: '',
fieldName: '',
fieldItem: undefined,
queryType: 'matchQuery',
queryLogic: '',
queryValue: {
eq: '',
lt: '',
gt: '',
lte: '',
gte: ''
}
}],
dataListDemo: dataListDemo
}
},
watch: {},
methods: {
clickHandle_fieldName(val) {
}
}
}
</script>
<style scoped>
.select-group >>> .el-select-group__title {
font-size: 14px;
font-weight: 600;
color: #409eff;
}
</style>
<style lang='scss' scoped>
.component-container {
padding: 10px;
.title {
display: block;
font-size: 16px;
font-weight: 600;
height: 30px;
line-height: 30px;
margin: 5px 0px;
padding-left: 5px;
}
.query-item-wrapper {
margin-bottom: 10px;
.query-item {
display: inline-block;
margin-right: 10px;
}
}
}
.disvisible{
visibility: hidden;
}
</style>

61
src/components/head/index.vue

@ -1,61 +0,0 @@
<template>
<div class="head">
<div class="head-left">
<div class="ceshi" />
<span v-show="isShowIcon" class="left-icon" />
<span class="text">{{ headLeft }}</span>
<!-- <svg class="icon-svg">
<use xlink:href="#icon-sync" />
</svg> -->
</div>
<div class="head-right">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
headLeft: {
type: String,
default: ''
},
isShowIcon: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
created() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.head {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
.head-left {
.left-icon {
display: inline-block;
width: 4px;
height: 12px;
background-color: #1e79ff;
border-radius: 25px;
margin-right: 6px;
}
.text {
padding-right: 16px;
}
.icon-svg {
color: #1e79ff;
}
}
}
</style>

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

@ -1,87 +0,0 @@
<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

@ -1,49 +0,0 @@
<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

@ -1,88 +0,0 @@
<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

@ -1,100 +0,0 @@
<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

@ -1,239 +0,0 @@
<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

@ -1,76 +0,0 @@
<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

@ -1,10 +0,0 @@
// 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

@ -1,7 +0,0 @@
// 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

@ -1,7 +0,0 @@
// 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

@ -1,234 +0,0 @@
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

@ -1,7 +0,0 @@
// 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

@ -1,366 +0,0 @@
/* 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

@ -1,7 +0,0 @@
// 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

@ -1,143 +0,0 @@
/* 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

@ -1,7 +0,0 @@
// 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

@ -1,235 +0,0 @@
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()
}())

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

@ -1,305 +0,0 @@
// 判断是否已引用
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 = Array.from(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 = Array.from(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

@ -1,56 +0,0 @@
/* 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

@ -1,7 +0,0 @@
// 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

174
src/components/input-select/display.vue

@ -1,174 +0,0 @@
<template>
<div>
<div>
<div class="title-wrapper">
必须
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_must" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
<div>
<div class="title-wrapper">
可以
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_should" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
<div>
<div class="title-wrapper">
排除
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_must_not" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
</div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import { findItem, findPathArray } from '@/utils/tree'
const options_matchValue = [
{ label: '匹配', value: 'eq' },
{ label: '大于', value: 'gt' },
{ label: '大于等于', value: 'gte' },
{ label: '小于', value: 'lt' },
{ label: '小于等于', value: 'lte' }
]
export default {
props: {
condition: { type: Array, default: () => [] }
},
data() {
return {
options_kpi: [],
queryItemData_must: [],
queryItemData_should: [],
queryItemData_must_not: []
}
},
watch: {
condition: {
handler(newVal, oldVal) {
if (this.options_kpi.length === 0) { this.getOptionsKPI() }
const arrayData = cloneDeep(newVal)
const must = []
const should = []
const must_not = []
// this.getOptionsKPI()
arrayData.forEach(item => {
const valueList = findPathArray(this.options_kpi, item.id, 'value', 'children')
const itemParentInfo = this.getItem(valueList[(valueList.length - 2) || 0])
const itemInfo = this.getItem(valueList[(valueList.length - 1) || 0])
// console.log(valueList, itemParentInfo, itemInfo, this.options_kpi, window.SITE_CONFIG['dict_colSearch'])
const obj = {
connection: item.connection,
itemName: itemParentInfo.label,
kpiId: item.id,
kpiName: itemInfo.label,
kpiType: itemInfo.type,
queryType: item.queryType, //
// queryTypeName: options_matchType.find((item2) => item2.value === item.queryType).label,
queryLogic: item.queryLogic, //
queryLogicName: options_matchValue.find((item2) => item2.value === item.queryLogic).label,
queryValue: item.queryValue //
}
if (item.connection === 'must') {
must.push(obj)
}
if (item.connection === 'should') {
should.push(obj)
}
if (item.connection === 'must_not') {
must_not.push(obj)
}
})
this.queryItemData_must = must
this.queryItemData_should = should
this.queryItemData_must_not = must_not
},
immediate: true
}
},
created() { this.getOptionsKPI() },
mounted() { },
methods: {
getItem(value) {
return findItem(this.options_kpi, value, 'value', 'children')
},
async getOptionsKPI() {
if (window.SITE_CONFIG['dict_colSearch']) {
this.options_kpi = window.SITE_CONFIG['dict_colSearch']
} else {
//
const { data: res } = await this.$http.get('/sys/table/dict/getList', { params: { type: 1 }})
this.options_kpi = res.data
}
}
}
}
</script>
<style lang="scss" scoped>
$width_title: 35px;
.title-wrapper {
display: inline-block;
width: $width_title;
vertical-align: top;
}
.select-wrapper {
display: inline-block;
width: calc(100% - #{$width_title});
.match-item {
display: inline-block;
border-radius: 15px;
background-color: #e6f7ff;
margin-right: 10px;
.match-item-name {
color: #000;
margin-left: 5px;
margin-right: 5px;
}
.match-item-kpi {
color: #fa0d35;
margin-left: 3px;
margin-right: 3px;
font-size: 13px;
}
.match-item-type {
color: #1e79ff;
margin-right: 5px;
}
.match-item-value {
color: #000;
margin-right: 5px;
}
}
}
</style>

99
src/components/input-select/index.vue

@ -1,99 +0,0 @@
<template>
<div class="input-container">
<!-- 显示的输入框用v-model绑定数据并且绑定focus事件 -->
<Input v-model="inputData" class="input-number" @on-focus="_showInputNumber" />
<!-- -->
<div class="input-dropdown-wrap">
<Dropdown trigger="custom" :visible="visibNormal" class="input-dropdown">
<Dropdown-menu slot="list">
<div class="dropdown-list">
<Row :key="item.code" v-for="item in arrayList" class="item" :value="item.code" @click.native="_inputNumChange(item.code)">{{ item.text }}</Row>
</div>
</Dropdown-menu>
</Dropdown>
</div>
</div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
export default {
props: {
arrayList: { //
type: Array,
default: []
}
},
data() {
return {
inputData: '1', //
visibNormal: false //
}
},
watch: {
inputData(newVal) {
this.$emit('getInputNum', newVal)
}
},
mounted() {
this.getOptionsKPI()
},
methods: {
//
_showInputNumber(e) {
const _this = this
if (this.visibNormal) return
this.visibNormal = true
//
e.target.addEventListener('click', (e) => {
e.stopPropagation()
})
document.addEventListener('click', _this._hideNormal)
},
//
_inputNumChange(data) {
this.$emit('getInputNum', data)
},
//
_hideNormal() {
let curTarget = event.target;
if(curTarget.nodeName === 'SPAN' && curTarget.classList.contains('switch')){
return
}
this.visibNormal = false
document.removeEventListener('click', this._hideNormal)
}
}
}
</script>
<style lang="scss" scoped>
.input-container {
.input-dropdown-wrap {
height: 0 !important;
overflow: hidden;
}
.dropdown-list {
height: 1.3rem;
overflow: auto;
border-bottom: .01rem solid #E4E4E4;
.item {
line-height: .25rem;
padding-left: .15rem;
&:hover {
background: grey;
}
}
}
.input-number {
width: 2.2rem;
}
.input-dropdown {
width: 2.2rem;
.ivu-select-dropdown {
margin-top: -.2rem;
}
}
}
</style>

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

@ -1,174 +0,0 @@
<template>
<div>
<div>
<div class="title-wrapper">
必须
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_must" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
<div>
<div class="title-wrapper">
可以
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_should" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
<div>
<div class="title-wrapper">
排除
</div>
<div class="select-wrapper">
<el-tag v-for="(item,index) in queryItemData_must_not" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
</div>
</div>
</div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import { findItem, findPathArray } from '@/utils/tree'
const options_matchValue = [
{ label: '匹配', value: 'eq' },
{ label: '大于', value: 'gt' },
{ label: '大于等于', value: 'gte' },
{ label: '小于', value: 'lt' },
{ label: '小于等于', value: 'lte' }
]
export default {
props: {
condition: { type: Array, default: () => [] }
},
data() {
return {
options_kpi: [],
queryItemData_must: [],
queryItemData_should: [],
queryItemData_must_not: []
}
},
watch: {
condition: {
handler(newVal, oldVal) {
if (this.options_kpi.length === 0) { this.getOptionsKPI() }
const arrayData = cloneDeep(newVal)
const must = []
const should = []
const must_not = []
// this.getOptionsKPI()
arrayData.forEach(item => {
const valueList = findPathArray(this.options_kpi, item.id, 'value', 'children')
const itemParentInfo = this.getItem(valueList[(valueList.length - 2) || 0])
const itemInfo = this.getItem(valueList[(valueList.length - 1) || 0])
// console.log(valueList, itemParentInfo, itemInfo, this.options_kpi, window.SITE_CONFIG['dict_colSearch'])
const obj = {
connection: item.connection,
itemName: itemParentInfo.label,
kpiId: item.id,
kpiName: itemInfo.label,
kpiType: itemInfo.type,
queryType: item.queryType, //
// queryTypeName: options_matchType.find((item2) => item2.value === item.queryType).label,
queryLogic: item.queryLogic, //
queryLogicName: options_matchValue.find((item2) => item2.value === item.queryLogic).label,
queryValue: item.queryValue //
}
if (item.connection === 'must') {
must.push(obj)
}
if (item.connection === 'should') {
should.push(obj)
}
if (item.connection === 'must_not') {
must_not.push(obj)
}
})
this.queryItemData_must = must
this.queryItemData_should = should
this.queryItemData_must_not = must_not
},
immediate: true
}
},
created() { this.getOptionsKPI() },
mounted() { },
methods: {
getItem(value) {
return findItem(this.options_kpi, value, 'value', 'children')
},
async getOptionsKPI() {
if (window.SITE_CONFIG['dict_colSearch']) {
this.options_kpi = window.SITE_CONFIG['dict_colSearch']
} else {
//
const { data: res } = await this.$http.get('/table/dict/optionsColumn', { params: { type: 1 }})
this.options_kpi = res.data
}
}
}
}
</script>
<style lang="scss" scoped>
$width_title: 35px;
.title-wrapper {
display: inline-block;
width: $width_title;
vertical-align: top;
}
.select-wrapper {
display: inline-block;
width: calc(100% - #{$width_title});
.match-item {
display: inline-block;
border-radius: 15px;
background-color: #e6f7ff;
margin-right: 10px;
.match-item-name {
color: #000;
margin-left: 5px;
margin-right: 5px;
}
.match-item-kpi {
color: #fa0d35;
margin-left: 3px;
margin-right: 3px;
font-size: 13px;
}
.match-item-type {
color: #1e79ff;
margin-right: 5px;
}
.match-item-value {
color: #000;
margin-right: 5px;
}
}
}
</style>

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

@ -1,397 +0,0 @@
<template>
<div>
<div>
<el-tag
v-for="(item,index) in dataList"
:key="index"
class="match-item"
closable
@close="btnRemove(item)"
@click="editItem(item)"
>
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
<span class="match-item-type">{{ item.queryLogicName }}</span>
<span class="match-item-value">{{ item.queryValue }}</span>
</el-tag>
<span class="btn-add">
<i class="el-icon-plus" @click="btnAdd" />
</span>
</div>
<div v-show="isAdd">
<el-form :inline="true" :model="dataForm" class="form-query" @submit.native.prevent>
<!-- KPI -->
<el-form-item>
<el-cascader
v-model="CascaderValue"
:options="options_kpi"
size="mini"
popper-class="kpi-select-filter"
class="item-query-kpi"
placeholder="请选择"
filterable
@change="changeHandle_kpi"
/>
</el-form-item>
<!-- 匹配逻辑 -->
<el-form-item>
<el-select v-model="dataForm.queryLogic" size="mini" class="item-query-logic" placeholder="请选择">
<el-option
v-for="item in options_matchValue"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
/>
</el-select>
</el-form-item>
<!-- 匹配数值 -->
<el-form-item>
<el-input-number
v-if="dataForm.kpiType==='number'"
v-model="dataForm.queryValue"
size="mini"
class="item-query-value"
placeholder="请输入"
/>
<el-input
v-if="dataForm.kpiType==='string'"
v-model="dataForm.queryValue"
size="mini"
class="item-query-value"
placeholder="请输入"
/>
<el-date-picker
v-if="dataForm.kpiType==='date'"
v-model="dataForm.queryValue"
size="mini"
align="right"
type="date"
placeholder="选择日期"
value-format="yyyy/MM/dd"
/>
<!-- 设备选择 -->
<el-select
v-if="dataForm.kpiType==='selectDevice'"
v-model="dataForm.queryValue"
filterable
size="mini"
placeholder="请选择"
>
<el-option
v-for="item in options_device"
:key="item.deviceId"
:label="item.deviceName+(item.location?'('+item.location+')':'')"
:value="item.deviceId"
>
<span style="float: left">{{ item.deviceName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.location?item.location:'' }}</span>
</el-option>
</el-select>
</el-form-item>
<!-- 按钮 -->
<el-form-item>
<el-button type="primary" icon="el-icon-check" size="mini" @click="btnOk" />
<el-button type="danger" icon="el-icon-close" size="mini" @click="btnCancel" />
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
// import { getBirthday, getAge, formatDate } from '@/utils'
import { findItem, findPathArray } from '@/utils/tree'
// const options_matchType = [
// { label: '', value: 'matchQuery' },
// { label: '', value: 'rangeQuery' }
// ]
// const demo = {
// connection: '', //
// id: '', // ID
// queryType: '', //
// queryLogic: 'eq',
// queryValue: ''
// }
const options_matchValue = [
{ label: '匹配', value: 'eq' },
{ label: '大于', value: 'gt' },
{ label: '大于等于', value: 'gte' },
{ label: '小于', value: 'lt' },
{ label: '小于等于', value: 'lte' }
]
export default {
props: {
value: { type: Array, default: () => [] },
connection: { type: String, default: '' }
},
data() {
return {
isAdd: false,
dataList: [],
options_kpi: [],
options_device: [],
options_matchValue: options_matchValue,
CascaderValue: [],
dataForm: {
itemName: '', // label
kpiName: '',
kpiId: '',
kpiType: 'string', // string,number,date
queryType: 'matchQuery',
queryLogic: 'eq',
queryValue: ''
}
}
},
watch: {
'dataForm.queryType': {
handler(newVal, oldVal) {
if (newVal !== 'rangeQuery') {
this.dataForm.queryLogic = 'eq'
this.options_matchValue = [
{ label: '匹配', value: 'eq' },
{ label: '大于', value: 'gt', disabled: true },
{ label: '大于等于', value: 'gte', disabled: true },
{ label: '小于', value: 'lt', disabled: true },
{ label: '小于等于', value: 'lte', disabled: true }
]
} else {
this.dataForm.queryLogic = 'gt'
this.options_matchValue = [
{ label: '匹配', value: 'eq', disabled: true },
{ label: '大于', value: 'gt' },
{ label: '大于等于', value: 'gte' },
{ label: '小于', value: 'lt' },
{ label: '小于等于', value: 'lte' }
]
}
},
immediate: true
},
value(val) {
const arrayData = cloneDeep(val)
// 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])
const itemInfo = this.getItem(valueList[(valueList.length - 1) || 0])
//
if (item.id.indexOf('DEVICE_ID') >= 0) {
const dict = cloneDeep(window.SITE_CONFIG['dict_device_item'])
const itemId = item.id.split('.')[0] || ''
const obj = dict.find(item2 => item2.value === itemId)
this.options_device = obj ? obj.children : []
}
return {
recId: item.recId,
itemName: item.itemName,
kpiId: item.id,
kpiName: item.kpiName,
kpiType: item.kpiType,
queryType: item.queryType, //
// queryTypeName: options_matchType.find((item2) => item2.value === item.queryType).label,
queryLogic: item.queryLogic, // queryValue=queryLogic
queryLogicName: options_matchValue.find((item2) => item2.value === item.queryLogic).label,
queryValue: item.queryValue //
}
})
}
},
created() {
this.getOptionsKPI()
},
mounted() { },
methods: {
changeHandle_kpi(valueList) {
if (valueList.length > 0) {
//
const parentValue = valueList[(valueList.length - 2) || 0]
const parentItem = this.getItem(parentValue)
//
const value = valueList[(valueList.length - 1) || 0]
const item = this.getItem(value)
const oldValType = this.dataForm.kpiType
this.dataForm.itemName = parentItem.label
this.dataForm.kpiId = item.id
this.dataForm.kpiName = item.label
this.dataForm.kpiType = item.fieldType
this.dataForm.queryType = (this.dataForm.kpiType === 'number' || this.dataForm.kpiType === 'date') ? 'rangeQuery' : 'matchQuery'
this.dataForm.queryValue = this.dataForm.kpiType === oldValType ? this.dataForm.queryValue : null
//
if (item.value.indexOf('DEVICE_ID') >= 0) {
// this.options_device = cloneDeep(window.SITE_CONFIG['dict_device']).filter(item2 => (item.value.split('.')[1] || '') === item2.datSource)
const dict = cloneDeep(window.SITE_CONFIG['dict_device_item'])
const itemId = item.value.split('.')[0] || ''
const obj = dict.find(item2 => item2.value === itemId)
this.options_device = obj ? obj.children : []
}
}
},
//
convertItem(item) {
const filterItem = {
...item,
connection: this.connection,
id: item.kpiId,
// queryType: item.queryType,
// queryValue: {}, // postgetlogic
queryValue: String(item.queryValue)
}
// filterItem.queryValue[item.queryLogic] = String(item.queryValue)
return filterItem
},
convertItemList(itemList) {
const list = []
itemList.forEach(item => {
list.push(this.convertItem(item))
})
return list
},
//
btnRemove(item) {
const index = this.dataList.findIndex((item2, index) => {
return item2 === item
})
this.dataList.splice(index, 1)
this.$emit('remove', this.convertItem(item))
this.$emit('input', this.convertItemList(this.dataList))
this.$emit('change', this.convertItemList(this.dataList))
},
//
editItem(item) {
if (!this.isAdd) {
this.isAdd = true
} else if (this.isAdd && item.kpiId === this.dataForm.kpiId) {
this.isAdd = false
}
this.dataForm = cloneDeep(item)
this.dataForm.recId = null
this.CascaderValue = findPathArray(this.options_kpi, this.dataForm.kpiId, 'value', 'children')
},
btnAdd() {
this.resetDataForm()
this.isAdd = true
},
btnCancel() {
this.isAdd = false
},
btnOk() {
if (!this.dataForm.kpiId ||
this.dataForm.queryValue === null ||
this.dataForm.queryValue === undefined ||
this.dataForm.queryValue === '') {
this.$message.error('请明确查询条件!')
return false
}
const item = { ...this.dataForm, queryLogicName: options_matchValue.find((item) => item.value === this.dataForm.queryLogic).label }
this.dataList.push(item)
this.$emit('add', this.convertItem(item))
this.$emit('input', this.convertItemList(this.dataList))
this.$emit('change', this.convertItemList(this.dataList))
},
resetDataForm() {
this.CascaderValue = []
this.dataForm = {
itemName: '',
kpiName: '',
kpiId: '',
kpiType: 'string',
queryType: 'matchQuery',
queryLogic: 'eq',
queryValue: ''
}
},
getItem(value) {
return findItem(this.options_kpi, value, 'value', 'children')
},
async getOptionsKPI() {
if (window.SITE_CONFIG['dict_colSearch']) {
this.options_kpi = window.SITE_CONFIG['dict_colSearch']
} else {
//
const { data: res } = await this.$http.get('/sys/table/dict/getList', { params: { type: 1, isSearch: 1 }})
if (res.data.length) {
res.data.forEach(item => {
item.label = item.tableDescription
item.value = item.tableName
item.list.forEach(row => {
row.label = row.fieldDescription
row.value = row.fieldName
})
item.children = JSON.parse(JSON.stringify(item.list))
})
}
this.options_kpi = res.data
}
}
}
}
</script>
<style lang="scss">
.kpi-select-filter .el-cascader-menu__wrap {
height: 400px;
}
</style>
<style lang="scss" scoped>
.match-item {
display: inline-block;
border-radius: 15px;
background-color: #e6f7ff;
margin-right: 10px;
.match-item-name {
color: #000;
margin-left: 5px;
margin-right: 5px;
}
.match-item-kpi {
color: #fa0d35;
margin-left: 3px;
margin-right: 3px;
font-size: 13px;
}
.match-item-type {
color: #1e79ff;
margin-right: 5px;
}
.match-item-value {
color: #000;
margin-right: 5px;
}
}
.btn-add {
padding: 5px;
cursor: pointer;
}
.form-query {
.item-query-kpi {
width: 300px;
}
.item-query-type {
width: 100px;
}
.item-query-logic {
width: 100px;
}
}
</style>

73
src/components/kpi-select/display.vue

@ -1,73 +0,0 @@
<template>
<div>
<el-tag v-for="(item,index) in kpiItemList" :key="index" size="small" class="match-item">
<span class="match-item-name">{{ item.itemName }}
(<span class="match-item-kpi">{{ item.kpiName }}</span>)
</span>
</el-tag>
</div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import { findItem, findPathArray } from '@/utils/tree'
export default {
props: {
type: { type: Number, default: 4 },
value: { type: Array, default: () => [] }
},
data() {
return {
options_kpi: [],
kpiItemList: []
}
},
watch: {
value: {
handler(newVal, oldVal) {
if (this.options_kpi.length === 0) { this.getOptionsKPI() }
const arrayData = cloneDeep(newVal)
const itemList = []
// this.getOptionsKPI()
arrayData.forEach(id => {
const valueList = findPathArray(this.options_kpi, id, 'value', 'children')
const itemParentInfo = findItem(this.options_kpi, valueList[(valueList.length - 2) || 0], 'value', 'children')
const itemInfo = findItem(this.options_kpi, id, 'value', 'children')
console.log(valueList, itemParentInfo, itemInfo, this.options_kpi)
itemList.push({
itemName: itemParentInfo.label,
kpiName: itemInfo.label
})
})
this.kpiItemList = itemList
},
immediate: true
}
},
created() { },
mounted() { },
methods: {
async getOptionsKPI() {
if (this.type === 4 && window.SITE_CONFIG.dict_colExport) {
this.options_kpi = window.SITE_CONFIG.dict_colExport
} else if (this.type === 2 && window.SITE_CONFIG.dict_colChart) {
this.options_kpi = window.SITE_CONFIG.dict_colChart
} else {
const { data: res } = await this.$http.get('/table/dict/optionsColumn', { params: { type: this.type }})
this.options_kpi = res.data
}
}
}
}
</script>
<style lang="scss">
.match-item{
margin-right: 5px;
}
</style>

92
src/components/kpi-select/index.vue

@ -1,92 +0,0 @@
<template>
<div>
<el-cascader
v-model="optionValue"
popper-class="kpi-select-filter"
:style="{ width: width }"
:options="options"
:props="optionSet"
:clearable="clearable"
filterable
@change="changeHandle"
/>
</div>
</template>
<script>
import { findItem, findPathArray } from '@/utils/tree'
export default {
props: {
type: { type: Number, default: 0 },
value: { type: Array, default: () => [] },
width: { type: String, default: '100%' },
optionSet: { type: Object, default: () => { return { multiple: true } } },
clearable: { type: Boolean, default: true }
},
data() {
return {
optionValue: [],
options: []
}
},
watch: {
value: {
handler(newVal, oldVal) {
if (this.options.length === 0) {
this.getOptions()
}
this.valueHandle()
},
immediate: true
}
},
created() { // this.getOptions()
},
mounted() { },
methods: {
valueHandle() {
const valuePathList = []
this.value.forEach(id => {
const val = findPathArray(this.options, id, 'value', 'children')
if (val) { valuePathList.push(val) }
})
this.optionValue = valuePathList
},
async getOptions() {
if (this.type === 4 && window.SITE_CONFIG.dict_colExport) {
this.options = window.SITE_CONFIG.dict_colExport
} else if (this.type === 2 && window.SITE_CONFIG.dict_colChart) {
this.options = window.SITE_CONFIG.dict_colChart
} else {
const { data: res } = await this.$http.get('/table/dict/optionsColumn', { params: { type: this.type }})
this.options = res.data
}
// this.valueHandle()
},
changeHandle(valueList) {
const idList = []
const itemList = []
valueList.forEach(arrayItem => {
if (arrayItem.length > 0) {
// id
const id = arrayItem[arrayItem.length - 1]
if (id) { idList.push(id) }
// item
const item = findItem(this.options, id, 'value', 'children')
if (item) { itemList.push(item) }
}
})
this.$emit('input', idList)
this.$emit('change', itemList)
}
}
}
</script>
<style lang="scss">
.kpi-select-filter .el-cascader-menu__wrap{
height: 400px;
}
</style>

226
src/components/patient-search/data-list.vue

@ -1,226 +0,0 @@
<template>
<div class="component-container searchContent">
<el-table
ref="multipleTable"
v-loading="dataListLoading"
:data="dataList"
@select="selectHandle"
@select-all="selectHandle"
>
<el-table-column type="selection" width="55" :selectable="selectable" />
<!-- 行展开 -->
<el-table-column type="expand">
<template slot-scope="scope">
<el-form label-width="90px" class="expand-form">
<!-- 摘要 -->
<el-form-item :label="'主要内容'">
<div class="overViewHtml" v-html="scope.row.allHighlight" />
</el-form-item>
<!-- 检查项目 -->
<el-form-item :label="'检查计次'">
<div class="exam">
<p v-for="(item, index) in scope.row.checkCount" :key="index">
<span class="exam-name" :title="item.checkName">{{ item.checkName }}</span>
<span class="exam-num">{{ item.count }}</span>
</p>
</div>
</el-form-item>
<template v-if="visibleChart">
<!-- 折线图 -->
<el-form-item :label="'折线图'">
<el-row :gutter="20">
<el-col :span="12">
<echarts-line-kpi :chart-data="scope.row.yanya" :title="'眼压'" />
</el-col>
<el-col :span="12">
<echarts-line-kpi-va :chart-data="scope.row.vision" :title="'视力'" />
</el-col>
</el-row>
</el-form-item>
</template>
</el-form>
</template>
</el-table-column>
<!-- 姓名 -->
<el-table-column :label="'姓名'" header-align="center" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ (scope.row.esPatientInfo?scope.row.esPatientInfo.patientName:'') | f_desensitize_name }}
</template>
</el-table-column>
<!-- 性别 -->
<el-table-column :label="'性别'" header-align="center" align="center">
<template slot-scope="scope">
{{ (scope.row.esPatientInfo?scope.row.esPatientInfo.patientSex:'') | f_sex }}
</template>
</el-table-column>
<!-- 年龄 -->
<el-table-column :label="'年龄'" header-align="center" align="center">
<template slot-scope="scope">
{{ (scope.row.esPatientInfo?scope.row.esPatientInfo.patientAge:'') }}
</template>
</el-table-column>
<!-- 身份证号 -->
<el-table-column prop="patientIdNumber" :label="'身份证号'" header-align="center" align="center">
<template slot-scope="scope">
{{ (scope.row.id) | f_desensitize_idNumber }}
</template>
</el-table-column>
<!-- 检索内容 -->
<!-- <el-table-column prop="patientIdNumber" :label="'检索内容'" header-align="center" align="center" show-overflow-tooltip>
<template slot-scope="scope">
<p v-html="scope.row.allHighlight" />
</template>
</el-table-column> -->
<!-- 操作 -->
<el-table-column label="操作" header-align="center" align="center" width="120">
<template slot-scope="scope">
<el-button type="text" size="small" @click="showDetail(scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import echartsLineKpi from '@/components/echarts/line-kpi'
import echartsLineKpiVa from '@/components/echarts/line-kpi-va'
import { findItem } from '@/utils/tree'
export default {
components: {
echartsLineKpi,
echartsLineKpiVa
},
props: {
dataListLoading: { type: Boolean, default: false },
dataList: { type: Array, default: () => [] },
visibleChart: { type: Boolean, default: false },
selectDisableIdList: { type: Array, default: () => [] },
projectId: { type: String, default: '' }
},
data() {
return {
selectIdList: [],
selectList: [],
patientId: ''
}
},
mounted() {
},
methods: {
getExamItem(obj) {
const result = []
for (const key in obj) {
if (obj[key]) {
const dictItem = findItem(window.SITE_CONFIG['dict_colSearch'], key, 'name', 'children')
console.log(window.SITE_CONFIG['dict_colSearch'])
result.push({ id: key, name: dictItem ? dictItem.label : '', num: obj[key] })
}
}
return result
},
selectHandle(selection, row) {
this.selectIdList = []
this.selectList = selection
selection.forEach(item => {
this.selectIdList.push(item.id)
})
this.$emit('vmSelectIdList', this.selectIdList)
this.$emit('vmSelectList', this.selectList)
},
clearSelect() {
console.log(1)
this.selectIdList = []
this.selectList = []
this.$refs.multipleTable.clearSelection()
},
selectable(row, index) {
return this.selectDisableIdList.indexOf(row.id) < 0
},
//
showDetail(scopeRow) {
this.$emit('viewDetail', scopeRow.esPatientInfo.patientId)
// this.patientId = scopeRow.patientId
const mzName = scopeRow.mzDoctorName ? scopeRow.mzDoctorName : ''
const jzNumber = scopeRow.jzNumber ? scopeRow.jzNumber : ''
window.sessionStorage.setItem('mzDoctorName', mzName)
window.sessionStorage.setItem('jzNumber', jzNumber)
}
}
}
</script>
<style lang="scss" scoped>
.searchContent {
//
.overViewHtml {
font-size: 14px;
line-height: normal;
white-space: pre-wrap;
}
.exam {
display: flex;
flex-wrap: wrap;
padding-bottom: 10px;
p {
display: flex;
flex-wrap: nowrap;
height: 32px;
line-height: 32px;
width: 18%;
background-color: #eee;
padding: 0 10px;
margin: 6px;
span {
display: block;
// flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-align: center;
}
$width_num: 60px;
.exam-name {
width: calc(100% - #{$width_num});
}
.exam-num {
width: $width_num;
color: #0072f9;
}
}
}
}
::v-deep .el-table__expanded-cell {
padding: 5px 10px;
background-color: #f5f7fa;
}
.dialog {
::v-deep .el-dialog__header {
padding: 10px 20px;
background: #696969;
.el-dialog__title {
color: #fff;
}
.el-dialog__headerbtn {
top: 10px;
font-size: 20px;
.el-dialog__close {
color: #fff;
font-weight: bolder;
}
}
}
::v-deep .el-dialog__body {
min-height: calc(100% - 60px);
background: #f5f5f5;
}
}
</style>

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

@ -1,276 +0,0 @@
<template>
<div class="project-main">
<div v-if="!detailViewVisible" style="height: 100%">
<el-card shadow="never" class="aui-card--fill">
<el-form
:inline="true"
:model="dataForm"
class="search-wrapper"
@submit.native.prevent
@keyup.enter.native="getDataListInitial"
>
<div class="search-wrapper-top">
<el-form-item class="search-item-input-wrapper">
<el-input v-model="keyWord" size="small" :placeholder="'全文检索(主要内容)关键词'" clearable>
<el-button slot="append" icon="el-icon-search" size="small" @click="getDataListInitial">搜索</el-button>
</el-input>
</el-form-item>
<!-- 筛选条件 -->
<el-form-item>
<el-button type="primary" size="small" @click="queryItemVisible=!queryItemVisible">筛选
<i v-if="!queryItemVisible" class="el-icon-arrow-right el-icon--right" />
<i v-else class="el-icon-arrow-down el-icon--right" />
</el-button>
</el-form-item>
<!-- slot -->
<el-form-item>
<slot name="btn" />
</el-form-item>
</div>
<transition name="slide-fade">
<div v-show="queryItemVisible" class="find-">
<!-- 查询条件 -->
<el-form-item label="必须" style="width:100%;">
<item-select v-model="queryItemData_must" :connection="'must'" />
</el-form-item>
<el-form-item label="可以" style="width:100%;">
<item-select v-model="queryItemData_should" :connection="'should'" />
</el-form-item>
<el-form-item label="排除" style="width:100%;">
<item-select v-model="queryItemData_must_not" :connection="'must_not'" />
</el-form-item>
</div>
</transition>
</el-form>
<!-- 查询结果 -->
<div class="result-wrapper">
<data-list
ref="dataList"
:data-list-loading="dataListLoading"
:data-list="dataList"
:project-id="projectId"
v-bind="$attrs"
@viewDetail="viewDetail"
v-on="$listeners"
/>
<!-- 分页 -->
<el-pagination
background
:current-page="page"
:page-sizes="[10, 20, 50, 100, 200, 500]"
:page-size="limit"
:total="total"
layout="total, prev, pager, next, jumper"
@size-change="pageSizeChangeHandle"
@current-change="pageCurrentChangeHandle"
/>
</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>-->
</div>
<detail-view v-if="detailViewVisible" ref="viewRef" :only-read="onlyRead" :is-search="'1'" :patient-id="patientId" @detailViewVisible="detailViewVisible=false" />
</div>
</template>
<script>
import detailView from '@/components/360View/index' // 360
import checked from '@/mixins/checked'
import checkedFooter from '@/components/checked-footer'
import dataList from './data-list.vue'
import itemSelect from '@/components/item-select'
import Cookies from 'js-cookie'
export default {
components: {
itemSelect,
detailView,
dataList,
checkedFooter
},
mixins: [checked],
inheritAttrs: false,
props: {
queryItem: { type: Object, default: () => { } }, //
projectId: { type: String, default: '' }
},
data() {
return {
uploadUrl: window.SITE_CONFIG['apiURL'] + '/patient/data/searchByExcel',
headers: {
token: window.sessionStorage.getItem('xa-token')
},
dataForm: {},
keyWord: '',
patientId: '',
limit: 10,
page: 1,
total: 0,
onlyRead: true,
dataListLoading: false, // loading
queryItemVisible: false,
isExpandAll: false,
detailViewVisible: false,
queryItemData_must: [],
queryItemData_should: [],
queryItemData_must_not: [],
dataList: [],
currentTableList: []
}
},
watch: {
queryItem: {
deep: true,
handler(val) {
if (val.must.length > 0 || val.should.length > 0 || val.must_not.length > 0) {
this.queryItemVisible = true
this.queryItemData_must = val.must
this.queryItemData_should = val.should
this.queryItemData_must_not = val.must_not
// this.getDataList()
}
}
}
},
created() { },
mounted() {
this.retrieval()
},
methods: {
reFresh() {
this.pageCurrentChangeHandle(this.page)
},
//
getDataListInitial() {
this.page = 1
this.retrieval()
},
viewDetail(val) {
this.patientId = val
this.detailViewVisible = true
},
//
retrieval() {
this.getDataList()
const queryItem = {
must: this.queryItemData_must,
should: this.queryItemData_should,
must_not: this.queryItemData_must_not
}
this.$emit('update:queryItem', queryItem)
// this.$emit('getQueryItem', queryItem)
},
getDataList() {
this.dataListLoading = true
this.$http.post('/search/page', {
filterItemList: [...this.queryItemData_must, ...this.queryItemData_should, ...this.queryItemData_must_not],
key: this.keyWord,
limit: this.limit,
page: this.page
}).then(({ data: res }) => {
this.dataListLoading = false
this.total = res.data.total
this.dataList = res.data.list
if (this.isExpandAll) {
this.$refs.dataList.expend()
}
}).catch(() => {
this.dataListLoading = false
})
},
// ,
pageSizeChangeHandle(val) {
this.page = 1
this.limit = val
this.retrieval()
},
// ,
pageCurrentChangeHandle(val) {
this.page = val
this.retrieval()
},
clearSelect() {
this.$refs.dataList.clearSelect()
},
beforeUpload() {
this.dataListLoading = true
},
//
onSuccess(response, file, fileList) {
this.$message.success('检索完成!')
this.dataListLoading = false
if (response && response.data) {
this.dataList = response.data
this.total = response.data.length
} else {
this.dataList = []
this.total = 0
}
},
onError() {
this.dataListLoading = false
}
}
}
</script>
<style lang='scss' scoped>
.aui-card--fill{
height: 100%;
::v-deep .el-card__body{
height: 100%;
overflow-y: auto;
}
}
.search-wrapper-top {
display: flex;
align-items: center;
.search-item-input-wrapper {
width: 400px;
padding-right: 10px;
flex: 1;
}
}
.result-wrapper {
margin-top: 15px;
}
.slide-fade-enter-active {
transition: all 0.3s ease;
}
.slide-fade-leave-active {
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter,
.slide-fade-leave-to {
transform: translateY(5px);
opacity: 0;
}
</style>
<style lang="scss">
.project-main {
height: 100%;
.search-wrapper-top {
.el-form-item__content {
width: 100%;
line-height: 0;
}
.el-form-item {
margin-bottom: 5px;
.el-switch .is-active {
color: inherit;
}
}
}
}
</style>

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

@ -1,149 +0,0 @@
<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

@ -1,150 +0,0 @@
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

@ -1,75 +0,0 @@
<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

@ -1,73 +0,0 @@
<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

@ -1,83 +0,0 @@
<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

@ -1,118 +0,0 @@
<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

@ -1,57 +0,0 @@
<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

@ -1,38 +0,0 @@
<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

@ -1,113 +0,0 @@
<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

@ -1,99 +0,0 @@
<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

@ -1,87 +0,0 @@
<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

@ -1,55 +0,0 @@
<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

@ -1,40 +0,0 @@
<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

@ -1,629 +0,0 @@
<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

@ -1,134 +0,0 @@
<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>

52
src/components/region-tree/index.vue

@ -1,52 +0,0 @@
<template>
<el-cascader
:value="value"
style="width:100%;"
:options="dataList"
:props="cascaderProps"
:placeholder="placeholder"
clearable
@change="$emit('input', $event)"
/>
</template>
<script>
import { treeDataTranslateChildren } from '@/utils'
export default {
props: {
id: {
type: String,
default: ''
},
value: {
type: Array,
default: () => []
},
placeholder: {
type: String,
default: '请选择地区'
}
},
data() {
return {
dataList: [],
cascaderProps: { multiple: false, value: 'id', label: 'name' }
}
},
mounted() {
this.getDataList()
},
methods: {
getDataList(id) {
return this.$http.get('/sys/region/tree').then(({ data: res }) => {
if (res.code === 0) {
this.dataList = treeDataTranslateChildren(res.data)
// this.dataList = treeDataTranslate(res.data, 'id', 'pid')
} else {
this.$message.error(res.msg)
}
}).catch(() => {})
}
}
}
</script>

195
src/components/time-line/index.vue

@ -1,195 +0,0 @@
<template>
<div class="time-line">
<div v-for="year in years" :key="year">
<!-- 年份 -->
<div class="time-line-year">
<div class="time-line-item-tail" />
<div class="time-line-item-date">{{ year }} </div>
</div>
<div v-for="(item, index) in filterYearDataList(year)" :key="index" class="time-line-item">
<!-- 节点 -->
<div class="time-line-item-node">
<i class="node" />
<!-- <div class="node" :class="{ nodeActive: item.active }" /> -->
</div>
<!-- 节点尾 -->
<div class="time-line-item-tail" />
<!-- 内容 -->
<div class="time-line-item-wrapper">
<!-- 抬头 -->
<div class="time-line-item-wrapper-title" @click="selectMenu(dataList, index)">
<span class="title-date">{{ item.date|convertDate }} </span>
<span class="title-name">{{ item.name }}</span>
</div>
<!-- 内容 -->
<div v-for="(item2, index2) in item.list" :key="index2" class="time-line-item-wrapper-item">
<span>{{ item2.name }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { formatDate } from '@/utils/index.js'
export default {
name: 'TimeLine',
props: {
dataList: {
type: Array,
required: true
}
},
data() {
return {
}
},
computed: {
years() {
const result = []
this.dataList.forEach(item => {
const year = formatDate(item.date, 'YYYY')
if (result.indexOf(year) < 0) {
result.push(year)
}
})
return result
}
},
methods: {
selectMenu(arr, index) {
arr[index].active = !arr[index].active
},
filterYearDataList(val) {
return this.dataList.filter(item => {
return item.date.indexOf(val) >= 0
})
}
}
}
</script>
<style lang="scss" scoped>
$color: #fff;
$containerBgColor: #333335;
$borderColor: #424242;
$paddingRight: 20px;
.time-line {
margin: 0;
padding: 5px $paddingRight;
font-size: 14px;
color: $color;
background-color: $containerBgColor;
list-style: none;
.time-line-year {
position: relative;
height: 50px;
//
.time-line-item-date {
position: relative;
top: 13px;
padding-left: 10px;
margin-left: -10px;
margin-right: -$paddingRight;
height: 24px;
line-height: 24px;
font-size: 16px;
font-style: oblique;
font-family: fantasy;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
background-color: #424242;
letter-spacing: 1px;
}
}
.time-line-item {
position: relative;
padding-bottom: 10px;
//
.time-line-item-node {
z-index: 3;
display: inline-block;
position: absolute;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
width: 16px;
height: 15px;
background-color: #fff;
border: 1px solid #3e9fff;
border-color: $borderColor;
.node {
width: 6px;
height: 6px;
border-radius: 50%;
background-color: #959595;
}
}
// wrapper
.time-line-item-wrapper {
position: relative;
padding-left: 28px;
top: -3px;
//
.time-line-item-wrapper-title {
color: $color;
.title-date {
display: inline-block;
padding-right: 10px;
color: #ecb36d;
}
.title-name {
display: inline-block;
background-color: #fff;
color: #000;
cursor: pointer;
padding: 0 10px;
border-radius: 5px;
}
}
//
.time-line-item-wrapper-item {
margin-top: 5px;
padding: 2px 0px;
// background-color: #fff;
color: #fff;
border-radius: 3px;
}
}
.transitionCon {
position: relative;
}
}
}
// 线
.time-line-item-tail {
position: absolute;
left: 7px;
top: 4px;
height: 100%;
border-left: 3px solid;
border-color: $color;
}
.nodeActive {
background-color: #3e9fff !important;
}
// .time-line .time-line-item:last-child .time-line-item-tail {
// display: none;
// }
</style>

54
src/components/user-select/index.vue

@ -1,54 +0,0 @@
<template>
<el-select
:value="value"
:placeholder="placeholder"
:multiple="multiple"
clearable
filterable
style="width:100%;"
@change="$emit('input', $event)"
>
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.jobNumber?`${item.realName}(${item.jobNumber})`:item.realName"
:value="item.id"
/>
</el-select>
</template>
<script>
export default {
props: {
deptId: { type: String, default: '' },
value: { type: String, default: '' },
multiple: { type: Boolean, default: false },
placeholder: { type: String, default: '请选择' }
},
data() {
return {
dataList: []
}
},
// watch: {
// deptId(newVal, oldval) {
// if (newVal) {
// this.getDataList()
// } else {
// this.dataList = []
// }
// }
// },
mounted() {
this.getDataList()
this.getDataList()
},
methods: {
//
getDataList(id) {
return this.$http.get('/project/getPresonListForAddProject').then(({ data: res }) => {
if (res.code === 0) { this.dataList = res.data } else { this.$message.error(res.msg) }
}).catch(() => {})
}
}
}
</script>

217
src/core/initAligningGuidelines.js

@ -1,217 +0,0 @@
/**
* Should objects be aligned by a bounding box?
* [Bug] Scaled objects sometimes can not be aligned by edges
* https://github.com/fabricjs/fabric.js/blob/master/lib/aligning_guidelines.js
*/
function initAligningGuidelines(canvas) {
var ctx = canvas.getSelectionContext(),
aligningLineOffset = 5,
aligningLineMargin = 4,
aligningLineWidth = 1,
aligningLineColor = 'rgb(0,255,0)',
viewportTransform,
zoom = 1;
function drawVerticalLine(coords) {
drawLine(
coords.x + 0.5,
coords.y1 > coords.y2 ? coords.y2 : coords.y1,
coords.x + 0.5,
coords.y2 > coords.y1 ? coords.y2 : coords.y1);
}
function drawHorizontalLine(coords) {
drawLine(
coords.x1 > coords.x2 ? coords.x2 : coords.x1,
coords.y + 0.5,
coords.x2 > coords.x1 ? coords.x2 : coords.x1,
coords.y + 0.5);
}
function drawLine(x1, y1, x2, y2) {
ctx.save();
ctx.lineWidth = aligningLineWidth;
ctx.strokeStyle = aligningLineColor;
ctx.beginPath();
ctx.moveTo(((x1 + viewportTransform[4]) * zoom), ((y1 + viewportTransform[5]) * zoom));
ctx.lineTo(((x2 + viewportTransform[4]) * zoom), ((y2 + viewportTransform[5]) * zoom));
ctx.stroke();
ctx.restore();
}
function isInRange(value1, value2) {
value1 = Math.round(value1);
value2 = Math.round(value2);
for (var i = value1 - aligningLineMargin, len = value1 + aligningLineMargin; i <= len; i++) {
if (i === value2) {
return true;
}
}
return false;
}
var verticalLines = [],
horizontalLines = [];
canvas.on('mouse:down', function () {
viewportTransform = canvas.viewportTransform;
zoom = canvas.getZoom();
});
canvas.on('object:moving', function (e) {
var activeObject = e.target,
canvasObjects = canvas.getObjects(),
activeObjectCenter = activeObject.getCenterPoint(),
activeObjectLeft = activeObjectCenter.x,
activeObjectTop = activeObjectCenter.y,
activeObjectBoundingRect = activeObject.getBoundingRect(),
activeObjectHeight = activeObjectBoundingRect.height / viewportTransform[3],
activeObjectWidth = activeObjectBoundingRect.width / viewportTransform[0],
horizontalInTheRange = false,
verticalInTheRange = false,
transform = canvas._currentTransform;
if (!transform) return;
// It should be trivial to DRY this up by encapsulating (repeating) creation of x1, x2, y1, and y2 into functions,
// but we're not doing it here for perf. reasons -- as this a function that's invoked on every mouse move
for (var i = canvasObjects.length; i--;) {
if (canvasObjects[i] === activeObject) continue;
var objectCenter = canvasObjects[i].getCenterPoint(),
objectLeft = objectCenter.x,
objectTop = objectCenter.y,
objectBoundingRect = canvasObjects[i].getBoundingRect(),
objectHeight = objectBoundingRect.height / viewportTransform[3],
objectWidth = objectBoundingRect.width / viewportTransform[0];
// snap by the horizontal center line
if (isInRange(objectLeft, activeObjectLeft)) {
verticalInTheRange = true;
verticalLines.push({
x: objectLeft,
y1: (objectTop < activeObjectTop)
? (objectTop - objectHeight / 2 - aligningLineOffset)
: (objectTop + objectHeight / 2 + aligningLineOffset),
y2: (activeObjectTop > objectTop)
? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
: (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(objectLeft, activeObjectTop), 'center', 'center');
}
// snap by the left edge
if (isInRange(objectLeft - objectWidth / 2, activeObjectLeft - activeObjectWidth / 2)) {
verticalInTheRange = true;
verticalLines.push({
x: objectLeft - objectWidth / 2,
y1: (objectTop < activeObjectTop)
? (objectTop - objectHeight / 2 - aligningLineOffset)
: (objectTop + objectHeight / 2 + aligningLineOffset),
y2: (activeObjectTop > objectTop)
? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
: (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(objectLeft - objectWidth / 2 + activeObjectWidth / 2, activeObjectTop), 'center', 'center');
}
// snap by the right edge
if (isInRange(objectLeft + objectWidth / 2, activeObjectLeft + activeObjectWidth / 2)) {
verticalInTheRange = true;
verticalLines.push({
x: objectLeft + objectWidth / 2,
y1: (objectTop < activeObjectTop)
? (objectTop - objectHeight / 2 - aligningLineOffset)
: (objectTop + objectHeight / 2 + aligningLineOffset),
y2: (activeObjectTop > objectTop)
? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
: (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(objectLeft + objectWidth / 2 - activeObjectWidth / 2, activeObjectTop), 'center', 'center');
}
// snap by the vertical center line
if (isInRange(objectTop, activeObjectTop)) {
horizontalInTheRange = true;
horizontalLines.push({
y: objectTop,
x1: (objectLeft < activeObjectLeft)
? (objectLeft - objectWidth / 2 - aligningLineOffset)
: (objectLeft + objectWidth / 2 + aligningLineOffset),
x2: (activeObjectLeft > objectLeft)
? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
: (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop), 'center', 'center');
}
// snap by the top edge
if (isInRange(objectTop - objectHeight / 2, activeObjectTop - activeObjectHeight / 2)) {
horizontalInTheRange = true;
horizontalLines.push({
y: objectTop - objectHeight / 2,
x1: (objectLeft < activeObjectLeft)
? (objectLeft - objectWidth / 2 - aligningLineOffset)
: (objectLeft + objectWidth / 2 + aligningLineOffset),
x2: (activeObjectLeft > objectLeft)
? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
: (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop - objectHeight / 2 + activeObjectHeight / 2), 'center', 'center');
}
// snap by the bottom edge
if (isInRange(objectTop + objectHeight / 2, activeObjectTop + activeObjectHeight / 2)) {
horizontalInTheRange = true;
horizontalLines.push({
y: objectTop + objectHeight / 2,
x1: (objectLeft < activeObjectLeft)
? (objectLeft - objectWidth / 2 - aligningLineOffset)
: (objectLeft + objectWidth / 2 + aligningLineOffset),
x2: (activeObjectLeft > objectLeft)
? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
: (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
});
activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop + objectHeight / 2 - activeObjectHeight / 2), 'center', 'center');
}
}
if (!horizontalInTheRange) {
horizontalLines.length = 0;
}
if (!verticalInTheRange) {
verticalLines.length = 0;
}
});
canvas.on('before:render', function () {
// fix 保存图片时报错
try {
canvas.clearContext(canvas.contextTop);
} catch (error) {
}
});
canvas.on('after:render', function () {
for (var i = verticalLines.length; i--;) {
drawVerticalLine(verticalLines[i]);
}
for (var i = horizontalLines.length; i--;) {
drawHorizontalLine(horizontalLines[i]);
}
verticalLines.length = horizontalLines.length = 0;
});
canvas.on('mouse:up', function () {
verticalLines.length = horizontalLines.length = 0;
canvas.renderAll();
});
}
export default initAligningGuidelines;

60
src/core/initControls.js

@ -1,60 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2023-01-09 22:49:02
* @LastEditors: 秦少卫
* @LastEditTime: 2023-01-09 23:08:54
* @Description: 控制条样式
*/
import { fabric } from 'fabric';
function initControls(canvas) {
var deleteIcon = "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";
var img = document.createElement('img');
img.src = deleteIcon;
fabric.Object.prototype.controls.deleteControl = new fabric.Control({
x: 0.5,
y: -0.5,
offsetY: -16,
offsetX: 16,
cursorStyle: 'pointer',
mouseUpHandler: deleteObject,
render: renderIcon,
cornerSize: 24
});
function deleteObject() {
const activeObject = canvas.getActiveObjects()
if (activeObject) {
activeObject.map(item => canvas.remove(item))
canvas.requestRenderAll()
canvas.discardActiveObject()
}
}
function renderIcon(ctx, left, top, styleOverride, fabricObject) {
var size = this.cornerSize;
ctx.save();
ctx.translate(left, top);
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
ctx.drawImage(img, -size / 2, -size / 2, size, size);
ctx.restore();
}
setControlsStyle()
}
function setControlsStyle(){
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.cornerSize = 10;
fabric.Object.prototype.cornerStrokeColor = '#C2C2C2';
fabric.Object.prototype.cornerColor = '#ffffff';
fabric.Object.prototype.cornerStyle = 'circle';
fabric.Object.prototype.borderColor = '#85CCF9';
}
export default initControls

86
src/core/initHotKeys.js

@ -1,86 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2022-12-07 23:50:05
* @LastEditors: 秦少卫
* @LastEditTime: 2023-01-07 02:06:16
* @Description: 快捷键功能
*/
import hotkeys from 'hotkeys-js'
import { cloneDeep } from 'lodash-es'
import { v4 as uuid } from 'uuid'
const keyNames = {
lrdu: 'left,right,down,up', // 左右上下
backspace: 'backspace', // backspace键盘
ctrlz: 'ctrl+z',
ctrlc: 'ctrl+c',
ctrlv: 'ctrl+v'
}
function initHotkeys(canvas) {
// 删除快捷键
hotkeys(keyNames.backspace, function() {
const activeObject = canvas.getActiveObjects()
if (activeObject) {
activeObject.map(item => canvas.remove(item))
canvas.requestRenderAll()
canvas.discardActiveObject()
}
})
// 移动快捷键
hotkeys(keyNames.lrdu, (event, handler) => {
const activeObject = canvas.getActiveObject()
if (activeObject) {
switch (handler.key) {
case 'left':
activeObject.set('left', activeObject.left - 1)
break
case 'right':
activeObject.set('left', activeObject.left + 1)
break
case 'down':
activeObject.set('top', activeObject.top + 1)
break
case 'up':
activeObject.set('top', activeObject.top - 1)
break
default:
}
canvas.renderAll()
}
})
// 复制粘贴
copyElement(canvas)
}
function copyElement(canvas) {
let copyEl = null
// 复制
hotkeys(keyNames.ctrlc, (event, handler) => {
const activeObject = canvas.getActiveObjects()
if (activeObject.length === 0) return
copyEl = cloneDeep(activeObject[0])
if (copyEl.left === activeObject[0].left) {
copyEl.left += 10
copyEl.top += 10
}
this.$message.success('复制成功')
})
// 粘贴
hotkeys(keyNames.ctrlv, (event, handler) => {
if (!copyEl) return this.$message.warning('暂无复制内容')
const myCopyEl = cloneDeep(copyEl)
myCopyEl.id = uuid()
copyEl.left += 10
copyEl.top += 10
canvas.add(myCopyEl)
canvas.setActiveObject(myCopyEl)
})
}
export default initHotkeys
export { keyNames, hotkeys }

89
src/core/initializeLineDrawing.js

@ -1,89 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2023-01-06 23:40:09
* @LastEditors: 秦少卫
* @LastEditTime: 2023-01-07 01:35:50
* @Description: 线条绘制
*/
import { v4 as uuid } from 'uuid';
import Arrow from "@/core/objects/Arrow";
function initializeLineDrawing (canvas, defaultPosition) {
let isDrawingLine = false,isDrawingLineMode = false, isArrow = false,
lineToDraw, pointer, pointerPoints
canvas.on('mouse:down', (o) => {
if (!isDrawingLineMode) return
isDrawingLine = true
pointer = canvas.getPointer(o.e)
pointerPoints = [pointer.x, pointer.y, pointer.x, pointer.y]
const nodeHandler = isArrow ? Arrow : fabric.Line
lineToDraw = new nodeHandler(pointerPoints, {
strokeWidth: 2,
stroke: '#000000',
...defaultPosition,
id: uuid(),
});
lineToDraw.selectable = false
lineToDraw.evented = false
lineToDraw.strokeUniform = true
canvas.add(lineToDraw)
});
canvas.on('mouse:move', (o) => {
if (!isDrawingLine) return
pointer = canvas.getPointer(o.e)
if (o.e.shiftKey) {
// calc angle
let startX = pointerPoints[0]
let startY = pointerPoints[1]
let x2 = pointer.x - startX
let y2 = pointer.y - startY
let r = Math.sqrt(x2 * x2 + y2 * y2)
let angle = (Math.atan2(y2, x2) / Math.PI * 180)
angle = parseInt(((angle + 7.5) % 360) / 15) * 15
let cosx = r * Math.cos(angle * Math.PI / 180)
let sinx = r * Math.sin(angle * Math.PI / 180)
lineToDraw.set({
x2: cosx + startX,
y2: sinx + startY
})
} else {
lineToDraw.set({
x2: pointer.x,
y2: pointer.y
})
}
canvas.renderAll()
});
canvas.on('mouse:up', () => {
if (!isDrawingLine) return
lineToDraw.setCoords()
isDrawingLine = false
});
return {
setArrow(params){
isArrow = params
},
setMode(params){
isDrawingLineMode = params
}
}
}
export default initializeLineDrawing;

46
src/core/objects/Arrow.js

@ -1,46 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2023-01-07 01:15:50
* @LastEditors: 秦少卫
* @LastEditTime: 2023-01-07 01:16:07
* @Description: 箭头元素
*/
import { fabric } from 'fabric';
const Arrow = fabric.util.createClass(fabric.Line, {
type: 'arrow',
superType: 'drawing',
initialize(points, options) {
if (!points) {
const { x1, x2, y1, y2 } = options;
points = [x1, y1, x2, y2];
}
options = options || {};
this.callSuper('initialize', points, options);
},
_render(ctx) {
this.callSuper('_render', ctx);
ctx.save();
const xDiff = this.x2 - this.x1;
const yDiff = this.y2 - this.y1;
const angle = Math.atan2(yDiff, xDiff);
ctx.translate((this.x2 - this.x1) / 2, (this.y2 - this.y1) / 2);
ctx.rotate(angle);
ctx.beginPath();
// Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
ctx.moveTo(5, 0);
ctx.lineTo(-5, 5);
ctx.lineTo(-5, -5);
ctx.closePath();
ctx.fillStyle = this.stroke;
ctx.fill();
ctx.restore();
},
});
Arrow.fromObject = (options, callback) => {
const { x1, x2, y1, y2 } = options;
return callback(new Arrow([x1, y1, x2, y2], options));
};
export default Arrow;

92
src/filters/index.js

@ -1,46 +1,46 @@
import { formatDate, formatTime, getAge, desensitizeField } from '@/utils/index.js'
// --------------------------------------------------【杂项】--------------------------------------------------
// 性别
export const f_sex = (val) => {
return val ? val.replace('性', '') : ''
}
// --------------------------------------------------【日期】--------------------------------------------------
// 月份日期过滤器
export const convertDate = (val) => {
return formatDate(val, 'MM-DD')
}
// 年过滤器
export const convertYear = (val) => {
return formatDate(val, 'MM-DD')
}
// 年月日过滤器(xxxx年x月xx日)
export const dateFilterOne = (val) => {
return formatDate(val, 'yyyy年MM月dd日')
}
// 年月日过滤器(yyyy-MM-dd)
export const dateFilterTwo = (val) => {
return formatDate(val, 'yyyy-MM-dd')
}
// 年月日过滤器(yyyyMMdd)
export const dateFilterThree = (val) => {
return formatDate(val, 'yyyyMMdd')
}
// 根据出生日期获取年龄
export const f_getAge = (val) => {
return val ? getAge(val) : ''
}
// --------------------------------------------------【脱敏】--------------------------------------------------
// 身份证号
export const f_desensitize_idNumber = (val) => {
return desensitizeField(val, 6, 4, '********')
}
// 联系电话
export const f_desensitize_phone = (val) => {
return desensitizeField(val, 4, 4, '****')
}
// 姓名
export const f_desensitize_name = (val) => {
return desensitizeField(val, 1, (val && val.length) > 2 ? 1 : 0)
}
import { formatDate, formatTime, getAge, desensitizeField } from '@/utils/index.js'
// --------------------------------------------------【杂项】--------------------------------------------------
// 性别
export const f_sex = (val) => {
return val ? val.replace('性', '') : ''
}
// --------------------------------------------------【日期】--------------------------------------------------
// 月份日期过滤器
export const convertDate = (val) => {
return formatDate(val, 'MM-DD')
}
// 年过滤器
export const convertYear = (val) => {
return formatDate(val, 'MM-DD')
}
// 年月日过滤器(xxxx年x月xx日)
export const dateFilterOne = (val) => {
return formatDate(val, 'yyyy年MM月dd日')
}
// 年月日过滤器(yyyy-MM-dd)
export const dateFilterTwo = (val) => {
return formatDate(val, 'yyyy-MM-dd')
}
// 年月日过滤器(yyyyMMdd)
export const dateFilterThree = (val) => {
return formatDate(val, 'yyyyMMdd')
}
// 根据出生日期获取年龄
export const f_getAge = (val) => {
return val ? getAge(val) : ''
}
// --------------------------------------------------【脱敏】--------------------------------------------------
// 身份证号
export const f_desensitize_idNumber = (val) => {
return desensitizeField(val, 6, 4, '********')
}
// 联系电话
export const f_desensitize_phone = (val) => {
return desensitizeField(val, 4, 4, '****')
}
// 姓名
export const f_desensitize_name = (val) => {
return desensitizeField(val, 1, (val && val.length) > 2 ? 1 : 0)
}

107
src/mixins/IntelligentFill.js

@ -1,107 +0,0 @@
export default {
data() {
return {
CRFLoading: false,
timer: null,
flag: 1,
multipleSelectFullSetTime: null
}
},
methods: {
// 智能填充
getFirstFeedbackData(title, id) {
console.log(this.timer)
this.timer ? clearInterval(this.timer) : ''
console.log('------------------')
this.CRFLoading = true
// 获取已保存的手术列表--调取hmcrf.multipleSelectFull()方法回显
this.$http.get(`/from/data/getFirstFeedbackData/${this.dataForm.formName}/${this.dataForm.patientIdNumber}/${id}`).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
const fillData = res.data
this.crfDataVisible = true
// 需要等待时间原因:load_content.vue文件iframe需要插入js、css等文件需要时间
// CRFLoading加载慢原因: quguang/from/data/getFirstFeedbackData接口速度慢
this.timer = setInterval(() => {
if (title === '智能填充') {
console.log(123, title)
this.isClick = true
this.oldCRFListItem = {}
if (this.$refs.crfComponent && this.$refs.crfComponent.$el.contentWindow.dataFill) {
this.$refs.crfComponent.$el.contentWindow.dataFill(fillData)
clearInterval(this.timer)
this.CRFLoading = false
} else {
clearInterval(this.timer)
}
} else if (title === '病历模板') {
console.log(456, title)
this.oldCRFListItem = {}
const ifr = document.getElementsByClassName('tox-edit-area__iframe')[0]
console.log(ifr.contentWindow)
console.log(ifr.contentWindow.dataFill)
if (ifr.contentWindow.dataFill) {
ifr.contentWindow.dataFill(fillData)
clearInterval(this.timer)
this.CRFLoading = false
}
}
}, 500)
}
}).catch(() => { })
},
// 获取已保存的手术列表--调取hmcrf.multipleSelectFull()方法回显
async getsaveOperaList(formId) {
// clearInterval(this.multipleSelectFullSetTime)
const { data: res } = await this.$http.get('/opera/patient/getExecuteOperaList', {
params: {
crfFormId: formId
}
})
if (res.code !== 0) {
return this.$message.error(res.msg)
} else {
const operaList = {
OD: [],
OS: [],
OU: []
}
// console.log(res.data)
res.data.forEach(item => {
if (item.eyeType === 'OD') {
operaList.OD = item.operaEntityList.map(item => item.operationName)
} else if (item.eyeType === 'OS') {
operaList.OS = item.operaEntityList.map(item => item.operationName)
} else if (item.eyeType === 'OU') {
operaList.OU = item.operaEntityList.map(item => item.operationName)
}
})
setTimeout(() => {
console.log('multipleSelectFull')
if (this.$refs.crfComponent && this.$refs.crfComponent.$el.contentWindow.multipleSelectFull) {
console.log(this.$refs.crfComponent)
// const ceshi = {
// OD: ['快速角膜胶原交联术[KXL]'],
// OS: ['激光老视矫正术(Presby MAX)']
// }
console.log(operaList)
this.$refs.crfComponent.$el.contentWindow.multipleSelectFull(operaList)
}
}, 2000)
// this.$nextTick(() => {
// if (this.$refs.crfComponent && this.$refs.crfComponent.$el.contentWindow.multipleSelectFull) {
// console.log(this.$refs.crfComponent)
// // const ceshi = {
// // OD: ['快速角膜胶原交联术[KXL]'],
// // OS: ['激光老视矫正术(Presby MAX)']
// // }
// console.log(operaList)
// this.$refs.crfComponent.$el.contentWindow.multipleSelectFull(operaList)
// }
// })
}
}
}
}

88
src/mixins/IntelligentFill.防止重复调取.js

@ -1,88 +0,0 @@
export default {
data() {
return {
CRFLoading: false,
timer: null,
flag: 1,
multipleSelectFullSetTime: null
}
},
methods: {
// 智能填充
getFirstFeedbackData(title, id) {
console.log(this.dataForm)
console.log(this.flag)
if (this.flag === 1) {
console.log('------------------')
this.flag++ // 解决多次调用定时器清除不掉的问题
this.CRFLoading = true
// 获取已保存的手术列表--调取hmcrf.multipleSelectFull()方法回显
console.log(99999999999999)
this.$http.get(`/from/data/getFirstFeedbackData/${this.dataForm.formName}/${this.dataForm.patientIdNumber}/${id}`).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
const fillData = res.data
this.crfDataVisible = true
this.timer = setInterval(() => {
if (title === '智能填充') {
console.log(123, title)
this.isClick = true
this.oldCRFListItem = {}
if (this.$refs.crfComponent && this.$refs.crfComponent.$el.contentWindow.dataFill) {
this.$refs.crfComponent.$el.contentWindow.dataFill(fillData)
clearInterval(this.timer)
this.flag = 1
this.CRFLoading = false
} else {
clearInterval(this.timer)
this.flag = 1
}
} else if (title === '病历模板') {
console.log(456, title)
this.oldCRFListItem = {}
const ifr = document.getElementsByClassName('tox-edit-area__iframe')[0]
console.log(ifr.contentWindow)
console.log(ifr.contentWindow.dataFill)
if (ifr.contentWindow.dataFill) {
ifr.contentWindow.dataFill(fillData)
clearInterval(this.timer)
this.flag = 1
this.CRFLoading = false
}
}
}, 500)
}
}).catch(() => { })
} else {
clearInterval(this.timer)
this.oldCRFListItem = {}
this.flag = 1
this.CRFLoading = false
console.log('flag', this.flag)
}
},
// 获取已保存的手术列表--调取hmcrf.multipleSelectFull()方法回显
async getsaveOperaList(formId) {
this.multipleSelectFullSetTime ? clearInterval(this.multipleSelectFullSetTime) : ''
const { data: res } = await this.$http.get('/opera/patient/getExecuteOperaList', {
params: {
crfFormId: formId
}
})
if (res.code !== 0) {
return this.$message.error(res.msg)
} else {
this.multipleSelectFullSetTime = setInterval(() => {
console.log('multipleSelectFull')
if (this.$refs.crfComponent && this.$refs.crfComponent.$el.contentWindow.multipleSelectFull) {
console.log(this.$refs.crfComponent)
clearInterval(this.multipleSelectFullSetTime)
this.$refs.crfComponent.$el.contentWindow.multipleSelectFull(res.data)
}
}, 500)
}
}
}
}

37
src/mixins/checked.js

@ -1,37 +0,0 @@
export default {
data() {
return {}
},
methods: {
// table-checkbox选择项发生变化时会触发该事件
handleSelectionChange(val) {
if (val.length === this.dataList.length) {
this.$refs.checkfooter.cheackAllFooter = true
} else {
this.$refs.checkfooter.cheackAllFooter = false
}
this.currentTableList = val
console.log(this.currentTableList)
},
// 全选
cheackAllChange(tableRef) {
if (this.cheackAllFooter) {
this.$parent.$refs[tableRef].toggleAllSelection()
} else {
this.$parent.$refs[tableRef].clearSelection()
}
},
// 反选
cheackReverseClick(tableRef) {
this.dataList.forEach((row) => {
this.$parent.$refs[tableRef].toggleRowSelection(row)
})
},
// 取消
cancelClick(tableRef) {
this.cheackAllFooter = false
this.cheackReverseFooter = false
this.$parent.$refs[tableRef].clearSelection()
}
}
}

16
src/mixins/full-screen.js

@ -1,16 +0,0 @@
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()
}
}
}

35
src/mixins/printModel.js

@ -1,35 +0,0 @@
export default {
data() {
return {
printHidden: true,
printIndex: 0,
printType: '',
print: {
id: '',
closeCallback: () => {
console.log('关闭')
this.$nextTick(() => {
this.printHidden = true
})
},
clickMounted: () => {
console.log('触发点击打印回调')
},
openCallback: () => {
console.log('执行打印')
this.printIndex += 1
}
}
}
},
watch: {
printIndex(val) {
if (val) {
this.printType = 'warning'
}
}
},
created() {
this.print.id = this.printId
}
}

35
src/mixins/qgyCRFData.js

@ -1,35 +0,0 @@
export default {
data() {
return {
}
},
methods: {
// 青光眼的数据获取不在crf/getFlowForm下的firstVisit中,需要单独调取此接口获取
getQgyCRFData() {
this.$http.get('/view/out/patient/getVisitOutPatientForHis', {
params: {
patientIdNumber: this.patientIdNumber,
patientId: this.patientId ? this.patientId : '',
visitDate: this.realVisitTime ? this.realVisitTime : '',
realVisitType: this.realVisitType ? this.realVisitType : ''
}
})
.then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
setTimeout(() => {
if (this.$refs.crfComponent) {
const ifr = this.$refs.crfComponent.$el
const ifrWin = ifr.contentWindow
console.log(ifr.contentWindow)
ifrWin.dataFill(res.data)
}
}, 800)
}
}).catch(() => { })
}
}
}

80
src/mixins/select.js

@ -1,80 +0,0 @@
export default {
inject: ['canvas', 'fabric', 'event'],
data() {
return {
mSelectMode: '', // one | multiple
mSelectOneType: '', // i-text | group ...
mSelectId: '', // 选择id
mSelectIds: [] // 选择id
}
},
created() {
this.event.on('selectOne', (e) => {
console.log('selectOne', e)
this.mSelectMode = 'one'
this.mSelectId = e[0].id
this.mSelectOneType = e[0].type
// console.log(e[0].id)
// console.log(e[0].type)
this.mSelectIds = e.map(item => item.id)
})
this.event.on('selectMultiple', (e) => {
console.log('selectMultiple')
this.mSelectMode = 'multiple'
this.mSelectId = ''
this.mSelectIds = e.map(item => item.id)
})
this.event.on('selectCancel', () => {
console.log('selectCancel')
this.mSelectId = ''
this.mSelectIds = []
this.mSelectMode = ''
this.mSelectOneType = ''
})
},
methods: {
/**
* @description: 保存data数据
* @param {Object} data 房间详情数据
*/
_mixinSelected({ event, selected }) {
if (selected.length === 1) {
const selectItem = selected[0]
this.mSelectMode = 'one'
this.mSelectOneType = selectItem.type
this.mSelectId = [selectItem.id]
this.mSelectActive = [selectItem]
} else if (selected.length > 1) {
this.mSelectMode = 'multiple'
this.mSelectActive = selected
this.mSelectId = selected.map(item => item.id)
} else {
this._mixinCancel()
}
},
/**
* @description: 保存data数据
* @param {Object} data 房间详情数据
*/
_mixinCancel(data) {
this.mSelectMode = ''
this.mSelectId = []
this.mSelectActive = []
this.mSelectOneType = ''
},
/**
* @description: 复制到剪切板
* @param {String} clipboardText 复制内容
*/
_mixinClipboard(clipboardText) {
this.$copyText(clipboardText).then(() => {
this.$Message.success('复制成功')
}, () => {
this.$Message.error('复制失败')
})
}
}
}

128
src/mixins/sign-NSV.js

@ -1,128 +0,0 @@
export default {
data() {
return {
plugin: null,
type: 1, // 1 验光师 2 配戴者 3 监护人
optomFlag: true,
wearerFlag: true,
guardianFlag: true,
readFlag: true,
doctorSign: '',
patientSign: '123',
guardianSign: '',
readerSign: ''
}
},
methods: {
initPlugin() {
if (this.plugin) {
this.plugin.DestroyPlugin()
}
this.plugin = new PluginNSV()
const that = this
console.log(this.plugin)
this.plugin.InitPlugin(function(state) {
if (state === 1) {
// set pen size
that.plugin.setPenSizeRange(1, 5, null)
// set pen color
that.plugin.setPenColor(0, 0, 0, null)
that.plugin.setDisplayMapMode(1, 0, 0, null)
console.log('succeeded')
} else {
console.log('fails')
}
})
/* confirm event*/
this.plugin.onConfirm = function() {
if (that.type === 1) {
that.optomFlag = false
} else if (that.type === 2) {
console.log(111111111111111111111111)
that.wearerFlag = false
} else if (that.type === 3) {
that.guardianFlag = false
} else if (that.type === 4) {
that.readFlag = false
}
that.saveSignToBase64()
that.endSign()
}
// /*clear event*/
this.plugin.onClear = function() {
this.clearSign()
}
/* cancel event*/
this.plugin.onCancel = function() {
this.endSign()
}
this.plugin.onStateChange = function(state) {}
this.plugin.onDevNotifyEvent = function(state) {
if (state === 1) {
console.log('connected')
} else {
console.log('disconnected')
}
}
},
beginSign(type) {
this.type = type
if (this.plugin) {
this.plugin.beginSign(function(state, args) {
})
}
// document.getElementById('img_sign_result').src = '';
},
clearSign() {
if (this.plugin) {
this.plugin.clearSign(function(state, args) {})
}
// Reset the image.
if (this.type === 1) {
this.doctorSign = ''
} else if (this.type === 2) {
this.patientSign = ''
} else if (this.type === 3) {
this.guardianSign = ''
} else if (this.type === 4) {
this.readerSign = ''
}
},
endSign() {
if (this.plugin) {
/* plugin.endSign(null);*/
this.plugin.endSign(function(state, args) {})
}
},
saveSignToBase64() {
console.log('base64')
if (this.plugin) {
// Get the plugin's signature image data.
this.plugin.saveSignToBase64(/* 615, 272*/0, 0, (state, args) => {
if (state) {
const img_base64_data = args[0]
console.log(img_base64_data)
const img_base64 = 'data:image/png;base64,' + img_base64_data
if (this.type === 1) {
this.doctorSign = img_base64
} else if (this.type === 2) {
this.patientSign = 'data:image/png;base64,' + img_base64_data
console.log(this.patientSign)
} else if (this.type === 3) {
this.guardianSign = img_base64
} else if (this.type === 4) {
this.readerSign = img_base64
}
} else {
// debugPrint("saveSignToBase64 error,description:" + args[0]);
}
})
}
}
}
}

121
src/mixins/styeFormSign.js

@ -1,121 +0,0 @@
import { Notification } from 'element-ui'
import emptySign from '@static/js/emptySign'
export default {
data() {
return {
plugin: null,
optomFlag: true,
wearerFlag: true,
guardianFlag: true,
readFlag: true,
currentSignText: ''
}
},
methods: {
// 销毁签字笔
destroyPlugin(state) {
console.log(this.plugin)
if (this.plugin) {
console.log('--------3333-------')
this.plugin.DestroyPlugin()
}
},
initPlugin(text) {
// console.log(JSON.parse(window.sessionStorage.getItem('signPlugin')))
// if (this.plugin) {
// this.plugin.DestroyPlugin()
// }
this.plugin = new PluginNSV()
// window.sessionStorage.setItem('signPlugin', JSON.stringify(this.plugin))
const that = this
console.log('plugin', this.plugin)
this.plugin.InitPlugin(function(state) {
if (state === 1) {
// set pen size
that.plugin.setPenSizeRange(1, 5, null)
// set pen color
that.plugin.setPenColor(0, 0, 0, null)
that.plugin.setDisplayMapMode(1, 0, 0, null)
console.log('succeeded')
that.beginSign(text)
} else {
console.log('fails')
}
})
/* confirm event*/
this.plugin.onConfirm = function() {
that.saveSignToBase64()
that.endSign()
}
// /*clear event*/
this.plugin.onClear = function() {
this.clearSign()
}
/* cancel event*/
this.plugin.onCancel = function() {
this.endSign()
}
this.plugin.onStateChange = function(state) {}
this.plugin.onDevNotifyEvent = function(state) {
if (state === 1) {
Notification.success({
title: '成功',
message: '签字笔已插入',
showClose: false,
duration: 800
})
} else {
Notification.error({
title: '提示',
message: '签字笔已拔出',
showClose: false,
duration: 800
})
}
}
},
beginSign(text) {
const that = this
that.currentSignText = text
console.log(that.plugin)
if (this.plugin) {
console.log(123)
this.plugin.beginSign(function(state, args) {
})
}
// document.getElementById('img_sign_result').src = '';
},
clearSign() {
if (this.plugin) {
this.plugin.clearSign(function(state, args) {})
}
},
endSign() {
if (this.plugin) {
/* plugin.endSign(null);*/
this.plugin.endSign(function(state, args) {})
}
},
saveSignToBase64() {
if (this.plugin) {
// Get the plugin's signature image data.
this.plugin.saveSignToBase64(/* 615, 272*/0, 0, (state, args) => {
if (state) {
const img_base64_data = args[0]
const img_base64 = 'data:image/png;base64,' + img_base64_data
this.formListValue[this.currentSignText] = img_base64
if (this.formListValue[this.currentSignText] === emptySign) {
this.$message.error('签字未成功请重新签字')
}
this.destroyPlugin()
} else {
// debugPrint("saveSignToBase64 error,description:" + args[0]);
}
})
}
}
}
}

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

@ -69,11 +69,6 @@ export const moduleRoutes = {
name: 'iframe',
meta: { title: 'iframe', isTab: true }
},
{
path: '/redirect',
name: 'redirect',
component: () => import('@/page-subspecialty/views/redirect')
},
{
path: '/360view',
name: '360view',

100
src/page-subspecialty/views/main-navbar-update-password.vue

@ -1,100 +0,0 @@
<template>
<el-dialog
:visible.sync="visible"
:title="$t('updatePassword.title')"
:close-on-click-modal="false"
:close-on-press-escape="false"
:append-to-body="true"
>
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="auto" @keyup.enter.native="dataFormSubmitHandle()">
<el-form-item :label="$t('updatePassword.username')">
<span>{{ $store.state.user.name }}</span>
</el-form-item>
<el-form-item prop="password" :label="$t('updatePassword.password')">
<el-input v-model="dataForm.password" type="password" :placeholder="$t('updatePassword.password')" />
</el-form-item>
<el-form-item prop="newPassword" :label="$t('updatePassword.newPassword')">
<el-input v-model="dataForm.newPassword" type="password" :placeholder="$t('updatePassword.newPassword')" />
</el-form-item>
<el-form-item prop="confirmPassword" :label="$t('updatePassword.confirmPassword')">
<el-input v-model="dataForm.confirmPassword" type="password" :placeholder="$t('updatePassword.confirmPassword')" />
</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 { clearLoginInfo } from '@/page-subspecialty/utils/request.js'
import { resetRouter } from '@/page-subspecialty/router/index.js'
export default {
data() {
return {
visible: false,
dataForm: {
password: '',
newPassword: '',
confirmPassword: ''
}
}
},
computed: {
dataRule() {
var validateConfirmPassword = (rule, value, callback) => {
if (this.dataForm.newPassword !== value) {
return callback(new Error(this.$t('updatePassword.validate.confirmPassword')))
}
callback()
}
return {
password: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
newPassword: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
{ validator: validateConfirmPassword, trigger: 'blur' }
]
}
}
},
methods: {
init() {
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
})
},
//
dataFormSubmitHandle: debounce(function() {
this.$refs['dataForm'].validate((valid) => {
if (!valid) {
return false
}
this.$http.put('/sys/user/password', this.dataForm).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
clearLoginInfo()
resetRouter()
this.$router.replace({ name: 'login' })
}
})
}).catch(() => {})
})
}, 1000, { 'leading': true, 'trailing': false })
}
}
</script>

132
src/page-subspecialty/views/main-navbar.vue

@ -1,132 +0,0 @@
<template>
<nav class="aui-navbar" :class="`aui-navbar--${$store.state.navbarLayoutType}`">
<div class="aui-navbar__header" style="height:100px;">
<!-- logo -->
<h1 class="aui-navbar__brand" @click="logoClick">
<a class="aui-navbar__brand-lg" href="javascript:;" style="text-align:center;">
<svg-icon icon-class="icon-yzk-login" style="font-size:36px" />
<div style="margin-top:5px;">眼科工作平台</div>
</a>
<a class="aui-navbar__brand-mini" href="javascript:;"> <svg-icon icon-class="icon-yzk-login" style="font-size:36px" /></a>
</h1>
</div>
<div class="aui-navbar__body">
<el-menu class="aui-navbar__menu mr-auto" mode="horizontal">
<!-- 收缩 -->
<el-menu-item index="1" @click="$store.state.sidebarFold = !$store.state.sidebarFold">
<svg class="icon-svg aui-navbar__icon-menu aui-navbar__icon-menu--switch" aria-hidden="true"><use xlink:href="#icon-outdent" /></svg>
</el-menu-item>
<!-- 刷新 -->
<el-menu-item index="2" style="padding:0 6px;" @click="refresh()">
<svg class="icon-svg aui-navbar__icon-menu aui-navbar__icon-menu--refresh" aria-hidden="true"><use xlink:href="#icon-sync" /></svg>
</el-menu-item>
<el-menu-item index="3" style="padding:0 6px;">
<bread-crumb />
</el-menu-item>
</el-menu>
<el-menu class="aui-navbar__menu" mode="horizontal">
<!-- 全屏 -->
<el-menu-item index="4" @click="fullscreenHandle()">
<svg-icon icon-class="fullscreen" />
</el-menu-item>
<!-- 头像按钮组 -->
<el-menu-item index="5" class="aui-navbar__avatar">
<el-dropdown placement="bottom" :show-timeout="0">
<span class="el-dropdown-link">
<img src="~@/assets/img/avatar.png">
<span>{{ $store.state.user.name }}</span>
<i class="el-icon-arrow-down" />
</span>
<el-dropdown-menu slot="dropdown">
<!-- 修改密码 -->
<el-dropdown-item @click.native="updatePasswordHandle()">修改密码</el-dropdown-item>
<!-- 退出 -->
<el-dropdown-item style="color:#FF4D4F" @click.native="logoutHandle()">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-menu-item>
</el-menu>
</div>
<!-- 弹窗, 修改密码 -->
<update-password v-if="updatePasswordVisible" ref="updatePassword" />
</nav>
</template>
<script>
import { messages } from '@/i18n'
import screenfull from 'screenfull'
import UpdatePassword from './main-navbar-update-password.vue'
import { clearLoginInfo } from '@/page-subspecialty/utils/request.js'
import breadCrumb from '@/components/bread-crumb'
import { resetRouter } from '@/page-subspecialty/router/index.js'
export default {
inject: ['refresh'],
components: {
UpdatePassword,
breadCrumb
},
data() {
return {
i18nMessages: messages,
updatePasswordVisible: false,
messageTip: false,
logo: require('@/assets/img/logo.png')
}
},
created() {
},
methods: {
logoClick() {
this.$store.commit('activeIndexFun', window.SITE_CONFIG.menuList[0].children[0].id)
this.$router.push({ name: 'outpatientManagement-call' })
},
//
fullscreenHandle() {
if (!screenfull.enabled) {
return this.$message({
message: this.$t('fullscreen.prompt'),
type: 'warning',
duration: 500
})
}
screenfull.toggle()
},
//
updatePasswordHandle() {
this.updatePasswordVisible = true
this.$nextTick(() => {
this.$refs.updatePassword.init()
})
},
// 退
logoutHandle() {
this.$confirm(this.$t('prompt.info', { handle: this.$t('logout') }), this.$t('prompt.title'), {
confirmButtonText: this.$t('confirm'),
cancelButtonText: this.$t('cancel'),
type: 'warning'
}).then(() => {
this.$http.post('/logout').then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
clearLoginInfo()
resetRouter()
this.$router.push({ name: 'login' })
this.$store.commit('activeIndexFun', window.SITE_CONFIG.menuList[0].children[0].id)
}).catch(() => {})
}).catch(() => {})
}
}
}
</script>
<style lang='scss' scoped>
.aui-navbar__header{
width: 160px;
}
.aui-navbar__brand{
font-size: 17px;
.sidebar-logo {
width: 36px;
height: 36px;
}
}
</style>

135
src/page-subspecialty/views/main-sidebar-sub-menu.vue

@ -1,135 +0,0 @@
<template>
<div class="left-menu">
<el-submenu v-if="menu.children && menu.children.length >= 1 && menu.children[0].isShow == 1" :index="menu.id" :popper-append-to-body="false">
<template slot="title">
<svg class="icon-svg aui-sidebar__menu-icon" aria-hidden="true"><use :xlink:href="`#${menu.icon}`" /></svg>
<span v-show="$store.state.sidebarFold===false">{{ menu.name }}</span>
</template>
<sub-menu v-for="item in menu.children" :key="item.id" :menu="item" />
</el-submenu>
<el-menu-item v-else ref="li" :index="menu.id" @click="openMenuHandle(menu.id)">
<!-- :href="isBrowserTabOpen(menu) ? iframeURL: 'javascript:;'"
:target="isBrowserTabOpen(menu) ? '_blank' : '_self'" -->
<a>
<svg class="icon-svg aui-sidebar__menu-icon" aria-hidden="true"><use :xlink:href="`#${menu.icon}`" /></svg>
<span v-show="$store.state.sidebarFold===false">{{ menu.name }}</span>
</a>
</el-menu-item>
</div>
</template>
<script>
import SubMenu from './main-sidebar-sub-menu.vue'
export default {
inject: ['refresh'],
name: 'SubMenu',
components: {
SubMenu
},
props: {
menu: {
type: Object,
required: true
}
},
data() {
return {
browserTabOpenList: [
// '1353981045241810946', // iframe
// '1344097112555024386'
],
iframeURL: '',
routerName: ''
}
},
watch: {
$route(val) {
// console.log(val)
this.routerName = val.name
}
},
created() {
this.routerName = this.$route.name
// this.$nextTick(() => {
// if (this.$refs.li) {
// const $li = this.$refs.li.$el
// const $a = $li.firstElementChild
// if ($a) {
// let pl = '0'; let pr = '0'
// if ($li.currentStyle) {
// pl = $li.currentStyle.paddingLeft
// pr = $li.currentStyle.paddingRight
// } else {
// pl = window.document.defaultView.getComputedStyle($li, null).paddingLeft
// pr = window.document.defaultView.getComputedStyle($li, null).paddingRight
// }
// $li.setAttribute('style', 'padding-left: 0; padding-right: 0;')
// $a.setAttribute('style', `padding-left: ${pl}; padding-right: ${pr};`)
// }
// }
// })
},
methods: {
// menuId
isMenuIdFun(menuId, dynamicMenuRoutes, callback) {
dynamicMenuRoutes.forEach((item) => {
if (item.meta.menuId === menuId) {
return callback && callback(item)
} else if (item.children.length > 0) {
this.isMenuIdFun(menuId, item.children, callback)
}
})
},
// Tab
isBrowserTabOpen(menu) {
return this.browserTabOpenList.filter(item => item === menu.id).length >= 1
// return false
},
// TabURL
getBrowserTabOpenURL(menuId) {
this.isMenuIdFun(menuId, window.SITE_CONFIG.dynamicMenuRoutes, (item) => {
this.iframeURL = item.meta.iframeURL
})
},
// id
openMenuHandle(menuId) {
this.$store.commit('activeIndexFun', menuId)
this.isMenuIdFun(menuId, window.SITE_CONFIG.dynamicMenuRoutes, (item) => {
// console.log(item)
setTimeout(() => {
if (this.routerName === item.name) {
this.refresh()
} else {
// console.log(item.name)
this.$router.push({
name: item.name
})
}
}, 200)
})
}
}
}
</script>
<style lang="scss">
.aui-sidebar__menu {
.el-menu-item > a {
display: block;
color: inherit;
text-decoration: none;
}
}
.left-menu {
.el-menu-item ,.el-submenu__title{
padding-left: 4px !important;
}
.el-menu--inline {
padding-left: 10px;
}
.el-submenu__icon-arrow {
top: 60%;
}
}
</style>

149
src/page-subspecialty/views/main-sidebar.vue

@ -1,149 +0,0 @@
<template>
<aside :class="['aui-sidebar', `aui-sidebar--${$store.state.sidebarLayoutSkin}`]">
<div class="aui-sidebar__inner">
<el-menu
:collapse="$store.state.sidebarFold"
:unique-opened="true"
:collapse-transition="false"
class="aui-sidebar__menu"
active-text-color="#fff"
:default-active="defauleActiveIndex"
>
<sub-menu v-for="menu in $store.state.sidebarMenuList" :key="menu.id" :menu="menu" />
</el-menu>
</div>
<!-- <el-tooltip class="item" effect="dark" content="可点击下载操作手册" placement="top">-->
<!-- <div v-if="!$store.state.sidebarFold" class="sidebar-operation-manual" style="width:30px" @click="exportclick(wordData)">-->
<!-- <i class="el-icon-question" />-->
<!-- </div>-->
<!-- <div v-else class="sidebar-operation-manual" style="width:40px" @click="exportclick(wordData)">-->
<!-- <i class="el-icon-question" style="font-size:18px;" />-->
<!-- </div>-->
<!-- </el-tooltip>-->
</aside>
</template>
<script>
import SubMenu from './main-sidebar-sub-menu'
import docxtemplater from 'docxtemplater'
import PizZip from 'pizzip'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'
export default {
components: {
SubMenu
},
data() {
return {
fileHref: '',
wordData: {
user_name: 'XXX',
remark: ''
}
}
},
computed: {
defauleActiveIndex: {
get() {
return this.$store.getters.defauleActiveIndex
},
set(val) {
}
}
},
created() {
const defauleActiveIndex = window.sessionStorage.getItem('defauleActiveIndex')
? window.sessionStorage.getItem('defauleActiveIndex') : window.SITE_CONFIG.menuList[0].children[0].id
setTimeout(() => {
this.$store.state.sidebarMenuList = window.SITE_CONFIG.menuList
}, 200)
this.$store.commit('activeIndexFun', defauleActiveIndex)
},
mounted() {
},
methods: {
exportclick(e) {
this.$message('暂时没有操作手册可下载')
return
const docxsrc = '../../../static/word/operation-manual-YSG.docx' //
const docxname = '眼科电子病历操作手册'//
//
JSZipUtils.getBinaryContent(docxsrc, function(error, content) {
// docxsrc
if (error) {
throw error
}
// PizZip
const zip = new PizZip(content)
// docx templater
const doc = new docxtemplater().loadZip(zip)
//
doc.setData({
...e// e使
})
try {
//
doc.render()
} catch (error) {
//
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
}
console.log(JSON.stringify({
error: e
}))
throw error
}
// docxtemplaterzip
const out = doc.getZip().generate({
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
})
//
saveAs(out, docxname)
})
}
}
}
</script>
<style lang="scss" scoped>
.sidebar-operation-manual {
font-size: 14px;
color: #fff;
height: 30px;
line-height: 30px;
text-align: center;
background-color: #3c4658;
border-radius: 4px;
position: absolute;
right: 10px;
bottom: 6px;
cursor: pointer;
z-index: 1;
.title {
display: inline-block;
padding-left: 10px;
}
}
</style>
<style lang="scss">
.aui-sidebar{
width: 160px !important;
}
.aui-sidebar__menu{
width: 160px;
}
.aui-sidebar__inner {
.el-menu-item:hover {
background: #545c64 !important;
}
}
</style>

19
src/page-subspecialty/views/modules/TEMP.vue

@ -1,19 +0,0 @@
<template>
<div>
123
</div>
</template>
<script>
export default {
data() {
return {
}
},
created() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

18
src/page-subspecialty/views/redirect.vue

@ -1,18 +0,0 @@
<template>
<div />
</template>
<script>
export default {
name: 'Reload',
props: {},
beforeCreate() {
console.log(this.$route.params)
this.$router.push({
name: this.$route.params.name
})
},
created() {
console.log(this.$route.params)
}
}
</script>

122
src/utils/LodopFuncs.js

@ -1,122 +0,0 @@
var CreatedOKLodop7766 = null; var CLodopIsLocal
// ====判断是否需要 Web打印服务CLodop:===
// ===(不支持插件的浏览器版本需要用它)===
export function needCLodop() {
try {
var ua = navigator.userAgent
if (ua.match(/Windows\sPhone/i)) { return true }
if (ua.match(/iPhone|iPod|iPad/i)) { return true }
if (ua.match(/Android/i)) { return true }
if (ua.match(/Edge\D?\d+/i)) { return true }
var verTrident = ua.match(/Trident\D?\d+/i)
var verIE = ua.match(/MSIE\D?\d+/i)
var verOPR = ua.match(/OPR\D?\d+/i)
var verFF = ua.match(/Firefox\D?\d+/i)
var x64 = ua.match(/x64/i)
if ((!verTrident) && (!verIE) && (x64)) { return true } else if (verFF) {
verFF = verFF[0].match(/\d+/)
if ((verFF[0] >= 41) || (x64)) { return true }
} else if (verOPR) {
verOPR = verOPR[0].match(/\d+/)
if (verOPR[0] >= 32) { return true }
} else if ((!verTrident) && (!verIE)) {
var verChrome = ua.match(/Chrome\D?\d+/i)
if (verChrome) {
verChrome = verChrome[0].match(/\d+/)
if (verChrome[0] >= 41) { return true }
}
}
return false
} catch (err) {
return true
}
}
// ====页面引用CLodop云打印必须的JS文件,用双端口(8000和18000)避免其中某个被占用:====
if (needCLodop()) {
var src1 = 'http://localhost:8000/CLodopfuncs.js?priority=1'
var src2 = 'http://localhost:18000/CLodopfuncs.js?priority=0'
var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement
var oscript = document.createElement('script')
oscript.src = src1
head.insertBefore(oscript, head.firstChild)
oscript = document.createElement('script')
oscript.src = src2
head.insertBefore(oscript, head.firstChild)
CLodopIsLocal = !!((src1 + src2).match(/\/\/localho|\/\/127.0.0./i))
}
// ====获取LODOP对象的主过程:====
export function getLodop(oOBJECT, oEMBED) {
var strHtmInstall = "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='install_lodop32.exe' target='_self'>执行安装</a>,安装后请刷新页面或重新进入。</font>"
var strHtmUpdate = "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='install_lodop32.exe' target='_self'>执行升级</a>,升级后请重新进入。</font>"
var strHtm64_Install = "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='install_lodop64.exe' target='_self'>执行安装</a>,安装后请刷新页面或重新进入。</font>"
var strHtm64_Update = "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='install_lodop64.exe' target='_self'>执行升级</a>,升级后请重新进入。</font>"
var strHtmFireFox = "<br><br><font color='#FF00FF'>(注意:如曾安装过Lodop旧版附件npActiveXPLugin,请在【工具】->【附加组件】->【扩展】中先卸它)</font>"
var strHtmChrome = "<br><br><font color='#FF00FF'>(如果此前正常,仅因浏览器升级或重安装而出问题,需重新执行以上安装)</font>"
var strCLodopInstall_1 = "<br><font color='#FF00FF'>Web打印服务CLodop未安装启动,点击这里<a href='CLodop_Setup_for_Win32NT.exe' target='_self'>下载执行安装</a>"
var strCLodopInstall_2 = "<br>(若此前已安装过,可<a href='CLodop.protocol:setup' target='_self'>点这里直接再次启动</a>)"
var strCLodopInstall_3 = ',成功后请刷新本页面。</font>'
var strCLodopUpdate = "<br><font color='#FF00FF'>Web打印服务CLodop需升级!点击这里<a href='CLodop_Setup_for_Win32NT.exe' target='_self'>执行升级</a>,升级后请刷新页面。</font>"
var LODOP
try {
var ua = navigator.userAgent
var isIE = !!(ua.match(/MSIE/i)) || !!(ua.match(/Trident/i))
if (needCLodop()) {
try {
LODOP = getCLodop()
} catch (err) { }
if (!LODOP && document.readyState !== 'complete') {
alert('网页还没下载完毕,请稍等一下再操作.')
return
}
if (!LODOP) {
// document.body.innerHTML = strCLodopInstall_1 + (CLodopIsLocal ? strCLodopInstall_2 : "") + strCLodopInstall_3 + document.body.innerHTML;
return
} else {
if (CLODOP.CVERSION < '3.0.8.3') {
document.body.innerHTML = strCLodopUpdate + document.body.innerHTML
}
if (oEMBED && oEMBED.parentNode) { oEMBED.parentNode.removeChild(oEMBED) }
if (oOBJECT && oOBJECT.parentNode) { oOBJECT.parentNode.removeChild(oOBJECT) }
}
} else {
var is64IE = isIE && !!(ua.match(/x64/i))
// =====如果页面有Lodop就直接使用,没有则新建:==========
if (oOBJECT || oEMBED) {
if (isIE) { LODOP = oOBJECT } else { LODOP = oEMBED }
} else if (!CreatedOKLodop7766) {
LODOP = document.createElement('object')
LODOP.setAttribute('width', 0)
LODOP.setAttribute('height', 0)
LODOP.setAttribute('style', 'position:absolute;left:0px;top:-100px;width:0px;height:0px;')
if (isIE) { LODOP.setAttribute('classid', 'clsid:2105C259-1E0C-4534-8141-A753534CB4CA') } else { LODOP.setAttribute('type', 'application/x-print-lodop') }
document.documentElement.appendChild(LODOP)
CreatedOKLodop7766 = LODOP
} else { LODOP = CreatedOKLodop7766 }
// =====Lodop插件未安装时提示下载地址:==========
if ((!LODOP) || (!LODOP.VERSION)) {
if (ua.indexOf('Chrome') >= 0) { document.body.innerHTML = strHtmChrome + document.body.innerHTML }
if (ua.indexOf('Firefox') >= 0) { document.body.innerHTML = strHtmFireFox + document.body.innerHTML }
document.body.innerHTML = (is64IE ? strHtm64_Install : strHtmInstall) + document.body.innerHTML
return LODOP
}
}
if (LODOP.VERSION < '6.2.2.6') {
if (!needCLodop()) { document.body.innerHTML = (is64IE ? strHtm64_Update : strHtmUpdate) + document.body.innerHTML }
}
// ===如下空白位置适合调用统一功能(如注册语句、语言选择等):==
// 添加注册码,打印就不会出现 “本页由lodop试用版输出 ”
LODOP.SET_LICENSES('', 'XXXXX', 'XXXX', '')
// =======================================================
return LODOP
} catch (err) {
alert('getLodop出错:' + err)
}
}

33
src/utils/eventHandler.js

@ -1,33 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2022-09-03 19:16:55
* @LastEditors: 秦少卫
* @LastEditTime: 2022-09-04 00:01:00
* @Description: 自定义事件
*/
import EventEmitter from 'events'
class EventHandle extends EventEmitter {
init(handler) {
this.handler = handler
this.handler.on('selection:created', (e) => this._selected(e))
this.handler.on('selection:updated', (e) => this._selected(e))
this.handler.on('selection:cleared', (e) => this._selected(e))
}
// 暴露单选多选事件
_selected(e) {
const actives = this.handler.getActiveObjects()
if (actives && actives.length === 1) {
this.emit('selectOne', actives)
} else if (actives && actives.length > 1) {
this.mSelectMode = 'multiple'
this.emit('selectMultiple', actives)
} else {
this.emit('selectCancel')
}
}
}
export default EventHandle

113
src/utils/tree.js

@ -1,113 +0,0 @@
/**
* 树形json中根据id查找并返回路径
* @param {Array} data
* @param {string} id
* @param {Array} indexArray
*/
export function findIndexArray(data, id, indexArray) {
const arr = Array.from(indexArray)
for (let i = 0, len = data.length; i < len; i++) {
arr.push(data[i].id)
if (data[i].id === id) {
return arr
}
const children = data[i].children
if (children && children.length) {
const result = findIndexArray(children, id, arr)
if (result.length > 0) return result
}
arr.pop()
}
return []
}
/**
* 树形json中根据字段值查找并返回路径
* @param {Array} data
* @param {string} fieldValue
* @param {string} fieldName
* @param {string} childrenName
* @param {Array} indexArray
* @returns 路径fieldName数组
*/
export function findPathArray(data, fieldValue, fieldName = 'id', childrenName = 'children', indexArray = []) {
const arr = Array.from(indexArray)
for (let i = 0, len = data.length; i < len; i++) {
arr.push(data[i][fieldName])
if (data[i][fieldName] === fieldValue) {
return arr
}
const children = data[i][childrenName]
if (children && children.length) {
const result = findPathArray(children, fieldValue, fieldName, childrenName, arr)
if (result.length > 0) return result
}
arr.pop()
}
return []
}
/**
* 树中查找指定对象
* @param {Array} data
* @param {String} fieldValue
* @param {String} childrenName
* @param {String} fieldName
* @returns 目标对象
*/
export function findItem(data, fieldValue, fieldName = 'id', childrenName = 'children') {
// console.log(data, fieldValue, fieldName)
for (let i = 0, len = data.length; i < len; i++) {
if (data[i][fieldName] && data[i][fieldName] === fieldValue) {
return data[i]
} else if (data[i][childrenName]) {
const temp = findItem(data[i][childrenName], fieldValue, fieldName, childrenName)
if (temp) {
return temp
}
}
}
}
/**
* 分组(2)
* @param {Array} array
* @param {String} groupKey
* @returns [数组]数组
*/
export function groupBy(array, groupKey = 'name', labelKey = 'label', idKey = 'id') {
const groups = {}
array.forEach(item => {
const groupValue = JSON.stringify(item[groupKey]) // 值转字段名
groups[groupValue] = groups[groupValue] || []
item.id = item[idKey] || ''
item.label = item[labelKey] || ''
groups[groupValue].push(item) // 分组
})
return Object.keys(groups).map(key => {
const item = { }
item.label = JSON.parse(key)
item.id = item[idKey] || item.label
item.children = groups[key]
return item
})
}
export function groupBy_getArray(array, groupKey = 'name') {
const groups = {}
array.forEach(item => {
const groupValue = JSON.stringify(item[groupKey]) // 值转字段名
groups[groupValue] = groups[groupValue] || []
groups[groupValue].push(item) // 分组
})
return Object.keys(groups).map(key => groups[key])
}
export function groupBy_getName(array, groupKey = 'name') {
const groups = {}
array.forEach(item => {
const groupValue = item[groupKey] // 值转字段名
groups[groupValue] = groups[groupValue] || []
})
return Object.keys(groups)
}

47
src/utils/utils.js

@ -1,47 +0,0 @@
/*
* @Author: 秦少卫
* @Date: 2022-09-05 22:21:55
* @LastEditors: 秦少卫
* @LastEditTime: 2022-09-05 23:00:29
* @Description: 工具文件
*/
import FontFaceObserver from 'fontfaceobserver'
/**
* @description: 图片文件转字符串
* @param {Blob|File} file 文件
* @return {String}
*/
export function getImgStr(file) {
return new Promise((resolve, reject) => {
try {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result)
};
} catch (error) {
reject(error)
}
});
}
/**
* @description: 根据json模板下载字体文件
* @param {String} str
* @return {Promise}
*/
export function downFontByJSON(str) {
const skipFonts = ['arial', 'Microsoft YaHei']
const fontFamilys = JSON.parse(str).objects.filter(item => {
// 为text 并且不为包含字体
return (item.type.includes('text') && !skipFonts.includes(item.fontFamily))
}).map(item => item.fontFamily)
const fontFamilysAll = fontFamilys.map(fontName => {
const font = new FontFaceObserver(fontName);
return font.load(null, 150000)
})
return Promise.all(fontFamilysAll)
}

16
static/css/hmcrf-add.css

@ -1,16 +0,0 @@
body {
/* 整个body不可点击 */
pointer-events: none;
}
/* textarea去除右下角拖拽键 */
textarea {
resize:none;
}
/* 签名按钮打印时不显示 */
.hmbutton {
display: none;
}
/* .hmselectmultiple {
border-radius: 6px;
} */

124
static/css/hmcrf.css

@ -1,124 +0,0 @@
html {
height: 100%;
}
body {
padding: 0px;
margin: 0px;
}
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar {
width: 6px;
/*滚动条宽度*/
height: 8px;
/*滚动条高度*/
background-color: rgb(224, 223, 223, .2);
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
-webkit-box-shadow: inset 0 0 0px white;
background-color: rgb(193, 193, 193);
/*滚动条的背景颜色*/
border-radius: 30px;
}
/* .MsoNormal {
display: inline-block;
} */
table {
border-collapse: collapse;
}
input,
textarea {
margin-right: 2px;
border-radius: 2px 2px 0 0;
outline: none;
background: transparent;
}
.border-1 {
border: none;
border-bottom: 1px solid #767676;
border-width: thin;
}
.border-2 {
border: revert;
border-width: thin;
}
.border-3 {
border: none;
}
textarea {
text-align: left !important;
max-width: 550px !important;
line-height: 18px;
overflow-y: hidden;
margin: 0 !important;
}
#work-unit {
max-width: 500px !important;
}
p {
margin: 0 0 12px 0;
}
p:last-child {
margin: 0;
}
.hmbutton {
/* padding: 5px 14px; */
border: none;
/* background: #409eff; */
/* color: #fff; */
color: #409eff;
cursor: pointer
}
@media print {
/* 避免表格断开 */
/* table{
page-break-after: avoid;
} */
/* 避免某行文字断裂 */
table {
/* page-break-inside: avoid; */
}
html {
zoom: 75%;
}
.mce-item-anchor {
display: none;
}
}
.el-input {
width: 100px !important;
}
.el-input__inner {
border: none !important;
text-align: right !important;
}
.el-radio {
margin-right: 8px !important;
}
.mce-item-table:not([border]), .mce-item-table:not([border]) caption, .mce-item-table:not([border]) td, .mce-item-table:not([border]) th, .mce-item-table[border="0"], .mce-item-table[border="0"] caption, .mce-item-table[border="0"] td, .mce-item-table[border="0"] th, table[style*="border-width: 0px"], table[style*="border-width: 0px"] caption, table[style*="border-width: 0px"] td, table[style*="border-width: 0px"] th {
border: none;
}
.hmselect {
border: none;
border-bottom: 1px solid #767676;
}

714
static/css/skins-tinymce/ui/oxide-dark/content.css

@ -1,714 +0,0 @@
/**
* 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/
*/
.mce-content-body .mce-item-anchor {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
cursor: default;
display: inline-block;
height: 12px !important;
padding: 0 2px;
-webkit-user-modify: read-only;
-moz-user-modify: read-only;
-webkit-user-select: all;
-moz-user-select: all;
-ms-user-select: all;
user-select: all;
width: 8px !important;
}
.mce-content-body .mce-item-anchor[data-mce-selected] {
outline-offset: 1px;
}
.tox-comments-visible .tox-comment {
background-color: #fff0b7;
}
.tox-comments-visible .tox-comment--active {
background-color: #ffe168;
}
.tox-checklist > li:not(.tox-checklist--hidden) {
list-style: none;
margin: 0.25em 0;
}
.tox-checklist > li:not(.tox-checklist--hidden)::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
cursor: pointer;
height: 1em;
margin-left: -1.5em;
margin-top: 0.125em;
position: absolute;
width: 1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
}
[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before {
margin-left: 0;
margin-right: -1.5em;
}
/* stylelint-disable */
/* http://prismjs.com/ */
/**
* Dracula Theme originally by Zeno Rocha [@zenorocha]
* https://draculatheme.com/
*
* Ported for PrismJS by Albert Vallverdu [@byverdu]
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
background: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #282a36;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #6272a4;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #ff79c6;
}
.token.boolean,
.token.number {
color: #bd93f9;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #50fa7b;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #f1fa8c;
}
.token.keyword {
color: #8be9fd;
}
.token.regex,
.token.important {
color: #ffb86c;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* stylelint-enable */
.mce-content-body {
overflow-wrap: break-word;
word-wrap: break-word;
}
.mce-content-body .mce-visual-caret {
background-color: black;
background-color: currentColor;
position: absolute;
}
.mce-content-body .mce-visual-caret-hidden {
display: none;
}
.mce-content-body *[data-mce-caret] {
left: -1000px;
margin: 0;
padding: 0;
position: absolute;
right: auto;
top: 0;
}
.mce-content-body .mce-offscreen-selection {
left: -2000000px;
max-width: 1000000px;
position: absolute;
}
.mce-content-body *[contentEditable=false] {
cursor: default;
}
.mce-content-body *[contentEditable=true] {
cursor: text;
}
.tox-cursor-format-painter {
cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default;
}
.mce-content-body figure.align-left {
float: left;
}
.mce-content-body figure.align-right {
float: right;
}
.mce-content-body figure.image.align-center {
display: table;
margin-left: auto;
margin-right: auto;
}
.mce-preview-object {
border: 1px solid gray;
display: inline-block;
line-height: 0;
margin: 0 2px 0 2px;
position: relative;
}
.mce-preview-object .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-preview-object[data-mce-selected="2"] .mce-shim {
display: none;
}
.mce-object {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
border: 1px dashed #aaa;
}
.mce-pagebreak {
border: 1px dashed #aaa;
cursor: default;
display: block;
height: 5px;
margin-top: 15px;
page-break-before: always;
width: 100%;
}
@media print {
.mce-pagebreak {
border: 0;
}
}
.tiny-pageembed .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tiny-pageembed[data-mce-selected="2"] .mce-shim {
display: none;
}
.tiny-pageembed {
display: inline-block;
position: relative;
}
.tiny-pageembed--21by9,
.tiny-pageembed--16by9,
.tiny-pageembed--4by3,
.tiny-pageembed--1by1 {
display: block;
overflow: hidden;
padding: 0;
position: relative;
width: 100%;
}
.tiny-pageembed--21by9 {
padding-top: 42.857143%;
}
.tiny-pageembed--16by9 {
padding-top: 56.25%;
}
.tiny-pageembed--4by3 {
padding-top: 75%;
}
.tiny-pageembed--1by1 {
padding-top: 100%;
}
.tiny-pageembed--21by9 iframe,
.tiny-pageembed--16by9 iframe,
.tiny-pageembed--4by3 iframe,
.tiny-pageembed--1by1 iframe {
border: 0;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-content-body[data-mce-placeholder] {
position: relative;
}
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
color: rgba(34, 47, 62, 0.7);
content: attr(data-mce-placeholder);
position: absolute;
}
.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
left: 1px;
}
.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before {
right: 1px;
}
.mce-content-body div.mce-resizehandle {
background-color: #4099ff;
border-color: #4099ff;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
height: 10px;
position: absolute;
width: 10px;
z-index: 10000;
}
.mce-content-body div.mce-resizehandle:hover {
background-color: #4099ff;
}
.mce-content-body div.mce-resizehandle:nth-of-type(1) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(2) {
cursor: nesw-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(3) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(4) {
cursor: nesw-resize;
}
.mce-content-body .mce-resize-backdrop {
z-index: 10000;
}
.mce-content-body .mce-clonedresizable {
cursor: default;
opacity: 0.5;
outline: 1px dashed black;
position: absolute;
z-index: 10001;
}
.mce-content-body .mce-clonedresizable.mce-resizetable-columns th,
.mce-content-body .mce-clonedresizable.mce-resizetable-columns td {
border: 0;
}
.mce-content-body .mce-resize-helper {
background: #555;
background: rgba(0, 0, 0, 0.75);
border: 1px;
border-radius: 3px;
color: white;
display: none;
font-family: sans-serif;
font-size: 12px;
line-height: 14px;
margin: 5px 10px;
padding: 5px;
position: absolute;
white-space: nowrap;
z-index: 10002;
}
.tox-rtc-user-selection {
position: relative;
}
.tox-rtc-user-cursor {
bottom: 0;
cursor: default;
position: absolute;
top: 0;
width: 2px;
}
.tox-rtc-user-cursor::before {
background-color: inherit;
border-radius: 50%;
content: '';
display: block;
height: 8px;
position: absolute;
right: -3px;
top: -3px;
width: 8px;
}
.tox-rtc-user-cursor:hover::after {
background-color: inherit;
border-radius: 100px;
box-sizing: border-box;
color: #fff;
content: attr(data-user);
display: block;
font-size: 12px;
font-weight: bold;
left: -5px;
min-height: 8px;
min-width: 8px;
padding: 0 12px;
position: absolute;
top: -11px;
white-space: nowrap;
z-index: 1000;
}
.tox-rtc-user-selection--1 .tox-rtc-user-cursor {
background-color: #2dc26b;
}
.tox-rtc-user-selection--2 .tox-rtc-user-cursor {
background-color: #e03e2d;
}
.tox-rtc-user-selection--3 .tox-rtc-user-cursor {
background-color: #f1c40f;
}
.tox-rtc-user-selection--4 .tox-rtc-user-cursor {
background-color: #3598db;
}
.tox-rtc-user-selection--5 .tox-rtc-user-cursor {
background-color: #b96ad9;
}
.tox-rtc-user-selection--6 .tox-rtc-user-cursor {
background-color: #e67e23;
}
.tox-rtc-user-selection--7 .tox-rtc-user-cursor {
background-color: #aaa69d;
}
.tox-rtc-user-selection--8 .tox-rtc-user-cursor {
background-color: #f368e0;
}
.tox-rtc-remote-image {
background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;
border: 1px solid #ccc;
min-height: 240px;
min-width: 320px;
}
.mce-match-marker {
background: #aaa;
color: #fff;
}
.mce-match-marker-selected {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::-moz-selection {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::selection {
background: #39f;
color: #fff;
}
.mce-content-body img[data-mce-selected],
.mce-content-body video[data-mce-selected],
.mce-content-body audio[data-mce-selected],
.mce-content-body object[data-mce-selected],
.mce-content-body embed[data-mce-selected],
.mce-content-body table[data-mce-selected] {
outline: 3px solid #4099ff;
}
.mce-content-body hr[data-mce-selected] {
outline: 3px solid #4099ff;
outline-offset: 1px;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus {
outline: 3px solid #4099ff;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover {
outline: 3px solid #4099ff;
}
.mce-content-body *[contentEditable=false][data-mce-selected] {
cursor: not-allowed;
outline: 3px solid #4099ff;
}
.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,
.mce-content-body.mce-content-readonly *[contentEditable=true]:hover {
outline: none;
}
.mce-content-body *[data-mce-selected="inline-boundary"] {
background-color: #4099ff;
}
.mce-content-body .mce-edit-focus {
outline: 3px solid #4099ff;
}
.mce-content-body td[data-mce-selected],
.mce-content-body th[data-mce-selected] {
position: relative;
}
.mce-content-body td[data-mce-selected]::-moz-selection,
.mce-content-body th[data-mce-selected]::-moz-selection {
background: none;
}
.mce-content-body td[data-mce-selected]::selection,
.mce-content-body th[data-mce-selected]::selection {
background: none;
}
.mce-content-body td[data-mce-selected] *,
.mce-content-body th[data-mce-selected] * {
outline: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
background-color: rgba(180, 215, 255, 0.7);
border: 1px solid transparent;
bottom: -1px;
content: '';
left: -1px;
mix-blend-mode: lighten;
position: absolute;
right: -1px;
top: -1px;
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
border-color: rgba(0, 84, 180, 0.7);
}
}
.mce-content-body img::-moz-selection {
background: none;
}
.mce-content-body img::selection {
background: none;
}
.ephox-snooker-resizer-bar {
background-color: #4099ff;
opacity: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ephox-snooker-resizer-cols {
cursor: col-resize;
}
.ephox-snooker-resizer-rows {
cursor: row-resize;
}
.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging {
opacity: 1;
}
.mce-spellchecker-word {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
height: 2rem;
}
.mce-spellchecker-grammar {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
}
.mce-toc {
border: 1px solid gray;
}
.mce-toc h2 {
margin: 4px;
}
.mce-toc li {
list-style-type: none;
}
table[style*="border-width: 0px"],
.mce-item-table:not([border]),
.mce-item-table[border="0"],
table[style*="border-width: 0px"] td,
.mce-item-table:not([border]) td,
.mce-item-table[border="0"] td,
table[style*="border-width: 0px"] th,
.mce-item-table:not([border]) th,
.mce-item-table[border="0"] th,
table[style*="border-width: 0px"] caption,
.mce-item-table:not([border]) caption,
.mce-item-table[border="0"] caption {
border: 1px dashed #bbb;
}
.mce-visualblocks p,
.mce-visualblocks h1,
.mce-visualblocks h2,
.mce-visualblocks h3,
.mce-visualblocks h4,
.mce-visualblocks h5,
.mce-visualblocks h6,
.mce-visualblocks div:not([data-mce-bogus]),
.mce-visualblocks section,
.mce-visualblocks article,
.mce-visualblocks blockquote,
.mce-visualblocks address,
.mce-visualblocks pre,
.mce-visualblocks figure,
.mce-visualblocks figcaption,
.mce-visualblocks hgroup,
.mce-visualblocks aside,
.mce-visualblocks ul,
.mce-visualblocks ol,
.mce-visualblocks dl {
background-repeat: no-repeat;
border: 1px dashed #bbb;
margin-left: 3px;
padding-top: 10px;
}
.mce-visualblocks p {
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
}
.mce-visualblocks h1 {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
}
.mce-visualblocks h2 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
}
.mce-visualblocks h3 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
}
.mce-visualblocks h4 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
}
.mce-visualblocks h5 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
}
.mce-visualblocks h6 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
}
.mce-visualblocks div:not([data-mce-bogus]) {
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
}
.mce-visualblocks section {
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
}
.mce-visualblocks article {
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
}
.mce-visualblocks blockquote {
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
}
.mce-visualblocks address {
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
}
.mce-visualblocks pre {
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
}
.mce-visualblocks figure {
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
}
.mce-visualblocks figcaption {
border: 1px dashed #bbb;
}
.mce-visualblocks hgroup {
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
}
.mce-visualblocks aside {
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
}
.mce-visualblocks ul {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
}
.mce-visualblocks ol {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
}
.mce-visualblocks dl {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
}
.mce-visualblocks:not([dir=rtl]) p,
.mce-visualblocks:not([dir=rtl]) h1,
.mce-visualblocks:not([dir=rtl]) h2,
.mce-visualblocks:not([dir=rtl]) h3,
.mce-visualblocks:not([dir=rtl]) h4,
.mce-visualblocks:not([dir=rtl]) h5,
.mce-visualblocks:not([dir=rtl]) h6,
.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),
.mce-visualblocks:not([dir=rtl]) section,
.mce-visualblocks:not([dir=rtl]) article,
.mce-visualblocks:not([dir=rtl]) blockquote,
.mce-visualblocks:not([dir=rtl]) address,
.mce-visualblocks:not([dir=rtl]) pre,
.mce-visualblocks:not([dir=rtl]) figure,
.mce-visualblocks:not([dir=rtl]) figcaption,
.mce-visualblocks:not([dir=rtl]) hgroup,
.mce-visualblocks:not([dir=rtl]) aside,
.mce-visualblocks:not([dir=rtl]) ul,
.mce-visualblocks:not([dir=rtl]) ol,
.mce-visualblocks:not([dir=rtl]) dl {
margin-left: 3px;
}
.mce-visualblocks[dir=rtl] p,
.mce-visualblocks[dir=rtl] h1,
.mce-visualblocks[dir=rtl] h2,
.mce-visualblocks[dir=rtl] h3,
.mce-visualblocks[dir=rtl] h4,
.mce-visualblocks[dir=rtl] h5,
.mce-visualblocks[dir=rtl] h6,
.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),
.mce-visualblocks[dir=rtl] section,
.mce-visualblocks[dir=rtl] article,
.mce-visualblocks[dir=rtl] blockquote,
.mce-visualblocks[dir=rtl] address,
.mce-visualblocks[dir=rtl] pre,
.mce-visualblocks[dir=rtl] figure,
.mce-visualblocks[dir=rtl] figcaption,
.mce-visualblocks[dir=rtl] hgroup,
.mce-visualblocks[dir=rtl] aside,
.mce-visualblocks[dir=rtl] ul,
.mce-visualblocks[dir=rtl] ol,
.mce-visualblocks[dir=rtl] dl {
background-position-x: right;
margin-right: 3px;
}
.mce-nbsp,
.mce-shy {
background: #aaa;
}
.mce-shy::after {
content: '-';
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}

726
static/css/skins-tinymce/ui/oxide-dark/content.inline.css

@ -1,726 +0,0 @@
/**
* 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/
*/
.mce-content-body .mce-item-anchor {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
cursor: default;
display: inline-block;
height: 12px !important;
padding: 0 2px;
-webkit-user-modify: read-only;
-moz-user-modify: read-only;
-webkit-user-select: all;
-moz-user-select: all;
-ms-user-select: all;
user-select: all;
width: 8px !important;
}
.mce-content-body .mce-item-anchor[data-mce-selected] {
outline-offset: 1px;
}
.tox-comments-visible .tox-comment {
background-color: #fff0b7;
}
.tox-comments-visible .tox-comment--active {
background-color: #ffe168;
}
.tox-checklist > li:not(.tox-checklist--hidden) {
list-style: none;
margin: 0.25em 0;
}
.tox-checklist > li:not(.tox-checklist--hidden)::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
cursor: pointer;
height: 1em;
margin-left: -1.5em;
margin-top: 0.125em;
position: absolute;
width: 1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
}
[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before {
margin-left: 0;
margin-right: -1.5em;
}
/* stylelint-disable */
/* http://prismjs.com/ */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* stylelint-enable */
.mce-content-body {
overflow-wrap: break-word;
word-wrap: break-word;
}
.mce-content-body .mce-visual-caret {
background-color: black;
background-color: currentColor;
position: absolute;
}
.mce-content-body .mce-visual-caret-hidden {
display: none;
}
.mce-content-body *[data-mce-caret] {
left: -1000px;
margin: 0;
padding: 0;
position: absolute;
right: auto;
top: 0;
}
.mce-content-body .mce-offscreen-selection {
left: -2000000px;
max-width: 1000000px;
position: absolute;
}
.mce-content-body *[contentEditable=false] {
cursor: default;
}
.mce-content-body *[contentEditable=true] {
cursor: text;
}
.tox-cursor-format-painter {
cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default;
}
.mce-content-body figure.align-left {
float: left;
}
.mce-content-body figure.align-right {
float: right;
}
.mce-content-body figure.image.align-center {
display: table;
margin-left: auto;
margin-right: auto;
}
.mce-preview-object {
border: 1px solid gray;
display: inline-block;
line-height: 0;
margin: 0 2px 0 2px;
position: relative;
}
.mce-preview-object .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-preview-object[data-mce-selected="2"] .mce-shim {
display: none;
}
.mce-object {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
border: 1px dashed #aaa;
}
.mce-pagebreak {
border: 1px dashed #aaa;
cursor: default;
display: block;
height: 5px;
margin-top: 15px;
page-break-before: always;
width: 100%;
}
@media print {
.mce-pagebreak {
border: 0;
}
}
.tiny-pageembed .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tiny-pageembed[data-mce-selected="2"] .mce-shim {
display: none;
}
.tiny-pageembed {
display: inline-block;
position: relative;
}
.tiny-pageembed--21by9,
.tiny-pageembed--16by9,
.tiny-pageembed--4by3,
.tiny-pageembed--1by1 {
display: block;
overflow: hidden;
padding: 0;
position: relative;
width: 100%;
}
.tiny-pageembed--21by9 {
padding-top: 42.857143%;
}
.tiny-pageembed--16by9 {
padding-top: 56.25%;
}
.tiny-pageembed--4by3 {
padding-top: 75%;
}
.tiny-pageembed--1by1 {
padding-top: 100%;
}
.tiny-pageembed--21by9 iframe,
.tiny-pageembed--16by9 iframe,
.tiny-pageembed--4by3 iframe,
.tiny-pageembed--1by1 iframe {
border: 0;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-content-body[data-mce-placeholder] {
position: relative;
}
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
color: rgba(34, 47, 62, 0.7);
content: attr(data-mce-placeholder);
position: absolute;
}
.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
left: 1px;
}
.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before {
right: 1px;
}
.mce-content-body div.mce-resizehandle {
background-color: #4099ff;
border-color: #4099ff;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
height: 10px;
position: absolute;
width: 10px;
z-index: 10000;
}
.mce-content-body div.mce-resizehandle:hover {
background-color: #4099ff;
}
.mce-content-body div.mce-resizehandle:nth-of-type(1) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(2) {
cursor: nesw-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(3) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(4) {
cursor: nesw-resize;
}
.mce-content-body .mce-resize-backdrop {
z-index: 10000;
}
.mce-content-body .mce-clonedresizable {
cursor: default;
opacity: 0.5;
outline: 1px dashed black;
position: absolute;
z-index: 10001;
}
.mce-content-body .mce-clonedresizable.mce-resizetable-columns th,
.mce-content-body .mce-clonedresizable.mce-resizetable-columns td {
border: 0;
}
.mce-content-body .mce-resize-helper {
background: #555;
background: rgba(0, 0, 0, 0.75);
border: 1px;
border-radius: 3px;
color: white;
display: none;
font-family: sans-serif;
font-size: 12px;
line-height: 14px;
margin: 5px 10px;
padding: 5px;
position: absolute;
white-space: nowrap;
z-index: 10002;
}
.tox-rtc-user-selection {
position: relative;
}
.tox-rtc-user-cursor {
bottom: 0;
cursor: default;
position: absolute;
top: 0;
width: 2px;
}
.tox-rtc-user-cursor::before {
background-color: inherit;
border-radius: 50%;
content: '';
display: block;
height: 8px;
position: absolute;
right: -3px;
top: -3px;
width: 8px;
}
.tox-rtc-user-cursor:hover::after {
background-color: inherit;
border-radius: 100px;
box-sizing: border-box;
color: #fff;
content: attr(data-user);
display: block;
font-size: 12px;
font-weight: bold;
left: -5px;
min-height: 8px;
min-width: 8px;
padding: 0 12px;
position: absolute;
top: -11px;
white-space: nowrap;
z-index: 1000;
}
.tox-rtc-user-selection--1 .tox-rtc-user-cursor {
background-color: #2dc26b;
}
.tox-rtc-user-selection--2 .tox-rtc-user-cursor {
background-color: #e03e2d;
}
.tox-rtc-user-selection--3 .tox-rtc-user-cursor {
background-color: #f1c40f;
}
.tox-rtc-user-selection--4 .tox-rtc-user-cursor {
background-color: #3598db;
}
.tox-rtc-user-selection--5 .tox-rtc-user-cursor {
background-color: #b96ad9;
}
.tox-rtc-user-selection--6 .tox-rtc-user-cursor {
background-color: #e67e23;
}
.tox-rtc-user-selection--7 .tox-rtc-user-cursor {
background-color: #aaa69d;
}
.tox-rtc-user-selection--8 .tox-rtc-user-cursor {
background-color: #f368e0;
}
.tox-rtc-remote-image {
background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;
border: 1px solid #ccc;
min-height: 240px;
min-width: 320px;
}
.mce-match-marker {
background: #aaa;
color: #fff;
}
.mce-match-marker-selected {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::-moz-selection {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::selection {
background: #39f;
color: #fff;
}
.mce-content-body img[data-mce-selected],
.mce-content-body video[data-mce-selected],
.mce-content-body audio[data-mce-selected],
.mce-content-body object[data-mce-selected],
.mce-content-body embed[data-mce-selected],
.mce-content-body table[data-mce-selected] {
outline: 3px solid #b4d7ff;
}
.mce-content-body hr[data-mce-selected] {
outline: 3px solid #b4d7ff;
outline-offset: 1px;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false][data-mce-selected] {
cursor: not-allowed;
outline: 3px solid #b4d7ff;
}
.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,
.mce-content-body.mce-content-readonly *[contentEditable=true]:hover {
outline: none;
}
.mce-content-body *[data-mce-selected="inline-boundary"] {
background-color: #b4d7ff;
}
.mce-content-body .mce-edit-focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body td[data-mce-selected],
.mce-content-body th[data-mce-selected] {
position: relative;
}
.mce-content-body td[data-mce-selected]::-moz-selection,
.mce-content-body th[data-mce-selected]::-moz-selection {
background: none;
}
.mce-content-body td[data-mce-selected]::selection,
.mce-content-body th[data-mce-selected]::selection {
background: none;
}
.mce-content-body td[data-mce-selected] *,
.mce-content-body th[data-mce-selected] * {
outline: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
background-color: rgba(180, 215, 255, 0.7);
border: 1px solid rgba(180, 215, 255, 0.7);
bottom: -1px;
content: '';
left: -1px;
mix-blend-mode: multiply;
position: absolute;
right: -1px;
top: -1px;
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
border-color: rgba(0, 84, 180, 0.7);
}
}
.mce-content-body img::-moz-selection {
background: none;
}
.mce-content-body img::selection {
background: none;
}
.ephox-snooker-resizer-bar {
background-color: #b4d7ff;
opacity: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ephox-snooker-resizer-cols {
cursor: col-resize;
}
.ephox-snooker-resizer-rows {
cursor: row-resize;
}
.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging {
opacity: 1;
}
.mce-spellchecker-word {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
height: 2rem;
}
.mce-spellchecker-grammar {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
}
.mce-toc {
border: 1px solid gray;
}
.mce-toc h2 {
margin: 4px;
}
.mce-toc li {
list-style-type: none;
}
table[style*="border-width: 0px"],
.mce-item-table:not([border]),
.mce-item-table[border="0"],
table[style*="border-width: 0px"] td,
.mce-item-table:not([border]) td,
.mce-item-table[border="0"] td,
table[style*="border-width: 0px"] th,
.mce-item-table:not([border]) th,
.mce-item-table[border="0"] th,
table[style*="border-width: 0px"] caption,
.mce-item-table:not([border]) caption,
.mce-item-table[border="0"] caption {
border: 1px dashed #bbb;
}
.mce-visualblocks p,
.mce-visualblocks h1,
.mce-visualblocks h2,
.mce-visualblocks h3,
.mce-visualblocks h4,
.mce-visualblocks h5,
.mce-visualblocks h6,
.mce-visualblocks div:not([data-mce-bogus]),
.mce-visualblocks section,
.mce-visualblocks article,
.mce-visualblocks blockquote,
.mce-visualblocks address,
.mce-visualblocks pre,
.mce-visualblocks figure,
.mce-visualblocks figcaption,
.mce-visualblocks hgroup,
.mce-visualblocks aside,
.mce-visualblocks ul,
.mce-visualblocks ol,
.mce-visualblocks dl {
background-repeat: no-repeat;
border: 1px dashed #bbb;
margin-left: 3px;
padding-top: 10px;
}
.mce-visualblocks p {
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
}
.mce-visualblocks h1 {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
}
.mce-visualblocks h2 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
}
.mce-visualblocks h3 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
}
.mce-visualblocks h4 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
}
.mce-visualblocks h5 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
}
.mce-visualblocks h6 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
}
.mce-visualblocks div:not([data-mce-bogus]) {
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
}
.mce-visualblocks section {
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
}
.mce-visualblocks article {
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
}
.mce-visualblocks blockquote {
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
}
.mce-visualblocks address {
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
}
.mce-visualblocks pre {
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
}
.mce-visualblocks figure {
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
}
.mce-visualblocks figcaption {
border: 1px dashed #bbb;
}
.mce-visualblocks hgroup {
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
}
.mce-visualblocks aside {
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
}
.mce-visualblocks ul {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
}
.mce-visualblocks ol {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
}
.mce-visualblocks dl {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
}
.mce-visualblocks:not([dir=rtl]) p,
.mce-visualblocks:not([dir=rtl]) h1,
.mce-visualblocks:not([dir=rtl]) h2,
.mce-visualblocks:not([dir=rtl]) h3,
.mce-visualblocks:not([dir=rtl]) h4,
.mce-visualblocks:not([dir=rtl]) h5,
.mce-visualblocks:not([dir=rtl]) h6,
.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),
.mce-visualblocks:not([dir=rtl]) section,
.mce-visualblocks:not([dir=rtl]) article,
.mce-visualblocks:not([dir=rtl]) blockquote,
.mce-visualblocks:not([dir=rtl]) address,
.mce-visualblocks:not([dir=rtl]) pre,
.mce-visualblocks:not([dir=rtl]) figure,
.mce-visualblocks:not([dir=rtl]) figcaption,
.mce-visualblocks:not([dir=rtl]) hgroup,
.mce-visualblocks:not([dir=rtl]) aside,
.mce-visualblocks:not([dir=rtl]) ul,
.mce-visualblocks:not([dir=rtl]) ol,
.mce-visualblocks:not([dir=rtl]) dl {
margin-left: 3px;
}
.mce-visualblocks[dir=rtl] p,
.mce-visualblocks[dir=rtl] h1,
.mce-visualblocks[dir=rtl] h2,
.mce-visualblocks[dir=rtl] h3,
.mce-visualblocks[dir=rtl] h4,
.mce-visualblocks[dir=rtl] h5,
.mce-visualblocks[dir=rtl] h6,
.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),
.mce-visualblocks[dir=rtl] section,
.mce-visualblocks[dir=rtl] article,
.mce-visualblocks[dir=rtl] blockquote,
.mce-visualblocks[dir=rtl] address,
.mce-visualblocks[dir=rtl] pre,
.mce-visualblocks[dir=rtl] figure,
.mce-visualblocks[dir=rtl] figcaption,
.mce-visualblocks[dir=rtl] hgroup,
.mce-visualblocks[dir=rtl] aside,
.mce-visualblocks[dir=rtl] ul,
.mce-visualblocks[dir=rtl] ol,
.mce-visualblocks[dir=rtl] dl {
background-position-x: right;
margin-right: 3px;
}
.mce-nbsp,
.mce-shy {
background: #aaa;
}
.mce-shy::after {
content: '-';
}

7
static/css/skins-tinymce/ui/oxide-dark/content.inline.min.css

File diff suppressed because one or more lines are too long

7
static/css/skins-tinymce/ui/oxide-dark/content.min.css

File diff suppressed because one or more lines are too long

29
static/css/skins-tinymce/ui/oxide-dark/content.mobile.css

@ -1,29 +0,0 @@
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection {
/* Note: this file is used inside the content, so isn't part of theming */
background-color: green;
display: inline-block;
opacity: 0.5;
position: absolute;
}
body {
-webkit-text-size-adjust: none;
}
body img {
/* this is related to the content margin */
max-width: 96vw;
}
body table img {
max-width: 95%;
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}

7
static/css/skins-tinymce/ui/oxide-dark/content.mobile.min.css

@ -1,7 +0,0 @@
/**
* 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/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save