hookehuyr

✨ feat(客户端): 书籍详情页完善相关功能

1 import { createApp } from 'vue'; 1 import { createApp } from 'vue';
2 -import { Button, Image as VanImage, Col, Row, Icon, Form, Field, CellGroup, ConfigProvider, Toast, Uploader, Empty, Tab, Tabs, Overlay, NumberKeyboard, Lazyload, List, PullRefresh } from 'vant'; 2 +import { Button, Image as VanImage, Col, Row, Icon, Form, Field, CellGroup, ConfigProvider, Toast, Uploader, Empty, Tab, Tabs, Overlay, NumberKeyboard, Lazyload, List, PullRefresh, Popup, Picker } from 'vant';
3 import router from './router'; 3 import router from './router';
4 import App from './App.vue'; 4 import App from './App.vue';
5 import axios from './utils/axios'; 5 import axios from './utils/axios';
...@@ -28,6 +28,8 @@ app.use(NumberKeyboard); ...@@ -28,6 +28,8 @@ app.use(NumberKeyboard);
28 app.use(Lazyload); 28 app.use(Lazyload);
29 app.use(List); 29 app.use(List);
30 app.use(PullRefresh); 30 app.use(PullRefresh);
31 +app.use(Popup);
32 +app.use(Picker);
31 33
32 app.use(ConfigProvider); 34 app.use(ConfigProvider);
33 35
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
3 <div class="modify-top"></div> 3 <div class="modify-top"></div>
4 <div class="book-detail"> 4 <div class="book-detail">
5 <div style="text-align: center;"> 5 <div style="text-align: center;">
6 - <van-image width="220" height="220" src="https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngc434046fdf1f9499d251b280af2568ddbe64839799d00a9aee226edbeb710aed" /> 6 + <van-image width="220" height="220"
7 + src="https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngc434046fdf1f9499d251b280af2568ddbe64839799d00a9aee226edbeb710aed" />
7 </div> 8 </div>
8 <div class="book-intro"> 9 <div class="book-intro">
9 <p class="book-post">逃家小兔绘本</p> 10 <p class="book-post">逃家小兔绘本</p>
...@@ -12,8 +13,12 @@ ...@@ -12,8 +13,12 @@
12 一场爱的捉迷藏就此展开了 13 一场爱的捉迷藏就此展开了
13 </div> 14 </div>
14 <div v-if="hasToggle"> 15 <div v-if="hasToggle">
15 - <div v-if="isToggle" @click="onToggle(false)" class="book-toggle-icon">展开&nbsp;<van-icon style="vertical-align: middle;" size="0.9rem" :name="icon_down" /></div> 16 + <div v-if="isToggle" @click="onToggle(false)" class="book-toggle-icon">展开&nbsp;
16 - <div v-else @click="onToggle(true)" class="book-toggle-icon">折叠&nbsp;<van-icon style="vertical-align: middle;" size="0.9rem" :name="icon_up" /></div> 17 + <van-icon style="vertical-align: middle;" size="0.9rem" :name="icon_down" />
18 + </div>
19 + <div v-else @click="onToggle(true)" class="book-toggle-icon">折叠&nbsp;
20 + <van-icon style="vertical-align: middle;" size="0.9rem" :name="icon_up" />
21 + </div>
17 </div> 22 </div>
18 </div> 23 </div>
19 24
...@@ -35,15 +40,15 @@ ...@@ -35,15 +40,15 @@
35 <div class="book-video-language"> 40 <div class="book-video-language">
36 <van-row> 41 <van-row>
37 <van-col span="6"> 42 <van-col span="6">
38 - <div class="uncheck">普通话</div> 43 + <div @click="toggleLanguage" :class="[check_mandarin ? 'checked' : 'uncheck']">普通话</div>
39 </van-col> 44 </van-col>
40 <van-col span="6"> 45 <van-col span="6">
41 - <div class="checked">方言</div> 46 + <div @click="toggleLanguage" :class="[check_localism ? 'checked' : 'uncheck']">方言</div>
42 </van-col> 47 </van-col>
43 - <van-col span="12"> 48 + <van-col span="12" v-if="check_localism" @click="showPicker = true">
44 <div class="choose-wrapper"> 49 <div class="choose-wrapper">
45 <div class="text"> 50 <div class="text">
46 - &nbsp;所有方言 51 + &nbsp;{{ chooseLanguage.text }}
47 </div> 52 </div>
48 <div class="icon"> 53 <div class="icon">
49 <van-icon name="arrow-down" />&nbsp; 54 <van-icon name="arrow-down" />&nbsp;
...@@ -51,29 +56,34 @@ ...@@ -51,29 +56,34 @@
51 </div> 56 </div>
52 </van-col> 57 </van-col>
53 </van-row> 58 </van-row>
59 + <van-popup v-model:show="showPicker" round position="bottom">
60 + <van-picker
61 + :columns="columns"
62 + :columns-field-names="{ text: 'text', value: 'val', children: 'children' }"
63 + @cancel="showPicker = false"
64 + @confirm="onConfirm"
65 + />
66 + </van-popup>
54 </div> 67 </div>
55 68
56 <div class="book-video-list"> 69 <div class="book-video-list">
57 - <van-list 70 + <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
58 - v-model:loading="loading" 71 + <div v-for="item in list" :key="item" style="height: 3rem;">{{ item }}</div>
59 - :finished="finished"
60 - finished-text="没有更多了"
61 - @load="onLoad">
62 - <div v-for="item in list" :key="item" style="height: 3rem;" >{{ item }}</div>
63 </van-list> 72 </van-list>
64 </div> 73 </div>
65 </div> 74 </div>
66 <div style="height: 5rem;"></div> 75 <div style="height: 5rem;"></div>
67 <div class="book-bar"> 76 <div class="book-bar">
68 - <div class="text"> 77 + <div @click="onSubscribe" class="text">
69 - <van-icon :name="icon_subscribed" size="1.25rem" style="margin: 0 auto;" /> 78 + <van-icon v-if="!is_subscribe" :name="icon_subscribed" size="1.25rem" style="margin: 0 auto;" />
79 + <van-icon v-else :name="icon_unsubscribe" size="1.25rem" style="margin: 0 auto;" />
70 <span style="font-size: 0.85rem;">订阅</span> 80 <span style="font-size: 0.85rem;">订阅</span>
71 </div> 81 </div>
72 <div class="button"> 82 <div class="button">
73 - <my-button type="custom" :custom-style="styleObject1">爱心捐书</my-button> 83 + <my-button @on-click="payFor" type="custom" :custom-style="styleObject1">爱心捐书</my-button>
74 </div> 84 </div>
75 <div class="button"> 85 <div class="button">
76 - <my-button type="custom" :custom-style="styleObject2">上传作品</my-button> 86 + <my-button @on-click="uploadVideo" type="custom" :custom-style="styleObject2">上传作品</my-button>
77 </div> 87 </div>
78 </div> 88 </div>
79 <to-me @on-click="gotoMe()"></to-me> 89 <to-me @on-click="gotoMe()"></to-me>
...@@ -99,33 +109,64 @@ import { Toast } from 'vant'; ...@@ -99,33 +109,64 @@ import { Toast } from 'vant';
99 const $route = useRoute(); 109 const $route = useRoute();
100 const $router = useRouter(); 110 const $router = useRouter();
101 111
102 - // 自定义按钮颜色样式 112 +// 自定义按钮颜色样式
103 - const styleObject1 = reactive({ 113 +const styleObject1 = reactive({
104 backgroundColor: '#FFFFFF', 114 backgroundColor: '#FFFFFF',
105 color: '#713610', 115 color: '#713610',
106 borderColor: '#713610' 116 borderColor: '#713610'
107 - }) 117 +})
108 - const styleObject2 = reactive({ 118 +const styleObject2 = reactive({
109 backgroundColor: '#F9D95C', 119 backgroundColor: '#F9D95C',
110 color: '#713610', 120 color: '#713610',
111 borderColor: '#F9D95C' 121 borderColor: '#F9D95C'
112 - }) 122 +})
113 123
114 - const items = reactive([]) 124 +const items = reactive([])
115 125
116 - const gotoMe = () => { 126 +const gotoMe = () => {
117 console.warn('跳转我的地址'); 127 console.warn('跳转我的地址');
118 - } 128 +}
119 129
120 - // 判断是否显示简介的展开图标 130 +// 判断是否显示简介的展开图标
121 - let hasToggle = ref(false); // 判断是否有展开文字,默认没有 131 +const hasToggle = ref(false); // 判断是否有展开文字,默认没有
122 - let isToggle = ref(true); // 判断展开状态,默认展开 132 +const isToggle = ref(true); // 判断展开状态,默认展开
123 133
124 - const onToggle = (v) => { // 展开/折叠 134 +const onToggle = (v) => { // 展开/折叠
125 isToggle.value = v 135 isToggle.value = v
136 +}
137 +
138 +// 切换视频语言
139 +const check_mandarin = ref(true);
140 +const check_localism = ref(false);
141 +const chooseLanguage = ref({ text: '普通话', val: '00' }); // 默认选中普通话
142 +const toggleLanguage = () => {
143 + check_mandarin.value = !check_mandarin.value;
144 + check_localism.value = !check_localism.value;
145 + // 修改默认语言绑定数据
146 + if (check_localism.value) {
147 + chooseLanguage.value = { text: columns[0]['text'], val: columns[0]['val'] }
148 + } else {
149 + chooseLanguage.value = { text: '普通话', val: '00' };
126 } 150 }
151 +}
152 +// 方言选择项
153 +const columns = [
154 + { text: '所有方言', val: '00' },
155 + { text: '沪语', val: '01' },
156 + { text: '粤语', val: '02' },
157 +];
158 +
159 +const showPicker = ref(false);
127 160
128 - onMounted(() => { 161 +const onConfirm = ({ selectedOptions }) => {
162 + showPicker.value = false;
163 + chooseLanguage.value = {
164 + text: selectedOptions[0].text,
165 + val: selectedOptions[0].val
166 + }
167 +};
168 +
169 +onMounted(() => {
129 // 判断是否显示简介的展开图标 170 // 判断是否显示简介的展开图标
130 hasToggle.value = tools.hasEllipsis('book-intro'); 171 hasToggle.value = tools.hasEllipsis('book-intro');
131 for (let index = 0; index < 20; index++) { 172 for (let index = 0; index < 20; index++) {
...@@ -134,14 +175,14 @@ const $router = useRouter(); ...@@ -134,14 +175,14 @@ const $router = useRouter();
134 avatar: 'https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg' 175 avatar: 'https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg'
135 }) 176 })
136 } 177 }
137 - }) 178 +})
138 179
139 - // 处理书籍下作品列表 180 +// 处理书籍下作品列表
140 - const list = ref([]); 181 +const list = ref([]);
141 - const loading = ref(false); 182 +const loading = ref(false);
142 - const finished = ref(false); 183 +const finished = ref(false);
143 184
144 - const onLoad = () => { 185 +const onLoad = () => {
145 // 异步更新数据 186 // 异步更新数据
146 // setTimeout 仅做示例,真实场景中一般为 ajax 请求 187 // setTimeout 仅做示例,真实场景中一般为 ajax 请求
147 setTimeout(() => { 188 setTimeout(() => {
...@@ -157,7 +198,23 @@ const $router = useRouter(); ...@@ -157,7 +198,23 @@ const $router = useRouter();
157 finished.value = true; 198 finished.value = true;
158 } 199 }
159 }, 1000); 200 }, 1000);
160 - }; 201 +};
202 +
203 +// 书籍订阅
204 +let is_subscribe = ref(false);
205 +const onSubscribe = () => {
206 + is_subscribe.value = !is_subscribe.value
207 +}
208 +
209 +// 爱心捐书
210 +const payFor = () => {
211 + console.warn('弹出框');
212 +}
213 +
214 +// 上传作品
215 +const uploadVideo = () => {
216 + console.warn('跳转页面');
217 +}
161 </script> 218 </script>
162 219
163 <script> 220 <script>
...@@ -165,12 +222,12 @@ import mixin from 'common/mixin'; ...@@ -165,12 +222,12 @@ import mixin from 'common/mixin';
165 222
166 export default { 223 export default {
167 mixins: [mixin.init], 224 mixins: [mixin.init],
168 - data () { 225 + data() {
169 return { 226 return {
170 227
171 } 228 }
172 }, 229 },
173 - mounted () { 230 + mounted() {
174 231
175 }, 232 },
176 methods: { 233 methods: {
...@@ -181,8 +238,10 @@ export default { ...@@ -181,8 +238,10 @@ export default {
181 238
182 <style lang="less" scoped> 239 <style lang="less" scoped>
183 @import url('@css/content-bg.less'); 240 @import url('@css/content-bg.less');
184 - .book-detail-page { 241 +
242 +.book-detail-page {
185 overflow: auto; 243 overflow: auto;
244 +
186 .book-detail { 245 .book-detail {
187 margin: 1rem; 246 margin: 1rem;
188 margin-top: 1.25rem; 247 margin-top: 1.25rem;
...@@ -190,29 +249,36 @@ export default { ...@@ -190,29 +249,36 @@ export default {
190 border-radius: 10px; 249 border-radius: 10px;
191 background-color: rgba(255, 255, 255, 1); 250 background-color: rgba(255, 255, 255, 1);
192 box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.13); 251 box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.13);
252 +
193 .book-intro { 253 .book-intro {
194 padding: 1rem; 254 padding: 1rem;
255 +
195 .book-post { 256 .book-post {
196 color: #222222; 257 color: #222222;
197 font-size: 1.25rem; 258 font-size: 1.25rem;
198 font-weight: bold; 259 font-weight: bold;
199 } 260 }
261 +
200 #book-intro { 262 #book-intro {
201 color: #333333; 263 color: #333333;
202 margin-top: 0.25rem; 264 margin-top: 0.25rem;
203 } 265 }
266 +
204 .book-toggle-icon { 267 .book-toggle-icon {
205 text-align: right; 268 text-align: right;
206 color: #713610; 269 color: #713610;
207 font-size: 1rem; 270 font-size: 1rem;
208 } 271 }
209 } 272 }
273 +
210 .book-video-title { 274 .book-video-title {
211 background-color: #F7F7F7; 275 background-color: #F7F7F7;
212 padding: 1rem 1.5rem; 276 padding: 1rem 1.5rem;
213 } 277 }
278 +
214 .book-video-language { 279 .book-video-language {
215 padding: 1rem; 280 padding: 1rem;
281 +
216 .uncheck { 282 .uncheck {
217 background: #F7F7F7; 283 background: #F7F7F7;
218 border-radius: 15px; 284 border-radius: 15px;
...@@ -221,6 +287,7 @@ export default { ...@@ -221,6 +287,7 @@ export default {
221 color: #222222; 287 color: #222222;
222 margin: 0 0.25rem; 288 margin: 0 0.25rem;
223 } 289 }
290 +
224 .checked { 291 .checked {
225 background: #F9D95C; 292 background: #F9D95C;
226 border-radius: 15px; 293 border-radius: 15px;
...@@ -229,6 +296,7 @@ export default { ...@@ -229,6 +296,7 @@ export default {
229 color: #222222; 296 color: #222222;
230 margin: 0 0.25rem; 297 margin: 0 0.25rem;
231 } 298 }
299 +
232 .choose-wrapper { 300 .choose-wrapper {
233 background: #F7F7F7; 301 background: #F7F7F7;
234 border-radius: 15px; 302 border-radius: 15px;
...@@ -236,11 +304,13 @@ export default { ...@@ -236,11 +304,13 @@ export default {
236 text-align: center; 304 text-align: center;
237 color: #B0B0B0; 305 color: #B0B0B0;
238 margin: 0 0.25rem; 306 margin: 0 0.25rem;
307 +
239 .text { 308 .text {
240 display: inline-block; 309 display: inline-block;
241 text-align: left; 310 text-align: left;
242 width: 80%; 311 width: 80%;
243 } 312 }
313 +
244 .icon { 314 .icon {
245 display: inline-block; 315 display: inline-block;
246 text-align: right; 316 text-align: right;
...@@ -248,11 +318,13 @@ export default { ...@@ -248,11 +318,13 @@ export default {
248 } 318 }
249 } 319 }
250 } 320 }
321 +
251 .book-video-list { 322 .book-video-list {
252 height: 20rem; 323 height: 20rem;
253 overflow: scroll; 324 overflow: scroll;
254 } 325 }
255 } 326 }
327 +
256 .book-bar { 328 .book-bar {
257 position: fixed; 329 position: fixed;
258 right: 0; 330 right: 0;
...@@ -263,6 +335,7 @@ export default { ...@@ -263,6 +335,7 @@ export default {
263 box-sizing: content-box; 335 box-sizing: content-box;
264 background-color: white; 336 background-color: white;
265 padding: 1rem; 337 padding: 1rem;
338 +
266 .text { 339 .text {
267 display: flex; 340 display: flex;
268 flex-direction: column; 341 flex-direction: column;
...@@ -271,6 +344,7 @@ export default { ...@@ -271,6 +344,7 @@ export default {
271 color: #713610; 344 color: #713610;
272 text-align: center; 345 text-align: center;
273 } 346 }
347 +
274 .button { 348 .button {
275 display: flex; 349 display: flex;
276 flex-direction: column; 350 flex-direction: column;
...@@ -279,5 +353,5 @@ export default { ...@@ -279,5 +353,5 @@ export default {
279 padding: 0 0.5rem; 353 padding: 0 0.5rem;
280 } 354 }
281 } 355 }
282 - } 356 +}
283 </style> 357 </style>
...\ No newline at end of file ...\ No newline at end of file
......