Browse Source

feat: page-case;

pull/1/head
Fox-33 1 month ago
parent
commit
1cf1f19d30
9 changed files with 609 additions and 5 deletions
  1. +1
    -1
      api/api.js
  2. +41
    -0
      api/model/case.js
  3. +43
    -0
      components/base/arrow.vue
  4. +158
    -0
      components/base/suspendDropdown.vue
  5. +3
    -1
      pages.json
  6. +198
    -0
      pages/index/case.vue
  7. +160
    -0
      pages_order/case/index.vue
  8. +2
    -2
      pages_order/thesis/index.vue
  9. +3
    -1
      uni.scss

+ 1
- 1
api/api.js View File

@ -5,7 +5,7 @@ import utils from '../utils/utils.js'
let limit = {}
let debounce = {}
const models = ['index']
const models = ['index', 'case']
const config = {
// 示例


+ 41
- 0
api/model/case.js View File

@ -0,0 +1,41 @@
// 案例相关接口
const api = {
/**
* 获取服务分类列表
*/
queryCategoryServiceList: {
url: '/config/queryCategoryServiceList',
method: 'GET',
},
/**
* 获取专业分类列表
*/
queryCategoryMajorList: {
url: '/config/queryCategoryMajorList',
method: 'GET',
},
/**
* 获取阶段分类列表
*/
queryCategoryPeriodList: {
url: '/config/queryCategoryPeriodList',
method: 'GET',
},
/**
* 获取案例文章列表
*/
queryAriticleList: {
url: '/index/queryAriticleList',
method: 'GET',
},
/**
* 获取案例文章详情
*/
queryAriticleById: {
url: '/index/queryAriticleById',
method: 'GET',
},
}
export default api

+ 43
- 0
components/base/arrow.vue View File

@ -0,0 +1,43 @@
<template>
<view class="arrow">
<view class="arrow-blank arrow-blank-top"></view>
<view class="arrow-blank arrow-blank-bottom"></view>
</view>
</template>
<script>
export default {
}
</script>
<style scoped lang="scss">
.arrow {
position: relative;
width: 28rpx;
height: 32rpx;
background-image: linear-gradient(to right, #A3BCEF, #4883F9);
&-blank {
position: absolute;
left: 0;
&-top {
top: 0;
border-top: 8rpx solid #FFFFFF;
border-right: 14rpx solid #FFFFFF;
border-bottom: 8rpx solid transparent;
border-left: 14rpx solid transparent;
}
&-bottom {
bottom: 0;
border-top: 8rpx solid transparent;
border-right: 14rpx solid #FFFFFF;
border-bottom: 8rpx solid #FFFFFF;
border-left: 14rpx solid transparent;
}
}
}
</style>

+ 158
- 0
components/base/suspendDropdown.vue View File

@ -0,0 +1,158 @@
<template>
<view class="drop-down">
<button class="btn" plain @click="openPicker" >
<view class="flex btn-label">
<view :style="{ color }">{{ label }}</view>
<uv-icon name="arrow-down-fill" :color="color" size="14rpx"></uv-icon>
</view>
</button>
<template v-if="popupVisible">
<view class="drop-down-overlay" @click="closePicker"></view>
<view class="card drop-down-popup" :style="popupStyle">
<view
v-for="item in options"
class="flex drop-down-option"
:class="[item.value === value ? 'is-active' : '']"
:key="item.value"
@click="onSelect(item.value)"
>
<text>{{ item.label }}</text>
</view>
</view>
</template>
</view>
</template>
<script>
export default {
props: {
value: {
type: String | Number,
default: null,
},
options: {
type: Array,
default() {
return []
}
},
label: {
type: String,
default: ''
},
},
data() {
return {
popupVisible: false,
popupStyle: {},
}
},
computed: {
isActive() {
return this.options.find(option => option.value === this.value)
},
color() {
return this.isActive ? '#4883F9' : '#000000'
}
},
methods: {
openPicker() {
this.popupVisible = true
return
uni.createSelectorQuery().in(this)
.select('.btn')
.fields({
node: true,
size: true,
rect: true,
})
.exec(async (res) => {
console.log('res', res)
const {
top,
left,
} = res[0]
console.log('top', top, 'left', left)
// this.popupStyle = {
// top: `${parseInt(top)}px`,
// left: `${parseInt(left)}px`,
// }
console.log('popupStyle', this.popupStyle)
this.popupVisible = true
})
},
closePicker() {
this.popupVisible = false
},
onSelect(val) {
const selected = this.value
const newVal = selected === val ? null : val
this.$emit('input', newVal)
this.$emit('change', newVal)
},
},
}
</script>
<style scoped lang="scss">
.drop-down {
position: relative;
clear: both;
.btn {
width: 213rpx;
padding: 27rpx 0;
font-size: 24rpx;
background: transparent;
border: none;
&-label {
column-gap: 9rpx;
}
}
&-overlay {
position: fixed;
width: 100vw;
height: calc(100vh - #{$navbar-height} - var(--status-bar-height) - 20rpx);
background: transparent;
bottom: 0;
left: 0;
font-size: 0;
}
&-popup {
position: absolute;
z-index: 99;
width: 213rpx;
background: #FFFFFF;
border-radius: 15rpx;
transform: translateY(-15rpx);
}
&-option {
color: #000000;
font-size: 24rpx;
padding: 7rpx 0;
text-align: center;
&.is-active {
color: #4883F9;
}
& + & {
border-top: 1rpx solid #EFEFEF;
}
}
}
</style>

+ 3
- 1
pages.json View File

@ -34,8 +34,10 @@
"root": "pages_order",
"pages": [{
"path": "thesis/search"
},{
}, {
"path": "thesis/index"
}, {
"path": "case/index"
}
]
}],


+ 198
- 0
pages/index/case.vue View File

@ -1,20 +1,218 @@
<template>
<view class="page__view">
<view class="bg"></view>
<view class="main">
<!-- 搜索栏 -->
<view class="search">
<uv-search v-model="keyword" placeholder="输入关键词搜索" bgColor="#FBFBFB" @custom="search" @search="search">
<template #prefix>
<image class="search-icon" src="@/static/image/icon-search.png" mode="widthFix"></image>
</template>
</uv-search>
</view>
<!-- 轮播图 -->
<view class="swiper">
<uv-swiper :list="bannerList" keyName="image" indicator indicatorMode="dot" indicatorActiveColor="#4883F9" indicatorInactiveColor="#FFFFFF" height="239rpx"></uv-swiper>
</view>
<view class="flex filter">
<view class="filter-item">
<suspendDropdown v-model="queryParams.categoryServiceId" label="服务分类筛选" :options="serviceOptions" @change="onFilterChange"></suspendDropdown>
</view>
<view class="filter-item">
<suspendDropdown v-model="queryParams.categoryMajorId" label="专业筛选" :options="majorOptions" @change="onFilterChange"></suspendDropdown>
</view>
<view class="filter-item">
<suspendDropdown v-model="queryParams.categoryPeriodId" label="阶段筛选" :options="periodOptions" @change="onFilterChange"></suspendDropdown>
</view>
</view>
<view class="list">
<view class="list-item" v-for="item in list" :key="item.id" @click="jumpToDetail(item.thesisId)">
<image class="img" :src="item.image" mode="aspectFill"></image>
</view>
</view>
</view>
<tabber select="case" />
</view>
</template>
<script>
import mixinsList from '@/mixins/list.js'
import tabber from '@/components/base/tabbar.vue'
import suspendDropdown from '@/components/base/suspendDropdown.vue'
export default {
mixins: [mixinsList],
components: {
tabber,
suspendDropdown,
},
data() {
return {
keyword: '',
bannerList: [],
serviceOptions: [],
majorOptions: [],
periodOptions: [],
list: [],
queryParams: {
pageNo: 1,
pageSize: 10,
title: null,
categoryServiceId: null,
categoryMajorId: null,
categoryPeriodId: null,
},
mixinsListApi: 'queryAriticleList',
}
},
onLoad() {
this.fetchBanner()
this.fetchOptions()
this.getData()
},
methods: {
// todo: delete
getData() {
this.list = [
{ id: '001', image: '/static/image/temp-1.png' },
{ id: '001', image: '/static/image/temp-2.png' },
{ id: '001', image: '/static/image/temp-3.png' },
]
this.total = this.list.length
},
search() {
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
this.queryParams.title = this.keyword
this.getData()
},
onFilterChange() {
this.queryParams.pageNo = 1
this.queryParams.pageSize = 10
this.getData()
},
//
async fetchBanner() {
try {
this.bannerList = (await this.$fetch('queryBannerList', { type: '1' }))?.records // type0- 1- 2- 3-
} catch (err) {
}
},
async fetchOptions() {
this.$fetch('queryCategoryServiceList').then(res => {
this.serviceOptions = res?.records?.map(item => ({ label: item.title, value: item.id })) || []
}).catch(err => {
})
this.$fetch('queryCategoryMajorList').then(res => {
this.majorOptions = res?.records?.map(item => ({ label: item.title, value: item.id })) || []
}).catch(err => {
})
this.$fetch('queryCategoryPeriodList').then(res => {
this.periodOptions = res?.records?.map(item => ({ label: item.title, value: item.id })) || []
}).catch(err => {
})
},
jumpToDetail(articleId) {
uni.navigateTo({
url: `/pages_order/case/index?articleId=${articleId}`
})
},
}
}
</script>
<style scoped lang="scss">
.bg {
width: 100%;
height: 438rpx;
background-image: linear-gradient(#4883F9, #4883F9, #4883F9, #FCFDFF);
}
.main {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 192rpx 0 182rpx 0;
}
.search {
margin: 0 18rpx;
width: calc(100% - 20rpx * 2);
background-color: #FFFFFF;
border-radius: 37rpx;
padding: 13rpx 0 13rpx 18rpx;
box-sizing: border-box;
display: flex;
align-items: center;
/deep/ .uv-search__action {
color: $uni-color;
padding: 10rpx 18rpx;
}
&-icon {
width: 26rpx;
height: auto;
}
}
.swiper {
margin: 29rpx 18rpx 0 18rpx;
border-radius: 25rpx 25rpx 0 0;
overflow: hidden;
/deep/ .uv-swiper-indicator__wrapper__dot {
width: 15rpx;
height: 15rpx;
}
/deep/ .uv-swiper-indicator__wrapper__dot--active {
width: 15rpx;
}
}
.filter {
column-gap: 33rpx;
padding: 0 23rpx;
background: #FFFFFF;
&-item {
flex: 1;
}
}
.list {
padding: 34rpx 37rpx;
&-item {
width: 100%;
height: 284rpx;
border-radius: 15rpx;
overflow: hidden;
& + & {
margin-top: 25rpx;
}
.img {
width: 100%;
height: 100%;
}
}
}
</style>

+ 160
- 0
pages_order/case/index.vue View File

@ -0,0 +1,160 @@
<template>
<view class="page__view">
<!-- 导航栏 -->
<navbar :title="title" leftClick @leftClick="$utils.navigateBack" bgColor="#4883F9" color="#FFFFFF" />
<!-- 轮播图 -->
<view class="swiper">
<uv-swiper :list="bannerList" keyName="image" :autoplay="bannerList.length" :indicator="bannerList.length" indicatorMode="dot" indicatorActiveColor="#4883F9" indicatorInactiveColor="#FFFFFF" height="424rpx"></uv-swiper>
</view>
<!-- 学生情况 -->
<view class="section">
<view class="section-header">
<arrow></arrow>
<view>学生情况</view>
</view>
<view class="section-content">
<!-- todo: check key -->
<uv-parse :content="detail.content"></uv-parse>
</view>
</view>
<!-- 服务项目 -->
<view class="section">
<view class="section-header">
<arrow></arrow>
<view>服务项目</view>
</view>
<view class="section-content">
<!-- todo: check key -->
<uv-parse :content="detail.content"></uv-parse>
</view>
</view>
<!-- 服务过程 -->
<view class="section">
<view class="section-header">
<arrow></arrow>
<view>服务过程</view>
</view>
<view class="section-content">
<!-- todo: check key -->
<uv-parse :content="detail.content"></uv-parse>
</view>
</view>
<!-- 服务结果 -->
<view class="section">
<view class="section-header">
<arrow></arrow>
<view>服务结果</view>
</view>
<view class="section-content">
<!-- todo: check key -->
<uv-parse :content="detail.content"></uv-parse>
</view>
</view>
<!-- 服务感受 -->
<view class="section">
<view class="section-header">
<arrow></arrow>
<view>服务感受</view>
</view>
<view class="section-content">
<!-- todo: check key -->
<uv-parse :content="detail.content"></uv-parse>
</view>
</view>
</view>
</template>
<script>
import arrow from '@/components/base/arrow.vue'
export default {
components: {
arrow,
},
data() {
return {
title: '',
bannerList: [],
detail: {},
}
},
onLoad({ articleId }) {
this.getData(articleId)
},
methods: {
async getData(articleId) {
try {
// todo
await this.$fetch('queryAriticleById', { articleId })
} catch (err) {
}
},
},
}
</script>
<style scoped lang="scss">
.page__view {
box-sizing: border-box;
padding-bottom: 36rpx;
background: #FFFFFF;
}
.swiper {
margin: 20rpx 18rpx 47rpx 18rpx;
/deep/ .uv-swiper-indicator__wrapper__dot {
width: 15rpx;
height: 15rpx;
}
/deep/ .uv-swiper-indicator__wrapper__dot--active {
width: 15rpx;
}
}
.section {
width: 100%;
padding: 0 18rpx;
box-sizing: border-box;
& + & {
margin-top: 40rpx;
}
&-header {
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 5rpx;
padding-left: 11rpx;
font-size: 32rpx;
font-weight: 700;
color: #000000;
}
&-content {
margin-top: 24rpx;
padding: 24rpx;
box-sizing: border-box;
white-space: pre-line;
font-size: 28rpx;
color: #000000;
background: #F8F8F8;
border-radius: 15rpx;
}
}
</style>

+ 2
- 2
pages_order/thesis/index.vue View File

@ -171,8 +171,8 @@
attachment: [],
}
},
onLoad({ id }) {
this.getData(id)
onLoad({ thesisId }) {
this.getData(thesisId)
},
methods: {
async getData(thesisId) {


+ 3
- 1
uni.scss View File

@ -93,4 +93,6 @@ $uni-font-size-paragraph:15px;
color: $uni-color;
text-align: center;
font-size: 28rpx;
}
}
$navbar-height: 100rpx;

Loading…
Cancel
Save