16 changed files with 786 additions and 40 deletions
Split View
Diff Options
-
11App.vue
-
1apis/commonApi.js
-
20apis/factoryApi.js
-
20apis/productionApi.js
-
6common/css/reset.scss
-
120components/business-components/banner.vue
-
153components/business-components/factoryItem.vue
-
4env/index.js
-
28pages.json
-
2pages/digital-workshops/index.vue
-
240pages/factory/index.vue
-
25pages/login/index.vue
-
4pages/mine/index.vue
-
190pages/smart-order/index.vue
-
BINstatic/imgs/factory/default-factory.png
-
2utils/hook.js
@ -0,0 +1,120 @@ |
|||
<template> |
|||
<view class="group_1"> |
|||
<swiper :current="swiperCurrent" @change="changeSwiper" class="swiper"> |
|||
<swiper-item v-for="(item, index) in list" :key="index"> |
|||
<image mode="aspectFit" v-if="item.type == 'image'" :src="item.url" class="image" @click="preview(item.url)" /> |
|||
<view v-if="item.type == 'video'" class="video-area"> |
|||
<image mode="aspectFit" @click="playVideo(index)" v-show="showIndex != index" :src="item.imageUrl" class="image" /> |
|||
<view> |
|||
<video v-if="showIndex == index" autoplay :src="item.url" class="video"></video> |
|||
</view> |
|||
</view> |
|||
</swiper-item> |
|||
</swiper> |
|||
<!-- <image @click="shareFactory" src="/static/imgs/general/share-gray-icon.png" class="image_1" /> --> |
|||
<view class="flex-col items-center text-wrapper"> |
|||
<text>{{ swiperCurrent + 1 }}/{{ list.length }}</text> |
|||
</view> |
|||
<image v-if="showClose" @click="closeVideo()" class="video-close" src="/static/imgs/promotion/video-close.png"></image> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
/** |
|||
* @property {Array<Object>} list - banner列表 |
|||
* @property {String} list.type - banner类型, image:图片,video:视频 |
|||
* @property {String} list.url - banner图片地址 |
|||
* @property {String} list.imageUrl - banner视频封面地址 |
|||
*/ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
swiperCurrent: 0, |
|||
showIndex: null, |
|||
showClose: false |
|||
} |
|||
}, |
|||
methods: { |
|||
changeSwiper(e) { |
|||
this.swiperCurrent = e.detail.current |
|||
}, |
|||
playVideo(index) { |
|||
this.showClose = true |
|||
this.showIndex = index |
|||
}, |
|||
closeVideo() { |
|||
this.showIndex = null |
|||
this.showClose = false |
|||
}, |
|||
preview(url) { |
|||
let urls = [] |
|||
for (let item of this.list) { |
|||
if (item.type == 'image') { |
|||
urls.push(item.url) |
|||
} |
|||
} |
|||
uni.previewImage({ |
|||
current: url, |
|||
urls: urls |
|||
}) |
|||
}, |
|||
shareFactory() { |
|||
this.$emit('share') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.group_1 { |
|||
color: rgb(255, 255, 255); |
|||
font-size: 28rpx; |
|||
line-height: 40rpx; |
|||
white-space: nowrap; |
|||
position: relative; |
|||
height: 440rpx; |
|||
width: 750rpx; |
|||
.swiper { |
|||
height: 440rpx; |
|||
width: 750rpx; |
|||
} |
|||
.image { |
|||
width: 750rpx; |
|||
height: 440rpx; |
|||
background-color: rgb(0, 0, 0); |
|||
} |
|||
.video-area { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: relative; |
|||
.video { |
|||
width: 750rpx; |
|||
height: 440rpx; |
|||
} |
|||
} |
|||
|
|||
.text-wrapper { |
|||
position: absolute; |
|||
right: 20rpx; |
|||
bottom: 62rpx; |
|||
background-color: rgba(0, 0, 0, 0.4); |
|||
border-radius: 20rpx; |
|||
width: 64rpx; |
|||
} |
|||
} |
|||
/** 定制关闭 */ |
|||
.video-close { |
|||
position: fixed; |
|||
bottom: 260rpx; |
|||
right: 32rpx; |
|||
width: 66rpx; |
|||
height: 66rpx; |
|||
z-index: 9999; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,153 @@ |
|||
<template> |
|||
<view class="list-item flex-row"> |
|||
<image :src="item.pictureUrl || '/static/imgs/factory/default-factory.png'" class="image_8" /> |
|||
<view class="center-group flex-col"> |
|||
<view class="flex-row"> |
|||
<text class="text_11 text-ellipsis">{{ item.name }}</text> |
|||
<view class="right-text-wrapper_1 flex-col"> |
|||
<text class="text_18">{{ item.score }}分</text> |
|||
</view> |
|||
</view> |
|||
<view class="center-group_1 flex-row"> |
|||
<image |
|||
src="https://project-user-resource-1256085488.cos.ap-guangzhou.myqcloud.com/611dd17441a9be0011f45822/620ccb0962a7d90011fe5c8f/16508554099266202544.png" |
|||
class="image_10" |
|||
/> |
|||
<text class="text_13">{{ item.address }}</text> |
|||
<text class="text_14">{{ item.mileage === -1 ? '未知' : '距您' + item.mileage + 'km' }}</text> |
|||
</view> |
|||
<view class="bottom-group flex-row" v-if="item.boxTags && item.boxTags.length > 0"> |
|||
<view v-for="(tag, index) in item.boxTags" :key="tag.id" class="text-wrapper flex-col items-center" :class="'text-wrapper_' + index"> |
|||
<text>{{ tag.name }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="flex-row group_10"> |
|||
<image v-for="pic in arrSlice(item.sampleBoxUrl, 3)" :key="pic" :src="pic" class="image_16" /> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
item: { |
|||
type: Object, |
|||
default: () => { |
|||
return {} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
arrSlice(arr, length) { |
|||
if (!arr) { |
|||
return [] |
|||
} |
|||
return arr.slice(0, length) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.list-item { |
|||
&:first-of-type { |
|||
border-top: solid 2rpx rgb(221, 221, 221); |
|||
} |
|||
padding: 25rpx 32rpx 21rpx; |
|||
border-bottom: solid 2rpx rgb(216, 216, 216); |
|||
.image_8 { |
|||
border-radius: 8rpx; |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
} |
|||
.center-group { |
|||
margin-left: 16rpx; |
|||
flex: 1 1 auto; |
|||
.text_11 { |
|||
color: rgb(51, 51, 51); |
|||
font-size: 34rpx; |
|||
font-weight: 500; |
|||
line-height: 48rpx; |
|||
white-space: nowrap; |
|||
max-width: 408rpx; |
|||
} |
|||
.center-group_1 { |
|||
margin-top: 12rpx; |
|||
padding: 0 2rpx; |
|||
color: rgb(51, 51, 51); |
|||
font-size: 26rpx; |
|||
line-height: 37rpx; |
|||
white-space: nowrap; |
|||
|
|||
.image_10 { |
|||
margin: 8rpx 0 5rpx; |
|||
width: 20rpx; |
|||
height: 23rpx; |
|||
} |
|||
.text_13 { |
|||
margin-left: 8rpx; |
|||
white-space: pre-wrap; |
|||
flex: 1 1 auto; |
|||
} |
|||
.text_14 { |
|||
margin-left: 24rpx; |
|||
font-size: 26rpx; |
|||
color: #888888; |
|||
} |
|||
} |
|||
.bottom-group { |
|||
margin-top: 17rpx; |
|||
flex-wrap: wrap; |
|||
.text-wrapper { |
|||
padding: 2rpx 4rpx; |
|||
margin-right: 6rpx; |
|||
font-size: 18rpx; |
|||
font-weight: 500; |
|||
line-height: 25rpx; |
|||
white-space: nowrap; |
|||
background-color: rgba(255, 77, 79, 0.08); |
|||
border-radius: 2rpx; |
|||
height: 29rpx; |
|||
} |
|||
.text-wrapper_0 { |
|||
border: solid 2rpx rgb(255, 77, 79); |
|||
color: rgb(255, 77, 79); |
|||
} |
|||
.text-wrapper_1 { |
|||
color: rgb(254, 134, 0); |
|||
border: solid 2rpx rgb(254, 136, 6); |
|||
} |
|||
.text-wrapper_2 { |
|||
color: rgb(19, 194, 194); |
|||
border: solid 2rpx rgb(19, 194, 194); |
|||
} |
|||
} |
|||
} |
|||
.right-text-wrapper_1 { |
|||
margin: 11rpx 14rpx 0 12rpx; |
|||
padding-top: 2rpx; |
|||
color: rgb(255, 255, 255); |
|||
font-size: 18rpx; |
|||
font-weight: 600; |
|||
line-height: 25rpx; |
|||
white-space: nowrap; |
|||
background-image: linear-gradient(90deg, rgb(255, 186, 101) 0%, rgb(255, 186, 101) 0%, rgb(255, 143, 53) 100%, rgb(255, 143, 53) 100%); |
|||
border-radius: 14rpx 2rpx 14rpx 14rpx; |
|||
height: 28rpx; |
|||
.text_18 { |
|||
margin-left: 6rpx; |
|||
margin-right: 5rpx; |
|||
} |
|||
} |
|||
.group_10 { |
|||
margin-top: 16rpx; |
|||
.image_16 { |
|||
border-radius: 4rpx; |
|||
margin-right: 16rpx; |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,8 +1,8 @@ |
|||
/** |
|||
* @description 唯一环境变量 |
|||
*/ |
|||
// const env = 'test'
|
|||
const env = 'test' |
|||
// const env = 'dev'
|
|||
const env = 'production' |
|||
// const env = 'production'
|
|||
|
|||
export default env |
|||
@ -0,0 +1,240 @@ |
|||
<template> |
|||
<view class="content"> |
|||
<uni-nav-bar statusBar fixed title="工厂直印"></uni-nav-bar> |
|||
<view class="flex-col group_3"> |
|||
<view class="group_4"> |
|||
<text class="text_4">热门推荐</text> |
|||
<view class="flex-row justify-between equal-division"> |
|||
<view class="flex-col equal-division-item" v-for="simple in simpleList" :key="simple.id" @click="go2('smart-order', { id: simple.id })"> |
|||
<image :src="simple.pictureUrl" class="image_3" /> |
|||
<text class="text_5 text-ellipsis">{{ simple.name }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="justify-between group_5"> |
|||
<text class="text_9">工厂直印</text> |
|||
<view class="group_6"> |
|||
<qn-select contentStyle="background: none; padding: 0;text-align: right;" :options="options" v-model="condition.sortFlag"></qn-select> |
|||
</view> |
|||
</view> |
|||
<view class="list"> |
|||
<scroll-list ref="list" :option="option" @load="upCallback" @refresh="downCallback"> |
|||
<factoryItem v-for="(item, index) in factoryList" :key="index" :item="item"></factoryItem> |
|||
</scroll-list> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { go2, back } from '@/utils/hook.js' |
|||
import { getFactoryList } from '@/apis/factoryApi' |
|||
import { getSimpleList } from '@/apis/productionApi' |
|||
import factoryItem from '@/components/business-components/factoryItem' |
|||
const options = [ |
|||
{ |
|||
label: '按距离排序', |
|||
value: 2 |
|||
}, |
|||
{ |
|||
label: '按评分排序', |
|||
value: 1 |
|||
} |
|||
] |
|||
export default { |
|||
components: { |
|||
factoryItem |
|||
}, |
|||
data() { |
|||
return { |
|||
options: Object.freeze(options), |
|||
condition: { |
|||
sortFlag: 1, |
|||
latitude: '', |
|||
longitude: '', |
|||
pageNum: 0, // 初始会执行一次下拉加载 |
|||
pageSize: 10 |
|||
}, |
|||
option: { |
|||
size: 10, |
|||
auto: true, |
|||
emptyText: '暂无数据~', |
|||
background: '#F7F8FA' |
|||
}, |
|||
simpleList: [], |
|||
factoryList: [] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
this.getLocation() |
|||
.then(() => { |
|||
this.condition.sortFlag = 2 |
|||
}) |
|||
.catch(() => { |
|||
this.condition.sortFlag = 1 |
|||
}) |
|||
}, |
|||
onShow() { |
|||
getSimpleList().then((res) => { |
|||
this.simpleList = res |
|||
}) |
|||
}, |
|||
watch: { |
|||
'condition.sortFlag': { |
|||
handler(val) { |
|||
if (val === 2) { |
|||
if (this.condition.latitude === null) { |
|||
uni.showModal({ |
|||
title: '提示', |
|||
content: '请先授权定位', |
|||
success: (res) => { |
|||
if (res.confirm) { |
|||
this.getLocation().catch(() => {}) |
|||
} |
|||
} |
|||
}) |
|||
} else { |
|||
this.downCallback() |
|||
} |
|||
return |
|||
} |
|||
if (val === 1) { |
|||
this.downCallback() |
|||
return |
|||
} |
|||
}, |
|||
immediate: true |
|||
}, |
|||
'condition.latitude': { |
|||
handler(val) { |
|||
if (val) { |
|||
this.downCallback() |
|||
} |
|||
}, |
|||
immediate: true |
|||
} |
|||
}, |
|||
methods: { |
|||
go2, |
|||
back, |
|||
getList() { |
|||
return new Promise((resolve, reject) => { |
|||
getFactoryList({ ...this.condition }) |
|||
.then((res) => { |
|||
if (res.current <= 1) { |
|||
this.factoryList = res.records |
|||
} else { |
|||
this.factoryList = this.factoryList.concat(res.records) |
|||
} |
|||
resolve({ list: this.factoryList, total: res.total }) |
|||
}) |
|||
.catch((err) => { |
|||
reject(err) |
|||
}) |
|||
}) |
|||
}, |
|||
downCallback() { |
|||
this.condition.pageNum = 1 |
|||
// this.$refs.list.load() |
|||
this.getList() |
|||
.then(({ list, total }) => { |
|||
this.$refs.list.refreshSuccess({ list, total }) |
|||
}) |
|||
.catch(() => { |
|||
this.$refs.list.refreshFail() |
|||
}) |
|||
}, |
|||
upCallback(page) { |
|||
this.condition.pageNum++ |
|||
this.getList() |
|||
.then(({ list, total }) => { |
|||
this.$refs.list.loadSuccess({ list, total }) |
|||
}) |
|||
.catch(() => { |
|||
this.$refs.list.loadFail() |
|||
}) |
|||
}, |
|||
getLocation() { |
|||
return new Promise((resolve, reject) => { |
|||
uni.getLocation({ |
|||
type: 'gcj02', |
|||
success: (res) => { |
|||
this.condition.latitude = res.latitude |
|||
this.condition.longitude = res.longitude |
|||
resolve() |
|||
}, |
|||
fail: (err) => { |
|||
this.condition.latitude = null |
|||
this.condition.longitude = null |
|||
reject() |
|||
} |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 750rpx; |
|||
height: 100vh; |
|||
.group_3 { |
|||
padding-top: 25rpx; |
|||
height: 100%; |
|||
.group_4 { |
|||
padding-left: 32rpx; |
|||
padding-right: 32rpx; |
|||
.text_4 { |
|||
color: rgb(51, 51, 51); |
|||
font-size: 36rpx; |
|||
font-weight: 500; |
|||
line-height: 50rpx; |
|||
white-space: nowrap; |
|||
} |
|||
.equal-division { |
|||
margin-top: 24rpx; |
|||
color: rgb(51, 51, 51); |
|||
font-size: 22rpx; |
|||
font-weight: 500; |
|||
line-height: 30rpx; |
|||
white-space: nowrap; |
|||
.equal-division-item { |
|||
padding-bottom: 11rpx; |
|||
background-color: #f6f7fa; |
|||
box-shadow: 0px 8rpx 28rpx -24rpx rgba(0, 0, 0, 0.1); |
|||
border-radius: 8rpx; |
|||
position: relative; |
|||
.text_5 { |
|||
width: 160rpx; |
|||
padding: 12rpx 10rpx; |
|||
} |
|||
} |
|||
.image_3 { |
|||
border-radius: 8rpx 8rpx 0px 0px; |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
} |
|||
} |
|||
} |
|||
.group_5 { |
|||
margin-top: 64rpx; |
|||
padding: 0 32rpx; |
|||
.text_9 { |
|||
color: rgb(51, 51, 51); |
|||
font-size: 36rpx; |
|||
font-weight: 500; |
|||
line-height: 50rpx; |
|||
white-space: nowrap; |
|||
} |
|||
.group_6 { |
|||
width: 360rpx; |
|||
} |
|||
} |
|||
.list { |
|||
margin-top: 18rpx; |
|||
flex: 1 1 0; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,190 @@ |
|||
<template> |
|||
<view class="content flex-col"> |
|||
<uni-nav-bar left-icon="back" @clickLeft="back" statusBar fixed title="智能下单"></uni-nav-bar> |
|||
<Banner :list="transformSwiper(info.pictureUrl)"></Banner> |
|||
<view class="flex-col group_7"> |
|||
<text class="text_6">{{ info.name }}</text> |
|||
<text class="text_7"> |
|||
{{ info.des }} |
|||
</text> |
|||
<view class="justify-between section_2"> |
|||
<view class="flex-row"> |
|||
<text>尺寸(mm)</text> |
|||
<view class="flex-row group_9"> |
|||
<text>厚度(mm)</text> |
|||
<text class="text_10">材质</text> |
|||
</view> |
|||
</view> |
|||
<text class="text_11">数量</text> |
|||
</view> |
|||
<view class="justify-between section_3"> |
|||
<text style="width: 160rpx">{{ info.size }}</text> |
|||
<text style="width: 110rpx">{{ info.thickness }}</text> |
|||
<text style="width: 160rpx">{{ info.texture }}</text> |
|||
<text style="width: 110rpx">{{ info.minimumOrderQuantity }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="list"> |
|||
<view class="justify-between group_10"> |
|||
<text class="text_16">推荐工厂列表</text> |
|||
</view> |
|||
<scroll-list ref="list" :option="option" @load="upCallback" @refresh="downCallback"> |
|||
<factoryItem v-for="item in factoryList" :key="item.id" :item="item"></factoryItem> |
|||
</scroll-list> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { go2, back } from '@/utils/hook.js' |
|||
import { getSimpleInfo } from '@/apis/productionApi' |
|||
import { getAffiliatedFactoryList } from '@/apis/factoryApi' |
|||
import Banner from '@/components/business-components/banner.vue' |
|||
import factoryItem from '@/components/business-components/factoryItem' |
|||
export default { |
|||
components: { |
|||
Banner, |
|||
factoryItem |
|||
}, |
|||
data() { |
|||
return { |
|||
info: {}, |
|||
condition: { |
|||
id: null, |
|||
pageNum: 0, // 初始会执行一次下拉加载 |
|||
pageSize: 10 |
|||
}, |
|||
option: { |
|||
size: 10, |
|||
auto: false, |
|||
emptyText: '暂无数据~', |
|||
background: '#F7F8FA' |
|||
}, |
|||
factoryList: [] |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
if (options.id) { |
|||
this.condition.id = options.id |
|||
this.getInfo(this.condition.id) |
|||
this.downCallback() |
|||
} |
|||
}, |
|||
methods: { |
|||
go2, |
|||
back, |
|||
getInfo(id) { |
|||
getSimpleInfo({ id }).then((res) => { |
|||
this.info = res |
|||
}) |
|||
}, |
|||
transformSwiper(list) { |
|||
if (list) { |
|||
return list.map((item) => { |
|||
return { |
|||
url: item, |
|||
type: 'image' |
|||
} |
|||
}) |
|||
} |
|||
return [] |
|||
}, |
|||
getList() { |
|||
return new Promise((resolve, reject) => { |
|||
getAffiliatedFactoryList({ ...this.condition }) |
|||
.then((res) => { |
|||
if (res.current <= 1) { |
|||
this.factoryList = res.records |
|||
} else { |
|||
this.factoryList = this.factoryList.concat(res.records) |
|||
} |
|||
resolve({ list: this.factoryList, total: res.total }) |
|||
}) |
|||
.catch((err) => { |
|||
reject(err) |
|||
}) |
|||
}) |
|||
}, |
|||
downCallback() { |
|||
this.condition.pageNum = 1 |
|||
this.getList() |
|||
.then(({ list, total }) => { |
|||
this.$refs.list.refreshSuccess({ list, total }) |
|||
}) |
|||
.catch(() => { |
|||
this.$refs.list.refreshFail() |
|||
}) |
|||
}, |
|||
upCallback(page) { |
|||
this.condition.pageNum++ |
|||
this.getList() |
|||
.then(({ list, total }) => { |
|||
this.$refs.list.loadSuccess({ list, total }) |
|||
}) |
|||
.catch(() => { |
|||
this.$refs.list.loadFail() |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 750rpx; |
|||
height: 100vh; |
|||
.list { |
|||
margin-top: 18rpx; |
|||
height: 60vh; |
|||
.group_10 { |
|||
padding: 19rpx 32rpx 18rpx; |
|||
} |
|||
} |
|||
} |
|||
.group_7 { |
|||
padding: 26rpx 32rpx 24rpx; |
|||
background-color: rgb(255, 255, 255); |
|||
.text_6 { |
|||
color: rgb(0, 0, 0); |
|||
font-size: 34rpx; |
|||
font-weight: 500; |
|||
line-height: 48rpx; |
|||
white-space: nowrap; |
|||
} |
|||
.text_7 { |
|||
margin-right: 9rpx; |
|||
margin-top: 16rpx; |
|||
color: rgb(51, 51, 51); |
|||
font-size: 28rpx; |
|||
line-height: 40rpx; |
|||
text-align: left; |
|||
} |
|||
.section_2 { |
|||
margin-top: 24rpx; |
|||
padding: 19rpx 32rpx 23rpx; |
|||
color: rgb(136, 136, 136); |
|||
font-size: 24rpx; |
|||
line-height: 33rpx; |
|||
white-space: nowrap; |
|||
background-color: rgb(247, 248, 250); |
|||
.text_11 { |
|||
margin-right: 54rpx; |
|||
} |
|||
.group_9 { |
|||
margin-left: 72rpx; |
|||
.text_10 { |
|||
margin-left: 40rpx; |
|||
} |
|||
} |
|||
} |
|||
.section_3 { |
|||
padding: 20rpx 30rpx; |
|||
color: rgb(51, 51, 51); |
|||
font-size: 22rpx; |
|||
line-height: 30rpx; |
|||
white-space: pre-wrap; |
|||
background-color: rgb(255, 255, 255); |
|||
border: solid 2rpx rgb(216, 216, 216); |
|||
} |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save