scene-select.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <Modal
  3. width="800px"
  4. title="添加场景"
  5. :visible="visible"
  6. @ok="okHandler"
  7. @cancel="visible = false"
  8. okText="确定"
  9. cancelText="取消"
  10. class="model-table"
  11. >
  12. <div>
  13. <div className="model-header">
  14. <p class="header-desc">
  15. 已选择数据<span>( {{ rowSelection.selectedRowKeys.length }} )</span>
  16. </p>
  17. <Search
  18. className="content-header-search"
  19. placeholder="输入名称搜索"
  20. v-model:value="keyword"
  21. allow-clear
  22. style="width: 264px"
  23. />
  24. </div>
  25. <div class="table-layout" v-if="filterScenes.length">
  26. <Table
  27. :row-key="(record) => record.modelId"
  28. :columns="cloumns"
  29. :rowSelection="rowSelection"
  30. :data-source="filterScenes"
  31. :pagination="false"
  32. >
  33. <template #bodyCell="{ column, record }">
  34. <template v-if="column.key === 'createStatus'">
  35. {{ record.createStatus === 2 ? "转换中……" : "可用" }}
  36. </template>
  37. </template>
  38. </Table>
  39. </div>
  40. <div style="padding: 1px" v-else>
  41. <Empty
  42. :description="keyword.length ? '暂无搜索结果' : '暂无结果'"
  43. :image="Empty.PRESENTED_IMAGE_SIMPLE"
  44. className="ant-empty ant-empty-normal"
  45. />
  46. </div>
  47. </div>
  48. </Modal>
  49. <div @click="visible = true">
  50. <slot></slot>
  51. </div>
  52. </template>
  53. <script lang="ts" setup>
  54. import { Modal, Input, Table, Empty } from "ant-design-vue";
  55. import { computed, nextTick, ref, watch, watchEffect } from "vue";
  56. import { scenes, save, SceneTypeDesc, getFuseModel } from "@/store";
  57. import { asyncTimeout, createLoadPack } from "@/utils";
  58. import { getSceneModel } from "@/sdk";
  59. import {
  60. fuseModels,
  61. createFuseModels,
  62. addFuseModel,
  63. fuseModelsLoaded,
  64. initialScenes,
  65. } from "@/store";
  66. import type { Scene } from "@/api";
  67. type Key = Scene["modelId"];
  68. const Search = Input.Search;
  69. const selectIds = computed(() => fuseModels.value.map((item) => item.modelId));
  70. const visible = ref(false);
  71. const keyword = ref("");
  72. const filterScenes = computed(() =>
  73. scenes.value
  74. .filter((item) => item.name && item.modelId && item.name.includes(keyword.value))
  75. .map((scene) => ({
  76. ...scene,
  77. createTime: scene.createTime.substr(0, 16),
  78. type: SceneTypeDesc[scene.type],
  79. }))
  80. );
  81. const selects = ref<Key[]>(selectIds.value);
  82. const rowSelection: any = ref({
  83. selectedRowKeys: selects,
  84. onChange: (ids: number[]) => {
  85. selects.value = Array.from(new Set(ids.concat(selectIds.value)));
  86. },
  87. getCheckboxProps: (record: Scene) => {
  88. console.error(record);
  89. return {
  90. disabled: selectIds.value.includes(record.modelId) || record.createStatus === 2,
  91. };
  92. },
  93. });
  94. const cloumns = [
  95. {
  96. width: "300px",
  97. title: "名称",
  98. dataIndex: "name",
  99. key: "name",
  100. },
  101. {
  102. title: "类型",
  103. dataIndex: "type",
  104. key: "type",
  105. },
  106. {
  107. title: "状态",
  108. dataIndex: "createStatus",
  109. key: "createStatus",
  110. },
  111. {
  112. title: "拍摄/创建时间",
  113. dataIndex: "createTime",
  114. key: "createTime",
  115. },
  116. ];
  117. const okHandler = createLoadPack(async () => {
  118. const models = selects.value
  119. .filter((modelId) => !fuseModels.value.some((model) => model.modelId === modelId))
  120. .map((modelId) => createFuseModels({ modelId }));
  121. const addPromises = models.map(addFuseModel);
  122. await Promise.all(addPromises);
  123. await new Promise<void>((resolve) => {
  124. nextTick(() => {
  125. const stop = watchEffect(() => {
  126. if (fuseModelsLoaded.value) {
  127. nextTick(() => {
  128. stop();
  129. resolve();
  130. });
  131. }
  132. });
  133. });
  134. });
  135. models.forEach((model) => {
  136. if (getSceneModel(model)) {
  137. model.rotation = getSceneModel(model)!.getDefaultRotation();
  138. }
  139. });
  140. await asyncTimeout(100);
  141. await save();
  142. visible.value = false;
  143. });
  144. watch(visible, (visible, oldvisible) => {
  145. if (visible !== oldvisible) {
  146. keyword.value = "";
  147. selects.value = selectIds.value;
  148. visible && initialScenes();
  149. }
  150. });
  151. </script>
  152. <style lang="less" scoped>
  153. .model-header {
  154. display: flex;
  155. justify-content: space-between;
  156. padding-bottom: 24px;
  157. align-items: center;
  158. }
  159. .table-layout {
  160. max-height: 500px;
  161. overflow-y: auto;
  162. }
  163. </style>
  164. <style lang="less">
  165. .model-header .header-desc {
  166. margin-bottom: 0;
  167. }
  168. .ant-modal-root .ant-table-tbody > tr > td {
  169. word-break: break-all;
  170. }
  171. </style>