index.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <script setup lang="ts">
  2. import IframeEditor from "./iframe-editor.vue";
  3. import { useCompShallowRef } from "@/utils/useCompRef";
  4. import { magicApi } from "@/utils/database/magic-api-request";
  5. import { getAllWards } from "@/api/login";
  6. import XcElOption from "@/components/xiao-chan/xc-el-option/XcElOption.vue";
  7. import * as api from "@/api/dashboardEditor/dashboardEditor";
  8. import { type TDashboardTemplate } from "@/api/dashboardEditor/dashboardEditor";
  9. import { BizException, ExceptionEnum } from "@/utils/BizException";
  10. import { stringIsBlank } from "@/utils/blank-utils";
  11. const dashboardEditorRef = useCompShallowRef(IframeEditor);
  12. const store = reactive({
  13. dataSource: [] as { code: string; name: string; group: string }[],
  14. group: {},
  15. currentWard: null,
  16. wardList: [],
  17. currentTemplate: {} as null | TDashboardTemplate,
  18. collapseValue: "",
  19. });
  20. const tmpGroupDataSource = computed(() => {
  21. const tmp = {};
  22. store.dataSource.forEach(item => {
  23. if (tmp[item.group]) {
  24. tmp[item.group].push(item);
  25. } else {
  26. tmp[item.group] = [item];
  27. }
  28. });
  29. return tmp;
  30. });
  31. async function handleWardChange(code) {
  32. store.currentTemplate = await api.getDashboardTemplateByWardCode(code);
  33. dashboardEditorRef.value.clearHtml();
  34. if (store.currentTemplate == null) {
  35. dashboardEditorRef.value.insertTable(17, 11);
  36. } else {
  37. dashboardEditorRef.value.setHtml(
  38. store.currentTemplate.htmlDataTemp || store.currentTemplate.htmlData || ""
  39. );
  40. }
  41. }
  42. onMounted(() => {
  43. magicApi({
  44. url: "/public/dashboard/dataSource",
  45. method: "post",
  46. data: { isSource: true },
  47. })
  48. .then(res => {
  49. store.dataSource = res.data;
  50. store.group = res.group;
  51. })
  52. .catch(() => {
  53. store.dataSource = [];
  54. });
  55. getAllWards()
  56. .then(res => {
  57. store.wardList = res;
  58. store.wardList.unshift({
  59. code: "defaultTemp",
  60. name: "默认模板",
  61. });
  62. })
  63. .catch(() => {
  64. store.wardList = [];
  65. });
  66. });
  67. async function handleSave(htmlData) {
  68. if (store.currentWard == null) {
  69. BizException(ExceptionEnum.MESSAGE_ERROR, "请先选择病区");
  70. }
  71. if (store.currentTemplate == null) {
  72. store.currentTemplate = {
  73. wardCode: store.currentWard,
  74. htmlDataTemp: htmlData,
  75. };
  76. } else {
  77. store.currentTemplate.htmlDataTemp = htmlData;
  78. store.currentTemplate.wardCode = store.currentWard;
  79. }
  80. store.currentTemplate = await api.saveTemplate(store.currentTemplate);
  81. }
  82. async function handleRelease() {
  83. if (stringIsBlank(store.currentTemplate?.htmlDataTemp)) {
  84. BizException(ExceptionEnum.MESSAGE_ERROR, "请先设置模板");
  85. }
  86. if (stringIsBlank(store.currentTemplate?.id)) {
  87. BizException(ExceptionEnum.MESSAGE_ERROR, "请先保存");
  88. }
  89. await api.release(store.currentTemplate.id);
  90. }
  91. function handlePreview() {
  92. if (stringIsBlank(store.currentTemplate?.id)) {
  93. BizException(ExceptionEnum.MESSAGE_ERROR, "请先打开模板");
  94. }
  95. window.open(
  96. `${location.origin}/inpatientBoardV2?tempId=${store.currentTemplate.id}&ward=${store.currentWard}`,
  97. "_blank"
  98. );
  99. }
  100. defineOptions({
  101. name: "dashboardEditor",
  102. });
  103. </script>
  104. <template>
  105. <div class="layout_container layout-horizontal">
  106. <aside style="width: 15vw" class="layout_card">
  107. <div class="layout_container">
  108. <header>
  109. <el-alert
  110. type="error"
  111. effect="dark"
  112. title="列宽可能拖动,但是列高不行,因为高度是不确定的,发布后才能看到效果。"
  113. :closable="false"
  114. ></el-alert>
  115. <el-form style="width: 100%">
  116. <el-form-item label="病区:">
  117. <el-select
  118. style="width: 100%"
  119. v-model="store.currentWard"
  120. @change="handleWardChange"
  121. >
  122. <xc-el-option :data="store.wardList" />
  123. </el-select>
  124. </el-form-item>
  125. <el-form-item>
  126. <el-button type="primary" @click="handleRelease">发布</el-button>
  127. <el-button type="success" @click="handlePreview">预览</el-button>
  128. </el-form-item>
  129. </el-form>
  130. </header>
  131. <div class="layout_main layout_container">
  132. <el-divider>数据源</el-divider>
  133. <div style="padding: 10px" class="layout_main">
  134. <el-collapse>
  135. <el-collapse-item
  136. v-for="(value, key) in store.group"
  137. :title="value"
  138. >
  139. <el-row :gutter="10">
  140. <el-col
  141. style="margin-top: 8px"
  142. :span="24 / 3"
  143. v-for="item in tmpGroupDataSource[key]"
  144. @click="
  145. () => {
  146. dashboardEditorRef.insert(item);
  147. }
  148. "
  149. >
  150. <el-tag size="large" style="width: 100%">
  151. {{ item.name }}
  152. </el-tag>
  153. </el-col>
  154. </el-row>
  155. </el-collapse-item>
  156. </el-collapse>
  157. </div>
  158. </div>
  159. </div>
  160. </aside>
  161. <div class="layout_main">
  162. <IframeEditor ref="dashboardEditorRef" @save="handleSave" />
  163. </div>
  164. </div>
  165. </template>
  166. <style lang="scss"></style>