Browse Source

工厂直印

devlop
mo-bai 3 years ago
parent
commit
3893c011f9
16 changed files with 786 additions and 40 deletions
  1. 11
      App.vue
  2. 1
      apis/commonApi.js
  3. 20
      apis/factoryApi.js
  4. 20
      apis/productionApi.js
  5. 6
      common/css/reset.scss
  6. 120
      components/business-components/banner.vue
  7. 153
      components/business-components/factoryItem.vue
  8. 4
      env/index.js
  9. 28
      pages.json
  10. 2
      pages/digital-workshops/index.vue
  11. 240
      pages/factory/index.vue
  12. 25
      pages/login/index.vue
  13. 4
      pages/mine/index.vue
  14. 190
      pages/smart-order/index.vue
  15. BIN
      static/imgs/factory/default-factory.png
  16. 2
      utils/hook.js

11
App.vue

@ -1,21 +1,14 @@
<script>
import { go2, changeTabbar } from '@/utils/hook.js'
import { go2 } from '@/utils/hook.js'
import { isString } from '@/utils/is.js'
import store from '@/store/index.js'
import handlePushMsg from '@/utils/handlePushMsg.js'
import { checkUpdate } from '@/apis/commonApi.js'
import { enterpriseType } from '@/enums/index.js'
export default {
onLaunch: function () {
const token = store.state.qnToken
if (token) {
const type = store.state.companyInfo.enterpriseType
changeTabbar(type)
if (type == enterpriseType.PERSONAL) {
go2('mall')
} else {
go2('digital-workshops')
}
go2('factory')
}
// #ifdef APP-PLUS
this.createPushEvent()

1
apis/commonApi.js

@ -44,7 +44,6 @@ function syncStore(res) {
}
store.commit('setUserInfo', userInfo)
// 根据企业类型切换tabbar
changeTabbar(company.enterpriseType)
} else {
let userInfo = {
name: '', // 没有企业就没有name,

20
apis/factoryApi.js

@ -32,3 +32,23 @@ export function getFactoryInfo(data = {}) {
data
})
}
/**
* 获取工厂直印列表
*/
export function getFactoryList(data = {}) {
return http.get({
url: `/base-paper-trading/get/packaging/enterprise/list/page`,
data
})
}
/**
* 获取样品盒关联工厂列表
*/
export function getAffiliatedFactoryList(data = {}) {
return http.get({
url: `/base-paper-trading/get/sample/box/relevance/enterprise/list/page`,
data
})
}

20
apis/productionApi.js

@ -43,3 +43,23 @@ export function getProductionInfo(data = {}) {
data
})
}
/**
* 获取样品盒列表
*/
export function getSimpleList(data = {}) {
return http.get({
url: `/base-paper-trading/get/sample/box/list`,
data
})
}
/**
* 获取样品盒详情
*/
export function getSimpleInfo(data = {}) {
return http.get({
url: `/base-paper-trading/get/sample/box/details`,
data
})
}

6
common/css/reset.scss

@ -86,6 +86,12 @@ text {
align-items: flex-end;
}
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
cover-view {
line-height: 1.5;
white-space: normal;

120
components/business-components/banner.vue

@ -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>

153
components/business-components/factoryItem.vue

@ -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>

4
env/index.js

@ -1,8 +1,8 @@
/**
* @description 唯一环境变量
*/
// const env = 'test'
const env = 'test'
// const env = 'dev'
const env = 'production'
// const env = 'production'
export default env

28
pages.json

@ -19,6 +19,14 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/factory/index",
"style": {
"navigationBarTitleText": "工厂直印",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/device-operation/index",
"style": {
@ -35,6 +43,14 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/smart-order/index",
"style": {
"navigationBarTitleText": "智能下单",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/promotion/index",
"style": {
@ -248,18 +264,18 @@
"borderStyle": "white",
"backgroundColor": "#f9f9f9",
"list": [
{
"pagePath": "pages/factory/index",
"iconPath": "static/imgs/tabbar/promotion-gray.png",
"selectedIconPath": "static/imgs/tabbar/promotion-blue.png",
"text": "工厂直印"
},
{
"pagePath": "pages/digital-workshops/index",
"iconPath": "static/imgs/tabbar/workshop-gray.png",
"selectedIconPath": "static/imgs/tabbar/workshop-blue.png",
"text": "数字车间"
},
{
"pagePath": "pages/promotion/index",
"iconPath": "static/imgs/tabbar/promotion-gray.png",
"selectedIconPath": "static/imgs/tabbar/promotion-blue.png",
"text": "推广"
},
{
"pagePath": "pages/mall/index",
"iconPath": "static/imgs/tabbar/mall-gray.png",

2
pages/digital-workshops/index.vue

@ -138,7 +138,7 @@ export default {
},
option: {
size: 10,
auto: true,
auto: false,
emptyText: '暂无设备~',
background: '#F7F8FA',
fontSize: '40rpx'

240
pages/factory/index.vue

@ -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>

25
pages/login/index.vue

@ -151,24 +151,13 @@ export default {
},
setAccountInfo(page = { url: 'digital-workshops', data: {}, isRedirect: true }) {
getBaseInfo({}, true).then((res) => {
if (res) {
//
// #ifdef APP-PLUS
let cid = plus.push.getClientInfo().clientid
let platform = uni.getSystemInfoSync().platform
pushCustomerBind(cid, platform)
// #endif
if (!res.enterpriseList || res.enterpriseList.length === 0) {
go2('select-role')
} else {
// //
let type = this.$store.state.companyInfo.enterpriseType
if (type == enterpriseType.PERSONAL) {
page.url = 'mall'
}
go2(page.url, page.data, page.isRedirect)
}
}
// useId
// #ifdef APP-PLUS
let cid = plus.push.getClientInfo().clientid
let platform = uni.getSystemInfoSync().platform
pushCustomerBind(cid, platform)
// #endif
go2(page.url, page.data, page.isRedirect)
})
}
},

4
pages/mine/index.vue

@ -32,7 +32,7 @@
</view>
</view>
</view>
<view class="card-area">
<view class="card-area" v-if="hasCompany">
<view class="header">
<text style="font-size: 30rpx; color: rgba(0, 0, 0, 0.85); font-weight: 600">我的设备</text>
</view>
@ -262,7 +262,7 @@ export default {
})
this.hasLogin && getBaseInfo({}, true)
!this.hasLogin && (this.fsInfo.status = -1)
this.hasLogin &&
this.hasCompany &&
getDeviceStatistics().then((res) => {
if (res) {
this.deviceInfo = res

190
pages/smart-order/index.vue

@ -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>

BIN
static/imgs/factory/default-factory.png

Before After
Width: 360  |  Height: 360  |  Size: 252 KiB

2
utils/hook.js

@ -2,7 +2,7 @@ import store from '@/store/index'
import { uploadUrl, XAPPID, enterpriseType } from '@/enums/index.js'
import { pushCustomerOff } from '@/apis/commonApi'
// 框架方法封装
const tabList = ['digital-workshops', 'promotion', 'mall', 'mine']
const tabList = ['digital-workshops', 'factory', 'mall', 'mine']
/**
* @param {string} 跳转的tabBar页面

Loading…
Cancel
Save