hookehuyr

✨ feat(幼儿园选择页,幼儿园书籍列表,书籍详情页): API数据联调

......@@ -2,15 +2,13 @@
<div class="book-item van-hairline--bottom" @click="handle">
<van-row>
<van-col span="8">
<van-image width="7rem" height="7rem" :src="item.avatar" style="text-align: center;" />
<van-image width="7rem" height="7rem" :src="item.cover" style="text-align: center;" />
</van-col>
<van-col class="wrapper" span="16">
<p class="title van-multi-ellipsis--l2">逃家小兔绘本</p>
<div v-if="type === 'C'" class="van-multi-ellipsis--l2 content">
从前有一只小兔子,总是想要离家出走。有一天,他对妈妈说如果有大灰狼怎么办,不要把门打开
</div>
<p class="title van-multi-ellipsis--l2">{{ item.name }}</p>
<div v-if="type === 'C'" class="van-multi-ellipsis--l2 content">{{ item.note }}</div>
<div class="sub">
<van-icon :name="icon_video" />&nbsp;&nbsp;<span>54个作品</span>
<van-icon :name="icon_video" />&nbsp;&nbsp;<span>{{ item.prod_num }}个作品</span>
</div>
<div v-if="type === 'B'" class="upload" @click="onUpload(item)">上传视频</div>
</van-col>
......
<template>
<div class="video-wrapper">
<div class="video-div" :id="'mui-player-' + item.case_id"></div>
<div class="video-div" :id="'mui-player-' + item.id"></div>
<div class="video-bar">
<van-row>
<van-col span="12" @click="goTo">
<van-image round width="2rem" height="2rem" style="vertical-align: bottom;"
src="https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg" />&nbsp;
<span style="font-size: 1.05rem;">王忆慈</span>
<van-image round width="2rem" height="2rem" style="vertical-align: middle;" :src="item.avatar" />&nbsp;
<span style="font-size: 1.05rem;vertical-align: middle;">{{ item.name }}</span>
</van-col>
<van-col span="12">
<div style="padding: 0.25rem; padding-top: 0.75rem; text-align: right;">
<span @click="setComment">
<van-icon :name="icon_liuyan" size="1.2rem" style="vertical-align: bottom;" />
67
{{ item.comment_num }}
</span>
&nbsp;&nbsp;&nbsp;
<span @click="setLike()">
<van-icon v-if="!detail.liked" :name="icon_dianzan1" size="1.2rem" style="vertical-align: bottom;" />
<van-icon v-if="!detail.is_like" :name="icon_dianzan1" size="1.2rem" style="vertical-align: bottom;" />
<van-icon v-else :name="icon_dianzan2" size="1.2rem" style="vertical-align: bottom;" />
10086
{{ item.favor_num }}
</span>
</div>
</van-col>
</van-row>
</div>
<div @click="goTo" style="color: #999999; padding: 0px 1rem 0.5rem;">杨浦民办科技幼稚园 | 藏语</div>
<div @click="goTo" style="color: #999999; padding: 0px 1rem 0.5rem;">{{ item.kg_name }} | {{ item.localism_type }}
</div>
</div>
</template>
......@@ -65,26 +65,26 @@ export default {
},
mounted() {
var mp = new MuiPlayer({
container: '#mui-player-' + this.item.case_id,
container: '#mui-player-' + this.item.id,
title: this.item.title,
src: this.item.video.url,
poster: this.item.cover.url,
src: this.item.video,
poster: this.item.cover,
autoFit: false,
videoAttribute: [ // 声明启用同层播放, 不让会自动全屏播放
{attrKey:'webkit-playsinline',attrValue:'webkit-playsinline'},
{attrKey:'playsinline',attrValue:'playsinline'},
{attrKey:'x5-video-player-type',attrValue:'h5-page'},
{ attrKey: 'webkit-playsinline', attrValue: 'webkit-playsinline' },
{ attrKey: 'playsinline', attrValue: 'playsinline' },
{ attrKey: 'x5-video-player-type', attrValue: 'h5-page' },
]
})
this.detail = _.cloneDeep(this.item)
},
methods: {
setLike() {
this.detail.liked = !this.detail.liked
this.detail.is_like = !this.detail.is_like
},
setComment() {
console.warn('跳转详情页,移动到留言页');
console.warn(this.detail.case_id);
console.warn(this.detail.id);
}
}
}
......@@ -96,14 +96,19 @@ export default {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.13);
.video-div {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.video-bar {
color: #713610;
padding: 1rem;
padding-bottom: 0.5rem;
.avatar {
}
}
}
</style>
\ No newline at end of file
......
import { ref } from 'vue'
import axios from '@/utils/axios';
import _ from 'lodash'
import { Toast } from 'vant';
export const useVideoList = ($route) => {
// 切换视频语言
const checkMandarin = ref(true); // 普通话选项卡
const checkLocalism = ref(false); // 方言选项卡
const chooseLanguage = ref({ text: '普通话', val: '普通话' }); // 默认选中普通话
const toggleLanguage = () => {
checkMandarin.value = !checkMandarin.value;
checkLocalism.value = !checkLocalism.value;
// 修改默认语言绑定数据
if (checkLocalism.value) {
// tslint:disable-next-line:no-string-literal
chooseLanguage.value = { text: columns[0]['text'], val: columns[0]['val'] }
} else {
chooseLanguage.value = { text: '普通话', val: '普通话' };
}
// 切换语言需要更新列表数据
offset.value = 0
prod_list.value = []
loading.value = true;
finished.value = false;
onLoad()
}
// 方言选择项
const columns = [
{ text: '所有方言', val: '所有方言' },
{ text: '沪语', val: '沪语' },
{ text: '粤语', val: '粤语' },
];
const showPicker = ref(false);
const onConfirm = ({ selectedOptions }) => {
showPicker.value = false;
chooseLanguage.value = {
text: selectedOptions[0].text,
val: selectedOptions[0].val
}
};
// 绑定页面数据
const bookInfo = ref('');
// tslint:disable-next-line: variable-name
const prod_list = ref([]);
const limit = ref(1)
const offset = ref(0)
// 处理书籍下作品列表
const loading = ref(false);
const finished = ref(false);
const onLoad = () => {
// 异步更新数据
axios.get('/srv/?a=book_info', {
params: {
book_id: $route.query.id,
localism_type: chooseLanguage.value.text,
limit: limit.value,
offset: offset.value
}
})
.then(res => {
if (res.data.code === 1) {
bookInfo.value = res.data.data;
prod_list.value = _.concat(prod_list.value, res.data.data.prod_list);
offset.value = prod_list.value.length;
loading.value = false;
// 数据全部加载完成
if (!res.data.data.prod_list.length) {
// 加载状态结束
finished.value = true;
}
} else {
// tslint:disable-next-line: no-console
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
// tslint:disable-next-line: no-console
console.error(err);
})
};
return {
toggleLanguage,
onLoad,
columns,
prod_list,
finished,
loading,
bookInfo,
showPicker,
checkLocalism,
checkMandarin,
onConfirm,
chooseLanguage
}
}
import axios from 'axios';
import router from '../router';
import _ from 'lodash'
// 请求拦截器
axios.interceptors.request.use(
config => {
// 发送请求前
if (config.method === 'get') {
// 绑定默认请求头
config.params = _.merge(config.params, {
f: 'voice',
client_id: '313939',
})
}
return config;
},
error => {
......
......@@ -3,15 +3,11 @@
<div class="modify-top"></div>
<div class="book-detail">
<div style="text-align: center;">
<van-image width="220" height="220"
src="https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngc434046fdf1f9499d251b280af2568ddbe64839799d00a9aee226edbeb710aed" />
<van-image width="220" height="220" :src="bookInfo.cover" />
</div>
<div class="book-intro">
<p class="book-post">逃家小兔绘本</p>
<div id="book-intro" :class="{ 'van-multi-ellipsis--l3': isToggle }">
从前有一只小兔子,总是想要离家出走。有一天他对妈妈说:“我要跑走啦!”“如果你跑走了我就去追你,因为你是我的小宝贝呀!”妈妈说。
一场爱的捉迷藏就此展开了
</div>
<p class="book-post">{{ bookInfo.name }}</p>
<div id="book-intro" :class="{ 'van-multi-ellipsis--l3': isToggle }">{{ bookInfo.note }}</div>
<div v-if="hasToggle">
<div v-if="isToggle" @click="onToggle(false)" class="book-toggle-icon">展开&nbsp;
<van-icon style="vertical-align: middle;" size="0.9rem" :name="icon_down" />
......@@ -32,7 +28,7 @@
<van-col span="12">
<div style="font-size: 1rem; color: #999999; text-align: right;">
<van-icon :name="icon_video" />
54个作品
{{ bookInfo.total }}个作品
</div>
</van-col>
</van-row>
......@@ -40,12 +36,12 @@
<div class="book-video-language">
<van-row>
<van-col span="6">
<div @click="toggleLanguage" :class="[check_mandarin ? 'checked' : 'uncheck']">普通话</div>
<div @click="toggleLanguage" :class="[checkMandarin ? 'checked' : 'uncheck']">普通话</div>
</van-col>
<van-col span="6">
<div @click="toggleLanguage" :class="[check_localism ? 'checked' : 'uncheck']">方言</div>
<div @click="toggleLanguage" :class="[checkLocalism ? 'checked' : 'uncheck']">方言</div>
</van-col>
<van-col span="12" v-if="check_localism" @click="showPicker = true">
<van-col span="12" v-if="checkLocalism" @click="showPicker = true">
<div class="choose-wrapper">
<div class="text">
&nbsp;{{ chooseLanguage.text }}
......@@ -65,7 +61,7 @@
<div class="book-video-list">
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
<template v-for="item in dataList" :key="item" style="height: 3rem;">
<template v-for="item in prod_list" :key="item" style="height: 3rem;">
<video-card :item="item"></video-card>
</template>
</van-list>
......@@ -92,14 +88,18 @@
<van-overlay :show="showNotice" z-index="1000">
<div class="wrapper" @click.stop>
<div class="block">
<div style="position: absolute; top: -2rem; right: 1rem; font-size: 1.5rem;"><van-icon name="close" color="#FFFFFF" @click="closeNotice" /></div>
<div style="position: absolute; top: -2rem; right: 1rem; font-size: 1.5rem;">
<van-icon name="close" color="#FFFFFF" @click="closeNotice" />
</div>
<div>
<van-image width="100" height="100" :src="icon_notice" />
<p style="margin: 1rem; font-size: 1.15rem; font-weight: bold; color: #222222;">温馨提示</p>
</div>
<div style="color: #333333;">
<p>您还没有实名认证</p>
<p>请点击 <van-icon :name="icon_me" /> 进行实名认证</p>
<p>请点击
<van-icon :name="icon_me" /> 进行实名认证
</p>
<p>实名认证之后再上传</p>
</div>
<div style="margin: 3rem 0;">
......@@ -111,7 +111,7 @@
</template>
<script setup>
import dataList from '@/mock/video_list'
import { useVideoList } from '@/composables/useVideoList.js'
import MyButton from '@/components/MyButton/index.vue'
import VideoCard from '@/components/VideoCard/index.vue'
......@@ -135,7 +135,7 @@ import { Toast } from 'vant';
const $route = useRoute();
const $router = useRouter();
const items = reactive([])
const { toggleLanguage, onLoad, columns, prod_list, finished, loading, bookInfo, showPicker, checkLocalism, checkMandarin, onConfirm, chooseLanguage } = useVideoList($route);
const gotoMe = () => {
console.warn('跳转我的地址');
......@@ -149,73 +149,13 @@ const onToggle = (v) => { // 展开/折叠
isToggle.value = v
}
// 切换视频语言
const check_mandarin = ref(true);
const check_localism = ref(false);
const chooseLanguage = ref({ text: '普通话', val: '00' }); // 默认选中普通话
const toggleLanguage = () => {
check_mandarin.value = !check_mandarin.value;
check_localism.value = !check_localism.value;
// 修改默认语言绑定数据
if (check_localism.value) {
chooseLanguage.value = { text: columns[0]['text'], val: columns[0]['val'] }
} else {
chooseLanguage.value = { text: '普通话', val: '00' };
}
}
// 方言选择项
const columns = [
{ text: '所有方言', val: '00' },
{ text: '沪语', val: '01' },
{ text: '粤语', val: '02' },
];
const showPicker = ref(false);
const onConfirm = ({ selectedOptions }) => {
showPicker.value = false;
chooseLanguage.value = {
text: selectedOptions[0].text,
val: selectedOptions[0].val
}
};
onMounted(() => {
// 判断是否显示简介的展开图标
nextTick(() => {
hasToggle.value = tools.hasEllipsis('book-intro');
})
for (let index = 0; index < 20; index++) {
items.push({
id: index,
avatar: 'https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg'
})
}
})
// 处理书籍下作品列表
const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const onLoad = () => {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
setTimeout(() => {
for (let i = 0; i < 20; i++) {
list.value.push(list.value.length + 1);
}
// 加载状态结束
loading.value = false;
// 数据全部加载完成
if (list.value.length >= 100) {
finished.value = true;
}
}, 1000);
};
// 书籍订阅
let is_subscribe = ref(false);
const onSubscribe = () => {
......@@ -250,20 +190,11 @@ export default {
mixins: [mixin.init],
data() {
return {
}
},
created() {
this.getList()
},
methods: {
getList() {
_.each(this.dataList, item => {
let video = item.video && item.video.url ? item.video.url : 'http://static.smartisanos.cn/common/video/t1-ui.mp4';
let cover = item.cover && item.cover.url ? item.cover.url : 'http://static.smartisanos.cn/pr/img/video/video_03_cc87ce5bdb.jpg';
item.options = { video: transCaseList(video, cover), autoplay: false, preload: 'none' }
})
}
}
}
</script>
......
......@@ -2,10 +2,13 @@
<div class="choose-book-page content-bg">
<div class="modify-top"></div>
<div class="belong-school">
<van-image round width="2rem" height="2rem" lazy-load src="https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg" style="vertical-align: text-bottom;" >
<template v-if="kg_id">
<van-image round width="2rem" height="2rem" lazy-load :src="kindergartenInfo.logo"
style="vertical-align: text-bottom;">
<template v-slot:error>加载失败</template>
</van-image>
<p class="title">杨浦民办科技幼稚园</p>
<p class="title">{{ kindergartenInfo.name }}</p>
</template>
</div>
<div style="position: relative;">
<div class="ding left"></div>
......@@ -21,7 +24,7 @@
<div class="ding right"></div>
</div>
<div class="book-list">
<template v-for="(item, key) in items" :key="key">
<template v-for="(item, key) in kindergartenInfo.book_list" :key="key">
<book-card type="C" :item="item" @on-click="onClick(item)"></book-card>
</template>
</div>
......@@ -34,23 +37,74 @@
import MyButton from '@/components/MyButton/index.vue'
import BookCard from '@/components/BookCard/index.vue'
import ShortcutFixed from '@/components/ShortcutFixed/index.vue'
import { ref, reactive, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from '@/utils/axios';
import _ from 'lodash'
import $ from 'jquery'
import { Toast } from 'vant';
const $route = useRoute();
const $router = useRouter();
// 自定义按钮颜色样式
const styleObject = reactive({
backgroundColor: '#F4675A',
color: '#FFFFFF',
borderColor: '#F4675A'
})
const items = reactive([])
// 页面数据绑定
const kg_id = $route.query.kg_id ? $route.query.kg_id : '';
const kindergartenInfo = ref({
id: '',
logo: '',
name: '',
book_list: []
});
onMounted(() => {
if (kg_id) { // 从学校列表进入
axios.get('/srv/?a=kg_book_list', {
params: {
kg_id
}
})
.then(res => {
if (res.data.code === 1) {
kindergartenInfo.value = res.data.data;
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
} else { // 从访客进入
axios.get('/srv/?a=book_list')
.then(res => {
if (res.data.code === 1) {
kindergartenInfo.value = {
book_list: res.data.data
}
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
}
})
// 跳转书籍详情页
const onClick = (item) => {
// 调整书籍详情页
$router.push({
path: '/client/bookDetail',
query: {
......@@ -58,17 +112,10 @@ const onClick = (item) => {
}
});
}
const gotoMe = () => {
console.warn('跳转我的地址');
}
onMounted(() => {
for (let index = 0; index < 20; index++) {
items.push({
id: index,
avatar: 'https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg'
})
}
})
</script>
<script>
......@@ -76,12 +123,12 @@ import mixin from 'common/mixin';
export default {
mixins: [mixin.init],
data () {
data() {
return {
}
},
mounted () {
mounted() {
},
methods: {
......@@ -92,9 +139,11 @@ export default {
<style lang="less" scoped>
@import url('@css/content-bg.less');
.choose-book-page {
.choose-book-page {
.belong-school {
padding: 1.5rem;
.title {
color: #222222;
display: inline-block;
......@@ -103,6 +152,7 @@ export default {
}
}
.book-list {
margin: 1rem;
margin-top: 1.25rem;
......@@ -111,6 +161,7 @@ export default {
background-color: rgba(255, 255, 255, 1);
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.13);
}
.ding {
z-index: 69;
position: absolute;
......@@ -120,12 +171,14 @@ export default {
background-image: url('@images/ding-left@2x.png');
background-size: contain;
background-repeat: no-repeat;
&.left {
left: 8rem;
}
&.right {
right: 8rem;
}
}
}
}
</style>
\ No newline at end of file
......
......@@ -5,7 +5,7 @@
<template v-for="(item, key) in schoolList" :key="key">
<right-side-list
@on-click="onClick(item)"
:avatar="item.avatar">
:avatar="item.logo">
{{ item.name }}
</right-side-list>
</template>
......@@ -15,26 +15,41 @@
<script setup>
import RightSideList from '@/components/RightSideList/index.vue'
import { reactive, onMounted } from 'vue';
import { ref, onMounted } from 'vue';
import axios from '@/utils/axios';
import $ from 'jquery'
import { useRoute, useRouter } from 'vue-router'
import { Toast } from 'vant';
const $route = useRoute();
const $router = useRouter();
const schoolList = reactive([])
const schoolList = ref([])
onMounted(() => {
for (let index = 0; index < 20; index++) {
schoolList.push({
id: index,
avatar: 'https://cdn.jsdelivr.net/npm/@vant/assets/cat.jpeg',
name: '中国福利会托儿所'
})
// 获取幼儿园列表页
axios.get('/srv/?a=kg_list')
.then(res => {
if (res.data.code === 1) {
schoolList.value = res.data.data;
} else {
console.warn(res);
Toast({
icon: 'close',
message: res.data.msg
});
}
})
.catch(err => {
console.error(err);
})
})
// 跳转幼儿园爱心书籍列表页
const onClick = (item) => {
$router.push({
path: '/client/chooseBook'
path: '/client/chooseBook',
query: {
kg_id: item.id
}
});
}
</script>
......
......@@ -34,7 +34,7 @@
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
, "src/store/index.ts"],
, "src/store/index.ts", "src/composables/useVideoList.js"],
"exclude": [
"node_modules"
]
......
......@@ -23,6 +23,7 @@ export default({ command, mode }) => {
alias: { // 将会被传递到 @rollup/plugin-alias 作为 entries 的选项。也可以是一个对象,或一个 { find, replacement } 的数组. 当使用文件系统路径的别名时,请始终使用绝对路径。相对路径的别名值会被原封不动地使用,因此无法被正常解析。 更高级的自定义解析方法可以通过 插件 实现。
"@": path.resolve(__dirname, "src"),
"@components": path.resolve(__dirname, "src/components"),
"@composables": path.resolve(__dirname, "src/composables"),
"@utils": path.resolve(__dirname, "src/utils"),
"@images": path.resolve(__dirname, "src/assets/images"),
"@css": path.resolve(__dirname, "src/assets/css"),
......