骑手端app代码仓库创建

This commit is contained in:
admin
2026-01-06 21:22:12 +08:00
commit 34c63780a8
467 changed files with 65334 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
<!-- 分类展示first-one 风格 -->
<template>
<view class="ss-flex-col">
<view class="goods-box" v-for="item in pagination.list" :key="item.id">
<s-goods-column
size="sl"
:data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
/>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
pagination: Object,
});
</script>
<style lang="scss" scoped>
.goods-box {
width: 100%;
}
</style>

View File

@@ -0,0 +1,66 @@
<!-- 分类展示first-two 风格 -->
<template>
<view>
<view class="ss-flex flex-wrap">
<view class="goods-box" v-for="item in pagination?.list" :key="item.id">
<view @click="sheep.$router.go('/pages/goods/index', { id: item.id })">
<view class="goods-img">
<image class="goods-img" :src="item.picUrl" mode="aspectFit" />
</view>
<view class="goods-content">
<view class="goods-title ss-line-1 ss-m-b-28">{{ item.name }}</view>
<view class="goods-price">{{ fen2yuan(item.price) }}</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
import { fen2yuan } from '@/sheep/hooks/useGoods';
const props = defineProps({
pagination: Object,
});
</script>
<style lang="scss" scoped>
.goods-box {
width: calc((100% - 20rpx) / 2);
margin-bottom: 20rpx;
.goods-img {
width: 100%;
height: 246rpx;
border-radius: 10rpx 10rpx 0px 0px;
}
.goods-content {
width: 100%;
background: #ffffff;
box-shadow: 0px 0px 20rpx 4rpx rgba(199, 199, 199, 0.22);
padding: 20rpx 0 32rpx 16rpx;
box-sizing: border-box;
border-radius: 0 0 10rpx 10rpx;
.goods-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
}
.goods-price {
font-size: 24rpx;
font-family: OPPOSANS;
font-weight: 500;
color: #e1212b;
}
}
&:nth-child(2n + 1) {
margin-right: 20rpx;
}
}
</style>

View File

@@ -0,0 +1,97 @@
<!-- 分类展示second-one 风格 -->
<template>
<view>
<!-- 一级分类的名字 -->
<!-- <view class="title-box ss-flex ss-col-center ss-row-center ss-p-b-30">
<view class="title-line-left" />
<view class="title-text ss-p-x-20">{{ props.data[activeMenu].name }}</view>
<view class="title-line-right" />
</view> -->
<view class="title-box ss-flex ss-p-b-30">
<view class="theme-line"></view>
<view class="title-text">{{ props.data[activeMenu].name }}</view>
</view>
<!-- 二级分类的名字 -->
<view class="goods-item-box ss-flex ss-flex-wrap ss-p-b-20">
<view
class="goods-item"
v-for="item in props.data[activeMenu].children"
:key="item.id"
@tap="
sheep.$router.go('/pages/goods/list', {
categoryId: item.id,
})
"
>
<image class="goods-img" :src="item.picUrl" mode="aspectFill" />
<view class="ss-p-10">
<view class="goods-title ss-line-1">{{ item.name }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
activeMenu: [Number, String],
});
</script>
<style lang="scss" scoped>
.title-box {
font-weight: 800;
font-size: 32rpx;
color: #333333;
.title-line-left,
.title-line-right {
width: 15px;
height: 1px;
background: #d2d2d2;
}
}
.goods-item {
width: calc((100% - 20px) / 3);
margin-right: 10px;
margin-bottom: 10px;
&:nth-of-type(3n) {
margin-right: 0;
}
.goods-img {
width: calc((100vw - 140px) / 3);
height: calc((100vw - 140px) / 3);
}
.goods-title {
font-size: 26rpx;
font-weight: bold;
color: #333333;
line-height: 40rpx;
text-align: center;
}
.goods-price {
color: $red;
line-height: 40rpx;
}
}
.theme-line {
margin-right: 15rpx;
width: 8rpx;
height: 28rpx;
background: var(--ui-BG-Main);
border-radius: 8rpx 8rpx 8rpx 8rpx;
}
</style>

480
pages/index/index.vue Normal file
View File

@@ -0,0 +1,480 @@
<!-- 接单页将原首页替换为接单页面含订单卡片顶部 tab底部批量操作栏 -->
<template>
<view class="receive-page">
<!-- 顶部区域状态 + tabs -->
<view class="top-area" :style="headerStyle">
<view class="top-bg"></view>
<view class="top-inner">
<view class="user-info">
<image class="user-avatar" :src="driverInfo.avatar || defaultAvatar" mode="cover" />
<view class="user-meta">
<!-- <text class="user-name">{{ driverInfo.nickName || '骑手姓名' }}</text> -->
<text class="user-status" @click="toggleOnline">{{ driverInfo.isOnline ? '在线中' : '离线' }}</text>
</view>
</view>
<view class="tabs">
<view :class="['tab', activeTab === 'pickup' ? 'active' : '']" @click="switchTab('pickup')">
<text>待取货</text>
<text class="count">({{ pickupCount }})</text>
</view>
<view :class="['tab', activeTab === 'delivering' ? 'active' : '']" @click="switchTab('delivering')">
<text>配送中</text>
<text class="count">({{ deliveringCount }})</text>
</view>
</view>
</view>
</view>
<!-- 订单列表 -->
<scroll-view class="order-list" scroll-y="true" :style="{ height: listHeight + 'px' }">
<view v-for="order in filteredOrders" :key="order.id" class="order-card">
<!-- 头部编号 -->
<view class="order-header">
<view class="order-badge">{{ order.type === 'pickup' ? '取' : '送' }}</view>
<view class="order-title">
<text class="shop-name">{{ order.shopName }}</text>
<text class="order-id">#{{ order.id }}</text>
</view>
<view class="order-status">{{ order.statusText }}</view>
</view>
<!-- 地址信息 -->
<view class="order-info">
<view class="address-row">
<view class="icon pickup"></view>
<view class="address-content">
<text class="address-title">{{ order.pickupAddress }}</text>
<text class="address-sub">商家已出餐 · {{ order.pickupNote || '' }}</text>
</view>
<view class="nav-icon" @click="openMap(order.pickupLat, order.pickupLng, order.pickupAddress)">导航</view>
</view>
<view class="address-row">
<view class="icon deliver"></view>
<view class="address-content">
<text class="address-title">{{ order.deliveryAddress }}</text>
<text class="address-sub">收货人{{ order.receiverName }} {{ order.receiverPhone ? ('尾号' + (order.receiverPhone + '').slice(-4)) : ''}}</text>
</view>
<view class="nav-icon" @click="openMap(order.deliveryLat, order.deliveryLng, order.deliveryAddress)">导航</view>
</view>
</view>
<!-- 备注 -->
<view class="order-note" v-if="order.note">
<text>顾客{{ order.note }}</text>
</view>
<!-- 操作区 -->
<view class="order-actions">
<view class="contact" @click="callPhone(order.receiverPhone)">
<text>联系</text>
</view>
<view class="confirm" @click="confirmArrive(order.id)">
<text>确认到店</text>
</view>
</view>
</view>
</scroll-view>
<!-- 底部批量操作栏 -->
<view class="bottom-bar">
<view class="batch-item" @click="scanQr">扫一扫取单</view>
<view class="batch-item" @click="openManualInput">输入用户单编码</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import sheep from '@/sheep';
// 驿站/骑手信息(从 store 获取或 mock
const driverInfo = ref({
isOnline: true,
nickName: '骑手张三',
avatar: ''
});
const defaultAvatar = 'https://huichibao.oss-cn-guangzhou.aliyuncs.com/1/material/348b8223-8d03-46aa-8836-6757e8beebd2.png';
// 页面状态
const activeTab = ref('pickup'); // 'pickup' | 'delivering'
const listHeight = ref(600);
// Mock 订单数据(真实项目应从后端接口拉取 / store
const orders = ref([
{
id: 1001,
type: 'pickup',
statusText: '待取货',
shopName: '取货点店铺名称',
pickupAddress: '广东省广州市天河区学院站荷光路118-121号',
pickupLat: 23.1,
pickupLng: 113.3,
pickupNote: '商家已出餐',
deliveryAddress: '广东省广州市天河区华景新城软件园区',
deliveryLat: 23.12,
deliveryLng: 113.31,
receiverName: '张先生',
receiverPhone: '13900001234',
note: '根据餐量提供餐具'
},
{
id: 1002,
type: 'pickup',
statusText: '待取货',
shopName: '乐易购(学院店)',
pickupAddress: '广东省广州市天河区学院站荷光路118--121号',
pickupLat: 23.11,
pickupLng: 113.32,
pickupNote: '',
deliveryAddress: '广东省广州市天河区某小区',
deliveryLat: 23.13,
deliveryLng: 113.33,
receiverName: '李女士',
receiverPhone: '13900005678',
note: ''
}
]);
// 计算各 tab 数量与过滤列表
const pickupCount = computed(() => orders.value.filter(o => o.type === 'pickup').length);
const deliveringCount = computed(() => orders.value.filter(o => o.type === 'delivering').length);
const filteredOrders = computed(() => {
if (activeTab.value === 'pickup') {
return orders.value.filter(o => o.type === 'pickup');
}
return orders.value.filter(o => o.type === 'delivering');
});
// 切换 tab
function switchTab(tab) {
activeTab.value = tab;
}
// 切换上线/下线(简单 UI 切换,建议接入后端)
function toggleOnline() {
driverInfo.value.isOnline = !driverInfo.value.isOnline;
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast(driverInfo.value.isOnline ? '已上线' : '已下线');
}
// 确认到店(演示:改变订单状态)
function confirmArrive(orderId) {
const order = orders.value.find(o => o.id === orderId);
if (!order) return;
// 示例逻辑:到店后将类型改为 delivering
if (order.type === 'pickup') {
order.type = 'delivering';
order.statusText = '配送中';
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已确认到店,开始配送');
}
}
// 拨打电话
function callPhone(phone) {
if (!phone) {
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('未找到联系电话');
return;
}
uni.makePhoneCall({
phoneNumber: phone
});
}
// 打开地图导航(使用 openLocation 打开经纬度或直接跳转小程序地图)
function openMap(lat, lng, name) {
if (!lat || !lng) {
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('无法获取坐标');
return;
}
uni.openLocation({
latitude: Number(lat),
longitude: Number(lng),
name: name || '',
scale: 18
});
}
// 底部操作(扫码、手动输入)
function scanQr() {
uni.scanCode({
onlyFromCamera: false,
success(res) {
const code = res.result || res.path || '';
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已识别:' + code);
},
fail() {
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('扫码失败');
}
});
}
function openManualInput() {
uni.navigateTo({
url: '/pages/index/user' // 示例跳转,按需替换为真实手动输入页面
});
}
// 入口:计算列表高度适配底部栏
onMounted(() => {
try {
const sys = uni.getSystemInfoSync();
const windowHeight = sys.windowHeight || 667;
// 留出顶部和底部空间
listHeight.value = windowHeight - 200;
} catch (e) {
// ignore
}
});
// 顶部安全区处理:参考 pages/index/user.vue 的实现
import { onShow } from '@dcloudio/uni-app';
const headerStyle = ref({});
function setHeaderSafeArea() {
try {
const sys = uni.getSystemInfoSync();
const statusBarHeightPx = sys?.statusBarHeight || 0;
const windowWidth = sys?.windowWidth || 375;
// 将 px 转为 rpx rpx = px / windowWidth * 750
const statusBarHeightRpx = Math.round((statusBarHeightPx / windowWidth) * 750);
headerStyle.value = {
paddingTop: statusBarHeightPx + 'px',
'--statusbar': statusBarHeightRpx + 'rpx'
};
} catch (e) {
// ignore
}
}
onMounted(() => {
setHeaderSafeArea();
// 计算列表高度适配底部栏
try {
const sys = uni.getSystemInfoSync();
const windowHeight = sys.windowHeight || 667;
// 留出顶部和底部空间
listHeight.value = windowHeight - 200;
} catch (e) {
// ignore
}
});
onShow(() => {
// 每次页面显示时重新计算(兼容热更或状态变化)
setHeaderSafeArea();
});
</script>
<style scoped>
.receive-page {
background: #fff;
min-height: 100vh;
position: relative;
}
.top-area {
position: relative;
/* 兼容刘海屏安全区处理 */
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
height: 220rpx;
}
.top-bg {
position: absolute;
left: 0;
right: 0;
top: 0;
/* 背景高度需要包含安全区高度 */
height: 270rpx;
height: calc(270rpx + constant(safe-area-inset-top));
height: calc(270rpx + env(safe-area-inset-top));
height: calc(270rpx + var(--statusbar, 0rpx));
background: #c292ee;
border-bottom-left-radius: 12rpx;
border-bottom-right-radius: 12rpx;
z-index: 0;
}
.top-inner {
position: absolute;
left: 0;
right: 0;
top: calc(var(--statusbar, 0rpx) + 30rpx);
z-index: 1;
padding: 0 30rpx;
display: flex;
flex-direction: column;
}
.user-info {
display: flex;
flex-direction: row;
align-items: center;
}
.user-avatar {
width: 110rpx;
height: 110rpx;
border-radius: 55rpx;
border: 4rpx solid rgba(255,255,255,0.6);
}
.user-meta {
margin-left: 20rpx;
}
.user-name {
font-size: 32rpx;
color: #fff;
font-weight: 700;
}
.user-status {
margin-top: 8rpx;
color: rgba(255,255,255,0.9);
font-size: 26rpx;
}
.tabs {
margin-top: 18rpx;
display: flex;
flex-direction: row;
gap: 20rpx;
}
.tab {
padding: 10rpx 20rpx;
background: rgba(255,255,255,0.12);
border-radius: 40rpx;
color: #fff;
display: flex;
align-items: center;
}
.tab.active {
background: #fff;
color: #6b3aa6;
}
.tab .count {
margin-left: 8rpx;
}
.order-list {
padding: 20rpx;
padding-right: 20rpx;
box-sizing: border-box;
background: #f7f7f7;
}
.order-card {
background: #fff;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 18rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
overflow: hidden;
box-sizing: border-box;
max-width: 100%;
}
.order-header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin-bottom: 12rpx;
}
.order-badge {
width: 54rpx;
height: 54rpx;
border-radius: 27rpx;
background: #e6f7ff;
color: #1890ff;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
}
.order-title {
flex: 1;
margin-left: 12rpx;
}
.shop-name {
font-size: 28rpx;
font-weight: 700;
}
.order-id {
color: #999;
margin-left: 8rpx;
}
.order-status {
color: #ff7a45;
}
.order-info {
margin-top: 8rpx;
}
.address-row {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 10rpx;
}
.icon {
width: 38rpx;
height: 38rpx;
border-radius: 19rpx;
background: #f2f2f2;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10rpx;
font-weight: 700;
}
.icon.pickup { background: #87d6ff; color: #fff; }
.icon.deliver { background: #ffd591; color: #fff; }
.address-content { flex: 1; min-width: 0; }
.address-title {
display: block;
font-size: 26rpx;
font-weight: 600;
/* 支持长地址换行,防止撑开布局 */
white-space: normal;
word-break: break-word;
}
.address-sub { display: block; font-size: 22rpx; color: #888; margin-top: 6rpx; }
.nav-icon { color: #1e9fff; padding: 6rpx 10rpx; }
.order-note { background: #f6f6f6; padding: 12rpx; border-radius: 8rpx; margin-top: 12rpx; color: #666; }
.order-actions {
display: flex;
flex-direction: row;
margin-top: 12rpx;
gap: 12rpx;
}
.contact {
flex: 1;
background: #fff;
border: 1rpx solid #ddd;
padding: 14rpx;
text-align: center;
border-radius: 8rpx;
color: #333;
}
.confirm {
flex: 2;
background: #1e9fff;
padding: 14rpx;
text-align: center;
border-radius: 8rpx;
color: #fff;
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 110rpx;
background: rgba(255,255,255,0.98);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
border-top: 1rpx solid #eee;
}
.batch-item {
background: #fff;
padding: 14rpx 20rpx;
border-radius: 40rpx;
border: 1rpx solid #ddd;
}
</style>

39
pages/index/login.vue Normal file
View File

@@ -0,0 +1,39 @@
<!-- 微信公众号的登录回调页 -->
<template>
<!-- 空登陆页 -->
<view />
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
onLoad(async (options) => {
// #ifdef H5
// 将 search 参数赋值到 options 中,方便下面解析
new URLSearchParams(location.search).forEach((value, key) => {
options[key] = value;
});
// 执行登录 or 绑定,注意需要 await 绑定
const event = options.event;
const code = options.code;
const state = options.state;
if (event === 'login') { // 场景一:登录
await sheep.$platform.useProvider().login(code, state);
} else if (event === 'bind') { // 场景二:绑定
await sheep.$platform.useProvider().bind(code, state);
}
// 检测 H5 登录回调
let returnUrl = uni.getStorageSync('returnUrl');
if (returnUrl) {
uni.removeStorage({key:'returnUrl'});
location.replace(returnUrl);
} else {
uni.switchTab({
url: '/',
});
}
// #endif
});
</script>

463
pages/index/user.vue Normal file
View File

@@ -0,0 +1,463 @@
<template>
<view class="page">
<!-- header -->
<view class="header-wrap" :style="headerStyle">
<view class="header-bg"></view>
<view class="header-inner">
<image class="avatar" :src="user.avatar || defautAvatar"></image>
<view class="user-meta">
<view class="user-name">{{ user.nickName || '姓名(账号)' }}</view>
<view class="user-status" @click="handleStatusToggle">
{{ user.isOnline ? '在线' : '离线' }}<uni-icons style="margin-left:10rpx;" type="right" size="13" color="#fff"></uni-icons>
</view>
</view>
</view>
</view>
<!-- stats card -->
<view class="stats-card">
<view class="stats-row">
<view class="stats-item">
<text class="stats-title">今日预计收入</text>
<text class="stats-value"> {{ formatMoney(todayIncome) }} </text>
<view class="stats-link" @click="openAccount">
我的账户 <uni-icons type="right" size="13"></uni-icons>
</view>
</view>
<view class="stats-item">
<text class="stats-title">今日完成单量</text>
<text class="stats-value"> {{ todayOrders }} </text>
<view class="stats-link" @click="openOrders">
订单统计 <uni-icons type="right" size="13"></uni-icons>
</view>
</view>
</view>
</view>
<!-- shortcuts -->
<view class="shortcuts">
<view class="shortcut" @click="openAttendance">
<image class="shortcut-icon" src="/static/img/order1.png" mode="aspectFit" />
<text class="shortcut-text">考勤排班</text>
</view>
<view class="shortcut" @click="openSalary">
<image class="shortcut-icon" src="/static/img/order2.png" mode="aspectFit" />
<text class="shortcut-text">薪资助手</text>
</view>
<view class="shortcut" @click="openSetting">
<!-- <image class="shortcut-icon" src="/static/img/edit.png" mode="aspectFit" /> -->
<view class="shortcut-icon">
<uni-icons type="gear" size="43"></uni-icons>
</view>
<text class="shortcut-text">设置</text>
</view>
</view>
</view>
<s-auth-modal />
<su-popup type="center" :show="showStatusPopup" round="14" :showClose="false">
<view class="modal-box">
<view class="modal-body">
<text class="modal-title">{{ modalTitle }}</text>
<text v-if="modalMsg" class="modal-msg">{{ modalMsg }}</text>
</view>
<view class="modal-footer">
<view class="modal-btn cancel" @click="cancelConfirm">取消</view>
<view class="modal-btn confirm" @click="confirmAction">确认</view>
</view>
</view>
</su-popup>
</template>
<script setup>
import {
computed,
ref
} from 'vue';
import {
onShow,
onPageScroll,
onPullDownRefresh
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
// 现有 store / 模板数据
const template = computed(() => sheep.$store('app').template.user);
const isLogin = computed(() => sheep.$store('user').isLogin);
const user = ref({});
const todayIncome = ref(0);
const todayOrders = ref(0);
const showBind = ref(false);
// 动态 header 内联样式,用于兼容不同平台的状态栏高度
const headerStyle = ref({});
const defautAvatar =
'https://huichibao.oss-cn-guangzhou.aliyuncs.com/1/material/348b8223-8d03-46aa-8836-6757e8beebd2.png';
// 格式化金额显示
function formatMoney(val) {
if (val == null) return '0';
return (Number(val) || 0).toFixed(1);
}
// 微信小程序的“手机号快速验证”
const getPhoneNumber = async (e) => {
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
sheep.$helper.toast('快捷登录失败');
return;
}
let result = await sheep.$platform.useProvider().mobileLogin(e.detail);
if (result) {
showBind.value = false;
}
};
// 页面显示时拉取用户信息并填充统计数据(从 store 获取或使用占位)
onShow(async () => {
const data = await sheep.$store('user').getInfo();
if (data) {
user.value = data;
// 兼容后端字段名,优先使用 data.todayIncome / data.income / placeholder
todayIncome.value = data.todayIncome ?? data.income ?? 137.9;
todayOrders.value = data.todayOrders ?? data.orders ?? 39;
if (data?.status == 1) {
console.log("清空缓存");
uni.clearStorageSync();
}
}
// 兼容处理:读取原生状态栏高度并设置 header 的 padding-toppx与 CSS 变量 --statusbarrpx
try {
const sys = uni.getSystemInfoSync();
const statusBarHeightPx = sys?.statusBarHeight || 0;
const windowWidth = sys?.windowWidth || 375;
// 将 px 转为 rpx rpx = px / windowWidth * 750
const statusBarHeightRpx = Math.round((statusBarHeightPx / windowWidth) * 750);
headerStyle.value = {
paddingTop: statusBarHeightPx + 'px',
'--statusbar': statusBarHeightRpx + 'rpx'
};
} catch (e) {
// ignore
}
});
// 确认弹框状态(上线/下线/禁止)
const showStatusPopup = ref(false);
const confirmType = ref(''); // 'online' | 'offline' | 'forbidden'
const modalTitle = ref('');
const modalMsg = ref('');
// 判断用户是否被禁止接单(兼容多种字段)
function isUserForbidden() {
const u = user.value || {};
return !!(u.forbidden || u.isForbidden || u.forbid || u.forbidReceive || u.disableReceive || u.receive === false);
}
// 点击状态:根据当前状态弹不同的确认框
function handleStatusToggle() {
if (user.value.isOnline) {
confirmType.value = 'offline';
modalTitle.value = '确认下线?';
modalMsg.value = '下线需平台进行核准\n此时正常接单请留意核准信息';
showStatusPopup.value = true;
return;
}
// 如果被禁止接单
if (isUserForbidden()) {
confirmType.value = 'forbidden';
modalTitle.value = '您处于禁止接单状态';
modalMsg.value = '暂无法上线上线';
showStatusPopup.value = true;
return;
}
// 普通从离线 -> 上线
confirmType.value = 'online';
modalTitle.value = '确认上线?';
modalMsg.value = '';
showStatusPopup.value = true;
}
function cancelConfirm() {
showStatusPopup.value = false;
}
async function confirmAction() {
const type = confirmType.value;
showStatusPopup.value = false;
if (type === 'online') {
// TODO: 调用后端接口变更上线状态
user.value.isOnline = true;
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已上线');
} else if (type === 'offline') {
user.value.isOnline = false;
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('已下线');
} else if (type === 'forbidden') {
// 仅展示信息,无操作
sheep.$helper && sheep.$helper.toast && sheep.$helper.toast('无法上线(禁止接单)');
}
// 可在此处调用 store 或 API 同步服务端状态,例如:
// await sheep.$store('user').setOnline(user.value.isOnline);
}
onPullDownRefresh(() => {
sheep.$store('user').updateUserData();
setTimeout(function() {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
// 跳转/交互方法(保留路由调用位置,用户可按需实现)
function goBack() {
uni.navigateBack();
}
function openAccount() {
uni.navigateTo({
url: '/pages/public/webview?type=account'
});
}
function openOrders() {
uni.navigateTo({
url: '/pages/index/order-list'
});
}
function openAttendance() {
uni.navigateTo({
url: '/pages/public/faq'
});
}
function openSalary() {
uni.navigateTo({
url: '/pages/public/richtext'
});
}
function openSetting() {
uni.navigateTo({
url: '/pages/public/setting'
});
}
</script>
<style scoped>
.page {
background: #ffffff;
min-height: 100vh;
}
/* header */
.header-wrap {
position: relative;
/* 适配刘海屏安全区:优先使用 constant/env兼容小程序与 iOS/Android 安全区 */
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
.header-bg {
/* 背景放置为绝对定位以覆盖安全区(兼容 env/constant 回退与 JS 动态 --statusbar */
position: absolute;
top: 0;
left: 0;
right: 0;
/* 背景高度需要包含安全区高度,优先使用 env/constant最后一行为回退值 */
height: 250rpx;
height: calc(250rpx + constant(safe-area-inset-top));
height: calc(250rpx + env(safe-area-inset-top));
/* JS 动态变量回退(当 env/constant 不可用时,使用 --statusbar单位 rpx */
height: calc(250rpx + var(--statusbar, 0rpx));
background: #9ad6f0;
/* 浅蓝 */
border-bottom-left-radius: 24rpx;
border-bottom-right-radius: 24rpx;
z-index: 0;
}
.header-inner {
position: absolute;
left: 32rpx;
/* 使用 CSS 变量保证当我们通过 JS 设置 --statusbar 时,内容会相对下移(单位 rpx */
top: calc(var(--statusbar, 0rpx) + 40rpx);
z-index: 1;
flex-direction: row;
display: flex;
align-items: center;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
border: 4rpx solid rgba(255, 255, 255, 0.6);
}
.user-meta {
margin-left: 20rpx;
}
.user-name {
font-size: 30rpx;
color: #fff;
font-weight: 600;
}
.user-status {
margin-top: 8rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.9);
}
.back {
position: absolute;
left: 18rpx;
top: calc(var(--statusbar, 0rpx) + 12rpx);
z-index: 2;
color: #fff;
font-size: 36rpx;
}
/* stats card */
.stats-card {
padding: 0 24rpx;
margin-top: 190rpx;
position: relative;
z-index: 3;
}
.stats-row {
background: #f6c98b;
/* 浅橙色 */
border-radius: 20rpx;
padding: 30rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.stats-item {
width: 48%;
}
.stats-title {
font-size: 24rpx;
color: #5b4a32;
}
.stats-value {
display: block;
margin-top: 12rpx;
font-size: 42rpx;
color: #222;
font-weight: 700;
}
.stats-link {
display: block;
margin-top: 12rpx;
font-size: 24rpx;
color: #7a5a3a;
}
/* shortcuts */
.shortcuts {
margin-top: 30rpx;
padding: 30rpx 40rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
position: relative;
z-index: 3;
}
.shortcut {
flex: 1;
align-items: center;
display: flex;
flex-direction: column;
}
.shortcut-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 12rpx;
}
.shortcut-text {
font-size: 24rpx;
color: #333;
}
/* popup 原有样式 */
.popup {
padding: 80rpx 0 50rpx;
}
.tip-text {
margin-bottom: 30rpx;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 44rpx;
text-align: center;
}
.bind-btn {
width: 630rpx;
height: 96rpx;
font-weight: 400;
font-size: 28rpx;
color: #FFFFFF;
line-height: 96rpx;
text-align: center;
font-style: normal;
background: #00B85B;
border-radius: 64rpx 64rpx 64rpx 64rpx;
}
/* 确认弹框样式su-popup 内部内容) */
.modal-box {
width: 640rpx;
background: #fff;
border-radius: 14rpx;
overflow: hidden;
}
.modal-body {
padding: 40rpx 30rpx;
text-align: center;
}
.modal-title {
display: block;
font-size: 30rpx;
color: #333;
margin-bottom: 10rpx;
}
.modal-msg {
display: block;
font-size: 24rpx;
color: #999;
line-height: 34rpx;
white-space: pre-line;
}
.modal-footer {
display: flex;
flex-direction: row;
border-top: 1rpx solid #eee;
}
.modal-btn {
flex: 1;
padding: 26rpx 0;
text-align: center;
font-size: 28rpx;
}
.modal-btn.cancel {
color: #666;
border-right: 1rpx solid #eee;
}
.modal-btn.confirm {
color: #1e9fff;
}
</style>

60
pages/public/error.vue Normal file
View File

@@ -0,0 +1,60 @@
<!-- 错误界面 -->
<template>
<view class="error-page">
<s-empty
v-if="errCode === 'NetworkError'"
icon="/static/internet-empty.png"
text="网络连接失败"
showAction
actionText="重新连接"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
<s-empty
v-else-if="errCode === 'TemplateError'"
icon="/static/internet-empty.png"
text="未找到模板"
showAction
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
<s-empty
v-else-if="errCode !== ''"
icon="/static/internet-empty.png"
:text="errMsg"
showAction
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import { ShoproInit } from '@/sheep';
const errCode = ref('');
const errMsg = ref('');
onLoad((options) => {
errCode.value = options.errCode;
errMsg.value = options.errMsg;
});
// 重新连接
async function onReconnect() {
uni.reLaunch({
url: '/pages/index/index',
});
await ShoproInit();
}
</script>
<style lang="scss" scoped>
.error-page {
width: 100%;
}
</style>

118
pages/public/faq.vue Normal file
View File

@@ -0,0 +1,118 @@
<!-- FAQ 常见问题 -->
<template>
<s-layout class="set-wrap" title="常见问题" :bgStyle="{ color: '#FFF' }">
<uni-collapse>
<uni-collapse-item v-for="(item, index) in state.list" :key="item">
<template v-slot:title>
<view class="ss-flex ss-col-center header">
<view class="ss-m-l-20 ss-m-r-20 icon">
<view class="rectangle">
<view class="num ss-flex ss-row-center ss-col-center">
{{ index + 1 < 10 ? '0' + (index + 1) : index + 1 }}
</view>
</view>
<view class="triangle"> </view>
</view>
<view class="title ss-m-t-36 ss-m-b-36">
{{ item.title }}
</view>
</view>
</template>
<view class="content ss-p-l-78 ss-p-r-40 ss-p-b-50 ss-p-t-20">
<text class="text">{{ item.content }}</text>
</view>
</uni-collapse-item>
</uni-collapse>
<s-empty
v-if="state.list.length === 0 && !state.loading"
text="暂无常见问题"
icon="/static/collect-empty.png"
/>
</s-layout>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import sheep from '@/sheep';
const state = reactive({
list: [],
loading: true,
});
async function getFaqList() {
const { error, data } = await sheep.$api.data.faq();
if (error === 0) {
state.list = data;
state.loading = false;
}
}
onLoad(() => {
// TODO 芋艿:【文章】目前简单做,使用营销文章,作为 faq
if (true) {
sheep.$router.go('/pages/public/richtext', {
title: '常见问题',
})
return;
}
getFaqList();
});
</script>
<style lang="scss" scoped>
.header {
.title {
font-size: 28rpx;
font-weight: 500;
color: #333333;
line-height: 30rpx;
max-width: 688rpx;
}
.icon {
position: relative;
width: 40rpx;
height: 40rpx;
.rectangle {
position: absolute;
left: 0;
top: 0;
width: 40rpx;
height: 36rpx;
background: var(--ui-BG-Main);
border-radius: 4px;
.num {
width: 100%;
height: 100%;
font-size: 24rpx;
font-weight: 500;
color: var(--ui-BG);
line-height: 32rpx;
}
}
.triangle {
width: 0;
height: 0;
border-left: 4rpx solid transparent;
border-right: 4rpx solid transparent;
border-top: 8rpx solid var(--ui-BG-Main);
position: absolute;
left: 16rpx;
bottom: -4rpx;
}
}
}
.content {
border-bottom: 1rpx solid #dfdfdf;
.text {
font-size: 26rpx;
color: #666666;
}
}
</style>

54
pages/public/richtext.vue Normal file
View File

@@ -0,0 +1,54 @@
<!-- 文章展示 -->
<template>
<s-layout class="set-wrap" :title="state.title" :bgStyle="{ color: '#FFF' }">
<view class="ss-p-30">
<mp-html class="richtext" :content="state.content" />
</view>
</s-layout>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import ArticleApi from '@/sheep/api/promotion/article';
const state = reactive({
title: '',
content: '',
});
async function getRichTextContent(id, title) {
const { code, data } = await ArticleApi.getArticle(id, title);
if (code !== 0) {
return;
}
state.content = data.content;
// 标题不一致时,修改标题
if (state.title !== data.title) {
state.title = data.title;
uni.setNavigationBarTitle({
title: state.title,
});
}
}
onLoad((options) => {
if (options.title) {
state.title = options.title;
uni.setNavigationBarTitle({
title: state.title,
});
}
getRichTextContent(options.id, options.title);
});
</script>
<style lang="scss" scoped>
.set-title {
margin: 0 30rpx;
}
.richtext {
}
</style>

242
pages/public/setting.vue Normal file
View File

@@ -0,0 +1,242 @@
<template>
<s-layout class="set-wrap" title="系统设置" :bgStyle="{ color: '#fff' }">
<view class="header-box ss-flex-col ss-row-center ss-col-center">
<image
class="logo-img ss-m-b-46"
:src="sheep.$url.cdn(appInfo.logo)"
mode="aspectFit"
></image>
<view class="name ss-m-b-24">{{ appInfo.name }}</view>
</view>
<view class="container-list">
<uni-list :border="false">
<!-- <uni-list-item
title="当前版本"
:rightText="appInfo.version"
showArrow
clickable
:border="false"
class="list-border"
@tap="onCheckUpdate"
/>
<uni-list-item
title="本地缓存"
:rightText="storageSize"
showArrow
:border="false"
class="list-border"
/>
<uni-list-item
title="关于我们"
showArrow
clickable
:border="false"
class="list-border"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '关于我们'
})
"
/> -->
<!-- 为了过审 只有 iOS-App 有注销账号功能 -->
<uni-list-item
v-if="isLogin && sheep.$platform.os === 'ios' && sheep.$platform.name === 'App'"
title="注销账号"
rightText=""
showArrow
clickable
:border="false"
class="list-border"
@click="onLogoff"
/>
</uni-list>
</view>
<view class="set-footer ss-flex-col ss-row-center ss-col-center">
<view class="agreement-box ss-flex ss-col-center ss-m-b-40">
<view class="ss-flex ss-col-center ss-m-b-10">
<!-- <view
class="tcp-text"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '用户协议'
})
"
>
用户协议
</view>
<view class="agreement-text"></view> -->
<view
class="tcp-text"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '隐私协议'
})
"
>
隐私协议
</view>
</view>
</view>
<!-- <view class="copyright-text ss-m-b-10">{{ appInfo.copyright }}</view> -->
<!-- <view class="copyright-text">{{ appInfo.copytime }}</view> -->
</view>
<su-fixed bottom placeholder>
<view class="ss-p-x-20 ss-p-b-40">
<button
class="loginout-btn ss-reset-button ui-BG-Main ui-Shadow-Main"
@tap="onLogout"
v-if="isLogin"
>
退出登录
</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { computed, reactive } from 'vue';
import AuthUtil from '@/sheep/api/member/auth';
const appInfo = computed(() => sheep.$store('app').info);
const isLogin = computed(() => sheep.$store('user').isLogin);
const storageSize = uni.getStorageInfoSync().currentSize + 'Kb';
const state = reactive({
showModal: false,
});
function onCheckUpdate() {
sheep.$platform.checkUpdate();
// 小程序初始化时已检查更新
// H5实时更新无需检查
// App 1.跳转应用市场更新 2.手动热更新 3.整包更新
}
// 注销账号
function onLogoff() {
uni.showModal({
title: '提示',
content: '确认注销账号?',
success: async function (res) {
if (!res.confirm) {
return;
}
const { code } = await AuthUtil.logout();
if (code !== 0) {
return;
}
sheep.$store('user').logout();
sheep.$router.go('/pages/index/user');
},
});
}
// 退出账号
function onLogout() {
uni.showModal({
title: '提示',
content: '确认退出账号?',
success: async function (res) {
if (!res.confirm) {
return;
}
const { code } = await AuthUtil.logout();
if (code !== 0) {
return;
}
try {
uni.clearStorageSync();
console.log('缓存清空成功');
} catch (e) {
console.log('缓存清空失败', e);
}
sheep.$store('user').logout();
sheep.$router.go('/pages/index/user');
},
});
}
</script>
<style lang="scss" scoped>
.container-list {
width: 100%;
}
.set-title {
margin: 0 30rpx;
}
.header-box {
padding: 100rpx 0;
.logo-img {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
}
.name {
font-size: 42rpx;
font-weight: 400;
color: $dark-3;
}
.version {
font-size: 32rpx;
font-weight: 500;
line-height: 32rpx;
color: $gray-b;
}
}
.set-footer {
margin: 100rpx 0 0 0;
.copyright-text {
font-size: 22rpx;
font-weight: 500;
color: $gray-c;
line-height: 30rpx;
}
.agreement-box {
font-size: 26rpx;
font-weight: 500;
.tcp-text {
color: var(--ui-BG-Main);
}
.agreement-text {
color: $dark-9;
}
}
}
.loginout-btn {
width: 100%;
height: 80rpx;
border-radius: 40rpx;
font-size: 30rpx;
}
.list-border {
font-size: 28rpx;
font-weight: 400;
color: #333333;
border-bottom: 2rpx solid #eeeeee;
}
:deep(.uni-list-item__content-title) {
font-size: 28rpx;
font-weight: 500;
color: #333;
}
:deep(.uni-list-item__extra-text) {
color: #bbbbbb;
font-size: 28rpx;
}
</style>

18
pages/public/webview.vue Normal file
View File

@@ -0,0 +1,18 @@
<!-- 网页加载 -->
<template>
<view>
<web-view :src="url" />
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
const url = ref('');
onLoad((options) => {
url.value = decodeURIComponent(options.url);
});
</script>
<style lang="scss" scoped></style>

470
pages/user/info.vue Normal file
View File

@@ -0,0 +1,470 @@
<!-- 用户信息 -->
<template>
<s-layout title="用户信息" class="set-userinfo-wrap">
<uni-forms
:model="state.model"
:rules="state.rules"
labelPosition="left"
border
class="form-box"
>
<!-- 头像 -->
<view class="ss-flex ss-row-center ss-col-center ss-p-t-60 ss-p-b-0 bg-white">
<view class="header-box-content">
<su-image
class="content-img"
isPreview
:current="0"
:src="state.model?.avatar"
:height="160"
:width="160"
:radius="80"
mode="scaleToFill"
/>
<view class="avatar-action">
<!-- #ifdef MP -->
<button
class="ss-reset-button avatar-action-btn"
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
>
修改
</button>
<!-- #endif -->
<!-- #ifndef MP -->
<button class="ss-reset-button avatar-action-btn" @tap="onChangeAvatar">修改</button>
<!-- #endif -->
</view>
</view>
</view>
<view class="bg-white ss-p-x-30">
<!-- 昵称 + 性别 -->
<uni-forms-item name="nickname" label="昵称">
<uni-easyinput
v-model="state.model.nickname"
type="nickname"
placeholder="设置昵称"
:inputBorder="false"
:placeholderStyle="placeholderStyle"
/>
</uni-forms-item>
<uni-forms-item name="sex" label="性别">
<view class="ss-flex ss-col-center ss-h-100">
<radio-group @change="onChangeGender" class="ss-flex ss-col-center">
<label class="radio" v-for="item in sexRadioMap" :key="item.value">
<view class="ss-flex ss-col-center ss-m-r-32">
<radio
:value="item.value"
color="var(--ui-BG-Main)"
style="transform: scale(0.8)"
:checked="parseInt(item.value) === state.model?.sex"
/>
<view class="gender-name">{{ item.name }}</view>
</view>
</label>
</radio-group>
</view>
</uni-forms-item>
<uni-forms-item name="mobile" label="手机号" @tap="onChangeMobile">
<uni-easyinput
v-model="userInfo.mobile"
placeholder="请绑定手机号"
:inputBorder="false"
disabled
:styles="{ disableColor: '#fff' }"
:placeholderStyle="placeholderStyle"
:clearable="false"
>
<template v-slot:right>
<view class="ss-flex ss-col-center">
<su-radio v-if="userInfo.verification?.mobile" :modelValue="true" />
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx"></text>
</button>
</view>
</template>
</uni-easyinput>
</uni-forms-item>
<!-- <uni-forms-item name="password" label="登录密码" @tap="onSetPassword">
<uni-easyinput
v-model="userInfo.password"
placeholder="点击修改登录密码"
:inputBorder="false"
:styles="{ disableColor: '#fff' }"
disabled
placeholderStyle="color:#BBBBBB;font-size:28rpx;line-height:normal"
:clearable="false"
>
<template v-slot:right>
<view class="ss-flex ss-col-center">
<su-radio
class="ss-flex"
v-if="userInfo.verification?.password"
:modelValue="true"
/>
<button v-else class="ss-reset-button ss-flex ss-col-center ss-row-center">
<text class="_icon-forward" style="color: #bbbbbb; font-size: 26rpx" />
</button>
</view>
</template>
</uni-easyinput>
</uni-forms-item> -->
</view>
<!-- <view class="bg-white ss-m-t-14">
<uni-list>
<uni-list-item
clickable
@tap="sheep.$router.go('/pages/user/address/list')"
title="地址管理"
showArrow
:border="false"
class="list-border"
/>
</uni-list>
</view> -->
</uni-forms>
<!-- 当前社交平台的绑定关系只处理 wechat 微信场景 -->
<!-- <view v-if="sheep.$platform.name !== 'H5'">
<view class="title-box ss-p-l-30">第三方账号绑定</view>
<view class="account-list ss-flex ss-row-between">
<view v-if="'WechatOfficialAccount' === sheep.$platform.name" class="ss-flex ss-col-center">
<image
class="list-img"
:src="sheep.$url.static('/static/img/shop/platform/WechatOfficialAccount.png')"
/>
<text class="list-name">微信公众号</text>
</view>
<view v-if="'WechatMiniProgram' === sheep.$platform.name" class="ss-flex ss-col-center">
<image
class="list-img"
:src="sheep.$url.static('/static/img/shop/platform/WechatMiniProgram.png')"
/>
<text class="list-name">微信小程序</text>
</view>
<view v-if="'App' === sheep.$platform.name" class="ss-flex ss-col-center">
<image
class="list-img"
:src="sheep.$url.static('/static/img/shop/platform/wechat.png')"
/>
<text class="list-name">微信开放平台</text>
</view>
<view class="ss-flex ss-col-center">
<view class="info ss-flex ss-col-center" v-if="state.thirdInfo">
<image class="avatar ss-m-r-20" :src="sheep.$url.cdn(state.thirdInfo.avatar)" />
<text class="name">{{ state.thirdInfo.nickname }}</text>
</view>
<view class="bind-box ss-m-l-20">
<button
v-if="state.thirdInfo.openid"
class="ss-reset-button relieve-btn"
@tap="unBindThirdOauth"
>
解绑
</button>
<button v-else class="ss-reset-button bind-btn" @tap="bindThirdOauth">绑定</button>
</view>
</view>
</view>
</view> -->
<su-fixed bottom placeholder bg="none">
<view class="footer-box ss-p-20">
<button class="ss-rest-button logout-btn ui-Shadow-Main" @tap="onSubmit">保存</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import { computed, reactive, onBeforeMount } from 'vue';
import sheep from '@/sheep';
import { clone } from 'lodash-es';
import { showAuthModal } from '@/sheep/hooks/useModal';
import FileApi from '@/sheep/api/infra/file';
import UserApi from '@/sheep/api/member/user';
const state = reactive({
model: {}, // 个人信息
rules: {},
thirdInfo: {}, // 社交用户的信息
});
const placeholderStyle = 'color:#BBBBBB;font-size:28rpx;line-height:normal';
const sexRadioMap = [
{
name: '男',
value: '1',
},
{
name: '女',
value: '2',
},
];
const userInfo = computed(() => sheep.$store('user').userInfo);
// 选择性别
function onChangeGender(e) {
state.model.sex = e.detail.value;
}
// 修改手机号
const onChangeMobile = () => {
showAuthModal('changeMobile');
};
// 选择微信的头像,进行上传
function onChooseAvatar(e) {
const tempUrl = e.detail.avatarUrl || '';
uploadAvatar(tempUrl);
}
// 手动选择头像,进行上传
function onChangeAvatar() {
uni.chooseImage({
success: async (chooseImageRes) => {
const tempUrl = chooseImageRes.tempFilePaths[0];
await uploadAvatar(tempUrl);
},
});
}
// 上传头像文件
async function uploadAvatar(tempUrl) {
if (!tempUrl) {
return;
}
let { data } = await FileApi.uploadFile(tempUrl);
state.model.avatar = data;
}
// 修改密码
function onSetPassword() {
showAuthModal('changePassword');
}
// 绑定第三方账号
async function bindThirdOauth() {
let result = await sheep.$platform.useProvider('wechat').bind();
if (result) {
await getUserInfo();
}
}
// 解绑第三方账号
function unBindThirdOauth() {
uni.showModal({
title: '解绑提醒',
content: '解绑后您将无法通过微信登录此账号',
cancelText: '再想想',
confirmText: '确定',
success: async function (res) {
if (!res.confirm) {
return;
}
const result = await sheep.$platform.useProvider('wechat').unbind(state.thirdInfo.openid);
if (result) {
await getUserInfo();
}
},
});
}
// 保存信息
async function onSubmit() {
const { code } = await UserApi.updateUser({
avatar: state.model.avatar,
nickname: state.model.nickname,
sex: state.model.sex,
});
if (code === 0) {
await getUserInfo();
}
}
// 获得用户信息
const getUserInfo = async () => {
// 个人信息
const userInfo = await sheep.$store('user').getInfo();
state.model = clone(userInfo);
// 获得社交用户的信息
if (sheep.$platform.name !== 'H5') {
const result = await sheep.$platform.useProvider('wechat').getInfo();
state.thirdInfo = result || {};
}
};
onBeforeMount(() => {
getUserInfo();
});
</script>
<style lang="scss" scoped>
:deep() {
.uni-file-picker {
border-radius: 50%;
}
.uni-file-picker__container {
margin: -14rpx -12rpx;
}
.file-picker__progress {
height: 0 !important;
}
.uni-list-item__content-title {
font-size: 28rpx !important;
color: #333333 !important;
line-height: normal !important;
}
.uni-icons {
font-size: 40rpx !important;
}
.is-disabled {
color: #333333;
}
}
:deep(.disabled) {
opacity: 1;
}
.gender-name {
font-size: 28rpx;
font-weight: 500;
line-height: normal;
color: #333333;
}
.title-box {
font-size: 28rpx;
font-weight: 500;
color: #666666;
line-height: 100rpx;
}
.logout-btn {
width: 710rpx;
height: 80rpx;
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
border-radius: 40rpx;
font-size: 30rpx;
font-weight: 500;
color: $white;
}
.radio-dark {
filter: grayscale(100%);
filter: gray;
opacity: 0.4;
}
.content-img {
border-radius: 50%;
}
.header-box-content {
position: relative;
width: 160rpx;
height: 160rpx;
overflow: hidden;
border-radius: 50%;
}
.avatar-action {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
z-index: 1;
width: 160rpx;
height: 46rpx;
background: rgba(#000000, 0.3);
.avatar-action-btn {
width: 160rpx;
height: 46rpx;
font-weight: 500;
font-size: 24rpx;
color: #ffffff;
}
}
// 绑定项
.account-list {
background-color: $white;
height: 100rpx;
padding: 0 20rpx;
.list-img {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.list-name {
font-size: 28rpx;
color: #333333;
}
.info {
.avatar {
width: 38rpx;
height: 38rpx;
border-radius: 50%;
overflow: hidden;
}
.name {
font-size: 28rpx;
font-weight: 400;
color: $dark-9;
}
}
.bind-box {
width: 100rpx;
height: 50rpx;
line-height: normal;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
.bind-btn {
width: 100%;
height: 100%;
border-radius: 25rpx;
background: #f4f4f4;
color: #999999;
}
.relieve-btn {
width: 100%;
height: 100%;
border-radius: 25rpx;
background: var(--ui-BG-Main-opacity-1);
color: var(--ui-BG-Main);
}
}
}
.list-border {
font-size: 28rpx;
font-weight: 400;
color: #333333;
border-bottom: 2rpx solid #eeeeee;
}
image {
width: 100%;
height: 100%;
}
</style>