@jx3box/jx3box-ui 2.0.6 → 2.0.7
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/.storybook/storybookMocks.js +23 -0
- package/README.md +39 -30
- package/assets/css/interact/qrcode.less +69 -0
- package/assets/css/wiki/wiki-comments.less +176 -0
- package/assets/css/wiki/wiki-panel.less +177 -0
- package/assets/css/wiki/wiki-revisions.less +62 -0
- package/package.json +1 -1
- package/src/App.vue +57 -1
- package/src/interact/Homework.vue +9 -10
- package/src/interact/QRcode.vue +104 -0
- package/src/single/VersionDialog.vue +2 -2
- package/src/stories/interact/QRcode.stories.js +59 -0
- package/src/stories/mockData.js +94 -0
- package/src/stories/wiki/GamePrice.stories.js +64 -0
- package/src/stories/wiki/WikiComments.stories.js +58 -0
- package/src/stories/wiki/WikiPanel.stories.js +69 -0
- package/src/stories/wiki/WikiRevisions.stories.js +47 -0
- package/src/wiki/GamePrice.vue +107 -0
- package/src/wiki/WikiComment.vue +153 -0
- package/src/wiki/WikiComments.vue +206 -0
- package/src/wiki/WikiPanel.vue +121 -0
- package/src/wiki/WikiRevisions.vue +125 -0
package/src/App.vue
CHANGED
|
@@ -75,11 +75,15 @@
|
|
|
75
75
|
client="std"
|
|
76
76
|
></Homework>
|
|
77
77
|
</div>
|
|
78
|
+
<h1 class="m-title">QRcode</h1>
|
|
79
|
+
<div class="m-block">
|
|
80
|
+
<QRcode v="cms" />
|
|
81
|
+
</div>
|
|
78
82
|
</el-tab-pane>
|
|
79
83
|
<el-tab-pane label="文章内容" name="content">
|
|
80
84
|
<el-radio-group v-model="post_id">
|
|
81
85
|
<el-radio value="23240">临时测试</el-radio>
|
|
82
|
-
<el-radio
|
|
86
|
+
<el-radio value="35605">Markdown</el-radio>
|
|
83
87
|
<el-radio value="32035">仅小册</el-radio>
|
|
84
88
|
<el-radio value="30017">仅联合创作者</el-radio>
|
|
85
89
|
<el-radio value="30582">小册和联合创作者</el-radio>
|
|
@@ -87,6 +91,29 @@
|
|
|
87
91
|
</el-radio-group>
|
|
88
92
|
<singlebox :post="post" />
|
|
89
93
|
</el-tab-pane>
|
|
94
|
+
<el-tab-pane label="百科组件" name="wiki">
|
|
95
|
+
<h1 class="m-title">游戏价格组件</h1>
|
|
96
|
+
<div class="m-block">
|
|
97
|
+
<GamePrice :price="100009999" :align="true"></GamePrice>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<h1 class="m-title">百科面板</h1>
|
|
101
|
+
<div class="m-block">
|
|
102
|
+
<WikiPanel :wiki-post="wiki_post">
|
|
103
|
+
<template #head-title>奇遇攻略</template>
|
|
104
|
+
</WikiPanel>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<h1 class="m-title">百科评论</h1>
|
|
108
|
+
<div class="m-block">
|
|
109
|
+
<WikiComments :source-id="12572" type="achievement" />
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<h1 class="m-title">百科修订</h1>
|
|
113
|
+
<div class="m-block">
|
|
114
|
+
<WikiRevisions type="achievement" :source-id="12572" />
|
|
115
|
+
</div>
|
|
116
|
+
</el-tab-pane>
|
|
90
117
|
<el-tab-pane label="移动组件" name="mobile">
|
|
91
118
|
<h1 class="m-title">Common</h1>
|
|
92
119
|
<el-switch v-model="showSuspendCommon" active-text="展示移动组件"></el-switch>
|
|
@@ -134,6 +161,7 @@ import { getPost } from "../service/cms";
|
|
|
134
161
|
import { get_item } from "../service/item";
|
|
135
162
|
import { getTopicDetails } from "../service/community";
|
|
136
163
|
import post_topics from "@jx3box/jx3box-common/data/post_topics.json";
|
|
164
|
+
import { wiki } from "@jx3box/jx3box-common/js/wiki.js";
|
|
137
165
|
|
|
138
166
|
// components
|
|
139
167
|
import singlebox from "./single/CmsSingle.vue";
|
|
@@ -143,6 +171,12 @@ import PostGuide from "./single/PostGuide.vue";
|
|
|
143
171
|
import Homework from "./interact/Homework.vue";
|
|
144
172
|
import PostVersion from "./single/PostVersion.vue";
|
|
145
173
|
import PostCollection from "./single/PostCollection.vue";
|
|
174
|
+
import QRcode from "./interact/QRcode.vue";
|
|
175
|
+
|
|
176
|
+
import GamePrice from "./wiki/GamePrice.vue";
|
|
177
|
+
import WikiComments from "./wiki/WikiComments.vue";
|
|
178
|
+
import WikiRevisions from "./wiki/WikiRevisions.vue";
|
|
179
|
+
import WikiPanel from "./wiki/WikiPanel.vue";
|
|
146
180
|
export default {
|
|
147
181
|
name: "App",
|
|
148
182
|
components: {
|
|
@@ -156,6 +190,12 @@ export default {
|
|
|
156
190
|
PostGuide,
|
|
157
191
|
PostVersion,
|
|
158
192
|
PostCollection,
|
|
193
|
+
QRcode,
|
|
194
|
+
|
|
195
|
+
GamePrice,
|
|
196
|
+
WikiComments,
|
|
197
|
+
WikiRevisions,
|
|
198
|
+
WikiPanel,
|
|
159
199
|
},
|
|
160
200
|
data() {
|
|
161
201
|
return {
|
|
@@ -183,6 +223,11 @@ export default {
|
|
|
183
223
|
showSuspendCommon: false,
|
|
184
224
|
|
|
185
225
|
community: {},
|
|
226
|
+
|
|
227
|
+
wiki_post: {
|
|
228
|
+
source: {},
|
|
229
|
+
post: null,
|
|
230
|
+
},
|
|
186
231
|
};
|
|
187
232
|
},
|
|
188
233
|
watch: {
|
|
@@ -264,10 +309,21 @@ export default {
|
|
|
264
309
|
this.community = res.data.data;
|
|
265
310
|
});
|
|
266
311
|
},
|
|
312
|
+
loadWiki() {
|
|
313
|
+
wiki.mix({ type: "achievement", id: 12572, client: this.client }).then((res) => {
|
|
314
|
+
const { post, source, compatible, isEmpty, users } = res;
|
|
315
|
+
this.wiki_post = {
|
|
316
|
+
post: post,
|
|
317
|
+
source: source,
|
|
318
|
+
users,
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
},
|
|
267
322
|
},
|
|
268
323
|
mounted() {
|
|
269
324
|
// this.loadItems();
|
|
270
325
|
this.loadCommunity();
|
|
326
|
+
this.loadWiki();
|
|
271
327
|
},
|
|
272
328
|
};
|
|
273
329
|
</script>
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
<!-- <a class="u-charge" :href="chargeLink" target="_blank">[充值]</a> -->
|
|
25
25
|
</div>
|
|
26
26
|
<el-radio-group class="u-homework-type" v-model="type" size="small" v-if="hasPermission">
|
|
27
|
-
<el-radio-button
|
|
28
|
-
<el-radio-button
|
|
27
|
+
<el-radio-button value="grant">品鉴</el-radio-button>
|
|
28
|
+
<el-radio-button value="reward">打赏</el-radio-button>
|
|
29
29
|
</el-radio-group>
|
|
30
30
|
<div class="u-list">
|
|
31
31
|
<em class="u-label">❤️ {{ type == "reward" ? "打赏" : "品鉴" }}</em>
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
<b>{{ item }}</b
|
|
36
36
|
>盒币
|
|
37
37
|
</el-radio>
|
|
38
|
-
<el-radio value="custom"
|
|
38
|
+
<el-radio value="custom" border>自定义</el-radio>
|
|
39
39
|
<el-input
|
|
40
40
|
v-model="amount"
|
|
41
41
|
v-show="count === 'custom'"
|
|
@@ -48,22 +48,21 @@
|
|
|
48
48
|
<em class="u-label">📝 寄语</em>
|
|
49
49
|
<div class="u-input">
|
|
50
50
|
<el-input
|
|
51
|
-
|
|
52
51
|
v-model="remark"
|
|
53
52
|
placeholder="请输入寄语(必填)"
|
|
54
53
|
:minlength="2"
|
|
55
54
|
:maxlength="30"
|
|
56
55
|
show-word-limit
|
|
57
56
|
></el-input>
|
|
58
|
-
<el-button
|
|
57
|
+
<el-button :disabled="fetchingCurrentRelease" @click="insertCurrentRelease"
|
|
59
58
|
>插入当前版本</el-button
|
|
60
59
|
>
|
|
61
60
|
</div>
|
|
62
61
|
</div>
|
|
63
62
|
</div>
|
|
64
63
|
<template #footer>
|
|
65
|
-
<el-button @click="onClose"
|
|
66
|
-
<el-button type="primary" @click="submit" :disabled="!ready || submitting"
|
|
64
|
+
<el-button @click="onClose">取 消</el-button>
|
|
65
|
+
<el-button type="primary" @click="submit" :disabled="!ready || submitting">确 定</el-button>
|
|
67
66
|
</template>
|
|
68
67
|
</el-dialog>
|
|
69
68
|
</div>
|
|
@@ -111,7 +110,7 @@ export default {
|
|
|
111
110
|
placeholder: {
|
|
112
111
|
type: String,
|
|
113
112
|
default: "",
|
|
114
|
-
}
|
|
113
|
+
},
|
|
115
114
|
},
|
|
116
115
|
emits: ["update:modelValue", "updateRecord"],
|
|
117
116
|
data: function () {
|
|
@@ -213,7 +212,7 @@ export default {
|
|
|
213
212
|
this.loadBoxcoinConfig();
|
|
214
213
|
|
|
215
214
|
if (this.hasPermission) {
|
|
216
|
-
this.type =
|
|
215
|
+
this.type = "grant";
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
218
|
},
|
|
@@ -301,7 +300,7 @@ export default {
|
|
|
301
300
|
});
|
|
302
301
|
},
|
|
303
302
|
onClose() {
|
|
304
|
-
this.show = false
|
|
303
|
+
this.show = false;
|
|
305
304
|
},
|
|
306
305
|
},
|
|
307
306
|
mounted() {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="trigger" class="w-qrcode" @click="togglePic" v-if="mode == 'cms'">
|
|
3
|
+
<img class="u-icon" svg-inline src="../../assets/img/widget/qr-code.svg" />
|
|
4
|
+
<span class="u-text">二维码</span>
|
|
5
|
+
</div>
|
|
6
|
+
<teleport to="body">
|
|
7
|
+
<div v-if="mode == 'cms' && active" class="u-qrcode u-qrcode-popup" :style="popupStyle" @click.stop>
|
|
8
|
+
<qrcode-vue class="u-pic" :value="value" :size="size" level="H"></qrcode-vue>
|
|
9
|
+
<span>扫一扫即可访问</span>
|
|
10
|
+
</div>
|
|
11
|
+
</teleport>
|
|
12
|
+
<div class="w-qrcode-static" v-if="mode == 'static'">
|
|
13
|
+
<div class="u-qrcode">
|
|
14
|
+
<qrcode-vue class="u-pic" :value="value" :size="size" level="H"></qrcode-vue>
|
|
15
|
+
<span class="u-txt"
|
|
16
|
+
><img class="u-icon" svg-inline src="../../assets/img/widget/qr-code.svg" />扫一扫手机访问</span
|
|
17
|
+
>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
import { nextTick } from "vue";
|
|
24
|
+
import QrcodeVue from "qrcode.vue";
|
|
25
|
+
export default {
|
|
26
|
+
name: "QRcode",
|
|
27
|
+
props: {
|
|
28
|
+
href: {
|
|
29
|
+
type: String,
|
|
30
|
+
default: "",
|
|
31
|
+
},
|
|
32
|
+
v: {
|
|
33
|
+
type: String,
|
|
34
|
+
default: "cms",
|
|
35
|
+
},
|
|
36
|
+
s: {
|
|
37
|
+
type: Number,
|
|
38
|
+
default: 100,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
data: function () {
|
|
42
|
+
return {
|
|
43
|
+
value: this.href || location.href,
|
|
44
|
+
size: this.s || 100,
|
|
45
|
+
active: false,
|
|
46
|
+
mode: this.v || "cms",
|
|
47
|
+
popupStyle: {
|
|
48
|
+
top: "0px",
|
|
49
|
+
left: "0px",
|
|
50
|
+
},
|
|
51
|
+
docClickHandler: null,
|
|
52
|
+
repositionHandler: null,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
computed: {},
|
|
56
|
+
methods: {
|
|
57
|
+
togglePic: function (e) {
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
this.active = !this.active;
|
|
60
|
+
if (this.active) {
|
|
61
|
+
nextTick(() => {
|
|
62
|
+
this.updatePopupPosition();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
updatePopupPosition: function () {
|
|
67
|
+
const trigger = this.$refs.trigger;
|
|
68
|
+
if (!trigger) return;
|
|
69
|
+
|
|
70
|
+
const rect = trigger.getBoundingClientRect();
|
|
71
|
+
this.popupStyle = {
|
|
72
|
+
top: `${rect.bottom + 5}px`,
|
|
73
|
+
left: `${rect.left + rect.width / 2}px`,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
mounted: function () {
|
|
78
|
+
this.docClickHandler = () => {
|
|
79
|
+
this.active = false;
|
|
80
|
+
};
|
|
81
|
+
this.repositionHandler = () => {
|
|
82
|
+
if (this.active) {
|
|
83
|
+
this.updatePopupPosition();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
document.addEventListener("click", this.docClickHandler);
|
|
88
|
+
window.addEventListener("resize", this.repositionHandler);
|
|
89
|
+
window.addEventListener("scroll", this.repositionHandler, true);
|
|
90
|
+
},
|
|
91
|
+
beforeUnmount: function () {
|
|
92
|
+
document.removeEventListener("click", this.docClickHandler);
|
|
93
|
+
window.removeEventListener("resize", this.repositionHandler);
|
|
94
|
+
window.removeEventListener("scroll", this.repositionHandler, true);
|
|
95
|
+
},
|
|
96
|
+
components: {
|
|
97
|
+
QrcodeVue,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<style lang="less">
|
|
103
|
+
@import "../../assets/css/interact/qrcode.less";
|
|
104
|
+
</style>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<div class="m-version-container" v-loading="loading">
|
|
11
11
|
<div class="m-toolbar">
|
|
12
12
|
<el-radio-group v-model="type">
|
|
13
|
-
<el-radio-button :
|
|
13
|
+
<el-radio-button :value="item.value" v-for="item in types" :key="item.value">{{
|
|
14
14
|
item.label
|
|
15
15
|
}}</el-radio-button>
|
|
16
16
|
</el-radio-group>
|
|
@@ -159,7 +159,7 @@ export default {
|
|
|
159
159
|
},
|
|
160
160
|
visible(val) {
|
|
161
161
|
this.$emit("update:modelValue", val);
|
|
162
|
-
}
|
|
162
|
+
},
|
|
163
163
|
},
|
|
164
164
|
methods: {
|
|
165
165
|
close() {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import QRcode from '../../interact/QRcode.vue';
|
|
2
|
+
import StoryPropsTable from '../components/StoryPropsTable.vue';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Interact/QRcode',
|
|
6
|
+
component: QRcode,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'fullscreen',
|
|
9
|
+
},
|
|
10
|
+
argTypes: {
|
|
11
|
+
href: { control: 'text' },
|
|
12
|
+
v: { control: 'radio', options: ['cms', 'static'] },
|
|
13
|
+
s: { control: { type: 'number', min: 80, max: 240, step: 10 } },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
href: 'https://www.jx3box.com',
|
|
22
|
+
v: 'cms',
|
|
23
|
+
s: 120,
|
|
24
|
+
},
|
|
25
|
+
render: (args) => ({
|
|
26
|
+
components: { QRcode, StoryPropsTable },
|
|
27
|
+
setup() {
|
|
28
|
+
return {
|
|
29
|
+
args,
|
|
30
|
+
propsInfo: [
|
|
31
|
+
{ name: 'href', type: 'String', default: 'location.href', description: '二维码指向地址。' },
|
|
32
|
+
{ name: 'v', type: 'String', default: '"cms"', description: '展示模式,支持弹出态和静态态。' },
|
|
33
|
+
{ name: 's', type: 'Number', default: '100', description: '二维码尺寸。' },
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
template: `
|
|
38
|
+
<div style="display:grid;gap:24px;padding:32px;background:linear-gradient(180deg,#f8fafc 0%,#eef2f7 100%);min-height:100vh;">
|
|
39
|
+
<section style="display:flex;align-items:center;justify-content:space-between;gap:24px;padding:24px;border-radius:20px;background:rgba(255,255,255,0.92);box-shadow:0 24px 60px rgba(15,23,42,0.08);">
|
|
40
|
+
<div>
|
|
41
|
+
<h2 style="margin:0;font-size:28px;color:#0f172a;">QRcode</h2>
|
|
42
|
+
<p style="margin:12px 0 0;color:#475569;line-height:1.8;">用于文章和百科详情页中的扫码访问入口。</p>
|
|
43
|
+
</div>
|
|
44
|
+
<QRcode v-bind="args" />
|
|
45
|
+
</section>
|
|
46
|
+
<StoryPropsTable title="QRcode" description="二维码组件参数说明。" :items="propsInfo" />
|
|
47
|
+
</div>
|
|
48
|
+
`,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const StaticCard = {
|
|
53
|
+
args: {
|
|
54
|
+
href: 'https://www.jx3box.com/wiki/achievement/1001',
|
|
55
|
+
v: 'static',
|
|
56
|
+
s: 140,
|
|
57
|
+
},
|
|
58
|
+
render: Default.render,
|
|
59
|
+
};
|
package/src/stories/mockData.js
CHANGED
|
@@ -273,3 +273,97 @@ export const mockCommitHistories = [
|
|
|
273
273
|
`,
|
|
274
274
|
},
|
|
275
275
|
];
|
|
276
|
+
|
|
277
|
+
export const mockWikiPost = {
|
|
278
|
+
type: 'achievement',
|
|
279
|
+
source_id: 1001,
|
|
280
|
+
post: {
|
|
281
|
+
title: '25 人普通西津渡首领机制',
|
|
282
|
+
level: 4,
|
|
283
|
+
updated: '2026-03-11T20:30:00+08:00',
|
|
284
|
+
},
|
|
285
|
+
users: [
|
|
286
|
+
{
|
|
287
|
+
id: 8,
|
|
288
|
+
nickname: '薄嘴唇靓仔',
|
|
289
|
+
avatar: 'https://cdn.jx3box.com/upload/avatar/2022/3/2/8_9860765.png',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: 17,
|
|
293
|
+
nickname: '藏剑校对君',
|
|
294
|
+
avatar: 'https://cdn.jx3box.com/upload/avatar/2022/3/2/8_9860765.png',
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const mockWikiStat = {
|
|
300
|
+
views: 32145,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export const mockWikiComments = {
|
|
304
|
+
list: [
|
|
305
|
+
{
|
|
306
|
+
id: 1,
|
|
307
|
+
parent_id: 0,
|
|
308
|
+
user_id: 8,
|
|
309
|
+
user_nickname: '薄嘴唇靓仔',
|
|
310
|
+
content: '<p>这条评论用于展示百科评论区的主楼样式、置顶和加精状态。</p>',
|
|
311
|
+
updated: '2026-03-11 20:40:00',
|
|
312
|
+
is_top: 1,
|
|
313
|
+
is_star: 1,
|
|
314
|
+
children: [
|
|
315
|
+
{
|
|
316
|
+
id: 2,
|
|
317
|
+
parent_id: 1,
|
|
318
|
+
user_id: 17,
|
|
319
|
+
user_nickname: '藏剑校对君',
|
|
320
|
+
content: '<p>回复楼层会通过递归组件继续渲染,方便在 Storybook 里检查层级样式。</p>',
|
|
321
|
+
updated: '2026-03-11 20:55:00',
|
|
322
|
+
is_top: 0,
|
|
323
|
+
is_star: 0,
|
|
324
|
+
children: [],
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
id: 3,
|
|
330
|
+
parent_id: 0,
|
|
331
|
+
user_id: 26,
|
|
332
|
+
user_nickname: '副本小助手',
|
|
333
|
+
content: '<p>第二条评论保留普通状态,用来对比按钮和时间信息。</p>',
|
|
334
|
+
updated: '2026-03-11 21:10:00',
|
|
335
|
+
is_top: 0,
|
|
336
|
+
is_star: 0,
|
|
337
|
+
children: [],
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
page: 1,
|
|
341
|
+
total: 2,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
export const mockWikiRevisions = [
|
|
345
|
+
{
|
|
346
|
+
id: 201,
|
|
347
|
+
source_id: 1001,
|
|
348
|
+
updated: '2026-03-11 21:00:00',
|
|
349
|
+
user_id: 8,
|
|
350
|
+
user_nickname: '薄嘴唇靓仔',
|
|
351
|
+
remark: '补充首领技能预警时序。',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
id: 202,
|
|
355
|
+
source_id: 1001,
|
|
356
|
+
updated: '2026-03-10 19:20:00',
|
|
357
|
+
user_id: 17,
|
|
358
|
+
user_nickname: '藏剑校对君',
|
|
359
|
+
remark: '修正文案并补充图片说明。',
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: 203,
|
|
363
|
+
source_id: 1001,
|
|
364
|
+
updated: '2026-03-09 16:45:00',
|
|
365
|
+
user_id: 26,
|
|
366
|
+
user_nickname: '副本小助手',
|
|
367
|
+
remark: '创建初版机制条目。',
|
|
368
|
+
},
|
|
369
|
+
];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import GamePrice from '../../wiki/GamePrice.vue';
|
|
2
|
+
import StoryPropsTable from '../components/StoryPropsTable.vue';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Wiki/GamePrice',
|
|
6
|
+
component: GamePrice,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'fullscreen',
|
|
9
|
+
},
|
|
10
|
+
argTypes: {
|
|
11
|
+
price: { control: 'text' },
|
|
12
|
+
align: { control: 'boolean' },
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
18
|
+
export const Default = {
|
|
19
|
+
args: {
|
|
20
|
+
price: 123456789,
|
|
21
|
+
align: false,
|
|
22
|
+
},
|
|
23
|
+
render: (args) => ({
|
|
24
|
+
components: { GamePrice, StoryPropsTable },
|
|
25
|
+
setup() {
|
|
26
|
+
return {
|
|
27
|
+
args,
|
|
28
|
+
examples: [0, 520, 12888, 123456789, -20800],
|
|
29
|
+
propsInfo: [
|
|
30
|
+
{ name: 'price', type: 'Number | String', default: '0', description: '以铜为最小单位的游戏货币值。' },
|
|
31
|
+
{ name: 'align', type: 'Boolean', default: 'false', description: '开启后按金额单位宽度对齐。' },
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
template: `
|
|
36
|
+
<div style="display:grid;gap:24px;padding:32px;background:linear-gradient(180deg,#f8fafc 0%,#eef2f7 100%);min-height:100vh;">
|
|
37
|
+
<section style="display:grid;gap:20px;padding:24px;border-radius:20px;background:rgba(255,255,255,0.92);box-shadow:0 24px 60px rgba(15,23,42,0.08);">
|
|
38
|
+
<div>
|
|
39
|
+
<h2 style="margin:0;font-size:28px;color:#0f172a;">GamePrice</h2>
|
|
40
|
+
<p style="margin:12px 0 0;color:#475569;line-height:1.8;">将整型金额拆解为砖金银铜并附带图标展示。</p>
|
|
41
|
+
</div>
|
|
42
|
+
<div style="font-size:28px;color:#0f172a;">
|
|
43
|
+
<GamePrice v-bind="args" />
|
|
44
|
+
</div>
|
|
45
|
+
<div style="display:grid;gap:12px;">
|
|
46
|
+
<div v-for="item in examples" :key="item" style="display:flex;align-items:center;justify-content:space-between;gap:24px;padding:14px 18px;border-radius:14px;background:#f8fafc;">
|
|
47
|
+
<code style="color:#475569;">{{ item }}</code>
|
|
48
|
+
<GamePrice :price="item" :align="args.align" />
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
<StoryPropsTable title="GamePrice" description="游戏金额展示组件入参。" :items="propsInfo" />
|
|
53
|
+
</div>
|
|
54
|
+
`,
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Aligned = {
|
|
59
|
+
args: {
|
|
60
|
+
price: 123456789,
|
|
61
|
+
align: true,
|
|
62
|
+
},
|
|
63
|
+
render: Default.render,
|
|
64
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import WikiComments from '../../wiki/WikiComments.vue';
|
|
2
|
+
import StorybookShell from '../layout/StorybookShell.vue';
|
|
3
|
+
import StoryPropsTable from '../components/StoryPropsTable.vue';
|
|
4
|
+
|
|
5
|
+
function seedEditorSession() {
|
|
6
|
+
try {
|
|
7
|
+
localStorage.setItem('created_at', String(Date.now()));
|
|
8
|
+
localStorage.setItem('logged_in', 'true');
|
|
9
|
+
localStorage.setItem('group', '64');
|
|
10
|
+
localStorage.setItem('name', 'Storybook编辑者');
|
|
11
|
+
localStorage.setItem('uid', '8');
|
|
12
|
+
localStorage.setItem('avatar', 'https://cdn.jx3box.com/upload/avatar/2022/3/2/8_9860765.png');
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// ignore storage failures in restricted contexts
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const meta = {
|
|
19
|
+
title: 'Wiki/WikiComments',
|
|
20
|
+
component: WikiComments,
|
|
21
|
+
parameters: {
|
|
22
|
+
layout: 'fullscreen',
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
type: { control: 'text' },
|
|
26
|
+
sourceId: { control: 'number' },
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
|
|
32
|
+
export const Default = {
|
|
33
|
+
args: {
|
|
34
|
+
type: 'achievement',
|
|
35
|
+
sourceId: 1001,
|
|
36
|
+
},
|
|
37
|
+
render: (args) => ({
|
|
38
|
+
components: { WikiComments, StorybookShell, StoryPropsTable },
|
|
39
|
+
setup() {
|
|
40
|
+
seedEditorSession();
|
|
41
|
+
return {
|
|
42
|
+
args,
|
|
43
|
+
propsInfo: [
|
|
44
|
+
{ name: 'type', type: 'String', default: '""', description: '百科条目类型。' },
|
|
45
|
+
{ name: 'sourceId', type: 'Number | String', default: '0', description: '百科条目源 ID。' },
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
template: `
|
|
50
|
+
<StorybookShell placement="main" :show-right-sidebar="false">
|
|
51
|
+
<div style="display:grid;gap:24px;">
|
|
52
|
+
<WikiComments v-bind="args" />
|
|
53
|
+
<StoryPropsTable title="WikiComments" description="百科评论区,已接入 Storybook mock 数据。" :items="propsInfo" />
|
|
54
|
+
</div>
|
|
55
|
+
</StorybookShell>
|
|
56
|
+
`,
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import WikiPanel from '../../wiki/WikiPanel.vue';
|
|
2
|
+
import { mockWikiPost } from '../mockData';
|
|
3
|
+
import StorybookShell from '../layout/StorybookShell.vue';
|
|
4
|
+
import StoryPropsTable from '../components/StoryPropsTable.vue';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Wiki/WikiPanel',
|
|
8
|
+
component: WikiPanel,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'fullscreen',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
export const Default = {
|
|
17
|
+
render: () => ({
|
|
18
|
+
components: { WikiPanel, StorybookShell, StoryPropsTable },
|
|
19
|
+
setup() {
|
|
20
|
+
return {
|
|
21
|
+
mockWikiPost,
|
|
22
|
+
propsInfo: [
|
|
23
|
+
{ name: 'wikiPost', type: 'Object', default: 'null', description: '百科详情数据,包含 post/users/source_id/type。' },
|
|
24
|
+
{ name: 'scene', type: 'String', default: '"default"', description: '面板所处场景,详情页使用 detail。' },
|
|
25
|
+
{ name: 'borderNone', type: 'Boolean', default: 'false', description: '控制外层是否显示边框。' },
|
|
26
|
+
{ name: 'showQR', type: 'Boolean', default: 'true', description: '在详情场景中展示二维码入口。' },
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
template: `
|
|
31
|
+
<StorybookShell placement="main" :show-right-sidebar="false">
|
|
32
|
+
<div style="display:grid;gap:24px;">
|
|
33
|
+
<WikiPanel :wiki-post="mockWikiPost" scene="detail">
|
|
34
|
+
<template #head-title>
|
|
35
|
+
<span>百科条目概览</span>
|
|
36
|
+
</template>
|
|
37
|
+
<template #head-actions>
|
|
38
|
+
<el-tag type="success">已发布</el-tag>
|
|
39
|
+
</template>
|
|
40
|
+
<template #body>
|
|
41
|
+
<div style="padding:4px 0 0;line-height:1.9;color:#475569;">
|
|
42
|
+
这里模拟百科详情页中的信息面板,可同时查看贡献者、热度、更新时间与二维码入口。
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
</WikiPanel>
|
|
46
|
+
<StoryPropsTable title="WikiPanel" description="百科信息面板基础容器。" :items="propsInfo" />
|
|
47
|
+
</div>
|
|
48
|
+
</StorybookShell>
|
|
49
|
+
`,
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const PlainPanel = {
|
|
54
|
+
render: () => ({
|
|
55
|
+
components: { WikiPanel, StorybookShell },
|
|
56
|
+
template: `
|
|
57
|
+
<StorybookShell placement="main" :show-left-sidebar="false" :show-right-sidebar="false">
|
|
58
|
+
<WikiPanel :border-none="true" :show-qr="false">
|
|
59
|
+
<template #head-title>
|
|
60
|
+
<span>普通面板</span>
|
|
61
|
+
</template>
|
|
62
|
+
<template #body>
|
|
63
|
+
<div style="line-height:1.9;color:#475569;">不传 \`wikiPost\` 时可作为通用分区容器使用。</div>
|
|
64
|
+
</template>
|
|
65
|
+
</WikiPanel>
|
|
66
|
+
</StorybookShell>
|
|
67
|
+
`,
|
|
68
|
+
}),
|
|
69
|
+
};
|