Browse Source

“新增下拉刷新,默认接口”

v1
Lj 9 months ago
parent
commit
13189a56e6
47 changed files with 2640 additions and 1585 deletions
  1. +23
    -0
      App.vue
  2. +2
    -2
      api/api.js
  3. +1
    -32
      api/config.js
  4. +25
    -29
      api/model/index.js
  5. +14
    -0
      pages.json
  6. +5
    -3
      pages/baoyou-city/baoyou-city.vue
  7. +88
    -12
      pages/component/home.vue
  8. +56
    -15
      pages/component/my.vue
  9. +100
    -196
      pages/component/recycle.vue
  10. +21
    -4
      pages/index/index.vue
  11. +9
    -0
      pages/manager/inspect-result.vue
  12. +13
    -0
      pages/manager/inspect.vue
  13. +31
    -20
      pages/manager/order-detail.vue
  14. +55
    -38
      pages/manager/order.vue
  15. +12
    -0
      pages/manager/staff-detail.vue
  16. +17
    -2
      pages/manager/staff.vue
  17. +12
    -0
      pages/manager/tui-apply-detail.vue
  18. +12
    -0
      pages/manager/tui-detail.vue
  19. +12
    -0
      pages/manager/tui.vue
  20. +12
    -0
      pages/manager/user-detail.vue
  21. +12
    -0
      pages/manager/user.vue
  22. +8
    -0
      pages/subcomponent/about.vue
  23. +8
    -0
      pages/subcomponent/add.vue
  24. +23
    -19
      pages/subcomponent/admin_customer.vue
  25. +8
    -0
      pages/subcomponent/admin_edit_profile.vue
  26. +271
    -189
      pages/subcomponent/admin_faq.vue
  27. +8
    -0
      pages/subcomponent/apply.vue
  28. +8
    -0
      pages/subcomponent/brand.vue
  29. +8
    -0
      pages/subcomponent/detail.vue
  30. +8
    -0
      pages/subcomponent/edit.vue
  31. +190
    -149
      pages/subcomponent/edit_profile.vue
  32. +10
    -2
      pages/subcomponent/faq.vue
  33. +373
    -0
      pages/subcomponent/inspection-report.vue
  34. +8
    -0
      pages/subcomponent/inspection.vue
  35. +25
    -4
      pages/subcomponent/order.vue
  36. +8
    -0
      pages/subcomponent/order_edit.vue
  37. +11
    -3
      pages/subcomponent/orders.vue
  38. +21
    -3
      pages/subcomponent/pickup.vue
  39. +195
    -0
      pages/subcomponent/promo-qrcode.vue
  40. +551
    -498
      pages/subcomponent/promotion.vue
  41. +18
    -10
      pages/subcomponent/promotion_info.vue
  42. +9
    -2
      pages/subcomponent/recycle_rules.vue
  43. +11
    -1
      pages/subcomponent/select.vue
  44. +226
    -342
      pages/subcomponent/upgrad.vue
  45. +8
    -0
      pages/subcomponent/wallet.vue
  46. +8
    -0
      pages/subcomponent/withdraw.vue
  47. +86
    -10
      wxcomponents/privacy-popup/privacy-popup.vue

+ 23
- 0
App.vue View File

@ -37,6 +37,29 @@
display: flex;
justify-content: center;
}
/* 每个页面公共css */
/* 解决小程序和app滚动条的问题 */
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
color: transparent;
}
/* 解决H5的问题 */
uni-scroll-view .uni-scroll-view::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
color: transparent;
}
</style>

+ 2
- 2
api/api.js View File

@ -57,10 +57,10 @@ export function api(key, data = {}, callback, loadingTitle) {
}
limit.set(req.url, Date.now())
}
console.log(!uni.getStorageSync('token'),'status');
// console.log(!uni.getStorageSync('token'),'status');
// 必须登录
if (req.auth && !uni.getStorageSync('token')) {
utils.toLogin()
// utils.toLogin()
return Promise.reject(new Error('需要登录'))
}


+ 1
- 32
api/config.js View File

@ -2,38 +2,7 @@ const config = {
// getConfig: { url: '/config_common/getConfig', method: 'GET', limit: 500 },
// 其他静态接口
// 获取地址列表
// getAddressList: {
// url: '/recycle-admin/applet/address/getAddressList',
// method: 'GET',
// limit : 500,
// showLoading : true,
// },
// // 保存或修改地址
// saveOrUpdateAddress: {
// url: '/recycle-admin/applet/address/saveOrUpdateAddress',
// method: 'POST',
// auth: true,
// },
// // 修改默认地址
// updateDefaultAddress: {
// url: '/recycle-admin/applet/address/updateDefaultAddress',
// method: 'POST',
// auth: true,
// limit : 500,
// showLoading : true,
// },
// // 获取地址详情
// getAddressInfo: {
// url: '/recycle-admin/applet/address/getAddressInfo',
// method: 'GET',
// auth: true,
// },
// //删除地址
// deleteAddress: {
// url: '/recycle-admin/applet/address/deleteAddress',
// method: 'POST',
// auth: true,
// },
}

+ 25
- 29
api/model/index.js View File

@ -3,15 +3,10 @@
const api = {
// 获取首页轮播图
getRiceBanner: {
url: '/index_common/getRiceBanner',
url: '/recycle-admin/applet/index/getBanner',
method: 'GET',
},
// 获取首页常规产品【废弃】
// getRiceCommonProductList: {
// url: '/index_common/getRiceCommonProductList',
// method: 'GET',
// },
// 获取首页跳转图标
getRiceIconList: {
url: '/index_common/getRiceIconList',
method: 'GET',
@ -172,41 +167,42 @@ const api = {
url: '/index_common/getRiceBlessing',
method: 'GET'
},
// 随机获取祝福语
getRiceBlessingWords: {
url: '/index_common/getRiceBlessingWords',
method: 'GET'
// 查询最近回收商品
getRecentGoodsList: {
url: '/recycle-admin/applet/index/getRecentGoodsList',
method: 'GET',
auth : false
},
// 根据订单标识修改订单祝福语背景
updateOrderBlessing: {
url: '/index_common/updateOrderBlessing',
method: 'POST',
auth : true,
// 最近回收
getQualityReport: {
url: '/recycle-admin/applet/index/getQualityReport',
method: 'GET',
auth : false,
limit : 1000,
},
// 1.收礼流程 =》点击收礼
getGiveShop: {
url: '/index_common/getGiveShop',
// 1.根据id获取对应商品列表
getGoodsBrandList: {
url: '/recycle-admin/applet/class/getGoodsBrandList',
method: 'GET',
auth : true,
auth : false,
limit : 1000,
},
// 2.点击抽奖 =》抽奖
getGiveShopLottery: {
url: '/index_common/getGiveShopLottery',
// 2.根据分类标识获取分类商品列表带分页
getClassGoodsList: {
url: '/recycle-admin/applet/class/getClassGoodsList',
method: 'GET',
auth : true,
auth : false,
limit : 1000,
},
// 获取我的礼品订单
getMyGiftOrder: {
url: '/index_common/getMyGiftOrder',
getPricePreviewClassList: {
url: '/recycle-admin/applet/class/getPricePreviewClassList',
method: 'GET',
auth : true,
auth : false,
},
// 获取我的礼品订单详情
getMyGiftOrderDetail: {
url: '/index_common/getMyGiftOrderDetail',
getAreaList: {
url: '/recycle-admin/applet/index/getAreaList',
method: 'GET',
auth : true,
},


+ 14
- 0
pages.json View File

@ -194,6 +194,20 @@
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "promo-qrcode",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "inspection-report",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
}
]
},


+ 5
- 3
pages/baoyou-city/baoyou-city.vue View File

@ -39,7 +39,8 @@ export default {
statusBarHeight: 0,
navBarHeight: 88, //
menuButtonInfo: null,
cityList: []
cityList: [],
bannerTop: 0 // banner
}
},
onLoad() {
@ -56,6 +57,7 @@ export default {
} else {
this.navBarHeight = 88 //
}
this.bannerTop = this.statusBarHeight + this.navBarHeight
this.$api('getFreeCityList', {}, res => {
if (res && res.success && Array.isArray(res.result)) {
this.cityList = res.result.filter(item => item.open === 'Y');
@ -79,7 +81,7 @@ export default {
}
.nav-bar {
background: #2081ee;
background: #2180ee;
position: fixed;
top: 0;
left: 0;
@ -99,7 +101,7 @@ export default {
}
.byc-banner {
margin:-120rpx 0 0 0;
margin: 0;
// border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 4rpx 24rpx rgba(60, 167, 250, 0.10);


+ 88
- 12
pages/component/home.vue View File

@ -40,7 +40,7 @@
<view class="Xiadan-section">
<image src="/static/home/不会下单.png" alt="" class="process-icon"/>
<text class="left-text">不会下单联系客服了解回收流程</text>
<view class="right">
<view class="right" @click="goService">
<image src="/static/home/联系客服.png" mode=""></image>
<text>联系客服</text>
</view>
@ -77,7 +77,8 @@
</view>
<view class="price-grid">
<view class="price-item" v-for="(item, index) in priceList" :key="index">
<image :src="item.icon" mode="aspectFit" class="item-icon"></image>
<image v-if="item.icon" :src="item.icon" mode="aspectFit" class="item-icon"></image>
<view v-else class="item-icon placeholder"></view>
<text class="item-name">{{item.name}}</text>
<text class="item-price">¥ {{item.price}}
<text class="item-price-right">/{{item.unit}}</text>
@ -96,7 +97,7 @@
class="record-item"
v-for="(item, index) in records"
:key="index"
@tap="goToInspectionReport(item)"
>
<image src="/static/home/1745571336565.png" mode=""></image>
<text class="location">{{item.location}}</text>
@ -166,12 +167,13 @@ export default {
return {
value:0,
processes: [
{ icon: '/static/home/① 在线预约.png', text: '在线预约' },
{ icon: '/static/home/② 快递上门.png', text: '快递上门' },
{ icon: '/static/home/③ 透明质检.png', text: '透明质检' },
{ icon: '/static/home/④ 现金打款.png', text: '现金打款' }
// { icon: '/static/home/ 线.png', text: '线' },
// { icon: '/static/home/ .png', text: '' },
// { icon: '/static/home/ .png', text: '' },
// { icon: '/static/home/ .png', text: '' }
],
priceList: [
priceList: [],
priceListStatic: [
{ icon: '/static/home/羽绒服.png', name: '羽绒服', price: '3-10', unit: '件' },
{ icon: '/static/home/鞋子.png', name: '鞋子', price: '3-10', unit: '件' },
{ icon: '/static/home/包包.png', name: '包包', price: '3-10', unit: '件' },
@ -179,9 +181,7 @@ export default {
{ icon: '/static/home/品牌服饰.png', name: '品牌服饰', price: '3-10', unit: '件' },
{ icon: '/static/home/T 恤衬衣.png', name: 'T恤衬衫', price: '3-10', unit: '件' },
{ icon: '/static/home/羽绒裤.png', name: '羽绒裤', price: '3-10', unit: '件' },
{ icon: '/static/home/儿童羽绒服.png', name: '儿童羽绒服', price: '3-10', unit: '件' },
{ icon: '/static/home/包包.png', name: '包包', price: '3-10', unit: '件' },
{ icon: '/static/home/床被.png', name: '床被', price: '3-10', unit: '件' }
{ icon: '/static/home/儿童羽绒服.png', name: '儿童羽绒服', price: '3-10', unit: '件' }
],
records: Array(6).fill().map(() => ({
location: '天津市',
@ -243,8 +243,77 @@ export default {
},
async onRefresh() {
await new Promise(resolve => setTimeout(resolve, 1000))
},
getAreaList() {
this.$api('getAreaList', {}, (res) => {
console.log(res,'getAreaList');
if (res.code == 200 && Array.isArray(res.result)) {
// sort
const sorted = res.result.slice().sort((a, b) => a.sort - b.sort)
this.processes = sorted.map(item => ({
icon: item.image,
text: item.title
}))
}
})
},
goService(){
uni.navigateTo({
url: '/pages/subcomponent/admin_faq'
})
},
getPricePreview() {
this.$api('getPricePreviewClassList', {}, res => {
if (res && res.success && Array.isArray(res.result)) {
console.log(res,'getPricePreview');
// sort
const firstLevel = res.result.filter(item => item.pid === '0').sort((a, b) => a.sort - b.sort)
this.priceList = firstLevel.map(item => {
//
const staticItem = this.priceListStatic.find(s => s.name.replace(/\s/g, '') === item.title.replace(/\s/g, ''))
console.log({
icon: staticItem ? staticItem.icon : '',
name: item.title,
price: staticItem ? staticItem.price : '',
unit: '件'
});
return {
icon: staticItem ? staticItem.icon : '',
name: item.title,
price: staticItem ? staticItem.price : '',
unit: '件'
}
})
}
})
},
getRecentGoods() {
this.$api('getRecentGoodsList', {}, res => {
if (res && res.success && Array.isArray(res.result) && res.result.length > 0) {
// records
this.records = res.result
} else {
//
this.records = Array(6).fill().map(() => ({
location: '天津市',
amount: '50',
userId: '5513'
}))
}
})
},
goToInspectionReport(item) {
uni.navigateTo({
url: '/pages/subcomponent/inspection-report'
})
}
},
onLoad() {
this.getAreaList();
this.getPricePreview();
this.getRecentGoods();
// console.log(this.processes,'222')
}
}
}
</script>
@ -496,6 +565,13 @@ export default {
width: 80rpx;
height: 80rpx;
margin-bottom: 10rpx;
&.placeholder {
width: 80rpx;
height: 80rpx;
margin-bottom: 10rpx;
background: #f5f5f5;
border-radius: 16rpx;
}
}
.item-name {


+ 56
- 15
pages/component/my.vue View File

@ -209,7 +209,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
value:2,
@ -231,7 +234,18 @@ export default {
}
},
methods: {
changeTo(e){
async onRefresh() {
console.log('开始刷新')
try {
await this.fetchUserInfo()
console.log('刷新完成')
return true // true
} catch (error) {
console.error('刷新失败', error)
throw error //
}
},
changeTo(e){
this.value = e
console.log(e,'111')
if(e==0){
@ -262,7 +276,7 @@ export default {
// '/pages/subcomponent/promotion',
'/pages/subcomponent/select',
'/pages/subcomponent/customer',
'/pages/subcomponent/edit',
'/pages/subcomponent/edit_profile',
'logout'
]
if (pages[index] === 'logout') {
@ -292,6 +306,7 @@ export default {
},
onShareCommission() {
uni.showToast({ title: '分享赚佣金', icon: 'none' });
uni.navigateTo({ url: '/pages/subcomponent/promotion' })
},
goOrderManage() {
uni.navigateTo({ url: '/pages/manager/order' })
@ -305,6 +320,22 @@ export default {
goTuiManage() {
uni.navigateTo({ url: '/pages/manager/tui' })
},
fetchUserInfo() {
console.log('开始获取用户信息')
if(uni.getStorageSync('token')){
this.login_status = getApp().globalData.login_status;
this.$api("getUserByToken",{},(res)=>{
console.log('获取用户信息响应:', res)
if(res.code == 200){
this.userInfo = res.result
console.log('更新用户信息成功')
}
})
} else {
console.log('未登录状态')
this.login_status = false;
}
},
},
computed: {
customStyle() {
@ -315,19 +346,29 @@ export default {
}
},
onLoad() {
if(uni.getStorageSync('token')){
this.login_status = getApp().globalData.login_status;
this.$api("getUserByToken",{},(res)=>{
if(res.code == 200){
console.log(res)
this.userInfo = res.result
}
}
)
}else{
this.login_status = false;
};
}
//
uni.startPullDownRefresh()
uni.$on('refreshUserInfo', () => {
this.fetchUserInfo()
})
this.fetchUserInfo()
},
onShow() {
this.fetchUserInfo()
},
onPullDownRefresh() {
console.log('触发下拉刷新')
this.fetchUserInfo()
setTimeout(() => {
console.log('停止下拉刷新')
uni.stopPullDownRefresh()
uni.showToast({
title: '刷新成功',
icon: 'success',
duration: 2000
})
}, 1000)
},
}
</script>


+ 100
- 196
pages/component/recycle.vue View File

@ -238,199 +238,23 @@ export default {
return {
value:1,
ishow:true,
currentCategory: 0,
tabbarHeight: 0,
categories: [
{ name: '羽绒服' },
{ name: '鞋子' },
{ name: '包包' },
{ name: '床被' },
{ name: '品牌服饰' },
{ name: 'T恤衬衫' }
//
staticCategories: [
{ id: 0, name: '羽绒服' },
{ id: 1, name: '鞋子' },
{ id: 2, name: '包包' },
{ id: 3, name: '床被' },
{ id: 4, name: '品牌服饰' },
{ id: 5, name: 'T恤衬衫' }
],
//
allProducts: {
//
0: [
{
name: '羽绒服',
desc: '允许脏破烂,160码以上',
price: '8',
quantity: 8,
icon: '/static/home/羽绒服.png'
},
{
name: '羽绒裤',
desc: '允许脏破烂,160码以上',
price: '4',
quantity: 1,
icon: '/static/home/羽绒裤.png'
},
{
name: '儿童羽绒服',
desc: '允许脏破烂,160码以上',
price: '4',
quantity: 1,
icon: '/static/home/儿童羽绒服.png'
},
{
name: '品牌羽绒服',
desc: '允许脏破烂,160码以上',
price: '10',
quantity: 1,
showBrandCheck: true,
icon: '/static/home/品牌服饰.png'
},
{
name: '羽绒夹克',
desc: '允许脏破烂,160码以上',
price: '4',
quantity: 0,
showBrandCheck: true,
icon: '/static/home/羽绒服.png'
}
],
//
1: [
{
name: '运动鞋',
desc: '允许轻微磨损,配对完整',
price: '5',
quantity: 0,
icon: '/static/home/运动鞋.png'
},
{
name: '皮鞋',
desc: '允许轻微磨损,配对完整',
price: '6',
quantity: 0,
icon: '/static/goods/leather-shoe.png'
},
{
name: '休闲鞋',
desc: '允许轻微磨损,配对完整',
price: '4',
quantity: 0,
icon: '/static/goods/casual-shoe.png'
},
{
name: '品牌鞋',
desc: '允许轻微磨损,配对完整',
price: '8',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-shoe.png'
}
],
//
2: [
{
name: '双肩包',
desc: '允许轻微磨损,拉链完好',
price: '5',
quantity: 0,
icon: '/static/goods/backpack.png'
},
{
name: '手提包',
desc: '允许轻微磨损,拉链完好',
price: '6',
quantity: 0,
icon: '/static/goods/handbag.png'
},
{
name: '品牌包包',
desc: '允许轻微磨损,拉链完好',
price: '15',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-bag.png'
}
],
//
3: [
{
name: '棉被',
desc: '允许轻微污渍,无破损',
price: '10',
quantity: 0,
icon: '/static/goods/quilt.png'
},
{
name: '毛毯',
desc: '允许轻微污渍,无破损',
price: '8',
quantity: 0,
icon: '/static/goods/blanket.png'
},
{
name: '床单',
desc: '允许轻微污渍,无破损',
price: '5',
quantity: 0,
icon: '/static/goods/sheet.png'
}
],
//
4: [
{
name: '品牌外套',
desc: '知名品牌,状态良好',
price: '15',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-coat2.png'
},
{
name: '品牌裤装',
desc: '知名品牌,状态良好',
price: '12',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-pants.png'
},
{
name: '品牌卫衣',
desc: '知名品牌,状态良好',
price: '10',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-sweater.png'
}
],
// T
5: [
{
name: 'T恤',
desc: '允许轻微污渍,无破损',
price: '3',
quantity: 0,
icon: '/static/goods/tshirt.png'
},
{
name: '衬衫',
desc: '允许轻微污渍,无破损',
price: '4',
quantity: 0,
icon: '/static/goods/shirt.png'
},
{
name: '长袖T恤',
desc: '允许轻微污渍,无破损',
price: '4',
quantity: 0,
icon: '/static/goods/long-tshirt.png'
},
{
name: '品牌T恤',
desc: '知名品牌,状态良好',
price: '8',
quantity: 0,
showBrandCheck: true,
icon: '/static/goods/brand-tshirt.png'
}
]
staticAllProducts: {
// ...allProducts
},
//
categories: [],
allProducts: {},
currentCategory: 0,
tabbarHeight: 0,
showDetailPanel: false,
showBrandPopup: false,
showRulePopup: false,
@ -503,14 +327,55 @@ export default {
});
}
},
fetchClassGoodsList() {
this.$api('getClassGoodsList', {}, res => {
if (res.code === 200 && Array.isArray(res.result) && res.result.length > 0) {
this.categories = res.result.map(item => ({
id: item.categoryId,
name: item.categoryName
}))
this.allProducts = {}
res.result.forEach(item => {
this.allProducts[item.categoryId] = (item.goodsList || []).map(good => ({
...good,
quantity: 0 //
}))
})
this.currentCategory = this.categories.length > 0 ? this.categories[0].id : 0
}
//
})
},
//
getCategoryItemCount(categoryIndex) {
const categoryItems = this.allProducts[categoryIndex] || []
getCategoryItemCount(categoryId) {
const categoryItems = this.allProducts[categoryId] || []
return categoryItems.reduce((sum, item) => sum + (item.quantity || 0), 0)
},
//
switchCategory(index) {
this.currentCategory = index
switchCategory(categoryId) {
this.currentCategory = categoryId
//
this.$set(this.allProducts, categoryId, [])
//
this.$api('getGoodsBrandList', { iconId: categoryId }, res => {
if (
res.code === 200 &&
res.result &&
Array.isArray(res.result.records) &&
res.result.records.length > 0
) {
//
this.$set(this.allProducts, categoryId, res.result.records.map(item => ({
...item,
quantity: 0
})))
} else {
//
if (this.staticAllProducts[categoryId]) {
this.$set(this.allProducts, categoryId, JSON.parse(JSON.stringify(this.staticAllProducts[categoryId])))
}
}
})
},
//
updateQuantity(index, delta) {
@ -630,6 +495,13 @@ export default {
this.showRulePopup = false
},
},
created() {
//
this.categories = this.staticCategories
this.allProducts = JSON.parse(JSON.stringify(this.staticAllProducts))
this.currentCategory = this.categories[0].id
this.fetchClassGoodsList()
},
mounted() {
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this)
@ -647,6 +519,9 @@ export default {
onPullDownRefresh() {
this.refreshData()
},
onLoad() {
this.fetchClassGoodsList()
},
}
</script>
@ -691,6 +566,12 @@ export default {
margin: 1rpx;
border-radius: 20rpx 0 0 0;
margin-right: 20rpx;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
&::-webkit-scrollbar {
width: 0 !important;
display: none; /* Chrome, Safari, Opera */
}
.category-item {
position: relative;
padding: 30rpx 20rpx;
@ -742,7 +623,12 @@ export default {
margin: 1rpx;
margin-left: 0;
border-radius: 0 20rpx 0 0;
// padding-bottom: calc(var(--window-bottom) + 100rpx);
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
&::-webkit-scrollbar {
width: 0 !important;
display: none; /* Chrome, Safari, Opera */
}
}
}
@ -1127,6 +1013,12 @@ export default {
overflow-y: auto;
max-height: 36vh;
padding: 0 24rpx;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
&::-webkit-scrollbar {
width: 0 !important;
display: none; /* Chrome, Safari, Opera */
}
}
.panel-item {
display: flex;
@ -1330,6 +1222,12 @@ export default {
overflow-y: auto;
max-height: 60vh;
padding: 0 24rpx;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
&::-webkit-scrollbar {
width: 0 !important;
display: none; /* Chrome, Safari, Opera */
}
}
.brand-letter {
font-size: 28rpx;
@ -1412,6 +1310,12 @@ export default {
padding: 0 40rpx;
box-sizing: border-box;
overflow-y: auto;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
&::-webkit-scrollbar {
width: 0 !important;
display: none; /* Chrome, Safari, Opera */
}
}
.rule-popup-desc {
font-size: 26rpx;


+ 21
- 4
pages/index/index.vue View File

@ -36,6 +36,7 @@
<PrivacyPopup
ref="privacyPopup"
:needPhone="needPhone"
@agree="handleAgreePrivacy"
@reject="handleRejectPrivacy"
@open-protocol="openProtocol"
@ -68,7 +69,8 @@ export default {
showProtocolDialog: false,
protocolDialogTitle: '',
protocolDialogContent: '',
configData: [] // getConfig result
configData: [], // getConfig result
needPhone: false //
}
},
onLoad() {
@ -155,7 +157,7 @@ export default {
},
//
handleAgreePrivacy() {
handleAgreePrivacy() {
uni.showLoading({
title: '登录中...'
})
@ -168,13 +170,23 @@ export default {
// console.log(res.code,'code')
if (res.code) {
self.$api('wxLogin', {code : res.code}, res => {
// console.log(res,'login')
console.log(res,'login')
if (res.code == 200) {
uni.hideLoading();
// console.log(res)
uni.setStorageSync('token',res.result.token);
uni.setStorageSync('openid',res.result.userInfo.appletOpenid);
uni.setStorageSync('openid',res.result.userInfo && res.result.userInfo.appletOpenid);
getApp().globalData.login_status = true;
if (res.result.userInfo) {
// userInfo
uni.reLaunch({
url: '/pages/component/home'
});
} else {
// userInfo
self.needPhone = true;
self.$refs.privacyPopup.open();
}
}
})
} else {
@ -214,12 +226,17 @@ export default {
</script>
<style scoped scss>
view {
padding-bottom: 0 !important;
}
.login-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f9ece5;
padding: 0 40rpx;
padding-bottom: env(safe-area-inset-bottom);
}
.app-header {


+ 9
- 0
pages/manager/inspect-result.vue View File

@ -113,7 +113,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
qualifiedList: [
@ -192,6 +194,13 @@ export default {
this.currentReasonItem.reasons = [...this.reasonChecked]
}
this.closeReasonPopup()
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
refreshData() {
//
//
}
}
}


+ 13
- 0
pages/manager/inspect.vue View File

@ -61,7 +61,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
categories: [
@ -108,7 +110,18 @@
} else {
item.unqualified = Math.max(0, (item.unqualified || 0) + delta)
}
},
refreshData() {
//
//
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 31
- 20
pages/manager/order-detail.vue View File

@ -15,7 +15,7 @@
<view v-if="order.cancelReason" class="cancel-reason">{{ order.cancelReason }}</view>
<view class="info-card-header">
<view class="info-title-wrap">
<text class="info-title">回收信息</text>
<text class="info-title">回收信息</text>
<view v-if="order.statusText === '不包邮'" class="tag-nobaoyou">不包邮</view>
</view>
<view class="status-tag" :class="order.statusClass" style="margin-left:auto;">{{ order.statusLabel }}</view>
@ -26,7 +26,7 @@
<image :src="step.icon" class="step-icon" />
<view class="step-label" :class="{active: idx === currentStep}">
<text class="step-num">{{ ['①','②','③','④'][idx] }}</text>
<text class="step-text">{{ step.text }}</text>
<text class="step-text">{{ step.text }}</text>
</view>
</view>
</view>
@ -34,12 +34,12 @@
<view class="base-info">
<view v-for="(item, i) in baseInfo" :key="item.label" class="base-info-row">
<view class="base-label-wrap">
<text class="base-label">{{ item.label }}</text>
<text class="base-label">{{ item.label }}</text>
</view>
<view class="base-value-wrap">
<text class="base-value">{{ item.value }}</text>
<text v-if="item.copy" class="copy-btn" @tap="copyText(item.value)">复制</text>
<uni-icons v-if="item.arrow" type="right" size="18" color="#bbb" />
<uni-icons v-if="item.arrow" type="right" size="18" color="#bbb" />
</view>
<view v-if="i < baseInfo.length-1" class="divider"></view>
</view>
@ -71,18 +71,18 @@
</view>
<view class="divider"></view>
</template>
<view v-for="item in order.items" :key="item.name" class="goods-row">
<image :src="item.img" class="goods-img" />
<view class="goods-info">
<text class="goods-name">{{ item.name }}</text>
<text class="goods-desc">{{ item.desc }}</text>
<view class="goods-price-row">
<text class="goods-price">¥ {{ item.price }} <text class="goods-unit">/</text></text>
<text class="goods-count">x{{ item.count }}</text>
<text class="goods-total">¥{{ item.total }}</text>
</view>
<view v-for="item in order.items" :key="item.name" class="goods-row">
<image :src="item.img" class="goods-img" />
<view class="goods-info">
<text class="goods-name">{{ item.name }}</text>
<text class="goods-desc">{{ item.desc }}</text>
<view class="goods-price-row">
<text class="goods-price">¥ {{ item.price }} <text class="goods-unit">/</text></text>
<text class="goods-count">x{{ item.count }}</text>
<text class="goods-total">¥{{ item.total }}</text>
</view>
</view>
</view>
</view>
</view>
@ -114,7 +114,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
@ -135,12 +137,7 @@ export default {
{ name: '品牌羽绒服', desc: '允许脏破烂,160码以上', price: 10, count: 8, total: 8, img: '/static/coat2.png' }
]
},
steps: [
{ text: '在线预约', icon: '/static/home/① 在线预约.png' },
{ text: '快递上门', icon: '/static/home/② 快递上门.png' },
{ text: '透明质检', icon: '/static/home/③ 透明质检.png' },
{ text: '现金打款', icon: '/static/home/④ 现金打款.png' }
],
steps: [],
currentStep: 3, // 4
baseInfo: [
// { label: '', value: this.order.cancelReason, show: !!this.order.cancelReason },
@ -168,8 +165,13 @@ export default {
this.currentStep = this.getCurrentStep(data.status)
console.log(this.order);
})
this.getAreaList();
},
methods: {
async onRefresh() {
await this.getAreaList()
// await
},
goBack() {
uni.navigateBack()
},
@ -200,6 +202,15 @@ export default {
uni.navigateTo({
url: '/pages/manager/inspect'
})
},
getAreaList() {
this.$api('getAreaList', {}, (res) => {
if (res.code == 200 && Array.isArray(res.result)) {
// sort
const sorted = res.result.slice().sort((a, b) => a.sort - b.sort)
this.steps = sorted.map(item => ({ text: item.title, icon: item.image }))
}
})
}
}
}


+ 55
- 38
pages/manager/order.vue View File

@ -61,7 +61,7 @@
</template>
<template v-else>
<view class="search-input-wrap">
<uni-icons type="search" size="22" color="#999" />
<uni-icons type="search" size="22" color="#999" />
<input
ref="searchInput"
class="search-input"
@ -86,7 +86,7 @@
<view v-if="order.statusText === '不包邮'" class="order-status-tag red">{{ order.statusText }}</view>
</view>
<view class="order-info-wrapper">
<view class="order-info">
<view class="order-info">
<view>
<text class="info-label">用户名</text>
<text class="info-value">{{ order.userName }}</text>
@ -128,7 +128,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
@ -297,6 +299,16 @@ export default {
}
})
},
refreshData() {
// TODO:
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>
@ -317,30 +329,35 @@ export default {
right: 0;
z-index: 100;
background: #fff;
padding: 0 20px;
height: 44px;
padding: 0 32rpx;
box-sizing: border-box;
.nav-title {
flex: 1;
text-align: center;
font-size: 18px;
font-size: 36rpx;
font-weight: bold;
color: #222;
}
.nav-icons {
display: flex;
align-items: center;
gap: 16px;
gap: 32rpx;
}
}
.order-tabs-scroll {
position: fixed;
left: 0; width: 100%;
left: 0;
width: 100%;
z-index: 99;
background: #fff;
border-bottom: 1px solid #f0f0f0;
height: 48px;
height: 96rpx;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
}
.order-tabs {
display: flex;
@ -349,10 +366,10 @@ export default {
.tab-item {
flex: 1 0 0%;
text-align: center;
font-size: 17px;
font-size: 34rpx;
color: #bfbfbf;
height: 48px;
line-height: 48px;
height: 96rpx;
line-height: 96rpx;
position: relative;
font-weight: 500;
transition: color 0.2s;
@ -429,24 +446,24 @@ export default {
margin: 0;
padding-top: calc(var(--status-bar-height, 0px) + 44px + 44px + 16px);
}
.order-card {
background: #fff;
.order-card {
background: #fff;
border-radius: 20px;
margin: 0 16px 16px 16px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.order-card-header {
display: flex;
justify-content: space-between;
.order-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
.order-id {
.order-id {
font-size: 16px;
font-weight: bold;
color: #222;
}
.order-status-tag {
font-weight: bold;
color: #222;
}
.order-status-tag {
font-size: 14px;
border-radius: 12px;
padding: 2px 12px;
@ -466,21 +483,21 @@ export default {
font-size: 14px;
border-radius: 12px;
padding: 2px 12px;
&.green { background: #e6f9e6; color: #1ecb1e; }
&.red { background: #ffeaea; color: #ff4d4f; }
&.orange { background: #fff7e6; color: #ffb400; }
&.blue { background: #e6f0ff; color: #409eff; }
&.gray { background: #f5f5f5; color: #999; }
}
}
.order-info {
&.green { background: #e6f9e6; color: #1ecb1e; }
&.red { background: #ffeaea; color: #ff4d4f; }
&.orange { background: #fff7e6; color: #ffb400; }
&.blue { background: #e6f0ff; color: #409eff; }
&.gray { background: #f5f5f5; color: #999; }
}
}
.order-info {
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
font-weight: 400;
font-size: 14px;
line-height: 1.4;
letter-spacing: 0;
vertical-align: middle;
color: #666;
color: #666;
margin-bottom: 12px;
view {
margin-bottom: 4px;
@ -502,10 +519,10 @@ export default {
font-size: 14px;
line-height: 1.4;
}
}
.order-card-footer {
display: flex;
align-items: center;
}
.order-card-footer {
display: flex;
align-items: center;
justify-content: center;
margin: 0 -20px -20px -20px;
padding: 0 20px;
@ -515,17 +532,17 @@ export default {
min-height: 60px;
position: relative;
.order-actions-bar {
display: flex;
display: flex;
flex: 1;
justify-content: center;
align-items: center;
gap: 48px;
.action-btn-bar {
display: flex;
display: flex;
flex-direction: column;
align-items: center;
align-items: center;
font-size: 14px;
color: #666;
color: #666;
margin-top: 8px;
margin-bottom: 8px;
uni-icons {


+ 12
- 0
pages/manager/staff-detail.vue View File

@ -37,7 +37,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
staff: {
@ -73,7 +75,17 @@ export default {
},
removeStaff() {
uni.showToast({ title: '已解除员工', icon: 'none' });
},
refreshData() {
// TODO:
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 17
- 2
pages/manager/staff.vue View File

@ -27,7 +27,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
staffList: [
@ -73,7 +75,17 @@ export default {
res.eventChannel.emit('staffDetail', staff);
}
});
}
},
refreshData() {
// TODO:
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>
@ -120,7 +132,10 @@ export default {
}
}
.staff-list {
margin-top: 120rpx;
margin-top: calc(100rpx + var(--status-bar-height));
padding: 32rpx 0;
min-height: calc(100vh - 100rpx - var(--status-bar-height));
box-sizing: border-box;
}
.staff-card {
background: #fff;


+ 12
- 0
pages/manager/tui-apply-detail.vue View File

@ -48,7 +48,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
apply: {
@ -97,7 +99,17 @@ export default {
},
approve() {
uni.showToast({ title: '已通过', icon: 'none' });
},
refreshData() {
// TODO: 广
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 12
- 0
pages/manager/tui-detail.vue View File

@ -56,7 +56,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
tui: {
@ -95,7 +97,17 @@ export default {
},
removeTui() {
uni.showToast({ title: '已解除推广官', icon: 'none' });
},
refreshData() {
// TODO: 广
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 12
- 0
pages/manager/tui.vue View File

@ -53,7 +53,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
currentTab: 0,
@ -115,7 +117,17 @@ export default {
res.eventChannel.emit('applyDetail', apply);
}
});
},
refreshData() {
// TODO: 广
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 12
- 0
pages/manager/user-detail.vue View File

@ -75,7 +75,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
user: {
@ -128,7 +130,17 @@ export default {
unblockUser() {
uni.showToast({ title: '已解除拉黑', icon: 'none' });
this.user.blocked = false;
},
refreshData() {
// TODO:
},
async onRefresh() {
await this.refreshData && this.refreshData()
}
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 12
- 0
pages/manager/user.vue View File

@ -55,7 +55,9 @@
</template>
<script>
import pullRefreshMixin from '../mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
searchText: '',
@ -153,6 +155,16 @@ export default {
}
});
},
refreshData() {
// TODO:
},
async onRefresh() {
await this.refreshData && this.refreshData()
},
},
onPullDownRefresh() {
this.refreshData && this.refreshData()
uni.stopPullDownRefresh()
}
}
</script>


+ 8
- 0
pages/subcomponent/about.vue View File

@ -74,7 +74,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0
@ -86,6 +89,11 @@ export default {
methods: {
goBack() {
uni.navigateBack();
},
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
}
}
}


+ 8
- 0
pages/subcomponent/add.vue View File

@ -57,7 +57,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
formData: {
@ -71,6 +74,11 @@ export default {
goBack() {
uni.navigateBack()
},
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
confirmAdd() {
//
if (!this.formData.name.trim()) {


+ 23
- 19
pages/subcomponent/admin_customer.vue View File

@ -92,34 +92,41 @@
</template>
<script>
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
export default {
components: {
emailPopup
},
mixins: [pullRefreshMixin],
components: {
emailPopup
},
data() {
return {
greeting: '下午好',
showPhonePopup: false,
showEmailPopup:false
showEmailPopup:false
}
},
created() {
this.updateGreeting()
},
methods: {
//
openEmailPopup() {
this.showEmailPopup = true
},
//
handleCloseEmailPopup() {
this.showEmailPopup = false
},
navigateBack() {
uni.navigateBack()
},
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
//
openEmailPopup() {
this.showEmailPopup = true
},
//
handleCloseEmailPopup() {
this.showEmailPopup = false
},
navigateBack() {
uni.navigateBack()
},
updateGreeting() {
const hour = new Date().getHours()
if (hour < 12) {
@ -130,9 +137,6 @@ export default {
this.greeting = '晚上好'
}
},
navigateBack() {
uni.navigateBack()
},
navigateToFAQ() {
//
uni.navigateTo({


+ 8
- 0
pages/subcomponent/admin_edit_profile.vue View File

@ -73,7 +73,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
userInfo: {
@ -89,6 +92,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 271
- 189
pages/subcomponent/admin_faq.vue View File

@ -1,123 +1,115 @@
<template>
<view class="faq-page">
<view class="faq-page" :style="{paddingTop: navBarHeightRpx + 'rpx'}">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="back-icon" @tap="navigateBack">
<uni-icons type="left" size="20"></uni-icons>
<view class="nav-bar" :style="{height: navBarHeightRpx + 'rpx', paddingTop: statusBarHeight + 'px'}">
<view class="nav-bar-inner">
<view class="back-icon" @tap="navigateBack">
<uni-icons type="left" size="22" color="#222"></uni-icons>
</view>
<view class="title">联系客服</view>
<view class="nav-bar-right"></view>
</view>
<view class="title">常见问题</view>
</view>
<!-- 主要内容区域 -->
<view class="content">
<!-- 推广相关 -->
<view class="section">
<view class="section-title">推广相关</view>
<view class="qa-list">
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
如何申请成为推广官
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
</view>
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
推广官的佣金如何计算
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
</view>
</view>
</view>
<!-- 订单回收相关 -->
<view class="section">
<view class="section-title">订单回收相关</view>
<view class="qa-list">
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
为什么我的订单显示"回收失败"
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
</view>
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
如果我的订单出现问题怎么办
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
</view>
</view>
</view>
<!-- 环保相关 -->
<view class="section">
<view class="section-title">环保相关</view>
<view class="qa-list">
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
回收的旧衣如何处理
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
</view>
<view class="qa-item">
<text class="question">
<text class="q-icon">Q</text>
哪些衣物可以回收
</text>
<text class="answer">您好如需帮助请优先选择以下方式联系我们</text>
<view class="content-card">
<view class="qa-list">
<view class="qa-item" v-for="(item, idx) in faqList" :key="idx">
<view class="question-row">
<text class="q-icon">Q</text>
<text class="question">{{item.q}}</text>
</view>
<view class="answer">{{item.a}}</view>
</view>
</view>
<!-- 底部提示 -->
<view class="dashed-line"></view>
<view class="bottom-tip">
如有任何问题或建议请随时与我们联系我们将竭诚为您服务
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-btn">
<button class="online-service-btn" @tap="openEmailPopup">联系在线客服</button>
<view class="bottom-btns">
<button class="btn-outline" @tap="callService">客服电话</button>
<button class="btn-gradient" @tap="openEmailPopup">联系在线客服</button>
</view>
<email-popup
:show="showEmailPopup"
@close="handleCloseEmailPopup"
/>
<!-- 客服电话底部弹窗 -->
<view v-if="showPhonePopup" class="phone-popup">
<view class="popup-mask" @tap="closePhonePopup"></view>
<view class="popup-content">
<view class="popup-header">
<text class="close-btn" @tap="closePhonePopup">关闭</text>
<text class="popup-title">客服电话</text>
</view>
<view class="popup-phone-row" @tap="makePhoneCall">
<text class="popup-phone">0731-599327-8899</text>
<view class="popup-phone-icon">
<uni-icons type="phone-filled" size="28" color="#222" />
</view>
</view>
</view>
</view>
</view>
<email-popup
:show="showEmailPopup"
@close="handleCloseEmailPopup"
/>
</template>
<script>
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
export default {
components: {
emailPopup
},
mixins: [pullRefreshMixin],
components: { emailPopup },
data() {
return {
showEmailPopup:false
statusBarHeight: 0,
navBarHeight: 0, // px
navBarHeightRpx: 0, // rpx
showEmailPopup: false,
showPhonePopup: false,
faqList: [
{q: '如何申请成为推广官?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
{q: '推广官的佣金如何计算?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
{q: '为什么我的订单显示"回收失败"?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
{q: '如果我的订单出现问题怎么办?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
{q: '回收的旧衣如何处理?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
{q: '哪些衣物可以回收?', a: '您好!如需帮助,请优先选择以下方式联系我们。'},
]
}
},
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
let navBarHeight = 24
try {
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
navBarHeight = menuButtonInfo.bottom + menuButtonInfo.top - sysInfo.statusBarHeight
} catch (e) {}
this.navBarHeight = navBarHeight
// pxrpx750稿
this.navBarHeightRpx = Math.round(navBarHeight * 750 / sysInfo.windowWidth)
},
methods: {
//
openEmailPopup() {
this.showEmailPopup = true
},
//
handleCloseEmailPopup() {
this.showEmailPopup = false
},
navigateBack() {
uni.navigateBack()
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
openEmailPopup() { this.showEmailPopup = true },
handleCloseEmailPopup() { this.showEmailPopup = false },
navigateBack() { uni.navigateBack() },
callService() {
//
this.showPhonePopup = true
},
closePhonePopup() {
this.showPhonePopup = false
},
handleOnlineService() {
//
uni.navigateTo({
url: '/pages/customer-service/index'
})
makePhoneCall() {
uni.makePhoneCall({ phoneNumber: '0731-599327-8899' })
}
}
}
@ -126,121 +118,211 @@ export default {
<style lang="scss" scoped>
.faq-page {
min-height: 100vh;
background: linear-gradient(to bottom,#ebffe6,5%,#ffffff);
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
background: linear-gradient(180deg, #fff3db 0%, #ffffff 100%);
padding-bottom: env(safe-area-inset-bottom);
}
.nav-bar {
display: flex;
align-items: center;
height: 88rpx;
padding-top: var(--status-bar-height);
.title {
font-family: PingFang SC;
font-weight: 500;
font-size: 16px;
line-height: 140%;
letter-spacing: 0%;
text-align: center;
vertical-align: middle;
color: #333;
margin-left: 30%;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
width: 100vw;
background: #fef4df;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.03);
.nav-bar-inner {
display: flex;
align-items: center;
height: 44px;
width: 100vw;
position: relative;
}
.back-icon {
width: 88rpx;
height: 88rpx;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
top: 0;
}
.title {
flex: 1;
text-align: center;
font-size: 18px;
font-weight: bold;
color: #222;
letter-spacing: 0.5px;
line-height: 44px;
}
.nav-bar-right {
width: 44px;
height: 44px;
position: absolute;
right: 0;
top: 0;
}
}
.content {
padding: 40rpx 30rpx;
.content-card {
margin: 88px 0 0 0;
padding: 0 0 32rpx 0;
width: 92vw;
max-width: 700rpx;
background: #fff;
width: 80%;
margin: 0 auto;
.section {
margin-bottom: 60rpx;
.section-title {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
line-height: 22px;
letter-spacing: 0%;
color: #666;
margin-bottom: 30rpx;
}
.qa-list {
.qa-item {
margin-bottom: 40rpx;
.question {
display: flex;
align-items: center;
font-family: PingFang SC;
font-weight: 600;
font-size: 18px;
line-height: 140%;
letter-spacing: 0%;
color: #333;
margin-bottom: 20rpx;
.q-icon {
color: #05b03f;
font-weight: bold;
margin-right: 16rpx;
}
}
.answer {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
line-height: 140%;
letter-spacing: 0%;
color: #999;
// line-height: 1.6;
padding-left: 40rpx;
}
}
}
}
border-radius: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(60, 167, 250, 0.08);
margin-left: auto;
margin-right: auto;
padding-top: 32rpx;
padding-bottom: 0;
}
.bottom-tip {
font-size: 26rpx;
color: #999;
text-align: center;
line-height: 1.6;
padding: 30rpx;
border-top: 1rpx solid rgba(0, 0, 0, 0.05);
}
.qa-list {
padding: 0 36rpx;
}
.qa-item {
margin-bottom: 36rpx;
}
.question-row {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
.q-icon {
color: #ffb300;
font-size: 32rpx;
font-weight: bold;
margin-right: 12rpx;
}
.question {
font-size: 32rpx;
font-weight: bold;
color: #222;
}
.answer {
font-size: 26rpx;
color: #999;
line-height: 1.7;
padding-left: 44rpx;
}
.dashed-line {
border-bottom: 2rpx dashed #e5e5e5;
margin: 24rpx 36rpx 0 36rpx;
}
.bottom-tip {
font-size: 24rpx;
color: #999;
text-align: left;
line-height: 1.6;
padding: 32rpx 36rpx 0 36rpx;
}
.bottom-btn {
.bottom-btns {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
.online-service-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(to right,#b9fdae,#09eadf);
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
z-index: 101;
display: flex;
justify-content: center;
align-items: center;
gap: 32rpx;
padding: 24rpx 36rpx calc(24rpx + env(safe-area-inset-bottom)) 36rpx;
background: #fff;
box-shadow: 0 -2rpx 12rpx rgba(0,0,0,0.03);
}
.btn-outline {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background: #fff;
color: #ffb300;
font-size: 32rpx;
border-radius: 44rpx;
border: 2rpx solid #ffb300;
margin-right: 0;
}
.btn-gradient {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(90deg, #ffdf8c 0%, #ffb300 100%);
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
margin-left: 0;
}
.phone-popup {
position: fixed;
left: 0; right: 0; bottom: 0; top: 0;
z-index: 9999;
display: flex;
align-items: flex-end;
justify-content: center;
.popup-mask {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
background: rgba(0,0,0,0.7);
z-index: 0;
}
.popup-content {
position: relative;
width: 100vw;
background: #fff;
border-radius: 24rpx 24rpx 0 0;
box-shadow: 0 -4rpx 32rpx rgba(0,0,0,0.08);
padding-bottom: env(safe-area-inset-bottom);
animation: popupUp 0.2s;
}
@keyframes popupUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.popup-header {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
border-bottom: 1px solid #f2f2f2;
position: relative;
.close-btn {
position: absolute;
left: 24px;
font-size: 17px;
color: #999;
}
.popup-title {
font-size: 18px;
color: #222;
font-weight: 600;
letter-spacing: 1px;
}
}
.popup-phone-row {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 0 32px 0;
.popup-phone {
font-size: 24px;
color: #222;
font-weight: 400;
letter-spacing: 1px;
margin-right: 18px;
}
.popup-phone-icon {
width: 44px;
height: 44px;
background: #f5f5f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>

+ 8
- 0
pages/subcomponent/apply.vue View File

@ -139,7 +139,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
formData: {
@ -174,6 +177,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
},


+ 8
- 0
pages/subcomponent/brand.vue View File

@ -36,7 +36,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
brandItems: [
@ -105,6 +108,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 8
- 0
pages/subcomponent/detail.vue View File

@ -170,7 +170,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
orderId: 'RE82738127861525',
@ -233,6 +236,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 8
- 0
pages/subcomponent/edit.vue View File

@ -54,7 +54,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
formData: {
@ -75,6 +78,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 190
- 149
pages/subcomponent/edit_profile.vue View File

@ -1,34 +1,40 @@
<template>
<view class="edit-profile">
<view class="edit-profile safe-area" :style="{paddingTop: navBarHeightRpx + 'rpx'}">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="back-icon" @tap="goBack">
<uni-icons type="left" size="20"></uni-icons>
</view>
<view class="title">修改信息</view>
</view>
<view class="nav-bar" :style="{height: (statusBarHeight + 88) + 'rpx', paddingTop: statusBarHeight + 'px'}">
<view class="back" @tap="goBack">
<uni-icons type="left" size="20" color="#222"></uni-icons>
</view>
<text class="title">修改信息</text>
<view class="nav-bar-right"></view>
</view>
<!-- 个人信息表单 -->
<view class="info-container">
<view class="info-card">
<text class="section-title">个人信息</text>
<view class="divider"></view>
<!-- 昵称 -->
<view class="info-item">
<text class="label">昵称</text>
<input type="text" v-model="userInfo.nickname" placeholder="请输入昵称" />
</view>
<view class="divider"></view>
<!-- 电话 -->
<view class="info-item">
<text class="label">电话</text>
<view class="phone-input">
<input type="number" v-model="userInfo.phone" placeholder="请输入手机号" />
<uni-icons type="eye" size="20" color="#999"></uni-icons>
<input
type="text"
:value="showPhone ? userInfo.phone : maskedPhone"
:readonly="!showPhone"
placeholder="请输入手机号"
@input="e => { if (showPhone) userInfo.phone = e.detail.value }"
/>
<uni-icons :type="showPhone ? 'eye' : 'eye-slash'" size="20" color="#999" @tap="showPhone = !showPhone"></uni-icons>
</view>
</view>
<view class="divider"></view>
<!-- 头像 -->
<view class="info-item avatar-section">
<text class="label">头像</text>
@ -73,9 +79,16 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
import OSS from '@/utils/oss-upload/oss/index.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarHeight: 44, // px
navBarHeightRpx: 88, // rpx
userInfo: {
nickname: '吴彦谋',
phone: '15888977617',
@ -85,68 +98,94 @@ export default {
uploadStatus: {
show: false,
type: 'loading' // loading, success, error
}
},
showPhone: false
}
},
computed: {
maskedPhone() {
//
return this.userInfo.phone ? '●'.repeat(this.userInfo.phone.length) : ''
}
},
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
let navBarHeight = 44
try {
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
navBarHeight = menuButtonInfo.bottom + menuButtonInfo.top - sysInfo.statusBarHeight
} catch (e) {}
this.navBarHeight = navBarHeight
this.navBarHeightRpx = Math.round(navBarHeight * 750 / sysInfo.windowWidth)
//
if (uni.getStorageSync('token')) {
this.$api('getUserByToken', {}, (res) => {
if (res.code === 200 && res.result) {
this.userInfo.nickname = res.result.nickName || ''
this.userInfo.phone = res.result.phone || ''
this.userInfo.avatar = res.result.headImage || ''
}
})
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},
async chooseImage() {
try {
const [tempFile] = await new Promise((resolve, reject) => {
const res = await new Promise((resolve, reject) => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => resolve(res.tempFilePaths),
success: resolve,
fail: reject
})
})
//
this.uploadStatus = {
show: true,
type: 'loading'
}
//
await new Promise(resolve => setTimeout(resolve, 1500))
//
const isSuccess = Math.random() > 0.3
if (isSuccess) {
this.userInfo.newAvatar = tempFile
this.uploadStatus.type = 'success'
} else {
throw new Error('Upload failed')
}
// 1
await new Promise(resolve => setTimeout(resolve, 1000))
this.uploadStatus.show = false
const tempFile = res.tempFilePaths[0]
this.uploadStatus = { show: true, type: 'loading' }
// OSS
const url = await OSS.ossUpload(tempFile)
this.userInfo.avatar = url
this.uploadStatus.type = 'success'
setTimeout(() => { this.uploadStatus.show = false }, 1000)
} catch (error) {
console.error('Upload failed:', error)
this.uploadStatus = {
show: true,
type: 'error'
}
// 1
setTimeout(() => {
this.uploadStatus.show = false
}, 1000)
this.uploadStatus = { show: true, type: 'error' }
setTimeout(() => { this.uploadStatus.show = false }, 1000)
}
},
saveProfile() {
uni.showToast({
title: '保存成功',
icon: 'success'
//
if (!this.userInfo.avatar) return uni.showToast({ title: '请上传头像', icon: 'none' })
if (!this.userInfo.nickname) return uni.showToast({ title: '请填写昵称', icon: 'none' })
if (!this.userInfo.phone) return uni.showToast({ title: '请填写手机号', icon: 'none' })
this.uploadStatus = { show: true, type: 'loading' }
console.log(this.userInfo,'this.userInfo');
this.$api('updateInfo', {
avatarUrl: this.userInfo.avatar,
nickName: this.userInfo.nickname,
phone: this.userInfo.phone
}, res => {
if (res.code === 200) {
this.uploadStatus.type = 'success'
setTimeout(() => {
this.uploadStatus.show = false
uni.$emit('refreshUserInfo')
uni.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => { uni.navigateBack() }, 1000)
}, 1000)
} else {
this.uploadStatus.type = 'error'
setTimeout(() => { this.uploadStatus.show = false }, 1000)
}
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
}
@ -156,132 +195,140 @@ export default {
.edit-profile {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
}
.nav-bar {
display: flex;
align-items: center;
height: 88rpx;
padding-top: var(--status-bar-height);
background: #fff;
padding: 0 30rpx;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
width: 100vw;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.03);
.back {
padding: 20rpx;
margin-left: -20rpx;
display: flex;
align-items: center;
height: 88rpx;
}
.title {
font-family: PingFang SC;
font-weight: 500;
font-size: 16px;
line-height: 140%;
letter-spacing: 0%;
flex: 1;
text-align: center;
vertical-align: middle;
color: #333;
margin-left: 30%;
font-size: 34rpx;
font-weight: 500;
color: #222;
letter-spacing: 0.5px;
line-height: 88rpx;
}
.back-icon {
width: 88rpx;
.nav-bar-right {
width: 44px;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
justify-content: flex-end;
}
}
.info-container {
margin-top: calc(88rpx + env(safe-area-inset-top));
padding: 30rpx;
margin-top: 48rpx;
/* 移除左右padding,留白交给卡片自身 */
}
.info-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
.section-title {
font-size: 32rpx;
background: linear-gradient(180deg, #fff7e6 0%, #fff 100%);
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(60, 167, 250, 0.08);
padding: 48rpx 32rpx 32rpx 32rpx;
width: 100%;
max-width: 700rpx;
margin: 0 auto;
margin-top: 0;
position: relative;
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #222;
margin-bottom: 24rpx;
}
.divider {
border-bottom: 2rpx solid #f2f2f2;
margin-bottom: 24rpx;
}
.info-item {
margin-bottom: 24rpx;
.label {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 40rpx;
margin-bottom: 12rpx;
display: block;
}
.info-item {
margin-bottom: 40rpx;
.label {
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
display: block;
}
input {
font-size: 32rpx;
color: #222;
width: 100%;
padding: 16rpx 0;
border: none;
background: none;
outline: none;
}
.phone-input {
display: flex;
align-items: center;
input {
font-size: 32rpx;
color: #333;
width: 100%;
padding: 20rpx 0;
border-bottom: 2rpx solid #f5f5f5;
}
.phone-input {
display: flex;
align-items: center;
border-bottom: 2rpx solid #f5f5f5;
input {
flex: 1;
border-bottom: none;
}
flex: 1;
}
}
.avatar-section {
.avatar-container {
display: flex;
gap: 20rpx;
}
.avatar-box {
width: 160rpx;
height: 160rpx;
background: #f5f5f5;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.new-avatar {
width: 160rpx;
height: 160rpx;
border-radius: 10rpx;
}
.avatar-section {
.avatar-container {
display: flex;
gap: 20rpx;
}
.avatar-box {
width: 120rpx;
height: 120rpx;
background: #f5f5f5;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.new-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 18rpx;
}
}
.save-button {
position: fixed;
left: 30rpx;
right: 30rpx;
bottom: calc(env(safe-area-inset-bottom) + 30rpx);
height: 90rpx;
background: #ffa500;
background: linear-gradient(90deg, #ffd01e 0%, #ffb400 100%);
border-radius: 45rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(255, 149, 0, 0.08);
text {
color: #fff;
font-size: 32rpx;
font-weight: 500;
}
}
.upload-status {
position: fixed;
top: 0;
@ -292,7 +339,6 @@ export default {
display: flex;
align-items: center;
justify-content: center;
.status-mask {
position: absolute;
top: 0;
@ -301,7 +347,6 @@ export default {
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.status-content {
position: relative;
width: 240rpx;
@ -313,12 +358,10 @@ export default {
align-items: center;
justify-content: center;
gap: 20rpx;
text {
color: #fff;
font-size: 28rpx;
}
.loading-icon {
width: 60rpx;
height: 60rpx;
@ -329,13 +372,11 @@ export default {
}
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.safe-area {
padding-bottom: env(safe-area-inset-bottom);
}
</style>

+ 10
- 2
pages/subcomponent/faq.vue View File

@ -91,17 +91,25 @@
</template>
<script>
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
import emailPopup from '@/wxcomponents/email-popup/email-popup.vue'
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
components: {
emailPopup
},
},
mixins: [pullRefreshMixin],
data() {
return {
showEmailPopup:false
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
//
openEmailPopup() {
this.showEmailPopup = true


+ 373
- 0
pages/subcomponent/inspection-report.vue View File

@ -0,0 +1,373 @@
<template>
<view class="inspection-page">
<!-- 顶部渐变导航栏 -->
<view class="nav-bar" :style="{height: navBarTotalHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-bar-inner">
<view class="back-icon" @tap="navigateBack">
<uni-icons type="left" size="22" color="#fff" />
</view>
<view class="nav-bar-title">质检报告</view>
<view class="nav-bar-right">
<uni-icons type="more-filled" size="22" color="#fff" />
</view>
</view>
</view>
<!-- 打钩标签区及说明 -->
<view class="feature-area" :style="{marginTop: navBarTotalHeight+statusBarHeight + 'px'}">
<view class="feature-desc">该报告由瀚海回收质检查验出具</view>
<view class="feature-tags">
<view class="tag" v-for="(t, i) in featureTags" :key="i">
<text class="check"></text>
<text class="text">{{t}}</text>
</view>
</view>
</view>
<!-- 主内容区卡片悬浮覆盖打钩区 -->
<view class="main-content">
<view class="inspection-card">
<view class="report-title">质检合格</view>
<view class="goods-list">
<view class="goods-item" v-for="(item, i) in goodsList" :key="i">
<image class="goods-img" :src="item.img" mode="aspectFit" />
<view class="goods-info">
<view class="goods-row">
<view class="goods-name">{{item.name}}</view>
<view v-if="item.detail" class="detail-link">查看详情 <uni-icons type="right" size="16" color="#bbb" /></view>
</view>
<view class="goods-desc">{{item.desc}}</view>
<view class="goods-bottom-row">
<view class="goods-price-row">
<text class="goods-price">{{item.price}}</text>
<text class="goods-unit">/</text>
<text class="goods-count">x{{item.count}}</text>
</view>
<view class="goods-total">{{item.total}}</view>
</view>
</view>
</view>
</view>
<view class="summary-row">
<text>件数<text class="highlight">{{totalCount}}</text> </text>
<text>结算金额<text class="highlight">{{totalAmount}}</text></text>
</view>
</view>
</view>
</view>
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarHeight: 14,
navBarTotalHeight: 14,
featureTags: ['透明检', '专业验', '公正评', '逐件验'],
goodsList: [
{
img: '/static/goods1.png',
name: '羽绒服',
desc: '允许脏破烂,160码以上',
price: 8,
count: 8,
total: 64
},
{
img: '/static/goods2.png',
name: '品牌羽绒服',
desc: '允许脏破烂,160码以上',
price: 10,
count: 1,
total: 8,
detail: true
}
]
}
},
computed: {
totalCount() {
return this.goodsList.reduce((sum, item) => sum + item.count, 0)
},
totalAmount() {
return this.goodsList.reduce((sum, item) => sum + item.total, 0).toFixed(1)
}
},
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
this.navBarHeight = 14
this.navBarTotalHeight = this.statusBarHeight + this.navBarHeight
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
}
}
}
</script>
<style lang="scss" scoped>
.inspection-page {
min-height: 100vh;
background: #422525;
// padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
}
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
width: 100vw;
background: #422525;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.03);
.nav-bar-inner {
display: flex;
align-items: center;
justify-content: center;
height: 44px;
width: 100vw;
position: relative;
}
.back-icon, .nav-bar-right {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
}
.back-icon { left: 0; }
.nav-bar-right { right: 0; }
.nav-bar-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: bold;
color: #fff;
letter-spacing: 2rpx;
line-height: 44px;
font-family: DingTalk JinBuTi;
font-weight: 400;
font-style: italic;
font-size: 28px;
line-height: 100%;
letter-spacing: 0%;
text-align: center;
// vertical-align: bottom;
}
}
.feature-area {
margin: 0 32rpx;
margin-top: 0;
margin-bottom: 0;
background:#422525;
border-radius: 32rpx;
// box-shadow: 0 4rpx 24rpx rgba(60, 167, 250, 0.08);
padding: 18rpx 24rpx 18rpx 24rpx;
display: flex;
flex-direction: column;
align-items: stretch;
}
.feature-desc {
text-align: center;
font-size: 22rpx;
color: #fff;
font-weight: 500;
margin-bottom: 10rpx;
margin-top: 18rpx;
letter-spacing: 1rpx;
}
.feature-tags {
margin: 0 32rpx;
background: #533030;
border-radius: 12rpx;
box-shadow: 0 4rpx 24rpx rgba(60, 167, 250, 0.08);
// padding: 0 24rpx;
width: 100%;
height: 80rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.tag {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
.check {
width: 36rpx;
height: 36rpx;
background: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #422525;
font-weight: bold;
margin-right: 10rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);
}
.text {
color: #fff;
font-size: 28rpx;
font-weight: bold;
}
}
}
.main-content {
margin-top: 20rpx;
padding-top: 88rpx;
background: linear-gradient(180deg, #fef7e6 0%, #fff 50%);
min-height: 100vh;
width: 100vw;
box-sizing: border-box;
position: relative;
z-index: 11;
border-radius: 40rpx 40rpx 0 0;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.inspection-card {
background: #fff;
border-radius: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(60, 167, 250, 0.08);
padding: 40rpx 32rpx 32rpx 32rpx;
margin: -60rpx auto 0 auto;
width: calc(100vw - 64rpx);
max-width: 700rpx;
display: flex;
flex-direction: column;
.report-title {
font-size: 32rpx;
font-weight: bold;
color: #222;
text-align: center;
margin-bottom: 12rpx;
}
.goods-list {
.goods-item {
display: flex;
align-items: center;
background: #fff;
border-radius: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(60, 167, 250, 0.04);
padding: 24rpx 20rpx;
margin-bottom: 20rpx;
.goods-img {
width: 80rpx;
height: 80rpx;
border-radius: 16rpx;
margin-right: 20rpx;
background: #f5f5f5;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
.goods-row {
display: flex;
justify-content: space-between;
align-items: center;
.goods-name {
font-size: 28rpx;
color: #222;
font-weight: bold;
}
.detail-link {
font-size: 24rpx;
color: #bbb;
display: flex;
align-items: center;
}
}
.goods-desc {
font-size: 24rpx;
color: #bbb;
margin-bottom: 8rpx;
}
.goods-bottom-row {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-top: 8rpx;
.goods-price-row {
display: flex;
align-items: baseline;
.goods-price {
font-size: 26rpx;
color: #f79400;
font-weight: bold;
}
.goods-unit {
font-size: 24rpx;
color: #f79400;
margin-left: 2rpx;
}
.goods-count {
font-size: 22rpx;
color: #bbb;
margin-left: 8rpx;
font-weight: normal;
}
}
.goods-total {
font-size: 28rpx;
color: #222;
font-weight: bold;
margin-left: 24rpx;
}
}
}
}
.goods-item:last-child { margin-bottom: 0; }
}
.summary-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 24rpx;
font-size: 28rpx;
color: #222;
.highlight {
color: #f79400;
font-weight: bold;
font-size: 30rpx;
}
}
}
.check {
width: 36rpx;
height: 36rpx;
background: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #13ac47;
font-weight: bold;
margin-right: 10rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);
}
</style>

+ 8
- 0
pages/subcomponent/inspection.vue View File

@ -100,7 +100,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
isQualified: false, //
@ -145,6 +148,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 25
- 4
pages/subcomponent/order.vue View File

@ -79,7 +79,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
tabs: [
@ -165,6 +168,11 @@ export default {
this.initOrderData()
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},
@ -247,14 +255,22 @@ export default {
.container {
min-height: 100vh;
background: #f8f8f8;
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
}
.nav-bar {
display: flex;
align-items: center;
height: 88rpx;
padding: 0 30rpx;
height: calc(88rpx + var(--status-bar-height));
padding: 0 32rpx;
padding-top: var(--status-bar-height);
background: #fff;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
box-sizing: border-box;
.back {
padding: 20rpx;
@ -266,13 +282,15 @@ export default {
text-align: center;
font-size: 34rpx;
font-weight: 500;
color: #222;
}
.right-btns {
display: flex;
gap: 30rpx;
align-items: center;
gap: 32rpx;
.more, .share {
.more, .target {
font-size: 40rpx;
color: #333;
}
@ -281,6 +299,9 @@ export default {
.content {
padding: 30rpx;
margin-top: calc(88rpx + var(--status-bar-height));
min-height: calc(100vh - 88rpx - var(--status-bar-height));
box-sizing: border-box;
.page-header {
display: flex;


+ 8
- 0
pages/subcomponent/order_edit.vue View File

@ -168,7 +168,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
address: '',
@ -237,6 +240,11 @@
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 11
- 3
pages/subcomponent/orders.vue View File

@ -197,7 +197,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
//
@ -322,9 +325,14 @@ export default {
},
methods: {
navigateBack(){
uni.navigateBack()
},
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
},
//
switchStatus(status) {
this.currentStatus = status


+ 21
- 3
pages/subcomponent/pickup.vue View File

@ -1,5 +1,5 @@
<template>
<view class="pickup-container">
<view class="pickup-container" :style="{paddingTop: navBarHeightRpx + 'rpx'}">
<!-- 顶部导航栏 -->
<view class="nav-bar" :style="{height: (statusBarHeight + 88) + 'rpx', paddingTop: statusBarHeight + 'px'}">
<view class="back" @tap="goBack">
@ -9,7 +9,7 @@
</view>
<!-- 内容区域 -->
<view class="content" :style="{marginTop: (statusBarHeight + 88) + 'rpx'}">
<view class="content">
<!-- 回收流程卡片 -->
<view class="card process-card">
<view class="card-title process-title">回收流程</view>
@ -141,10 +141,15 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarHeight: 0, // px
navBarHeightRpx: 0, // rpx
fromRecycle: false,
address: '',
selectedAddress: null,
@ -237,7 +242,15 @@ export default {
this.$forceUpdate()
})
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
let navBarHeight = 44
try {
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
navBarHeight = menuButtonInfo.bottom + menuButtonInfo.top - sysInfo.statusBarHeight
} catch (e) {}
this.navBarHeight = navBarHeight
this.navBarHeightRpx = Math.round(navBarHeight * 750 / sysInfo.windowWidth)
},
onUnload() {
//
@ -264,6 +277,11 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 195
- 0
pages/subcomponent/promo-qrcode.vue View File

@ -0,0 +1,195 @@
<template>
<view class="promo-modal-page">
<!-- 顶部导航栏 -->
<view class="nav-bar" :style="{height: navBarTotalHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-bar-inner">
<view class="back-icon" @tap="navigateBack">
<uni-icons type="left" size="22" color="#222" />
</view>
<view class="nav-bar-title">推广链接</view>
<view class="nav-bar-right">
<uni-icons type="more-filled" size="22" color="#222" />
</view>
</view>
</view>
<!-- 用户信息 -->
<view class="user-info-modal" :style="{ marginTop: navBarTotalHeight + 'px' }">
<view class="avatar-frame">
<image class="avatar-img" :src="userInfo.avatar" mode="aspectFill" />
</view>
<view class="nickname">{{userInfo.name}}</view>
</view>
<!-- 二维码区 -->
<view class="qrcode-modal-section">
<image class="qrcode-img" :src="qrcodeUrl" mode="aspectFit" />
<view class="invite-code">邀请码{{inviteCode}}</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-btns-modal">
<button class="btn gray">分享给好友</button>
<button class="btn green">保存到本地</button>
</view>
</view>
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarHeight: 44,
navBarTotalHeight: 44,
userInfo: {
avatar: '/static/avatar.png',
name: '战斗世界',
},
qrcodeUrl: '/static/qrcode.png',
inviteCode: '888888',
}
},
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
this.navBarHeight = 44
this.navBarTotalHeight = this.statusBarHeight + this.navBarHeight
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
},
}
}
</script>
<style lang="scss" scoped>
.promo-modal-page {
min-height: 100vh;
background: linear-gradient(to bottom, #f6fff2 0%, #fff 100%);
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
width: 100vw;
background: linear-gradient(to right, #b2f08d 0%, #39e9d2 100%);
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.03);
.nav-bar-inner {
display: flex;
align-items: center;
height: 44px;
width: 100vw;
position: relative;
}
.back-icon, .nav-bar-right {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
}
.back-icon { left: 0; }
.nav-bar-right { right: 0; }
.nav-bar-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: bold;
color: #222;
letter-spacing: 2rpx;
line-height: 44px;
}
}
.user-info-modal {
display: flex;
flex-direction: column;
align-items: center;
.avatar-frame {
width: 104rpx;
height: 104rpx;
border-radius: 10rpx;
overflow: hidden;
background: #f2f2f2;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.10);
.avatar-img {
width: 104rpx;
height: 104rpx;
object-fit: cover;
display: block;
}
}
.nickname {
margin-top: 24rpx;
font-size: 32rpx;
font-weight: bold;
color: #222;
text-align: center;
}
}
.qrcode-modal-section {
margin-top: 48rpx;
width: 80vw;
display: flex;
flex-direction: column;
align-items: center;
.qrcode-img {
width: 80vw;
height: 80vw;
max-width: 480rpx;
max-height: 480rpx;
background: #fff;
border-radius: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);
}
.invite-code {
margin-top: 32rpx;
font-size: 30rpx;
color: #222;
font-weight: bold;
text-align: center;
}
}
.bottom-btns-modal {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: space-between;
padding: 24rpx 32rpx calc(env(safe-area-inset-bottom) + 24rpx) 32rpx;
background: #fff;
z-index: 100;
.btn {
flex: 1;
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: bold;
margin: 0 12rpx;
border: none;
&.gray {
background: linear-gradient(90deg, #f7f7f7, #f2f2f2);
color: #888;
}
&.green {
background: linear-gradient(90deg, #b2f08d, #39e9d2);
color: #fff;
}
}
}
}
</style>

+ 551
- 498
pages/subcomponent/promotion.vue
File diff suppressed because it is too large
View File


+ 18
- 10
pages/subcomponent/promotion_info.vue View File

@ -105,21 +105,29 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
},
apply(){
uni.navigateTo({
url: '/pages/component/apply'
})
},
upgrade(){
uni.navigateTo({
url: '/pages/component/upgrad'
})
}
apply(){
uni.navigateTo({
url: '/pages/component/apply'
})
},
upgrade(){
uni.navigateTo({
url: '/pages/component/upgrad'
})
}
}
}
</script>


+ 9
- 2
pages/subcomponent/recycle_rules.vue View File

@ -45,7 +45,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
showPopup: false,
@ -136,9 +139,13 @@ export default {
}
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack(
)
uni.navigateBack()
},
showDetail(item) {
this.currentItem = item


+ 11
- 1
pages/subcomponent/select.vue View File

@ -107,8 +107,10 @@
<script>
import regionData from '@/pages/subcomponent/region-data.js'
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
@ -193,6 +195,11 @@ export default {
this.mode = options.mode || ''
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
getAddressList(callback) {
this.$api('getAddressList', {}, res => {
if (res && res.result && res.result.records) {
@ -424,7 +431,10 @@ export default {
}
.address-list {
padding: 20rpx;
padding: 32rpx;
margin-top: calc(88rpx + var(--status-bar-height));
min-height: calc(100vh - 88rpx - var(--status-bar-height) - 140rpx - env(safe-area-inset-bottom));
box-sizing: border-box;
.address-item {
background: #fff;


+ 226
- 342
pages/subcomponent/upgrad.vue View File

@ -1,140 +1,71 @@
<template>
<view class="upgrade-page">
<!-- 顶部区域 -->
<view class="header">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<!-- 顶部导航栏 -->
<view class="nav-bar" :style="{height: navBarTotalHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-bar-inner">
<view class="back-icon" @tap="navigateBack">
<uni-icons type="left" size="20"></uni-icons>
<uni-icons type="left" size="22" color="#222" />
</view>
<view class="title">回收侠·推客联盟</view>
</view>
<!-- 特点标签 -->
<view class="feature-tags">
<view class="tag">
<text class="iconfont check"></text>
<text>收益高</text>
</view>
<view class="tag">
<text class="iconfont check"></text>
<text>品类全</text>
</view>
<view class="tag">
<text class="iconfont check"></text>
<text>到账快</text>
</view>
<view class="tag">
<text class="iconfont check"></text>
<text>城市多</text>
<view class="nav-bar-title">回收侠·推客联盟</view>
<view class="nav-bar-right">
<uni-icons type="more-filled" size="22" color="#222" />
</view>
</view>
</view>
<!-- 主要内容区域 -->
<view class="content">
<view class="page-header">
<text class="title">升级推广官</text>
<view class="contact-service" @tap="contactService">
<text class="icon">🎧</text>
<text>联系客服</text>
</view>
<!-- 打钩标签区 -->
<view class="feature-tags" :style="{marginTop: navBarTotalHeight + 'px'}">
<view class="tag" v-for="(t, i) in featureTags" :key="i">
<text class="check"></text>
<text class="text">{{t}}</text>
</view>
<view class="subtitle">升级推广官需支付 [X] 元费用</view>
<!-- 表单区域 -->
<view class="form">
<!-- 姓名输入 -->
</view>
<!-- 主内容区 -->
<view class="main-content">
<view class="upgrade-card">
<view class="upgrade-title-row">
<text class="upgrade-title">申请推广官</text>
<view class="contact-service" @tap="contactService">
<uni-icons type="headphones" size="22" color="#df8155" />
<text class="contact-text">联系客服</text>
</view>
</view>
<!-- 表单区 -->
<view class="form-item">
<text class="label">姓名</text>
<input
class="input"
type="text"
placeholder="请输入"
placeholder-class="placeholder"
v-model="formData.name"
/>
<input class="input" type="text" placeholder="请输入" v-model="formData.name" />
</view>
<!-- 电话输入 -->
<view class="form-item">
<text class="label">电话</text>
<input
class="input"
type="number"
placeholder="请输入"
placeholder-class="placeholder"
v-model="formData.phone"
/>
</view>
<!-- 职业选择 -->
<view class="form-item" @tap="showPicker('occupation')">
<text class="label">职业</text>
<view class="picker-value">
<text :class="{'placeholder': !formData.occupation}">
{{formData.occupation || '请选择'}}
</text>
<text class="iconfont arrow">></text>
</view>
</view>
<!-- 年龄选择 -->
<view class="form-item" @tap="showPicker('age')">
<text class="label">年龄</text>
<view class="picker-value">
<text :class="{'placeholder': !formData.age}">
{{formData.age || '请选择'}}
</text>
<text class="iconfont arrow">></text>
</view>
<input class="input" type="number" placeholder="请输入" v-model="formData.phone" />
</view>
<!-- 推广时间选择 -->
<view class="form-item" @tap="showPicker('promotionTime')">
<text class="label">每日可花推广时间</text>
<view class="picker-value">
<text :class="{'placeholder': !formData.promotionTime}">
{{formData.promotionTime || '请选择'}}
</text>
<text class="iconfont arrow">></text>
<text :class="{'placeholder': !formData.promotionTime}">{{formData.promotionTime || '请选择'}}</text>
<uni-icons type="right" size="18" color="#bbb" />
</view>
</view>
</view>
<!-- 说明文字 -->
<view class="description">
"支付费用后,您将成为更高等级的推广官,享受更高额度的佣金及相关权益,包括但不限于优先推广资源、专属培训课程、一对一业务指导等"
<view class="desc-text">
"支付费用后,您将成为更高等级的推广官,享受更高额度的佣金及相关权益,包括但不限于优先推广资源、专属培训课程、一对一业务指导等"
</view>
</view>
</view>
<!-- 底部按钮 -->
<!-- 底部按钮区 -->
<view class="bottom-btns">
<button class="submit-btn" @tap="submitForm">提交</button>
<button class="btn gray">升级推广官</button>
<button class="btn green" @tap="submitForm">提交</button>
</view>
<!-- 选择器弹窗 -->
<view class="picker-popup" v-if="showPickerPopup">
<view class="popup-mask" @tap="hidePicker"></view>
<view class="popup-content">
<view class="popup-header">
<text class="reset">重置</text>
<text class="title">{{pickerTitle}}</text>
<text class="reset" @tap="resetPicker">重置</text>
<text class="title">每日可花推广时间</text>
</view>
<picker-view
class="picker-view"
:value="[currentPickerIndex]"
@change="onPickerChange"
:indicator-style="indicatorStyle"
>
<picker-view class="picker-view" :value="[currentPickerIndex]" @change="onPickerChange" :indicator-style="indicatorStyle">
<picker-view-column>
<view
class="picker-item"
v-for="(item, index) in currentPickerOptions"
:key="index"
:class="{'selected-item': index === currentPickerIndex}"
>{{item}}</view>
<view class="picker-item" v-for="(item, index) in pickerOptions" :key="index" :class="{'selected-item': index === currentPickerIndex}">{{item}}</view>
</picker-view-column>
</picker-view>
<button class="confirm-btn" @tap="confirmPicker">确认</button>
@ -144,55 +75,46 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
navBarHeight: 44,
navBarTotalHeight: 44,
featureTags: ['收益高', '品类全', '到账快', '城市多'],
formData: {
name: '',
phone: '',
occupation: '',
age: '',
promotionTime: ''
},
showPickerPopup: false,
currentPickerType: '',
currentPickerIndex: 0,
indicatorStyle: 'height: 88rpx; border: none;',
pickerOptions: {
occupation: ['产品摄影师', '外呼专员', '宝妈', '导购员', '产品经理'],
age: ['28岁', '29岁', '30岁', '31岁', '32岁'],
promotionTime: ['2小时', '3小时', '4小时', '5小时', '6小时']
}
pickerOptions: ['2小时', '3小时', '4小时', '5小时', '6小时']
}
},
computed: {
pickerTitle() {
const titles = {
occupation: '职业',
age: '年龄',
promotionTime: '每日可花推广时间'
}
return titles[this.currentPickerType] || ''
},
currentPickerOptions() {
return this.pickerOptions[this.currentPickerType] || []
}
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight
this.navBarHeight = 44
this.navBarTotalHeight = this.statusBarHeight + this.navBarHeight
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
navigateBack() {
uni.navigateBack()
},
contactService() {
uni.showToast({
title: '正在连接客服...',
icon: 'none'
})
uni.navigateTo({ url: '/pages/subcomponent/admin_faq' })
},
showPicker(type) {
this.currentPickerType = type
const currentValue = this.formData[this.currentPickerType]
this.currentPickerIndex = this.currentPickerOptions.indexOf(currentValue)
if (this.currentPickerIndex === -1) this.currentPickerIndex = 0
showPicker() {
this.showPickerPopup = true
},
hidePicker() {
@ -203,16 +125,14 @@ export default {
this.currentPickerIndex = index
},
confirmPicker() {
const selectedValue = this.currentPickerOptions[this.currentPickerIndex]
this.formData[this.currentPickerType] = selectedValue
this.formData.promotionTime = this.pickerOptions[this.currentPickerIndex]
this.hidePicker()
},
resetPicker() {
this.currentPickerIndex = 0
},
submitForm() {
console.log('提交表单数据:', this.formData)
uni.showToast({
title: '提交成功',
icon: 'success'
})
uni.showToast({ title: '提交成功', icon: 'success' })
}
}
}
@ -221,214 +141,218 @@ export default {
<style lang="scss" scoped>
.upgrade-page {
min-height: 100vh;
background: linear-gradient(to right,#9be48f,#42dfc2);
padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
background: linear-gradient(180deg, #eaffe6 0%, #fff 30%);
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
}
.header {
background: linear-gradient(to right,#9be48f,#42dfc2);
padding: 0 30rpx;
padding-bottom: 20rpx;
.nav-bar {
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
width: 100vw;
background: linear-gradient(to right, #b2f08d 0%, #39e9d2 100%);
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.03);
.nav-bar-inner {
display: flex;
align-items: center;
// justify-content: space-between;
height: 88rpx;
padding-top: var(--status-bar-height);
.title {
font-family: DingTalk JinBuTi;
font-weight: 400;
font-style: italic;
font-size: 50rpx;
line-height: 100%;
letter-spacing: 0%;
vertical-align: bottom;
color: #333;
margin-left: 10%;
}
.back-icon, .more-icon {
width: 88rpx;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
.iconfont {
font-size: 40rpx;
color: #333;
}
}
height: 44px;
width: 100vw;
position: relative;
}
.back-icon, .nav-bar-right {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
}
.back-icon { left: 0; }
.nav-bar-right { right: 0; }
.nav-bar-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: bold;
color: #222;
letter-spacing: 2rpx;
line-height: 44px;
}
}
.feature-tags {
.feature-tags {
position: relative;
z-index: 1;
margin: 0 32rpx;
margin-top: 0;
margin-bottom: 0;
background: linear-gradient(to right, #b2f08d 0%, #39e9d2 100%);
border-radius: 32rpx;
box-shadow: 0 4rpx 24rpx rgba(60, 167, 250, 0.08);
padding: 0 24rpx;
height: 80rpx;
display: flex;
justify-content: space-between;
align-items: center;
.tag {
flex: 1;
display: flex;
justify-content: space-between;
width: 90%;
margin: 0 auto;
margin-top: 10rpx;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 20rpx;
background: linear-gradient(to right,#9be48f,#42dfc2);
.tag {
// background: rgba(255, 255, 255, 0.8);
border-radius: 30rpx;
padding: 12rpx 24rpx;
align-items: center;
justify-content: center;
.check {
width: 36rpx;
height: 36rpx;
background: #fff;
border-radius: 50%;
display: flex;
align-items: center;
.check {
color: #4CAF50;
margin-right: 8rpx;
font-size: 24rpx;
}
text {
font-size: 24rpx;
color: #333;
}
justify-content: center;
font-size: 28rpx;
color: #13ac47;
font-weight: bold;
margin-right: 10rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08);
}
.text {
color: #fff;
font-size: 28rpx;
font-weight: bold;
}
}
}
.content {
padding: 40rpx 30rpx;
background: linear-gradient(to bottom,#eaffe6,6%,#fcfffb);
border-radius: 40rpx 40rpx 0 0;
margin-top: 20rpx;
.main-content {
margin-top: -48rpx;
padding-top: 88rpx;
background: linear-gradient(180deg, #eaffe6 0%, #fff 30%);
min-height: 100vh;
width: 100vw;
box-sizing: border-box;
position: relative;
z-index: 11;
border-radius: 40rpx 40rpx 0 0;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.page-header {
.upgrade-card {
width: 92vw;
max-width: 700rpx;
margin: 40rpx auto 0 auto;
background: #fff;
border-radius: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(60, 167, 250, 0.08);
padding: 40rpx 32rpx 32rpx 32rpx;
display: flex;
flex-direction: column;
align-items: stretch;
.upgrade-title-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 60rpx;
.title {
font-size: 40rpx;
margin-bottom: 32rpx;
.upgrade-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
color: #222;
}
.contact-service {
display: flex;
align-items: center;
padding: 12rpx 24rpx;
border-radius: 10rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
border: 2rpx solid #df8155;
background: #fff0d2;
.icon {
margin-right: 8rpx;
font-size: 28rpx;
.contact-text {
color: #df8155;
font-size: 22rpx;
margin-left: 4rpx;
}
text {
font-size: 26rpx;
color: #da7143;
uni-icons {
font-size: 20rpx !important;
}
}
}
.subtitle {
font-size: 28rpx;
color: #666;
margin-bottom: 40rpx;
}
.form {
.form-item {
margin-bottom: 40rpx;
.label {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
line-height: 140%;
letter-spacing: 0%;
color: #343534;
font-weight: normal;
margin-bottom: 16rpx;
display: block;
}
.input {
width: 100%;
height: 88rpx;
background: transparent;
padding: 0;
.form-item {
margin-bottom: 32rpx;
.label {
font-size: 28rpx;
color: #222;
margin-bottom: 12rpx;
display: block;
}
.input {
width: 100%;
height: 72rpx;
background: transparent;
padding: 0;
font-size: 30rpx;
border: none;
border-bottom: 1rpx solid #eee;
&::placeholder {
color: #bbb;
font-size: 30rpx;
border: none;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.08);
&::placeholder {
color: rgba(153, 153, 153, 0.35);
font-size: 30rpx;
}
}
.picker-value {
width: 100%;
height: 88rpx;
background: transparent;
padding: 0;
display: flex;
align-items: center;
justify-content: space-between;
border: none;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.08);
text {
font-size: 30rpx;
color: #333;
&.placeholder {
color: rgba(153, 153, 153, 0.35);
}
}
.arrow {
color: #999;
font-size: 24rpx;
transform: rotate(90deg);
opacity: 0.5;
}
}
.picker-value {
width: 100%;
height: 72rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid #eee;
.placeholder {
color: #bbb;
}
text {
font-size: 30rpx;
color: #222;
}
}
}
.description {
.desc-text {
font-size: 26rpx;
color: #666;
line-height: 1.6;
padding: 30rpx;
margin-top: 40rpx;
margin-top: 32rpx;
text-align: center;
}
}
.bottom-btns {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
.submit-btn {
width: 100%;
bottom: 0;
display: flex;
justify-content: space-between;
padding: 24rpx 32rpx calc(env(safe-area-inset-bottom) + 24rpx) 32rpx;
background: #fff;
z-index: 100;
.btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 44rpx;
font-size: 32rpx;
background: linear-gradient(90deg, #91dba5, #7ed4a6);
color: #fff;
font-weight: bold;
margin: 0 12rpx;
border: none;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
box-shadow: none;
&.gray {
background: linear-gradient(180deg, #f8f8f8 0%, #f2f4f6 100%);
color: #222;
border: 2rpx solid #e5e5e5;
}
&.green {
background: linear-gradient(90deg, #b2f08d, #39e9d2);
color: #222;
border: none;
}
}
}
@ -439,7 +363,6 @@ export default {
right: 0;
bottom: 0;
z-index: 999;
.popup-mask {
position: absolute;
top: 0;
@ -448,7 +371,6 @@ export default {
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.popup-content {
position: absolute;
left: 0;
@ -457,7 +379,6 @@ export default {
background: #fff;
border-radius: 24rpx 24rpx 0 0;
padding-bottom: calc(env(safe-area-inset-bottom) + 40rpx);
.popup-header {
display: flex;
align-items: center;
@ -465,13 +386,11 @@ export default {
position: relative;
justify-content: center;
border-bottom: 1rpx solid #f5f5f5;
.title {
font-size: 32rpx;
color: #333;
font-weight: normal;
}
.reset {
position: absolute;
left: 30rpx;
@ -479,12 +398,10 @@ export default {
color: #666;
}
}
.picker-view {
width: 100%;
height: 440rpx;
background: #fff;
.picker-item {
height: 88rpx;
line-height: 88rpx;
@ -494,7 +411,6 @@ export default {
font-weight: normal;
}
}
.confirm-btn {
margin: 30rpx;
height: 88rpx;
@ -507,36 +423,4 @@ export default {
}
}
}
::v-deep .uni-picker-view-indicator {
height: 88rpx !important;
background-color: rgba(245, 245, 245, 0.3);
}
::v-deep .uni-picker-view-mask {
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4)),
linear-gradient(0deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4));
}
::v-deep .uni-picker-view-content {
.picker-item {
transition: all 0.2s;
}
}
::v-deep .uni-picker-view-indicator::after,
::v-deep .uni-picker-view-indicator::before {
display: none;
}
::v-deep .selected-item {
font-size: 34rpx !important;
color: #333 !important;
font-weight: 600 !important;
}
::v-deep .placeholder {
color: rgba(153, 153, 153, 0.35) !important;
font-size: 30rpx;
}
</style>

+ 8
- 0
pages/subcomponent/wallet.vue View File

@ -70,7 +70,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
@ -104,6 +107,11 @@ export default {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 8
- 0
pages/subcomponent/withdraw.vue View File

@ -67,7 +67,10 @@
</template>
<script>
import pullRefreshMixin from '@/mixins/pullRefreshMixin.js'
export default {
mixins: [pullRefreshMixin],
data() {
return {
statusBarHeight: 0,
@ -80,6 +83,11 @@ export default {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
},
methods: {
async onRefresh() {
//
await new Promise(resolve => setTimeout(resolve, 1000))
this.stopPullRefresh()
},
goBack() {
uni.navigateBack()
},


+ 86
- 10
wxcomponents/privacy-popup/privacy-popup.vue View File

@ -1,5 +1,5 @@
<template>
<uni-popup ref="popup" type="bottom" :mask-click="false" class="bottom-popup">
<uni-popup ref="popup" type="bottom" background-color="#fff" :mask-click="false" class="bottom-popup">
<view class="popup-container">
<!-- 标题 -->
<view class="popup-title">用户隐私保护提示</view>
@ -16,7 +16,18 @@
<!-- 操作按钮 -->
<view class="popup-buttons">
<button class="popup-btn reject" @click="handleReject">拒绝</button>
<button class="popup-btn agree" @click="handleAgree" open-type="getRealtimePhoneNumber" @getrealtimephonenumber="getrealtimephonenumber">同意</button>
<button
v-if="needPhone"
class="popup-btn agree"
open-type="getRealtimePhoneNumber"
@getrealtimephonenumber="getrealtimephonenumber"
@click="handleAgree"
>同意</button>
<button
v-else
class="popup-btn agree"
@click="handleAgree"
>同意</button>
</view>
</view>
</uni-popup>
@ -24,6 +35,12 @@
<script>
export default {
props: {
needPhone: {
type: Boolean,
default: false
}
},
methods: {
getrealtimephonenumber (e) {
console.log(e.detail.code,'11') //
@ -61,6 +78,10 @@ export default {
//
openProtocol(type) {
this.$emit('open-protocol', type)
},
// needPhone
setNeedPhone(val) {
this.$emit('update:needPhone', val)
}
}
}
@ -75,12 +96,17 @@ export default {
.popup-container {
padding: 40rpx;
background: #fff;
border-radius: 24rpx 24rpx 0 0;
border-radius: 24rpx 24rpx 0 0;
width: 100%;
box-sizing: border-box;
max-height: 80vh;
overflow-y: auto;
/* padding-bottom: env(safe-area-inset-bottom); */
}
/* 标题样式 */
.popup-title {
font-size: 26rpx;
font-size: 32rpx;
font-weight: bold;
text-align: left;
margin-bottom: 30rpx;
@ -93,33 +119,37 @@ export default {
line-height: 1.6;
color: #666;
margin-bottom: 40rpx;
word-wrap: break-word;
word-break: break-all;
}
.highlight {
color: #4c6eae;
display: inline;
}
/* 按钮容器 */
.popup-buttons {
display: flex;
justify-content: space-between;
padding: 0 20rpx;
margin-top: 20rpx;
}
/* 按钮基础样式 */
.popup-btn {
/* flex: 1; */
width: 30%;
height: 80rpx;
line-height: 80rpx;
/* border-radius: 40rpx; */
width: 45%;
height: 88rpx;
line-height: 88rpx;
font-size: 32rpx;
border-radius: 44rpx;
text-align: center;
}
/* 拒绝按钮 */
.popup-btn.reject {
background-color: #f5f5f5;
color: #666;
margin-right: 20rpx;
}
/* 同意按钮 */
@ -132,4 +162,50 @@ export default {
.popup-btn::after {
border: none;
}
/* 适配不同屏幕尺寸 */
@media screen and (max-height: 700px) {
.popup-container {
padding: 30rpx;
}
.popup-title {
font-size: 28rpx;
margin-bottom: 20rpx;
}
.popup-content {
font-size: 26rpx;
margin-bottom: 30rpx;
}
.popup-btn {
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
}
}
/* 适配小屏幕 */
@media screen and (max-height: 600px) {
.popup-container {
padding: 20rpx;
}
.popup-title {
font-size: 26rpx;
margin-bottom: 15rpx;
}
.popup-content {
font-size: 24rpx;
margin-bottom: 20rpx;
}
.popup-btn {
height: 70rpx;
line-height: 70rpx;
font-size: 26rpx;
}
}
</style>

Loading…
Cancel
Save