IndividualInterventionProgram.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <template>
  2. <div class="h-full w-full flex">
  3. <LeftMenu v-model:active="menuActive" :menus="menus" @change="menuChange" />
  4. <div class="flex-1 h-full overflow-y-auto p-4">
  5. <template v-if="!menuActive">
  6. <div v-for="(item, index) in menus.slice(1)" :key="index">
  7. <template v-if="item.content && item.content != '<p><br></p>'">
  8. <div class="font-bold mt-2 mb-2">{{ item.title }}:</div>
  9. <div class="p-4 bg-gray-50 rounded">
  10. <div v-html="item.content"></div>
  11. </div>
  12. </template>
  13. </div>
  14. <el-empty
  15. v-if="
  16. !menus
  17. .slice(1)
  18. .filter(v => v.content && v.content != '<p><br></p>').length
  19. "
  20. :image="emptyImg"
  21. class=""
  22. >
  23. <template #description>
  24. <el-button
  25. v-if="menus[1]"
  26. type="primary"
  27. link
  28. plain
  29. @click="
  30. menuActive = 1;
  31. menuChange(1, menus[1]);
  32. "
  33. >暂未填写,去填写</el-button
  34. >
  35. </template>
  36. </el-empty>
  37. </template>
  38. <template v-else-if="menuActive">
  39. <Editor v-model:value="menus[menuActive].content" :key="menuActive" />
  40. </template>
  41. <template v-if="menuActive">
  42. <div class="flex justify-end py-4">
  43. <el-popconfirm
  44. title="是否确认清空内容?"
  45. @confirm="menus[menuActive].content = ''"
  46. >
  47. <template #reference>
  48. <el-button type="warning" plain>清空内容</el-button>
  49. </template>
  50. </el-popconfirm>
  51. <el-button
  52. type="primary"
  53. plain
  54. @click="
  55. menuActive = 0;
  56. menuChange(0, menus[0]);
  57. "
  58. >去预览</el-button
  59. >
  60. </div>
  61. <div class="p-4 rounded bg-gray-50">
  62. <div class="flex items-center space-x-2">
  63. <span class="font-bold">系统建议:</span>
  64. <el-input
  65. v-model.trim="searchVal"
  66. clearable
  67. placeholder="请输入标题搜索"
  68. class="w-fit"
  69. ></el-input>
  70. <el-button type="primary">搜索</el-button>
  71. </div>
  72. <div class="space-y-4 pt-6">
  73. <el-collapse
  74. v-model="collapseActive"
  75. accordion
  76. class="py-4"
  77. @change="collapseChange"
  78. >
  79. <!-- v-for="(item, index) in menus[menuActive]?.articleList" -->
  80. <div
  81. v-for="(item, index) in filterArticleList"
  82. :key="index"
  83. class="bg-white px-4 py-2 rounded flex items-center"
  84. >
  85. <CirclePlusFilled
  86. class="w-6 cursor-pointer text-blue-500 mr-4"
  87. @click="addArticle(item)"
  88. />
  89. <el-collapse-item :name="index" class="flex-1">
  90. <template #title>
  91. <div class="font-bold">
  92. {{ item.label }}
  93. </div>
  94. </template>
  95. <div class="flex-1">
  96. <div class="text-gray-500">
  97. <div v-html="item.content"></div>
  98. </div>
  99. </div>
  100. </el-collapse-item>
  101. </div>
  102. </el-collapse>
  103. <!-- <el-collapse-item title="Consistency" name="1"></el-collapse-item> -->
  104. </div>
  105. </div>
  106. </template>
  107. </div>
  108. </div>
  109. </template>
  110. <script setup>
  111. import {
  112. computed,
  113. watch,
  114. markRaw,
  115. ref,
  116. inject,
  117. onMounted,
  118. provide,
  119. defineAsyncComponent,
  120. nextTick
  121. } from "vue";
  122. import { useRoute, useRouter } from "vue-router";
  123. import emptyImg from "@/assets/icon-empty-left.png";
  124. import LeftMenu from "./LeftMenu.vue";
  125. import { Search, CirclePlusFilled } from "@element-plus/icons-vue";
  126. import Editor from "@/components/Editor.vue";
  127. import { request, deduplicateArrayByKeys } from "@/utils";
  128. const getArticle = inject("getArticle");
  129. const getNodeRelationship = inject("getNodeRelationship");
  130. const getBatchNodeRelationships = inject("getBatchNodeRelationships");
  131. const parentState = inject("parentState");
  132. const diseaseMangeNode = inject("diseaseMangeNode");
  133. const updateStateValueForKey = inject("updateStateValueForKey");
  134. const menus = ref([]);
  135. watch(
  136. () => menus.value,
  137. () => {
  138. updateStateValueForKey(
  139. "personalizeInterventions",
  140. menus.value
  141. .filter(v => v.id)
  142. .map(v => {
  143. return {
  144. id: v.id,
  145. title: v.label,
  146. content: v.content
  147. };
  148. })
  149. );
  150. },
  151. {
  152. deep: true
  153. }
  154. );
  155. const menuActive = ref(0);
  156. const searchVal = ref("");
  157. const filterArticleList = computed(() =>
  158. menus.value[menuActive.value].articleList.filter(v =>
  159. v.label.includes(searchVal.value)
  160. )
  161. );
  162. const waitDefaultAppend = [];
  163. const init = async () => {
  164. const personalizeInterventions = parentState.value.personalizeInterventions;
  165. let articleList = await getNodeRelationship(
  166. diseaseMangeNode.value,
  167. "干预方式"
  168. );
  169. articleList = articleList
  170. .map(v => {
  171. return {
  172. id: v.mId,
  173. label: v.mProperties.name,
  174. articleId: v.mProperties["文章ID"]
  175. };
  176. })
  177. .sort((a, b) => a.sort - b.sort);
  178. let temp = await getBatchNodeRelationships(
  179. articleList.map(v => v.id).join(),
  180. "类别属于"
  181. );
  182. await Promise.all(
  183. parentState.value.etiologies
  184. .filter(v => v.id)
  185. .map(async v => {
  186. const data = await getNodeRelationship(v.id, "推荐干预方式");
  187. waitDefaultAppend.push(
  188. ...(data || []).map(v => {
  189. return {
  190. id: v.mId,
  191. label: v.mProperties.name,
  192. articleId: v.mProperties["文章ID"]
  193. };
  194. })
  195. );
  196. })
  197. );
  198. let classify = [];
  199. temp.forEach(async v => {
  200. let findClassify = classify.find(v2 => v2.id == v.mId);
  201. // let findArticle = waitDefaultAppend.find(v2 => v.nId == v2.id)?.articleId || ''
  202. // let appendContent = findArticle ? await getArticle(findArticle).content : ''
  203. let appendContent = "";
  204. if (findClassify) {
  205. findClassify.articleList.push(articleList.find(v2 => v2.id == v.nId));
  206. findClassify.content += appendContent;
  207. } else {
  208. classify.push({
  209. id: v.mId,
  210. label: v.mProperties.name,
  211. title: v.mProperties.name,
  212. content:
  213. (personalizeInterventions.find(v2 => v2.id == v.mId)?.content || "") +
  214. appendContent,
  215. articleList: [articleList.find(v2 => v2.id == v.nId)],
  216. sort: v.mProperties["排序"]
  217. });
  218. }
  219. });
  220. // temp = temp.map(v => {
  221. // return {
  222. // id: v.mId,
  223. // label: v.mProperties.name,
  224. // title: v.mProperties.name,
  225. // content: personalizeInterventions.find(v2 => v2.id == v.mId)?.content || "",
  226. // articleList: [],
  227. // sort: v.mProperties["排序"]
  228. // };
  229. // }).forEach(v => {
  230. // })
  231. // .sort((a, b) => a.sort - b.sort)
  232. // deduplicateArrayByKeys(, ['id'])
  233. menus.value = classify.sort((a, b) => a.sort - b.sort);
  234. menus.value = [{ label: "干预方案预览", fixed: true }, ...menus.value];
  235. // console.log();
  236. // menus.value = data
  237. // .map(v => {
  238. // return {
  239. // id: v.mId,
  240. // label: v.mProperties.name,
  241. // title: v.mProperties.name,
  242. // content: personalizeInterventions.find(v2 => v2.id == v.mId)?.content || "",
  243. // articleList: [],
  244. // sort: v.mProperties["排序"]
  245. // };
  246. // })
  247. // .sort((a, b) => a.sort - b.sort);
  248. // menus.value = [{ label: "干预方案预览", fixed: true }, ...menus.value];
  249. };
  250. init();
  251. const menuChange = async (i, menu) => {
  252. if (menu.id && !menu.articleList.length) {
  253. const data = await getNodeRelationship(menu.id, "干预方式");
  254. menu.articleList = (data || []).map(v => {
  255. return {
  256. id: v.mId,
  257. label: v.mProperties.name,
  258. articleId: v.mProperties["文章ID"],
  259. content: ""
  260. };
  261. });
  262. }
  263. searchVal.value = "";
  264. };
  265. const collapseActive = ref();
  266. const collapseChange = async idx => {
  267. if (
  268. idx != undefined &&
  269. !menus.value[menuActive.value].articleList[idx].content
  270. ) {
  271. const detail = await getArticle(
  272. menus.value[menuActive.value]?.articleList[idx].articleId
  273. );
  274. menus.value[menuActive.value].articleList[idx].content = detail.content;
  275. }
  276. };
  277. const addArticle = async item => {
  278. if (!item.content) {
  279. const detail = await getArticle(item.articleId);
  280. item.content = detail.content;
  281. }
  282. menus.value[menuActive.value].content += item.content;
  283. };
  284. </script>
  285. <style lang="scss" scoped></style>