@jx3box/jx3box-ui 2.2.10 → 2.2.12
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 +1 -1
- package/service/suspend.js +2 -1
- package/src/CommonFooter.vue +5 -5
- package/src/SuspendCommon.vue +14 -4
- package/src/footer/resource.vue +519 -75
- package/src/single/SimpleThx.vue +8 -1
- package/src/stories/layout/SuspendCommon.stories.js +1 -0
- package/src/stories/single/RightAffix.stories.js +3 -0
- package/src/stories/single/SimpleThx.stories.js +2 -1
package/package.json
CHANGED
package/service/suspend.js
CHANGED
|
@@ -50,9 +50,10 @@ function later(data) {
|
|
|
50
50
|
return $next().post(`/api/next2/userdata/watch-later/item`, data);
|
|
51
51
|
}
|
|
52
52
|
// 收藏相关
|
|
53
|
-
function setCollect(id, type, post_title) {
|
|
53
|
+
function setCollect(id, type, post_title, author_id) {
|
|
54
54
|
return $next().post(`/api/article/favorites/add/${id}/${type}`, {
|
|
55
55
|
post_title: post_title,
|
|
56
|
+
author_id,
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
function getCollectList(id, type) {
|
package/src/CommonFooter.vue
CHANGED
|
@@ -33,7 +33,7 @@ import FooterResource from "./footer/resource.vue";
|
|
|
33
33
|
import FooterCopyright from "./footer/copyright.vue";
|
|
34
34
|
import i18nMixin from "../i18n/mixin";
|
|
35
35
|
export default {
|
|
36
|
-
name: "
|
|
36
|
+
name: "CommonFooter",
|
|
37
37
|
mixins: [i18nMixin],
|
|
38
38
|
components: {
|
|
39
39
|
FooterOfficial,
|
|
@@ -53,7 +53,7 @@ body::after {
|
|
|
53
53
|
bottom: 0;
|
|
54
54
|
background: #111827;
|
|
55
55
|
}
|
|
56
|
-
.c-footer--v4{
|
|
56
|
+
.c-footer--v4 {
|
|
57
57
|
box-sizing: border-box;
|
|
58
58
|
padding: 3rem 1.5rem;
|
|
59
59
|
background: #111827;
|
|
@@ -113,7 +113,7 @@ body::after {
|
|
|
113
113
|
font-size: 1.5rem;
|
|
114
114
|
line-height: 2rem;
|
|
115
115
|
font-weight: 700;
|
|
116
|
-
letter-spacing:
|
|
116
|
+
letter-spacing: 0;
|
|
117
117
|
color: #fff;
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -125,8 +125,8 @@ body::after {
|
|
|
125
125
|
color: #9ca3af;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
.u-logo{
|
|
129
|
-
fill
|
|
128
|
+
.u-logo {
|
|
129
|
+
fill: #fff;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
.c-footer--v4__popover {
|
package/src/SuspendCommon.vue
CHANGED
|
@@ -466,6 +466,7 @@ export default {
|
|
|
466
466
|
avatar: "", //作者头像
|
|
467
467
|
author_id: "", //作者id
|
|
468
468
|
},
|
|
469
|
+
author_id: "",
|
|
469
470
|
subscribeType: "", //订阅类型,用于区分调用百科、文章、作者、帖子等订阅接口,
|
|
470
471
|
postType: "", //订阅、收藏接口的type,如'face','bps','article'等
|
|
471
472
|
id: "", //页面数据ID,用于收藏订阅操作
|
|
@@ -500,6 +501,15 @@ export default {
|
|
|
500
501
|
fixIsActive() {
|
|
501
502
|
return this.fixList.some((item) => item.url === this.fixPageConfig.url);
|
|
502
503
|
},
|
|
504
|
+
authorId() {
|
|
505
|
+
return this.drawerConfig.author_id || this.drawerConfig.author?.author_id || "";
|
|
506
|
+
},
|
|
507
|
+
subscribeData() {
|
|
508
|
+
return {
|
|
509
|
+
title: this.drawerConfig.title,
|
|
510
|
+
author_id: this.authorId,
|
|
511
|
+
};
|
|
512
|
+
},
|
|
503
513
|
},
|
|
504
514
|
mounted() {
|
|
505
515
|
this.fixList = JSON.parse(localStorage.getItem(this.fixPageConfig.key)) || [];
|
|
@@ -590,7 +600,7 @@ export default {
|
|
|
590
600
|
this.collectInfo = {};
|
|
591
601
|
});
|
|
592
602
|
} else {
|
|
593
|
-
setCollect(conf.id, conf.postType, conf.title).then((res) => {
|
|
603
|
+
setCollect(conf.id, conf.postType, conf.title, this.authorId).then((res) => {
|
|
594
604
|
this.isCollect = true;
|
|
595
605
|
this.collectInfo = res.data?.data;
|
|
596
606
|
});
|
|
@@ -629,7 +639,7 @@ export default {
|
|
|
629
639
|
this.$emit("subscribe", { isSubscribe: false });
|
|
630
640
|
});
|
|
631
641
|
} else {
|
|
632
|
-
subscribePost(conf.id,
|
|
642
|
+
subscribePost(conf.id, this.subscribeData).then((res) => {
|
|
633
643
|
this.isSubscribe = true;
|
|
634
644
|
this.subscribeInfo = res.data?.data;
|
|
635
645
|
this.$emit("subscribe", { isSubscribe: true });
|
|
@@ -644,7 +654,7 @@ export default {
|
|
|
644
654
|
this.$emit("subscribe", { isSubscribe: false });
|
|
645
655
|
});
|
|
646
656
|
} else {
|
|
647
|
-
subscribeArticle(conf.postType, conf.id,
|
|
657
|
+
subscribeArticle(conf.postType, conf.id, this.subscribeData).then((res) => {
|
|
648
658
|
this.isSubscribe = true;
|
|
649
659
|
this.subscribeInfo = res.data?.data;
|
|
650
660
|
this.$emit("subscribe", { isSubscribe: true });
|
|
@@ -659,7 +669,7 @@ export default {
|
|
|
659
669
|
this.$emit("subscribe", { isSubscribe: false });
|
|
660
670
|
});
|
|
661
671
|
} else {
|
|
662
|
-
subscribeWiki(conf.postType, conf.id,
|
|
672
|
+
subscribeWiki(conf.postType, conf.id, this.subscribeData).then((res) => {
|
|
663
673
|
this.isSubscribe = true;
|
|
664
674
|
this.subscribeInfo = res.data?.data;
|
|
665
675
|
this.$emit("subscribe", { isSubscribe: true });
|
package/src/footer/resource.vue
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{{ $jx3boxT("jx3boxUi.commonFooter.downloadCenter", "下载中心") }}
|
|
5
5
|
</h3>
|
|
6
6
|
<div class="c-footer-resource__grid">
|
|
7
|
-
<div v-for="item in downloadLinks" :key="item.
|
|
7
|
+
<div v-for="item in downloadLinks" :key="item.key">
|
|
8
8
|
<el-popover v-if="item.qrcode" trigger="hover" placement="top" popper-class="c-footer--v4__popover">
|
|
9
9
|
<div class="c-footer-resource__qrcode">
|
|
10
10
|
<img
|
|
@@ -15,58 +15,26 @@
|
|
|
15
15
|
<span class="c-footer-resource__qrcode-label">{{ getDownloadLabel(item) }}</span>
|
|
16
16
|
</div>
|
|
17
17
|
<template #reference>
|
|
18
|
-
<
|
|
19
|
-
class="c-footer-resource__download"
|
|
20
|
-
:href="item.href || '#'"
|
|
21
|
-
:target="item.href ? '_blank' : null"
|
|
22
|
-
:rel="item.href ? 'noopener noreferrer' : null"
|
|
23
|
-
@click="handleLinkClick($event, item)"
|
|
24
|
-
>
|
|
18
|
+
<button class="c-footer-resource__download" type="button">
|
|
25
19
|
<span class="c-footer-resource__download-icon">
|
|
26
|
-
<img :src="item.icon"
|
|
20
|
+
<img :src="item.icon" alt="" aria-hidden="true" />
|
|
27
21
|
</span>
|
|
28
22
|
<span>{{ getDownloadName(item) }}</span>
|
|
29
|
-
</
|
|
23
|
+
</button>
|
|
30
24
|
</template>
|
|
31
25
|
</el-popover>
|
|
32
|
-
<
|
|
33
|
-
v-else-if="item.placeholder"
|
|
34
|
-
trigger="hover"
|
|
35
|
-
placement="top"
|
|
36
|
-
:show-after="150"
|
|
37
|
-
popper-class="c-footer--v4__popover"
|
|
38
|
-
>
|
|
39
|
-
<div class="c-footer-resource__placeholder">
|
|
40
|
-
{{ item.placeholder }}
|
|
41
|
-
</div>
|
|
42
|
-
<template #reference>
|
|
43
|
-
<a
|
|
44
|
-
class="c-footer-resource__download"
|
|
45
|
-
:href="item.href || '#'"
|
|
46
|
-
:target="item.href ? '_blank' : null"
|
|
47
|
-
:rel="item.href ? 'noopener noreferrer' : null"
|
|
48
|
-
@click="handleLinkClick($event, item)"
|
|
49
|
-
>
|
|
50
|
-
<span class="c-footer-resource__download-icon">
|
|
51
|
-
<img :src="item.icon" :alt="getDownloadName(item)" />
|
|
52
|
-
</span>
|
|
53
|
-
<span>{{ getDownloadName(item) }}</span>
|
|
54
|
-
</a>
|
|
55
|
-
</template>
|
|
56
|
-
</el-popover>
|
|
57
|
-
<a
|
|
26
|
+
<button
|
|
58
27
|
v-else
|
|
59
28
|
class="c-footer-resource__download"
|
|
60
|
-
:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@click="handleLinkClick($event, item)"
|
|
29
|
+
:class="{ 'is-active': activePlatform === item.key && downloadDialogVisible }"
|
|
30
|
+
type="button"
|
|
31
|
+
@click="openDownloadDialog(item)"
|
|
64
32
|
>
|
|
65
33
|
<span class="c-footer-resource__download-icon">
|
|
66
|
-
<img :src="item.icon"
|
|
34
|
+
<img :src="item.icon" alt="" aria-hidden="true" />
|
|
67
35
|
</span>
|
|
68
36
|
<span>{{ getDownloadName(item) }}</span>
|
|
69
|
-
</
|
|
37
|
+
</button>
|
|
70
38
|
</div>
|
|
71
39
|
</div>
|
|
72
40
|
|
|
@@ -98,75 +66,286 @@
|
|
|
98
66
|
{{ $jx3boxT("jx3boxUi.commonFooter.add", "添加") }}
|
|
99
67
|
</a>
|
|
100
68
|
</div>
|
|
69
|
+
|
|
70
|
+
<el-dialog
|
|
71
|
+
v-model="downloadDialogVisible"
|
|
72
|
+
:title="activeDialogTitle"
|
|
73
|
+
width="960px"
|
|
74
|
+
class="m-footer-app-dialog"
|
|
75
|
+
>
|
|
76
|
+
<div
|
|
77
|
+
v-loading="appConfigLoading"
|
|
78
|
+
class="m-footer-app-download"
|
|
79
|
+
>
|
|
80
|
+
<div class="u-app-header">
|
|
81
|
+
<img class="u-app-icon" :src="appLogo" :alt="appName" @error="handleLogoError" />
|
|
82
|
+
<div class="u-app-meta">
|
|
83
|
+
<div class="u-app-name">{{ appName }}</div>
|
|
84
|
+
<div class="u-app-version">{{ appVersion }}</div>
|
|
85
|
+
<div
|
|
86
|
+
v-if="appDescription"
|
|
87
|
+
class="u-app-desc-box"
|
|
88
|
+
:class="{
|
|
89
|
+
'is-expanded': appDescExpanded,
|
|
90
|
+
'is-foldable': hasDescFold(appDescription),
|
|
91
|
+
}"
|
|
92
|
+
@click="toggleAppDesc"
|
|
93
|
+
>
|
|
94
|
+
<el-icon v-if="hasDescFold(appDescription)" class="u-desc-toggle">
|
|
95
|
+
<ArrowUp v-if="appDescExpanded" />
|
|
96
|
+
<ArrowDown v-else />
|
|
97
|
+
</el-icon>
|
|
98
|
+
<div class="u-app-desc">
|
|
99
|
+
{{ getFoldedDesc(appDescription, appDescExpanded) }}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="u-app-download-action">
|
|
104
|
+
<el-button
|
|
105
|
+
class="u-app-store-button"
|
|
106
|
+
type="primary"
|
|
107
|
+
:disabled="!activeDownloadUrl"
|
|
108
|
+
@click="openActiveDownload"
|
|
109
|
+
>
|
|
110
|
+
<el-icon class="u-button-icon"><Download /></el-icon>
|
|
111
|
+
<span>{{ activeDownloadText }}</span>
|
|
112
|
+
</el-button>
|
|
113
|
+
<div v-if="activePlatform === 'android'" class="u-app-download-tip">
|
|
114
|
+
仅支持 Android 10 及以上系统
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div class="u-app-preview">
|
|
120
|
+
<div class="u-app-preview-tabs">
|
|
121
|
+
<button
|
|
122
|
+
v-for="device in previewDevices"
|
|
123
|
+
:key="device.key"
|
|
124
|
+
type="button"
|
|
125
|
+
class="u-preview-tab"
|
|
126
|
+
:class="{ 'is-active': activePreviewDevice === device.key }"
|
|
127
|
+
@click="activePreviewDevice = device.key"
|
|
128
|
+
>
|
|
129
|
+
{{ device.label }}
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="u-app-preview-list" :class="`is-${activePreviewDevice}`">
|
|
134
|
+
<div v-for="image in currentPreviewImages" :key="image" class="u-app-preview-card">
|
|
135
|
+
<el-image
|
|
136
|
+
class="u-app-preview-image"
|
|
137
|
+
:src="image"
|
|
138
|
+
:preview-src-list="currentPreviewImages"
|
|
139
|
+
:initial-index="currentPreviewImages.indexOf(image)"
|
|
140
|
+
fit="cover"
|
|
141
|
+
preview-teleported
|
|
142
|
+
/>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</el-dialog>
|
|
101
148
|
</section>
|
|
102
149
|
</template>
|
|
103
150
|
|
|
104
151
|
<script>
|
|
152
|
+
import { ArrowDown, ArrowUp, Download } from "@element-plus/icons-vue";
|
|
105
153
|
import { copyText } from "../../utils";
|
|
106
154
|
import i18nMixin from "../../i18n/mixin";
|
|
155
|
+
import { getConfig } from "../../service/cms";
|
|
156
|
+
|
|
157
|
+
const APP_LOGO_FALLBACK = "https://cdn.jx3box.com/design/app/logo/jx3box-icon-512.png";
|
|
158
|
+
const APPLE_STORE_LINK = "https://apps.apple.com/cn/app/id6761459300";
|
|
159
|
+
const HARMONY_STORE_LINK = "https://appgallery.huawei.com/app/xxx";
|
|
160
|
+
const APP_CONFIG_KEYS = ["android_apk", "android_versions", "app_logo", "app_version_desc"];
|
|
161
|
+
|
|
107
162
|
export default {
|
|
108
163
|
name: "FooterResource",
|
|
109
164
|
mixins: [i18nMixin],
|
|
110
165
|
props: [],
|
|
111
|
-
components: {},
|
|
166
|
+
components: { ArrowDown, ArrowUp, Download },
|
|
112
167
|
data: function () {
|
|
113
168
|
return {
|
|
169
|
+
downloadDialogVisible: false,
|
|
170
|
+
activePlatform: "appStore",
|
|
171
|
+
activePreviewDevice: "phone",
|
|
172
|
+
appDescExpanded: false,
|
|
173
|
+
appConfig: {},
|
|
174
|
+
appConfigLoading: false,
|
|
175
|
+
appConfigLoaded: false,
|
|
176
|
+
previewDevices: [
|
|
177
|
+
{ key: "phone", label: "Phone" },
|
|
178
|
+
{ key: "pad", label: "Pad" },
|
|
179
|
+
],
|
|
180
|
+
previewImages: {
|
|
181
|
+
phone: [
|
|
182
|
+
"https://cdn.jx3box.com/design/app/phone/phone1.jpg",
|
|
183
|
+
"https://cdn.jx3box.com/design/app/phone/phone2.jpg",
|
|
184
|
+
"https://cdn.jx3box.com/design/app/phone/phone3.jpg",
|
|
185
|
+
],
|
|
186
|
+
pad: [
|
|
187
|
+
"https://cdn.jx3box.com/design/app/pad/pad1.jpg",
|
|
188
|
+
"https://cdn.jx3box.com/design/app/pad/pad2.jpg",
|
|
189
|
+
"https://cdn.jx3box.com/design/app/pad/pad3.jpg",
|
|
190
|
+
],
|
|
191
|
+
},
|
|
114
192
|
downloadLinks: [
|
|
115
193
|
{
|
|
116
194
|
key: "appStore",
|
|
117
195
|
name: "App Store",
|
|
118
|
-
href: "",
|
|
119
196
|
icon: require("../../assets/img/common/ios.svg"),
|
|
120
|
-
// qrcode: require("../../assets/img/common/ios.jpg"),
|
|
121
|
-
placeholder: "即将上线",
|
|
122
197
|
},
|
|
123
198
|
{
|
|
124
199
|
key: "android",
|
|
125
200
|
name: "Android",
|
|
126
|
-
href: "",
|
|
127
201
|
icon: require("../../assets/img/common/android.svg"),
|
|
128
|
-
// qrcode: require("../../assets/img/common/android.jpg"),
|
|
129
|
-
placeholder: "即将上线",
|
|
130
202
|
},
|
|
131
203
|
{
|
|
132
204
|
key: "harmonyNext",
|
|
133
205
|
name: "鸿蒙 NEXT",
|
|
134
|
-
href: "",
|
|
135
206
|
icon: require("../../assets/img/common/harmony.svg"),
|
|
136
|
-
// qrcode: require("../../assets/img/common/harmony.jpg"),
|
|
137
|
-
placeholder: "即将上线",
|
|
138
207
|
},
|
|
139
208
|
{
|
|
140
209
|
key: "miniProgram",
|
|
141
210
|
name: "小程序",
|
|
142
211
|
labelKey: "jx3boxHelper",
|
|
143
212
|
label: "JX3BOX小助手",
|
|
144
|
-
href: "",
|
|
145
213
|
icon: require("../../assets/img/common/miniprogram.svg"),
|
|
146
214
|
qrcode: require("../../assets/img/common/miniprogram.jpg"),
|
|
147
215
|
},
|
|
148
216
|
],
|
|
149
217
|
};
|
|
150
218
|
},
|
|
151
|
-
computed: {
|
|
219
|
+
computed: {
|
|
220
|
+
activePlatformItem() {
|
|
221
|
+
return this.downloadLinks.find((item) => item.key === this.activePlatform) || this.downloadLinks[0];
|
|
222
|
+
},
|
|
223
|
+
activePlatformLabel() {
|
|
224
|
+
return this.getDownloadName(this.activePlatformItem);
|
|
225
|
+
},
|
|
226
|
+
activeDialogTitle() {
|
|
227
|
+
const map = {
|
|
228
|
+
appStore: "App Store",
|
|
229
|
+
android: "Android",
|
|
230
|
+
harmonyNext: "鸿蒙NEXT",
|
|
231
|
+
};
|
|
232
|
+
return map[this.activePlatform] || this.activePlatformLabel;
|
|
233
|
+
},
|
|
234
|
+
appLogo() {
|
|
235
|
+
return this.appConfig.app_logo || APP_LOGO_FALLBACK;
|
|
236
|
+
},
|
|
237
|
+
appName() {
|
|
238
|
+
return "魔盒APP";
|
|
239
|
+
},
|
|
240
|
+
appVersion() {
|
|
241
|
+
return this.appConfig.android_versions || "";
|
|
242
|
+
},
|
|
243
|
+
appDescription() {
|
|
244
|
+
return this.appConfig.app_version_desc || "";
|
|
245
|
+
},
|
|
246
|
+
androidDownloadUrl() {
|
|
247
|
+
return this.appConfig.android_apk || "";
|
|
248
|
+
},
|
|
249
|
+
activeDownloadUrl() {
|
|
250
|
+
if (this.activePlatform === "android") return this.androidDownloadUrl;
|
|
251
|
+
if (this.activePlatform === "harmonyNext") return HARMONY_STORE_LINK;
|
|
252
|
+
return APPLE_STORE_LINK;
|
|
253
|
+
},
|
|
254
|
+
activeDownloadText() {
|
|
255
|
+
const map = {
|
|
256
|
+
appStore: "前往苹果商店",
|
|
257
|
+
android: "下载 Android",
|
|
258
|
+
harmonyNext: "前往鸿蒙商店",
|
|
259
|
+
};
|
|
260
|
+
return map[this.activePlatform] || "立即下载";
|
|
261
|
+
},
|
|
262
|
+
currentPreviewImages() {
|
|
263
|
+
return this.previewImages[this.activePreviewDevice] || [];
|
|
264
|
+
},
|
|
265
|
+
},
|
|
152
266
|
watch: {},
|
|
153
267
|
methods: {
|
|
154
268
|
copyText,
|
|
155
269
|
getDownloadName(item) {
|
|
156
|
-
if (item?.key)
|
|
157
|
-
|
|
158
|
-
const maybe = `jx3boxUi.commonFooter.${k}`;
|
|
159
|
-
return this.$jx3boxT(maybe, item.name || k);
|
|
160
|
-
}
|
|
161
|
-
return item?.name || "";
|
|
270
|
+
if (!item?.key) return item?.name || "";
|
|
271
|
+
return this.$jx3boxT(`jx3boxUi.commonFooter.${item.key}`, item.name || item.key);
|
|
162
272
|
},
|
|
163
273
|
getDownloadLabel(item) {
|
|
164
|
-
if (item?.labelKey)
|
|
274
|
+
if (item?.labelKey) {
|
|
165
275
|
return this.$jx3boxT(`jx3boxUi.commonFooter.${item.labelKey}`, item.label || item.labelKey);
|
|
276
|
+
}
|
|
166
277
|
return item?.label || "";
|
|
167
278
|
},
|
|
168
|
-
|
|
169
|
-
|
|
279
|
+
openDownloadDialog(item) {
|
|
280
|
+
this.activePlatform = item.key;
|
|
281
|
+
this.activePreviewDevice = "phone";
|
|
282
|
+
this.appDescExpanded = false;
|
|
283
|
+
this.downloadDialogVisible = true;
|
|
284
|
+
this.loadAppConfig();
|
|
285
|
+
},
|
|
286
|
+
openActiveDownload() {
|
|
287
|
+
if (!this.activeDownloadUrl) return;
|
|
288
|
+
window.open(this.activeDownloadUrl, "_blank", "noopener,noreferrer");
|
|
289
|
+
},
|
|
290
|
+
loadAppConfig() {
|
|
291
|
+
const storeConfig = this.getStoreAppConfig();
|
|
292
|
+
if (storeConfig) {
|
|
293
|
+
this.appConfig = {
|
|
294
|
+
...this.appConfig,
|
|
295
|
+
...storeConfig,
|
|
296
|
+
};
|
|
297
|
+
this.appConfigLoaded = true;
|
|
298
|
+
return Promise.resolve();
|
|
299
|
+
}
|
|
300
|
+
if (this.appConfigLoading || this.appConfigLoaded) return Promise.resolve();
|
|
301
|
+
this.appConfigLoading = true;
|
|
302
|
+
return getConfig({ subtype: "app" })
|
|
303
|
+
.then((items) => {
|
|
304
|
+
this.appConfig = this.getAppConfigFromItems(items);
|
|
305
|
+
this.appConfigLoaded = true;
|
|
306
|
+
})
|
|
307
|
+
.catch(() => {
|
|
308
|
+
this.appConfig = {};
|
|
309
|
+
})
|
|
310
|
+
.finally(() => {
|
|
311
|
+
this.appConfigLoading = false;
|
|
312
|
+
});
|
|
313
|
+
},
|
|
314
|
+
getStoreAppConfig() {
|
|
315
|
+
const config = this.$store?.state?.config || {};
|
|
316
|
+
const appConfig = APP_CONFIG_KEYS.reduce((result, key) => {
|
|
317
|
+
if (config[key]) result[key] = config[key];
|
|
318
|
+
return result;
|
|
319
|
+
}, {});
|
|
320
|
+
return Object.keys(appConfig).length ? appConfig : null;
|
|
321
|
+
},
|
|
322
|
+
getAppConfigFromItems(items) {
|
|
323
|
+
if (!Array.isArray(items)) return {};
|
|
324
|
+
return items.reduce((config, item) => {
|
|
325
|
+
if (!item?.key || !APP_CONFIG_KEYS.includes(item.key)) return config;
|
|
326
|
+
if (item.subtype && item.subtype !== "app") return config;
|
|
327
|
+
config[item.key] = item.val;
|
|
328
|
+
return config;
|
|
329
|
+
}, {});
|
|
330
|
+
},
|
|
331
|
+
getDescLines(description) {
|
|
332
|
+
return String(description || "")
|
|
333
|
+
.replace(/\\r\\n|\\n|\\r/g, "\n")
|
|
334
|
+
.split(/\r?\n/);
|
|
335
|
+
},
|
|
336
|
+
hasDescFold(description) {
|
|
337
|
+
return this.getDescLines(description).length > 1;
|
|
338
|
+
},
|
|
339
|
+
getFoldedDesc(description, expanded = false) {
|
|
340
|
+
const lines = this.getDescLines(description);
|
|
341
|
+
return expanded ? lines.join("\n") : lines[0] || "";
|
|
342
|
+
},
|
|
343
|
+
toggleAppDesc() {
|
|
344
|
+
if (!this.hasDescFold(this.appDescription)) return;
|
|
345
|
+
this.appDescExpanded = !this.appDescExpanded;
|
|
346
|
+
},
|
|
347
|
+
handleLogoError(e) {
|
|
348
|
+
e.target.src = APP_LOGO_FALLBACK;
|
|
170
349
|
},
|
|
171
350
|
gotoQQbot() {
|
|
172
351
|
window.open("/qqbot", "_blank");
|
|
@@ -190,7 +369,7 @@ export default {
|
|
|
190
369
|
font-size: 14px;
|
|
191
370
|
font-weight: 600;
|
|
192
371
|
line-height: 20px;
|
|
193
|
-
letter-spacing: 0
|
|
372
|
+
letter-spacing: 0;
|
|
194
373
|
}
|
|
195
374
|
|
|
196
375
|
&__grid {
|
|
@@ -225,17 +404,10 @@ export default {
|
|
|
225
404
|
line-height: 16px;
|
|
226
405
|
}
|
|
227
406
|
|
|
228
|
-
&__placeholder {
|
|
229
|
-
padding: 12px;
|
|
230
|
-
text-align: center;
|
|
231
|
-
font-size: 12px;
|
|
232
|
-
font-weight: 600;
|
|
233
|
-
line-height: 16px;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
407
|
&__download {
|
|
237
408
|
display: flex;
|
|
238
409
|
align-items: center;
|
|
410
|
+
width: 100%;
|
|
239
411
|
height: 48px;
|
|
240
412
|
padding: 0 16px;
|
|
241
413
|
border: 1px solid #374151;
|
|
@@ -244,12 +416,16 @@ export default {
|
|
|
244
416
|
color: #d1d5db;
|
|
245
417
|
font-size: 12px;
|
|
246
418
|
line-height: 16px;
|
|
419
|
+
text-align: left;
|
|
247
420
|
text-decoration: none;
|
|
248
|
-
|
|
421
|
+
cursor: pointer;
|
|
422
|
+
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
|
|
249
423
|
|
|
250
|
-
&:hover
|
|
424
|
+
&:hover,
|
|
425
|
+
&.is-active {
|
|
251
426
|
border-color: #3b82f6;
|
|
252
427
|
background: #374151;
|
|
428
|
+
color: #fff;
|
|
253
429
|
}
|
|
254
430
|
}
|
|
255
431
|
|
|
@@ -260,6 +436,7 @@ export default {
|
|
|
260
436
|
width: 16px;
|
|
261
437
|
height: 16px;
|
|
262
438
|
margin-right: 10px;
|
|
439
|
+
flex-shrink: 0;
|
|
263
440
|
|
|
264
441
|
img {
|
|
265
442
|
display: block;
|
|
@@ -317,7 +494,7 @@ export default {
|
|
|
317
494
|
font-size: 10px;
|
|
318
495
|
font-weight: 700;
|
|
319
496
|
line-height: 14px;
|
|
320
|
-
letter-spacing: 0
|
|
497
|
+
letter-spacing: 0;
|
|
321
498
|
text-transform: uppercase;
|
|
322
499
|
}
|
|
323
500
|
|
|
@@ -346,4 +523,271 @@ export default {
|
|
|
346
523
|
}
|
|
347
524
|
}
|
|
348
525
|
}
|
|
526
|
+
|
|
527
|
+
.m-footer-app-dialog {
|
|
528
|
+
margin-top: 5vh !important;
|
|
529
|
+
width: min(960px, calc(100vw - 32px)) !important;
|
|
530
|
+
|
|
531
|
+
.el-dialog__header {
|
|
532
|
+
margin-right: 0;
|
|
533
|
+
padding: 20px 24px 12px;
|
|
534
|
+
border-bottom: 1px solid #e5eaf4;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.el-dialog__title {
|
|
538
|
+
color: #1f2937;
|
|
539
|
+
font-size: 18px;
|
|
540
|
+
font-weight: 700;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.el-dialog__body {
|
|
544
|
+
padding: 24px;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.m-footer-app-download {
|
|
548
|
+
min-height: 280px;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.u-app-header {
|
|
552
|
+
display: flex;
|
|
553
|
+
align-items: flex-start;
|
|
554
|
+
gap: 16px;
|
|
555
|
+
padding: 0 0 24px;
|
|
556
|
+
border-bottom: 1px solid #e5eaf4;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.u-app-icon {
|
|
560
|
+
width: 72px;
|
|
561
|
+
height: 72px;
|
|
562
|
+
border: 1px solid #e5eaf4;
|
|
563
|
+
border-radius: 18px;
|
|
564
|
+
object-fit: cover;
|
|
565
|
+
flex-shrink: 0;
|
|
566
|
+
box-shadow: 0 10px 24px rgba(79, 115, 201, 0.14);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.u-app-meta {
|
|
570
|
+
flex: 1;
|
|
571
|
+
min-width: 0;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.u-app-name {
|
|
575
|
+
color: #111827;
|
|
576
|
+
font-size: 22px;
|
|
577
|
+
font-weight: 700;
|
|
578
|
+
line-height: 1.3;
|
|
579
|
+
word-break: break-word;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.u-app-version {
|
|
583
|
+
margin-top: 6px;
|
|
584
|
+
color: #2d63ef;
|
|
585
|
+
font-size: 14px;
|
|
586
|
+
font-weight: 600;
|
|
587
|
+
line-height: 1.5;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.u-app-desc-box {
|
|
591
|
+
display: flex;
|
|
592
|
+
align-items: flex-start;
|
|
593
|
+
gap: 6px;
|
|
594
|
+
margin-top: 10px;
|
|
595
|
+
color: #4b5563;
|
|
596
|
+
|
|
597
|
+
&.is-foldable {
|
|
598
|
+
cursor: pointer;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
&.is-expanded {
|
|
602
|
+
.u-app-desc {
|
|
603
|
+
display: block;
|
|
604
|
+
white-space: pre-wrap;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.u-desc-toggle {
|
|
610
|
+
margin-top: 6px;
|
|
611
|
+
color: #8a94a6;
|
|
612
|
+
flex-shrink: 0;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.u-app-desc {
|
|
616
|
+
display: -webkit-box;
|
|
617
|
+
overflow: hidden;
|
|
618
|
+
color: #4b5563;
|
|
619
|
+
font-size: 14px;
|
|
620
|
+
line-height: 1.8;
|
|
621
|
+
white-space: pre-wrap;
|
|
622
|
+
word-break: break-word;
|
|
623
|
+
-webkit-box-orient: vertical;
|
|
624
|
+
-webkit-line-clamp: 1;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.u-app-download-action {
|
|
628
|
+
margin-left: auto;
|
|
629
|
+
flex-shrink: 0;
|
|
630
|
+
display: flex;
|
|
631
|
+
flex-direction: column;
|
|
632
|
+
align-items: flex-end;
|
|
633
|
+
gap: 8px;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.u-app-store-button {
|
|
637
|
+
flex-shrink: 0;
|
|
638
|
+
|
|
639
|
+
.u-button-icon {
|
|
640
|
+
margin-right: 6px;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.u-app-download-tip {
|
|
645
|
+
color: #8a94a6;
|
|
646
|
+
font-size: 12px;
|
|
647
|
+
line-height: 18px;
|
|
648
|
+
white-space: nowrap;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.u-app-preview {
|
|
652
|
+
padding-top: 24px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.u-app-preview-tabs {
|
|
656
|
+
display: flex;
|
|
657
|
+
justify-content: center;
|
|
658
|
+
gap: 12px;
|
|
659
|
+
margin-bottom: 20px;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.u-preview-tab {
|
|
663
|
+
min-width: 108px;
|
|
664
|
+
padding: 10px 18px;
|
|
665
|
+
border: 1px solid #d7e1f5;
|
|
666
|
+
border-radius: 999px;
|
|
667
|
+
background: #f7f9fe;
|
|
668
|
+
color: #5c6b84;
|
|
669
|
+
font-size: 14px;
|
|
670
|
+
font-weight: 600;
|
|
671
|
+
cursor: pointer;
|
|
672
|
+
transition: all 0.2s ease;
|
|
673
|
+
|
|
674
|
+
&:hover {
|
|
675
|
+
border-color: #9ab6ff;
|
|
676
|
+
color: #2d63ef;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
&.is-active {
|
|
680
|
+
border-color: #4f73c9;
|
|
681
|
+
background: linear-gradient(135deg, #eff4ff 0%, #dfe9ff 100%);
|
|
682
|
+
color: #2349a6;
|
|
683
|
+
box-shadow: 0 10px 20px rgba(79, 115, 201, 0.16);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.u-app-preview-list {
|
|
688
|
+
display: grid;
|
|
689
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
690
|
+
gap: 16px;
|
|
691
|
+
|
|
692
|
+
&.is-phone {
|
|
693
|
+
.u-app-preview-card {
|
|
694
|
+
aspect-ratio: 9 / 16;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
&.is-pad {
|
|
699
|
+
.u-app-preview-card {
|
|
700
|
+
aspect-ratio: 3 / 4;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.u-app-preview-card {
|
|
706
|
+
padding: 10px;
|
|
707
|
+
border: 1px solid #e0e8f7;
|
|
708
|
+
border-radius: 18px;
|
|
709
|
+
background: linear-gradient(180deg, #f9fbff 0%, #eef3ff 100%);
|
|
710
|
+
box-shadow: 0 10px 24px rgba(79, 115, 201, 0.08);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.u-app-preview-image {
|
|
714
|
+
display: block;
|
|
715
|
+
width: 100%;
|
|
716
|
+
height: 100%;
|
|
717
|
+
overflow: hidden;
|
|
718
|
+
border-radius: 12px;
|
|
719
|
+
background: #fff;
|
|
720
|
+
cursor: pointer;
|
|
721
|
+
|
|
722
|
+
.el-image__inner {
|
|
723
|
+
width: 100%;
|
|
724
|
+
height: 100%;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
@media screen and (max-width: @phone) {
|
|
730
|
+
.m-footer-app-dialog {
|
|
731
|
+
width: calc(100vw - 24px) !important;
|
|
732
|
+
|
|
733
|
+
.el-dialog__header {
|
|
734
|
+
padding: 18px 16px 12px;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.el-dialog__body {
|
|
738
|
+
padding: 16px;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
.u-app-header {
|
|
742
|
+
display: grid;
|
|
743
|
+
grid-template-columns: 64px minmax(0, 1fr);
|
|
744
|
+
gap: 14px;
|
|
745
|
+
padding-bottom: 18px;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.u-app-icon {
|
|
749
|
+
width: 64px;
|
|
750
|
+
height: 64px;
|
|
751
|
+
border-radius: 16px;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.u-app-name {
|
|
755
|
+
font-size: 20px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.u-app-download-action {
|
|
759
|
+
grid-column: 1 / -1;
|
|
760
|
+
width: 100%;
|
|
761
|
+
margin-left: 0;
|
|
762
|
+
align-items: stretch;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.u-app-store-button {
|
|
766
|
+
width: 100%;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.u-app-download-tip {
|
|
770
|
+
text-align: center;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.u-app-preview {
|
|
774
|
+
padding-top: 18px;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.u-app-preview-tabs {
|
|
778
|
+
gap: 10px;
|
|
779
|
+
margin-bottom: 16px;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.u-preview-tab {
|
|
783
|
+
min-width: 0;
|
|
784
|
+
flex: 1;
|
|
785
|
+
padding: 10px 12px;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.u-app-preview-list {
|
|
789
|
+
grid-template-columns: 1fr;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
349
793
|
</style>
|
package/src/single/SimpleThx.vue
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
:client="client"
|
|
17
17
|
/>
|
|
18
18
|
<Like :postId="postId" :postType="postType"></Like>
|
|
19
|
-
<fav :postId="postId" :postType="postType" :postTitle="postTitle" :author_id="
|
|
19
|
+
<fav :postId="postId" :postType="postType" :postTitle="postTitle" :author_id="postAuthorId"></fav>
|
|
20
20
|
<boxcoin-user
|
|
21
21
|
:postId="postId"
|
|
22
22
|
:postType="postType"
|
|
@@ -96,6 +96,10 @@ export default {
|
|
|
96
96
|
type: [Number, String],
|
|
97
97
|
default: 0,
|
|
98
98
|
},
|
|
99
|
+
authorId: {
|
|
100
|
+
type: [Number, String],
|
|
101
|
+
default: 0,
|
|
102
|
+
},
|
|
99
103
|
authors: {
|
|
100
104
|
type: Array,
|
|
101
105
|
default: () => [],
|
|
@@ -150,6 +154,9 @@ export default {
|
|
|
150
154
|
post_keys: function () {
|
|
151
155
|
return [this.postId, this.postType];
|
|
152
156
|
},
|
|
157
|
+
postAuthorId: function () {
|
|
158
|
+
return this.authorId || this.userId;
|
|
159
|
+
},
|
|
153
160
|
},
|
|
154
161
|
watch: {
|
|
155
162
|
post_keys: {
|
|
@@ -13,6 +13,7 @@ const meta = {
|
|
|
13
13
|
postId: { control: 'number' },
|
|
14
14
|
postType: { control: 'text' },
|
|
15
15
|
postTitle: { control: 'text' },
|
|
16
|
+
authorId: { control: 'number' },
|
|
16
17
|
showComment: { control: 'boolean' },
|
|
17
18
|
},
|
|
18
19
|
};
|
|
@@ -24,6 +25,7 @@ export const Default = {
|
|
|
24
25
|
postId: 80449,
|
|
25
26
|
postType: 'bbs',
|
|
26
27
|
postTitle: '轻剑驭风版本攻略示例',
|
|
28
|
+
authorId: 8,
|
|
27
29
|
showComment: true,
|
|
28
30
|
},
|
|
29
31
|
render: (args) => ({
|
|
@@ -58,6 +60,7 @@ export const Default = {
|
|
|
58
60
|
{ name: 'postId', type: 'String | Number', default: '""', description: '当前文章 ID,用于收藏查询。' },
|
|
59
61
|
{ name: 'postType', type: 'String', default: '""', description: '文章类型,例如 bbs / pvx。' },
|
|
60
62
|
{ name: 'postTitle', type: 'String', default: '""', description: '文章标题,用于收藏请求。' },
|
|
63
|
+
{ name: 'authorId', type: 'String | Number', default: '""', description: '收藏请求携带的作者 UID。' },
|
|
61
64
|
{ name: 'showComment', type: 'Boolean | Number', default: 'false', description: '是否展示评论入口按钮。' },
|
|
62
65
|
],
|
|
63
66
|
};
|
|
@@ -22,6 +22,7 @@ export const Default = {
|
|
|
22
22
|
{ name: 'postType', type: 'String', default: '""', required: true, description: '文章类型。' },
|
|
23
23
|
{ name: 'postTitle', type: 'String', default: '""', description: '文章标题。' },
|
|
24
24
|
{ name: 'userId', type: 'Number | String', default: '0', description: '作者 UID。' },
|
|
25
|
+
{ name: 'authorId', type: 'Number | String', default: '0', description: '收藏请求携带的作者 UID,未传时回退到 userId。' },
|
|
25
26
|
{ name: 'adminBoxcoinEnable / userBoxcoinEnable', type: 'Boolean', default: 'false', description: '控制打赏区显示。' },
|
|
26
27
|
{ name: 'presetConfig', type: 'Object', default: '{}', description: 'Storybook 下可直接注入打赏配置,避免空态。' },
|
|
27
28
|
],
|
|
@@ -30,7 +31,7 @@ export const Default = {
|
|
|
30
31
|
template: `
|
|
31
32
|
<div style="display:grid;gap:24px;">
|
|
32
33
|
<section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);">
|
|
33
|
-
<SimpleThx post-type="bbs" post-title="轻剑驭风版本攻略示例" :post-id="80449" :user-id="8" :admin-boxcoin-enable="true" :user-boxcoin-enable="true" :allow-gift="true" :preset-config="presetConfig" />
|
|
34
|
+
<SimpleThx post-type="bbs" post-title="轻剑驭风版本攻略示例" :post-id="80449" :user-id="8" :author-id="8" :admin-boxcoin-enable="true" :user-boxcoin-enable="true" :allow-gift="true" :preset-config="presetConfig" />
|
|
34
35
|
</section>
|
|
35
36
|
<StoryPropsTable title="SimpleThx" description="简化互动条组件。" :items="propsInfo" />
|
|
36
37
|
</div>
|