bl-common-vue3 3.8.113 → 3.8.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bl-common-vue3",
3
- "version": "3.8.113",
3
+ "version": "3.8.115",
4
4
  "main": "index.js",
5
5
  "module": "index.js",
6
6
  "description": "bailing vue3 common components lib",
@@ -25,6 +25,7 @@
25
25
  :mobileAnnexUploadConfig="mobileAnnexUploadConfig"
26
26
  @handleRequest="handleRequest"
27
27
  @handleAddSuccess="handleAddSuccess"
28
+ @previewFile="previewClick"
28
29
  />
29
30
  </template>
30
31
  <a-table
@@ -52,11 +53,9 @@
52
53
  <a-tooltip v-if="record.annex_type == 2">
53
54
  <template #title>{{ t('AttachmentInfo.index.559728-5') }}</template>
54
55
  <a-button
55
- type="link"
56
- :disabled="record.online_preview && !record.online_preview.previewUrl &&
57
- record.online_preview.documentType !== 'pic'
58
- "
59
- @click="previewClick(record)"
56
+ type="link"
57
+ :disabled="!canPreviewFile(record)"
58
+ @click="previewClick(record)"
60
59
  >
61
60
  <template #icon>
62
61
  <EyeOutlined/>
@@ -86,6 +85,7 @@
86
85
  :mobileAnnexUploadConfig="mobileAnnexUploadConfig"
87
86
  @handleRequest="handleRequest"
88
87
  @handleAddSuccess="handleAddSuccess"
88
+ @previewFile="previewClick"
89
89
  />
90
90
  <a-tooltip v-if="record.operate.includes('Topping')">
91
91
  <template #title>{{ t('AttachmentInfo.index.559728-6') }}</template>
@@ -136,6 +136,23 @@
136
136
  </template>
137
137
  </a-table>
138
138
  </a-card>
139
+
140
+ <!-- 预览图片 -->
141
+ <PreviewImg
142
+ :visible="imgVisible"
143
+ :index="0"
144
+ :list="imgList"
145
+ @close="onCloseImgPreview"
146
+ />
147
+
148
+ <!-- 文档预览 -->
149
+ <PreviewFile
150
+ :visible="previewFileVisible"
151
+ :urlData="previewUrlData"
152
+ :title="previewUrlData.name"
153
+ :esignDetail="{esignCheck: true}"
154
+ @close="onClosePreviewFile"
155
+ />
139
156
  </section>
140
157
  </template>
141
158
 
@@ -166,6 +183,8 @@ import {
166
183
  } from "ant-design-vue";
167
184
  import {t, loadLanguageAsync} from "../../locale";
168
185
  import AddAction from "./modules/AddAction.vue";
186
+ import PreviewImg from "../PreviewImg/index.vue";
187
+ import PreviewFile from "../PreviewFile/index.vue";
169
188
  export default defineComponent({
170
189
  name: "ContractAttachmentInfo",
171
190
  components: {
@@ -181,6 +200,8 @@ export default defineComponent({
181
200
  "a-tooltip": Tooltip,
182
201
  "a-button": Button,
183
202
  "a-space": Space,
203
+ PreviewImg: PreviewImg,
204
+ PreviewFile,
184
205
  },
185
206
  props: {
186
207
  active: {
@@ -315,7 +336,12 @@ export default defineComponent({
315
336
  disabled: false,
316
337
  };
317
338
  },
318
- }
339
+ },
340
+ // 是否自定义预览
341
+ isCustomPreview: {
342
+ type: Boolean,
343
+ default: false,
344
+ },
319
345
  },
320
346
  setup(props, context) {
321
347
  const homeCrumb = { key: "home", parentId: 0, title: t('AttachmentInfo.index.559728-8') };
@@ -345,7 +371,6 @@ export default defineComponent({
345
371
  annexAdd: props.annexAdd,
346
372
  serviceFrom: props.serviceFrom,
347
373
  };
348
- console.log(addParams.value, "!111");
349
374
  if (type != 3) {
350
375
  addVisible.value = true;
351
376
  }
@@ -542,17 +567,124 @@ export default defineComponent({
542
567
  const randomStr = utils.getRandomUid(18);
543
568
  let loaded = false;
544
569
 
570
+ // 获取文件后缀,统一处理带 query/hash 的预览地址
571
+ const getFileSuffix = (file) => {
572
+ if (!file) return "";
573
+ return file.split("?")[0].split("#")[0].split(".").pop().toLowerCase();
574
+ };
575
+
576
+ // 判断是否为图片文件
577
+ const isImageFile = (file) => {
578
+ if (!file) return false;
579
+ const imageExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"];
580
+ return imageExtensions.includes(getFileSuffix(file));
581
+ };
582
+
583
+ // 判断是否为媒体文件
584
+ const isMediaFile = (file) => {
585
+ if (!file) return false;
586
+ const videoExtensions = ["mp4","mov","m4v","webm","ogv","avi","wmv","mkv","flv","mpeg"];
587
+ const radioExtensions = ["mp3","wav","ogg","m4a","aac","flac","wma"];
588
+ return [...videoExtensions, ...radioExtensions].includes(getFileSuffix(file));
589
+ };
590
+
591
+ // 统一整理附件预览数据,避免不同入口分别判断图片和文档逻辑
592
+ const resolvePreviewData = (record = {}) => {
593
+ const filePath = record.file_path || "";
594
+ const previewInfo = record.preview_url || record.online_preview || {};
595
+ const previewUrl = previewInfo.previewUrl || "";
596
+ const documentType = previewInfo.documentType || "";
597
+ const fileName = record.name || "";
598
+ const sourceUrl = previewUrl || filePath;
599
+
600
+ if (sourceUrl && (documentType === "pic" || isImageFile(sourceUrl))) {
601
+ return {
602
+ type: "image",
603
+ url: sourceUrl,
604
+ name: fileName,
605
+ };
606
+ }
607
+
608
+ if (getFileSuffix(filePath) === "pdf") {
609
+ return {
610
+ type: "file",
611
+ previewUrl: `/public_web/pdf/web/viewer.html?file=${encodeURIComponent(filePath)}`,
612
+ url: filePath,
613
+ name: fileName,
614
+ };
615
+ }
616
+
617
+ if (previewUrl) {
618
+ return {
619
+ type: "file",
620
+ previewUrl,
621
+ url: filePath || previewUrl,
622
+ name: fileName,
623
+ };
624
+ }
625
+
626
+ return null;
627
+ };
628
+
629
+ // 判断是否可预览文件
630
+ const canPreviewFile = (record = {}) => {
631
+ return !!resolvePreviewData(record) || !!record.file_path;
632
+ };
633
+
545
634
  // 在线预览
546
635
  const imgVisible = ref(false);
547
636
  const imgList = ref([]);
548
637
  const previewUrlData = ref({});
638
+ const previewFileVisible = ref(false);
639
+
640
+ // 关闭图片预览
641
+ const onCloseImgPreview = () => {
642
+ imgVisible.value = false;
643
+ imgList.value = [];
644
+ };
645
+
646
+ // 关闭预览文件
647
+ const onClosePreviewFile = () => {
648
+ previewFileVisible.value = false;
649
+ previewUrlData.value = {};
650
+ };
651
+
652
+ // 预览文件
549
653
  const previewClick = (record) => {
550
- window.microApp.forceDispatch({
551
- type: "previewFile",
552
- visible: true,
553
- file: { url: record.file_path },
554
- filePreviewUrl: record.preview_url.previewUrl,
555
- });
654
+ if(props.isCustomPreview){
655
+ context.emit("previewFile", record);
656
+ return;
657
+ }
658
+ // 视频和音频文件直接由浏览器打开,避免进入 iframe 预览导致无法播放
659
+ if (record.file_path && isMediaFile(record?.file_path)) {
660
+ record.file_path && window.open(record.file_path);
661
+ return;
662
+ }
663
+ if (window.__MICRO_APP_ENVIRONMENT__) {
664
+ window.microApp.forceDispatch({
665
+ type: "previewFile",
666
+ visible: true,
667
+ file: {
668
+ url: record?.file_path || '',
669
+ name: record?.name || '',
670
+ },
671
+ filePreviewUrl: record?.preview_url?.previewUrl || record?.online_preview?.previewUrl || '',
672
+ });
673
+ } else {
674
+ const previewData = resolvePreviewData(record);
675
+ if (previewData?.type === "image") {
676
+ imgList.value = [previewData.url];
677
+ imgVisible.value = true;
678
+ return;
679
+ }
680
+ if (previewData?.type === "file") {
681
+ previewUrlData.value = previewData;
682
+ previewFileVisible.value = true;
683
+ return;
684
+ }
685
+ // 没有可预览地址时,保留浏览器原生打开行为,避免误拦截下载型文件
686
+ record.file_path && window.open(record.file_path);
687
+ }
556
688
  };
557
689
 
558
690
  // 附件编辑
@@ -592,7 +724,6 @@ export default defineComponent({
592
724
  if(props.typeFrom){
593
725
  attachParams.typeFrom = props.typeFrom;
594
726
  }
595
- console.log("attachParams", attachParams);
596
727
  getDataList();
597
728
  loaded = true;
598
729
  };
@@ -716,11 +847,15 @@ export default defineComponent({
716
847
  downloadFile,
717
848
  previewClick,
718
849
  previewUrlData,
850
+ previewFileVisible,
851
+ onClosePreviewFile,
719
852
 
720
853
  imgList,
721
854
  imgVisible,
855
+ onCloseImgPreview,
722
856
  multiAddVisible,
723
857
  handleRequest,
858
+ canPreviewFile,
724
859
 
725
860
  getAnnexEdit,
726
861
  mobileAnnexUploadConfigInfo,
@@ -81,6 +81,7 @@
81
81
  :annexAdd="annexAdd"
82
82
  :getFile="getFile"
83
83
  @handleCommit="handleAddSuccess"
84
+ @previewFile="previewClick"
84
85
  @request="handleRequest"/>
85
86
  </template>
86
87
 
@@ -265,6 +266,11 @@ export default defineComponent({
265
266
  return props.getFile ? {} : params;
266
267
  });
267
268
 
269
+ // 预览文件
270
+ const previewClick = (previewData) => {
271
+ context.emit("previewFile", previewData);
272
+ };
273
+
268
274
  return {
269
275
  t,
270
276
  multiAddVisible,
@@ -277,6 +283,7 @@ export default defineComponent({
277
283
  handleAddSuccess,
278
284
  handleRequest,
279
285
  addRequest,
286
+ previewClick,
280
287
  };
281
288
  },
282
289
  });
@@ -245,16 +245,33 @@ export default {
245
245
  const imgVisible = ref(false);
246
246
  const imgList = ref([]);
247
247
  const previewClick = (record) => {
248
+ let fileUrl = record.response.data.fileUrl || '';
249
+ let previewUrl = record.response.data.previewUrl || '';
250
+ const fileName = record?.originFileObj?.name || record?.name || '';
248
251
  if (record.type.startsWith("image")) {
249
- imgList.value = [record.response.data.fileUrl];
252
+ imgList.value = [fileUrl];
250
253
  imgVisible.value = true;
251
254
  } else {
252
- window.microApp.forceDispatch({
253
- type: "previewFile",
254
- visible: true,
255
- file: { url: record.response.data.fileUrl },
256
- filePreviewUrl: record.response.data.previewUrl,
257
- });
255
+ if (window.__MICRO_APP_ENVIRONMENT__) {
256
+ window.microApp.forceDispatch({
257
+ type: "previewFile",
258
+ visible: true,
259
+ file: {
260
+ url: fileUrl,
261
+ name: fileName,
262
+ },
263
+ filePreviewUrl: previewUrl || '',
264
+ });
265
+ } else {
266
+ let previewData = {
267
+ file_path: fileUrl,
268
+ preview_url: {
269
+ previewUrl
270
+ },
271
+ name: fileName,
272
+ }
273
+ context.emit("previewFile", previewData);
274
+ }
258
275
  }
259
276
  };
260
277
 
@@ -0,0 +1,158 @@
1
+ <template>
2
+ <a-modal v-model:visible="showModal" :title="t('PreviewFile.printModal.title')" @cancel="handleOk">
3
+ <div>
4
+ {{ t('PreviewFile.printModal.noticeStart') }}
5
+ <div
6
+ class="text-blue"
7
+ style="display: inline-block; cursor: pointer"
8
+ @click="downloadExe"
9
+ >
10
+ {{ t('PreviewFile.printModal.download') }}
11
+ <cloud-download-outlined style="font-size: 20px" />
12
+ </div>
13
+ {{ t('PreviewFile.printModal.noticeEnd') }}
14
+ </div>
15
+ <template #footer>
16
+ <div style="text-align: right">
17
+ <a-button type="primary" @click="handleOk">{{ t('PreviewFile.printModal.ok') }}</a-button>
18
+ </div>
19
+ </template>
20
+ </a-modal>
21
+ </template>
22
+
23
+ <script>
24
+ import { onUnmounted, reactive, toRefs, watch } from "vue";
25
+ import { CloudDownloadOutlined } from "@ant-design/icons-vue";
26
+ import { message, Modal, Button } from "ant-design-vue";
27
+ import { t, loadLanguageAsync } from "../../locale";
28
+ import utils from "../../common/utils/util";
29
+
30
+ export default {
31
+ components: {
32
+ CloudDownloadOutlined,
33
+ 'a-button': Button,
34
+ 'a-modal': Modal
35
+ },
36
+ props: {
37
+ usePrint: {
38
+ type: Boolean,
39
+ default: false,
40
+ },
41
+ file_list: {
42
+ type: Array,
43
+ default: () => [],
44
+ },
45
+ },
46
+ setup(props, context) {
47
+ const state = reactive({
48
+ showModal: false,
49
+ });
50
+
51
+ const printHost = "http://127.0.0.1:19889/api";
52
+
53
+ // 带超时的本地接口请求,避免插件无响应时页面一直挂起
54
+ const requestWithTimeout = async (url, options = {}, timeout = 2000) => {
55
+ const controller = new AbortController();
56
+ const timer = window.setTimeout(() => controller.abort(), timeout);
57
+ try {
58
+ return await fetch(url, {
59
+ ...options,
60
+ signal: controller.signal,
61
+ });
62
+ } finally {
63
+ window.clearTimeout(timer);
64
+ }
65
+ };
66
+
67
+ // 连接成功后,把文件列表发给本地打印插件
68
+ const commitPrint = async () => {
69
+ const param = {
70
+ file_list: props.file_list,
71
+ };
72
+ console.log(JSON.stringify(param));
73
+ try {
74
+ const response = await requestWithTimeout(
75
+ `${printHost}/printDoc`,
76
+ {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ },
81
+ body: JSON.stringify(param),
82
+ },
83
+ 2000
84
+ );
85
+ if (!response.ok) {
86
+ throw new Error(response.statusText || "print failed");
87
+ }
88
+ message.success(t("PreviewFile.printModal.success"));
89
+ context.emit("change");
90
+ } catch (error) {
91
+ message.error(error?.message || error);
92
+ }
93
+ };
94
+
95
+ // 先检查本地打印插件是否已连接,未连接时展示下载提示
96
+ const connect = async () => {
97
+ try {
98
+ const response = await requestWithTimeout(`${printHost}/connect`, {
99
+ method: "GET",
100
+ }, 1000);
101
+ if (!response.ok) {
102
+ throw new Error(response.statusText || "connect failed");
103
+ }
104
+ console.log(await response.text());
105
+ await commitPrint();
106
+ } catch (error) {
107
+ console.error(error);
108
+ state.showModal = true;
109
+ }
110
+ };
111
+
112
+ // 下载网页打印插件安装包
113
+ const downloadExe = () => {
114
+ const url =
115
+ "https://bailing-customer-1305744786.cos.ap-nanjing.myqcloud.com/http_printer/%E7%BD%91%E9%A1%B5%E6%89%93%E5%8D%B0%E6%8F%92%E4%BB%B6.exe";
116
+ window.open(url);
117
+ };
118
+
119
+ // 关闭提示弹窗并通知父组件结束本次打印动作
120
+ const handleOk = () => {
121
+ state.showModal = false;
122
+ context.emit("change");
123
+ };
124
+
125
+ // 外部触发打印时,尝试连接本地插件
126
+ watch(() => props.usePrint, (value) => {
127
+ if (value) {
128
+ connect();
129
+ } else {
130
+ state.showModal = false;
131
+ }
132
+ });
133
+
134
+ // 保持当前组件的语言环境和全局语言一致
135
+ const handleLangChange = (event) => {
136
+ loadLanguageAsync(event.newValue);
137
+ };
138
+
139
+ loadLanguageAsync(utils.getLang());
140
+ window.addEventListener("setBLLang", handleLangChange);
141
+ onUnmounted(() => {
142
+ window.removeEventListener("setBLLang", handleLangChange);
143
+ });
144
+
145
+ return {
146
+ ...toRefs(state),
147
+ t,
148
+ downloadExe,
149
+ connect,
150
+ commitPrint,
151
+ handleOk,
152
+ };
153
+ },
154
+ };
155
+ </script>
156
+
157
+ <style lang="less" scoped>
158
+ </style>
@@ -0,0 +1,293 @@
1
+ <template>
2
+ <div>
3
+ <a-modal
4
+ :width="1200"
5
+ :visible="visible"
6
+ centered
7
+ :footer="null"
8
+ :bodyStyle="{
9
+ padding: '0',
10
+ }"
11
+ destroyOnClose
12
+ @cancel="onClose"
13
+ >
14
+ <div class="content">
15
+ <a-spin :tip="t('PreviewFile.loading')" :spinning="spinLoading" :style="{ height: spinHeight }">
16
+ <iframe
17
+ v-if="previewUrl"
18
+ :height="clientHeight * 0.85"
19
+ width="100%"
20
+ :src="previewUrl"
21
+ allowtransparency="true"
22
+ allowfullscreen="true"
23
+ allowfullscreenInteractive="true"
24
+ scrolling="no"
25
+ border="0"
26
+ frameborder="0"
27
+ @load="handleLoad"
28
+ ></iframe>
29
+ </a-spin>
30
+ </div>
31
+ <template #title>
32
+ <a-space>
33
+ <div>{{ displayTitle }}</div>
34
+ <div v-if="esignDetail.esignCheck && (fileUrl || canPrint)">
35
+ <a-space>
36
+ <a-button v-if="fileUrl" :loading="esignLoading" type="primary" @click="operateClick('download')">
37
+ <DownloadOutlined />
38
+ {{ t('PreviewFile.download') }}
39
+ </a-button>
40
+ <a-button v-if="canPrint" type="primary" @click="printFile">
41
+ <PrinterOutlined />
42
+ {{ t('PreviewFile.print') }}
43
+ </a-button>
44
+ </a-space>
45
+ </div>
46
+ </a-space>
47
+ </template>
48
+ </a-modal>
49
+ <!--打印-->
50
+ <print-modal :file_list="printList" :usePrint="showModal" @change="showModal = false" />
51
+ </div>
52
+ </template>
53
+
54
+ <script>
55
+ import { computed, defineComponent, onUnmounted, reactive, toRefs, watch } from "vue";
56
+ import { Modal, Spin, Button, Space } from "ant-design-vue";
57
+ import { DownloadOutlined, PrinterOutlined } from "@ant-design/icons-vue";
58
+ import PrintModal from './PrintModal.vue';
59
+ import { t, loadLanguageAsync } from "../../locale";
60
+ import utils from "../../common/utils/util";
61
+
62
+ export default defineComponent({
63
+ name: "PreviewFile",
64
+ components: {
65
+ PrintModal,
66
+ DownloadOutlined,
67
+ PrinterOutlined,
68
+ "a-modal": Modal,
69
+ "a-spin": Spin,
70
+ "a-button": Button,
71
+ "a-space": Space,
72
+ },
73
+ props: {
74
+ visible: {
75
+ type: Boolean,
76
+ default: false,
77
+ },
78
+ esignDetail: {
79
+ type: Object,
80
+ default: () => {
81
+ return {};
82
+ },
83
+ },
84
+ title: {
85
+ type: String,
86
+ default: () => {
87
+ return t('PreviewFile.defaultTitle')
88
+ },
89
+ },
90
+ urlData: {
91
+ type: Object,
92
+ default: () => {
93
+ return {};
94
+ },
95
+ },
96
+ type: {
97
+ type: String,
98
+ default: "",
99
+ },
100
+ },
101
+ setup(props, {emit}) {
102
+ const state = reactive({
103
+ previewUrl: "",
104
+ fileUrl: "",
105
+ name: "",
106
+ clientHeight: document.body.clientHeight,
107
+ esignLoading: false,
108
+ spinLoading: true,
109
+ showModal: false,
110
+ canPrint: false,
111
+ printList: [],
112
+ });
113
+
114
+ // 预览弹窗标题统一使用多语言兜底,避免父组件不传标题时出现空白
115
+ const displayTitle = computed(() => props.title || t('PreviewFile.defaultTitle'));
116
+
117
+ // 重置所有预览状态,避免关闭后再次打开时残留上一次的文件信息
118
+ const resetPreviewState = () => {
119
+ state.previewUrl = "";
120
+ state.fileUrl = "";
121
+ state.name = "";
122
+ state.esignLoading = false;
123
+ state.spinLoading = true;
124
+ state.showModal = false;
125
+ state.canPrint = false;
126
+ state.printList = [];
127
+ };
128
+
129
+ // 获取文件后缀,统一处理带 query/hash 的预览地址
130
+ const getFileSuffix = (fileUrl = "") => {
131
+ if (!fileUrl) return "";
132
+ return fileUrl.split("?")[0].split("#")[0].split(".").pop().toLowerCase();
133
+ };
134
+
135
+ const operateClick = (action) => {
136
+ // 下载按钮只处理本地可下载的文档类型,其他文件直接交给浏览器打开
137
+ if (action == "download") {
138
+ const fileType = getFileSuffix(state.fileUrl);
139
+ let type = "";
140
+ if (["xlsx", "xls"].includes(fileType)) {
141
+ type = 'xlsx'
142
+ }
143
+ if (["docx", "doc"].includes(fileType)) {
144
+ type = 'word'
145
+ }
146
+ if (["pdf"].includes(fileType)) {
147
+ type = 'pdf'
148
+ }
149
+ if (state.name && ["pdf", "word", "xlsx"].includes(type)) {
150
+ if (state.esignLoading) {
151
+ return;
152
+ }
153
+ state.esignLoading = true;
154
+ fetchDownloadFile({
155
+ url: state.fileUrl,
156
+ name: state.name,
157
+ type,
158
+ });
159
+ } else {
160
+ window.open(state.fileUrl);
161
+ }
162
+ return;
163
+ }
164
+ };
165
+
166
+ // 使用浏览器能力完成本地下载,避免把下载链接再次交给预览页处理
167
+ const fetchDownloadFile = async (data) => {
168
+ if (!data?.url) {
169
+ state.esignLoading = false;
170
+ return;
171
+ }
172
+ let downloadUrl = "";
173
+ try {
174
+ const response = await fetch(data.url, {
175
+ method: "get",
176
+ mode: "cors",
177
+ });
178
+ if (!response.ok) {
179
+ throw new Error("download failed");
180
+ }
181
+ const res = await response.blob();
182
+ const typeObj = {
183
+ pdf: "application/pdf",
184
+ word: "application/msword",
185
+ xlsx: "application/vnd.ms-excel",
186
+ };
187
+ downloadUrl = window.URL.createObjectURL(
188
+ new Blob([res], {
189
+ type: typeObj[data.type] || "",
190
+ })
191
+ );
192
+ const link = document.createElement("a");
193
+ link.href = downloadUrl;
194
+ link.setAttribute("download", data.name);
195
+ document.body.appendChild(link);
196
+ link.click();
197
+ link.remove();
198
+ } catch (error) {
199
+ window.open(data.url);
200
+ } finally {
201
+ if (downloadUrl) {
202
+ window.URL.revokeObjectURL(downloadUrl);
203
+ }
204
+ state.esignLoading = false;
205
+ }
206
+ };
207
+
208
+ const onClose = () => {
209
+ resetPreviewState();
210
+ emit("close");
211
+ };
212
+
213
+ const handleLoad = () => {
214
+ state.spinLoading = false;
215
+ };
216
+
217
+ const spinHeight = computed(() => {
218
+ return state.clientHeight * 0.85 + "px";
219
+ });
220
+
221
+ // 打开弹窗时重建预览状态,关闭时清理现场,避免上一个文件的状态串到下一个文件
222
+ watch(
223
+ () => [props.visible, props.urlData?.previewUrl, props.urlData?.url, props.urlData?.name],
224
+ ([visible]) => {
225
+ if (visible) {
226
+ state.previewUrl = props.urlData?.previewUrl || "";
227
+ state.fileUrl = props.urlData?.url || "";
228
+ state.name = props.urlData?.name || "";
229
+ state.canPrint = state.fileUrl.endsWith(".docx");
230
+ state.spinLoading = !!state.previewUrl;
231
+ state.esignLoading = false;
232
+ state.showModal = false;
233
+ state.printList = [];
234
+ } else {
235
+ resetPreviewState();
236
+ }
237
+ }
238
+ );
239
+
240
+ const printFile = () => {
241
+ state.printList = [state.fileUrl];
242
+ state.showModal = true;
243
+ };
244
+
245
+ // 同步当前系统语言,保证单独使用该组件时多语言也能正常切换
246
+ const handleLangChange = (event) => {
247
+ loadLanguageAsync(event.newValue);
248
+ };
249
+
250
+ loadLanguageAsync(utils.getLang());
251
+ window.addEventListener("setBLLang", handleLangChange);
252
+ onUnmounted(() => {
253
+ window.removeEventListener("setBLLang", handleLangChange);
254
+ });
255
+
256
+ return {
257
+ ...toRefs(state),
258
+ t,
259
+ displayTitle,
260
+ onClose,
261
+ operateClick,
262
+ spinHeight,
263
+ handleLoad,
264
+ printFile,
265
+ };
266
+ },
267
+ });
268
+ </script>
269
+
270
+ <style lang="less" scoped>
271
+ .content {
272
+ width: 100%;
273
+ display: flex;
274
+ justify-content: center;
275
+ }
276
+
277
+ .el-loading {
278
+ position: fixed;
279
+ left: 0;
280
+ right: 0;
281
+ top: 0;
282
+ bottom: 0;
283
+ z-index: 1000;
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ background: rgba(255, 255, 255, 0.6);
288
+ }
289
+
290
+ :deep(.ant-spin-nested-loading) {
291
+ width: 100%;
292
+ }
293
+ </style>
@@ -31,7 +31,7 @@
31
31
  <bl-icon v-if="dataRef.slotIcon === 'topCompanyIcon'" type="tree-jigou" class="tree-icon" />
32
32
  <GoldenFilled v-if="dataRef.slotIcon === 'departmentIcon'" class="tree-icon" />
33
33
  <bl-icon v-if="dataRef.slotIcon === 'villageIcon'" type="tree-xiangmu" class="tree-icon" />
34
- <bl-icon v-if="dataRef.slotIcon === 'buildIcon'" :type="getIcon('buildIcon')" class="tree-icon" />
34
+ <bl-icon v-if="dataRef.slotIcon === 'buildIcon'" :type="getIcon('buildIcon', dataRef)" class="tree-icon" />
35
35
  <bl-icon v-if="dataRef.slotIcon === 'layerIcon'" :type="getIcon('layerIcon')" class="tree-icon" />
36
36
  <bl-icon v-if="dataRef.slotIcon === 'roomIcon'" :type="getIcon('roomIcon')" class="tree-icon" />
37
37
  </template>
@@ -87,6 +87,9 @@ import utils from "../../common/utils/util";
87
87
  import { ROOM_TYPE_ICONS } from "../../common/utils/constant";
88
88
  import {t, loadLanguageAsync} from "../../locale";
89
89
 
90
+ const VENUE_BUILD_TYPE = 1;
91
+ const isVenueBuild = (buildType) => Number(buildType) === VENUE_BUILD_TYPE;
92
+
90
93
  export default defineComponent({
91
94
  name: "VillageTree",
92
95
  props: {
@@ -187,12 +190,11 @@ export default defineComponent({
187
190
  return props.roomType?.length && props.roomType.every((v) => [4, 5].includes(Number(v)))
188
191
  });
189
192
 
190
- const getIcon = (type) => {
191
- let icon = ROOM_TYPE_ICONS.default[type];
192
- if (props.iconType) {
193
- icon = ROOM_TYPE_ICONS[props.iconType] ? ROOM_TYPE_ICONS[props.iconType][type] : ROOM_TYPE_ICONS.default[type];
194
- }
195
- return icon;
193
+ const getIcon = (type, data = {}) => {
194
+ const iconType = type === "buildIcon" && isVenueBuild(data.build_type)
195
+ ? "area"
196
+ : props.iconType;
197
+ return ROOM_TYPE_ICONS[iconType]?.[type] || ROOM_TYPE_ICONS.default[type];
196
198
  };
197
199
 
198
200
  /** 点击选中当前项 */
@@ -539,10 +541,11 @@ export default defineComponent({
539
541
  type_txt: village.type_txt,
540
542
  },
541
543
  slotIcon: "buildIcon",
542
- isLeaf: props.display == 2 ? true : false,
544
+ // 场地没有楼层层级,作为叶子节点展示,避免继续请求楼层数据。
545
+ isLeaf: isVenueBuild(build.build_type) || props.display == 2,
543
546
  disabled : props.isdisabledNumber ? ( props.isdisabledNumber == 2 ? false : true ) : false,
544
547
  };
545
- const match = regExp.exec(build.build_name);
548
+ const match = isVenueBuild(build.build_type) ? null : regExp.exec(build.build_name);
546
549
  if (match) {
547
550
  const group1 = match[1]; // 提取"数字栋"
548
551
  if (group1.length >= 2 && build.build_name.slice(group1.length).length > 0) {
@@ -51,3 +51,5 @@ export { default as PublicExtensionField } from "./PublicExtensionField/index.vu
51
51
  export { default as BlCreateChatBtn } from "./BlChat/createChatBtn.vue";//发起讨论按钮
52
52
  export { default as BlModal } from "./BlModal/index.vue";
53
53
  export { default as BlDrawer } from "./BlDrawer/index.vue";
54
+ export { default as BlTinymceEditor } from "./BlTinymceEditor/index.vue";
55
+ export { default as PreviewFile } from "./PreviewFile/index.vue";
@@ -515,5 +515,15 @@
515
515
  "DepartmentUser.index.555981-1": "展開",
516
516
  "DepartmentUser.index.555981-2": "收起",
517
517
  "BlMobileAnnexUpload.index.676543-0": "此 QR Code 於 15 分鐘內有效",
518
- "AttchmentInfo.userShow": "對業戶开放"
518
+ "AttchmentInfo.userShow": "對業戶开放",
519
+ "PreviewFile.loading": "載入中...",
520
+ "PreviewFile.printModal.title": "提示訊息",
521
+ "PreviewFile.printModal.noticeStart": "您目前尚未開啟網頁列印插件,請先開啟或",
522
+ "PreviewFile.printModal.download": "點擊下載",
523
+ "PreviewFile.printModal.noticeEnd": "。電腦需安裝 Microsoft Word 或 WPS Office 才能使用。",
524
+ "PreviewFile.printModal.ok": "好的",
525
+ "PreviewFile.printModal.success": "發送成功",
526
+ "PreviewFile.download": "文件下載",
527
+ "PreviewFile.print": "列印文件",
528
+ "PreviewFile.defaultTitle": "預覽文件"
519
529
  }
@@ -515,5 +515,15 @@
515
515
  "DepartmentUser.index.555981-1": "Expand",
516
516
  "DepartmentUser.index.555981-2": "Collapse",
517
517
  "BlMobileAnnexUpload.index.676543-0": "This QR code is valid for 15 minutes",
518
- "AttchmentInfo.userShow": "Show to Users"
518
+ "AttchmentInfo.userShow": "Show to Users",
519
+ "PreviewFile.loading": "Loading...",
520
+ "PreviewFile.printModal.title": "Notice",
521
+ "PreviewFile.printModal.noticeStart": "The web print plugin is not open. Open it or",
522
+ "PreviewFile.printModal.download": "download it",
523
+ "PreviewFile.printModal.noticeEnd": ". Microsoft Word or WPS Office is also required.",
524
+ "PreviewFile.printModal.ok": "OK",
525
+ "PreviewFile.printModal.success": "Sent",
526
+ "PreviewFile.download": "Download File",
527
+ "PreviewFile.print": "Print File",
528
+ "PreviewFile.defaultTitle": "Preview File"
519
529
  }
@@ -515,5 +515,15 @@
515
515
  "DepartmentUser.index.555981-1": "展開",
516
516
  "DepartmentUser.index.555981-2": "折りたたむ",
517
517
  "BlMobileAnnexUpload.index.676543-0": "このQRコードは15分間有効です",
518
- "AttchmentInfo.userShow": "ユーザー表示"
518
+ "AttchmentInfo.userShow": "ユーザー表示",
519
+ "PreviewFile.loading": "読み込み中...",
520
+ "PreviewFile.printModal.title": "お知らせ",
521
+ "PreviewFile.printModal.noticeStart": "Web 印刷プラグインが起動していません。起動するか、",
522
+ "PreviewFile.printModal.download": "ダウンロードしてください",
523
+ "PreviewFile.printModal.noticeEnd": "。Microsoft Word または WPS Office も必要です。",
524
+ "PreviewFile.printModal.ok": "OK",
525
+ "PreviewFile.printModal.success": "送信しました",
526
+ "PreviewFile.download": "ファイルダウンロード",
527
+ "PreviewFile.print": "ファイル印刷",
528
+ "PreviewFile.defaultTitle": "ファイルをプレビュー"
519
529
  }
@@ -515,5 +515,15 @@
515
515
  "BlMobileAnnexUpload.index-0": "查看二維碼",
516
516
  "BlMobileAnnexUpload.index-1": "使用手機掃碼上載",
517
517
  "modules.ListFieldModal.082665-0": "選項內容不能留空",
518
- "AttchmentInfo.userShow": "對業戶开放"
518
+ "AttchmentInfo.userShow": "對業戶开放",
519
+ "PreviewFile.loading": "載入中...",
520
+ "PreviewFile.printModal.title": "提示訊息",
521
+ "PreviewFile.printModal.noticeStart": "您目前尚未開啟網頁列印插件,請先開啟或",
522
+ "PreviewFile.printModal.download": "點擊下載",
523
+ "PreviewFile.printModal.noticeEnd": "。電腦需安裝 Microsoft Word 或 WPS Office 才能使用。",
524
+ "PreviewFile.printModal.ok": "好的",
525
+ "PreviewFile.printModal.success": "發送成功",
526
+ "PreviewFile.download": "文件下載",
527
+ "PreviewFile.print": "列印文件",
528
+ "PreviewFile.defaultTitle": "預覽文件"
519
529
  }
@@ -515,5 +515,15 @@
515
515
  "DepartmentUser.index.555981-1": "展开",
516
516
  "DepartmentUser.index.555981-2": "收起",
517
517
  "BlMobileAnnexUpload.index.676543-0": "该二维码十五分钟内有效",
518
- "AttchmentInfo.userShow": "对业户开放"
518
+ "AttchmentInfo.userShow": "对业户开放",
519
+ "PreviewFile.loading": "加载中...",
520
+ "PreviewFile.printModal.title": "温馨提示",
521
+ "PreviewFile.printModal.noticeStart": "您当前没有打开网页打印插件,请先打开或者",
522
+ "PreviewFile.printModal.download": "点击下载",
523
+ "PreviewFile.printModal.noticeEnd": "。电脑需要同时安装微软word软件或者wps软件,才能使用。",
524
+ "PreviewFile.printModal.ok": "好的",
525
+ "PreviewFile.printModal.success": "发送成功",
526
+ "PreviewFile.download": "文档下载",
527
+ "PreviewFile.print": "文档打印",
528
+ "PreviewFile.defaultTitle": "预览文档"
519
529
  }