liujie
23 小时以前 384bce80449b17651937429038c4370dbce60e7b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
<template>
    <view class="sub-account-page">
        <!-- 顶部筛选栏:等级筛选标签 + 搜索入口 -->
        <view class="filter-bar">
            <view class="level-tabs">
                <view
                    v-for="tab in levelTabs"
                    :key="tab.value"
                    class="level-tab"
                    :class="{ 'level-tab--active': activeLevel === tab.value }"
                    @tap="_handleLevelChange(tab.value)"
                >
                    {{ tab.label }}
                </view>
            </view>
            <view class="search-icon" @tap="_handleSearch"></view>
        </view>
 
        <!-- 子账号列表:无数据时展示空态 -->
        <scroll-view class="account-list" scroll-y>
            <view v-if="subAccountList.length === 0" class="empty-tip">
                <text class="empty-text">暂无子账号</text>
            </view>
 
            <view
                v-for="item in subAccountList"
                :key="item.id"
                class="account-item"
                @tap="_handleViewDetail(item)"
            >
                <!-- 头像占位:纯 CSS 绘制的人像剪影 -->
                <view class="avatar"></view>
 
                <view class="item-info">
                    <view class="item-top">
                        <text class="account-name">{{ item.name }}</text>
                        <view class="level-badge">{{ item.level }}</view>
                    </view>
                    <text class="account-phone">{{ item.phone }}</text>
                </view>
 
                <!-- 纯 CSS 右箭头,避免 > 被小程序模板转义 -->
                <view class="arrow-icon"></view>
            </view>
        </scroll-view>
 
        <!-- 底部新增账号按钮 -->
        <view class="bottom-bar">
            <view class="add-btn" @tap="_handleAddAccount">新增账号</view>
        </view>
    </view>
</template>
 
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getSubAccountList } from '@/api/index.js'
 
// ======================== 数据定义区域 ========================
 
// 等级筛选标签,value 为空表示「全部」
const levelTabs = ref([
    { label: '全部', value: '' },
    { label: 'L1', value: 'L1' },
    { label: 'L2', value: 'L2' },
    { label: 'L3', value: 'L3' }
])
 
// 当前选中的等级
const activeLevel = ref('')
 
// 子账号列表数据
const subAccountList = ref([])
 
// ======================== 方法定义区域 ========================
 
/**
 * 加载子账号列表
 * 后端接口就绪前以本地模拟数据兜底,保证页面可视
 */
const _loadSubAccountList = async () => {
    try {
        const { data } = await getSubAccountList({ level: activeLevel.value })
        subAccountList.value = (data && data.list) || []
    } catch (e) {
        subAccountList.value = _getMockList(activeLevel.value)
    }
}
 
/**
 * 按等级过滤模拟数据(私有工具方法)
 * @param {String} level 等级筛选值,空串表示全部
 */
const _getMockList = (level) => {
    const mockList = [
        { id: 1, name: '张三', level: 'L1', phone: '13612346666' },
        { id: 2, name: '李四', level: 'L1', phone: '13612346666' },
        { id: 3, name: '王五', level: 'L2', phone: '13612346666' },
        { id: 4, name: '赵六', level: 'L3', phone: '13612346666' }
    ]
    return level ? mockList.filter((item) => item.level === level) : mockList
}
 
/** 切换等级筛选 */
const _handleLevelChange = (level) => {
    if (activeLevel.value === level) return
    activeLevel.value = level
    _loadSubAccountList()
}
 
/** 搜索入口(搜索页待开发) */
const _handleSearch = () => {
    uni.showToast({ title: '搜索功能开发中', icon: 'none' })
}
 
/** 查看子账号详情 */
const _handleViewDetail = (item) => {
    uni.navigateTo({
        url: '/pages/sub-account/detail?id=' + item.id,
        fail: () => {
            uni.showToast({ title: '子账号详情开发中', icon: 'none' })
        }
    })
}
 
/** 新增子账号 */
const _handleAddAccount = () => {
    uni.navigateTo({
        url: '/pages/sub-account/add',
        fail: () => {
            uni.showToast({ title: '新增账号功能开发中', icon: 'none' })
        }
    })
}
 
onLoad(() => {
    _loadSubAccountList()
})
</script>
 
<style scoped lang="scss">
/* 页面最外层:纵向弹性布局,撑满整屏 */
.sub-account-page {
    display: flex;
    flex-direction: column;
    height: 100vh;
    background-color: #ffffff;
}
 
/* 顶部筛选栏 */
.filter-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 24rpx 28rpx;
    background-color: #ffffff;
}
 
.level-tabs {
    display: flex;
    align-items: center;
    gap: 16rpx;
}
 
/* 等级筛选标签:默认灰底,选中深蓝底白字 */
.level-tab {
    min-width: 96rpx;
    height: 56rpx;
    padding: 0 24rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #eef1f5;
    border-radius: 8rpx;
    font-size: 26rpx;
    color: #6b7280;
    box-sizing: border-box;
}
 
.level-tab--active {
    background-color: #0b3b68;
    color: #ffffff;
    font-weight: 600;
}
 
/* 搜索图标:纯 CSS 绘制的放大镜 */
.search-icon {
    position: relative;
    width: 44rpx;
    height: 44rpx;
}
 
.search-icon::before {
    content: '';
    position: absolute;
    top: 4rpx;
    left: 4rpx;
    width: 28rpx;
    height: 28rpx;
    border: 3rpx solid #1f2329;
    border-radius: 50%;
    box-sizing: border-box;
}
 
.search-icon::after {
    content: '';
    position: absolute;
    bottom: 6rpx;
    right: 4rpx;
    width: 14rpx;
    height: 3rpx;
    background-color: #1f2329;
    border-radius: 2rpx;
    transform: rotate(45deg);
}
 
/* 列表区域:占据筛选栏与底部按钮之间的剩余空间 */
.account-list {
    flex: 1;
    background-color: #ffffff;
}
 
/* 空态提示 */
.empty-tip {
    display: flex;
    justify-content: center;
    padding-top: 200rpx;
}
 
.empty-text {
    font-size: 28rpx;
    color: #9aa1ab;
}
 
/* 子账号列表项 */
.account-item {
    display: flex;
    align-items: center;
    padding: 28rpx;
    border-bottom: 1rpx solid #f0f2f5;
}
 
/* 头像占位:灰底圆角 + CSS 人像剪影 */
.avatar {
    position: relative;
    width: 88rpx;
    height: 88rpx;
    border-radius: 16rpx;
    background-color: #eceff3;
    overflow: hidden;
    flex-shrink: 0;
}
 
.avatar::before {
    /* 头部 */
    content: '';
    position: absolute;
    top: 16rpx;
    left: 50%;
    width: 30rpx;
    height: 30rpx;
    border-radius: 50%;
    background-color: #c7ccd6;
    transform: translateX(-50%);
}
 
.avatar::after {
    /* 身体 */
    content: '';
    position: absolute;
    bottom: 8rpx;
    left: 50%;
    width: 52rpx;
    height: 32rpx;
    border-radius: 26rpx 26rpx 0 0;
    background-color: #c7ccd6;
    transform: translateX(-50%);
}
 
/* 列表项文字信息 */
.item-info {
    flex: 1;
    margin-left: 24rpx;
    display: flex;
    flex-direction: column;
}
 
.item-top {
    display: flex;
    align-items: center;
    margin-bottom: 12rpx;
}
 
.account-name {
    font-size: 30rpx;
    font-weight: 600;
    color: #1f2329;
}
 
/* 等级胶囊标签 */
.level-badge {
    margin-left: 16rpx;
    padding: 2rpx 18rpx;
    background-color: #67b72c;
    color: #ffffff;
    font-size: 22rpx;
    font-weight: 700;
    border-radius: 6rpx;
    line-height: 1.4;
}
 
.account-phone {
    font-size: 26rpx;
    color: #8f959e;
}
 
/* 列表项右侧箭头 */
.arrow-icon {
    width: 14rpx;
    height: 14rpx;
    border-top: 3rpx solid #c0c4cc;
    border-right: 3rpx solid #c0c4cc;
    transform: rotate(45deg);
    margin-left: 16rpx;
    box-sizing: border-box;
    flex-shrink: 0;
}
 
/* 底部按钮区 */
.bottom-bar {
    padding: 20rpx 28rpx;
    padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
    padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
    background-color: #ffffff;
    border-top: 1rpx solid #f0f2f5;
}
 
.add-btn {
    height: 88rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #0b3b68;
    color: #ffffff;
    font-size: 30rpx;
    font-weight: 600;
    border-radius: 8rpx;
}
</style>