ソースを参照

Merge branch 'dev' of http://8.152.195.41:3000/alien/group_lawyer_app into dev

sunshibo 4 週間 前
コミット
ca1f93c76e

+ 12 - 0
api/login.js

@@ -57,3 +57,15 @@ export function getCodeImg() {
     timeout: 20000
   })
 }
+
+// 发送短信
+export function sendSmsCode(phone) {
+  return request({
+    url: '/ali/sendSms',
+    headers: {
+      isToken: false
+    },
+    method: 'get',
+    data: { phone }
+  })
+}

+ 25 - 0
api/setUserInfo.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+// 获取律师事务所列表
+export function getFirmList() {
+  return request({
+    url: '/lawyer/firm/getList',
+    method: 'get'
+  })
+}
+
+// 获取法律问题场景列表
+export function getLegalProblemScenarioList() {
+  return request({
+    url: '/lawyer/legalProblemScenar/getList',
+    method: 'get'
+  })
+}
+
+// 获取擅长领域列表
+export function getExpertiseAreaList() {
+  return request({
+    url: '/lawyer/expertiseArea/getList',
+    method: 'get'
+  })
+}

+ 1 - 1
components/barNavigasiHandap.vue

@@ -129,7 +129,7 @@ export default {
 	background-color: #F5F5F5;
 	padding: 16rpx 24rpx;
 	padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
-	z-index: 9999;
+	z-index: 98;
 	box-sizing: border-box;
 }
 

+ 2 - 1
config.js

@@ -1,7 +1,8 @@
 // 应用全局配置
 module.exports = {
-  baseUrl: 'https://vue.ruoyi.vip/prod-api',
+  // baseUrl: 'https://vue.ruoyi.vip/prod-api',
   // baseUrl: 'http://localhost:8080',
+  baseUrl: 'http://192.168.2.101:8899',
   // 应用信息
   appInfo: {
     // 应用名称

+ 7 - 1
pages.json

@@ -7,6 +7,12 @@
       "navigationBarBackgroundColor": "transparent"
     }
   }, {
+    "path": "pages/setUserInfo",
+    "style": {
+      "navigationBarTitleText": "设置用户信息",
+      "navigationStyle": "custom"
+    }
+  },{
     "path": "pages/register",
     "style": {
       "navigationBarTitleText": "注册",
@@ -113,4 +119,4 @@
     "navigationBarBackgroundColor": "#ffffff",
     "navigationStyle": "custom"
   }
-}
+}

+ 505 - 0
pages/indexOrder/components/orderFilter.vue

@@ -0,0 +1,505 @@
+<template>
+	<view>
+		<uni-popup ref="popup" type="bottom" :is-mask-click="true" @change="handlePopupChange">
+			<view class="filter-popup">
+				<!-- 标题栏 -->
+				<view class="filter-header">
+					<text class="filter-title">筛选</text>
+					<text class="filter-cancel" @click="handleCancel">取消</text>
+				</view>
+				
+				<!-- 日期范围输入 -->
+				<view class="date-range-section">
+					<view 
+						class="date-input" 
+						:class="{ 'active': activeDateType === 'start' }"
+						@click="selectDateType('start')"
+					>
+						<text class="date-label">起始日期</text>
+						<text class="date-value" :class="{ 'placeholder': !startDate }">
+							{{ startDate || '-年-月-日' }}
+						</text>
+						<view class="date-underline"></view>
+					</view>
+					<view 
+						class="date-input" 
+						:class="{ 'active': activeDateType === 'end' }"
+						@click="selectDateType('end')"
+					>
+						<text class="date-label">截止日期</text>
+						<text class="date-value" :class="{ 'placeholder': !endDate }">
+							{{ endDate || '-年-月-日' }}
+						</text>
+						<view class="date-underline"></view>
+					</view>
+				</view>
+				
+				<!-- 日期选择器 -->
+				<view class="date-picker-section">
+					<view class="picker-wrapper">
+						<picker-view 
+							class="date-picker-view" 
+							:value="pickerValue" 
+							@change="handlePickerChange"
+							:indicator-style="indicatorStyle"
+						>
+							<picker-view-column>
+								<view class="picker-item" v-for="(year, index) in years" :key="index">
+									<text>{{ year }}年</text>
+								</view>
+							</picker-view-column>
+							<picker-view-column>
+								<view class="picker-item" v-for="(month, index) in months" :key="index">
+									<text>{{ month }}月</text>
+								</view>
+							</picker-view-column>
+							<picker-view-column>
+								<view class="picker-item" v-for="(day, index) in days" :key="index">
+									<text>{{ day }}日</text>
+								</view>
+							</picker-view-column>
+						</picker-view>
+						<!-- 选中行指示器 -->
+						<view class="picker-indicator"></view>
+					</view>
+				</view>
+				
+				<!-- 底部按钮 -->
+				<view class="filter-footer">
+					<view class="btn-reset" @click="handleReset">重置</view>
+					<view class="btn-confirm" @click="handleConfirm">确定</view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+export default {
+	name: 'OrderNyaringProp',
+	data() {
+		const currentDate = new Date()
+		const currentYear = currentDate.getFullYear()
+		const currentMonth = currentDate.getMonth() + 1
+		const currentDay = currentDate.getDate()
+		
+		return {
+			activeDateType: 'start', // 'start' | 'end'
+			startDate: '',
+			endDate: '',
+			// 日期选择器的值 [年索引, 月索引, 日索引]
+			pickerValue: [0, 0, 0],
+			// 年份列表
+			years: [],
+			// 月份列表
+			months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
+			// 日期列表(动态生成)
+			days: [],
+			// 当前选中的日期
+			selectedYear: currentYear,
+			selectedMonth: currentMonth,
+			selectedDay: currentDay,
+			// 选择器指示器样式
+			indicatorStyle: `height: 50px; line-height: 50px;`,
+			show:false
+		}
+	},
+	mounted() {
+		this.initYears()
+		this.initDays()
+		this.initPickerValue()
+	},
+	methods: {
+		/**
+		 * 初始化年份列表(2022-2025)
+		 */
+		initYears() {
+			const years = []
+			for (let i = 2022; i <= 2025; i++) {
+				years.push(i)
+			}
+			this.years = years
+		},
+		
+		/**
+		 * 初始化日期列表
+		 */
+		initDays() {
+			const days = []
+			const daysInMonth = this.getDaysInMonth(this.selectedYear, this.selectedMonth)
+			for (let i = 1; i <= daysInMonth; i++) {
+				days.push(i)
+			}
+			this.days = days
+		},
+		open(){
+			
+		},
+		/**
+		 * 获取某年某月的天数
+		 */
+		getDaysInMonth(year, month) {
+			return new Date(year, month, 0).getDate()
+		},
+		
+		/**
+		 * 初始化选择器值
+		 */
+		initPickerValue() {
+			const currentDate = new Date()
+			const currentYear = currentDate.getFullYear()
+			const currentMonth = currentDate.getMonth() + 1
+			const currentDay = currentDate.getDate()
+			
+			// 如果已有选中的日期,使用选中的日期;否则使用当前日期
+			let year = currentYear
+			let month = currentMonth
+			let day = currentDay
+			
+			if (this.activeDateType === 'start' && this.startDate) {
+				const date = this.parseDate(this.startDate)
+				if (date) {
+					year = date.year
+					month = date.month
+					day = date.day
+				}
+			} else if (this.activeDateType === 'end' && this.endDate) {
+				const date = this.parseDate(this.endDate)
+				if (date) {
+					year = date.year
+					month = date.month
+					day = date.day
+				}
+			}
+			
+			this.selectedYear = year
+			this.selectedMonth = month
+			this.selectedDay = day
+			
+			// 先更新日期列表
+			this.updateDays()
+			
+			// 更新选择器索引
+			const yearIndex = this.years.indexOf(year)
+			const monthIndex = this.months.indexOf(month)
+			const dayIndex = this.days.indexOf(day)
+			
+			this.pickerValue = [
+				yearIndex >= 0 ? yearIndex : 0,
+				monthIndex >= 0 ? monthIndex : 0,
+				dayIndex >= 0 ? dayIndex : 0
+			]
+		},
+		
+		/**
+		 * 选择日期类型(起始日期或截止日期)
+		 */
+		selectDateType(type) {
+			if (this.activeDateType === type) return
+			this.activeDateType = type
+			// 延迟初始化,确保DOM更新
+			this.$nextTick(() => {
+				this.initPickerValue()
+			})
+		},
+		
+		/**
+		 * 处理选择器变化
+		 */
+		handlePickerChange(e) {
+			const [yearIndex, monthIndex, dayIndex] = e.detail.value
+			
+			this.selectedYear = this.years[yearIndex]
+			this.selectedMonth = this.months[monthIndex]
+			
+			// 更新日期列表
+			this.updateDays()
+			
+			// 确保选中的日期不超过当月最大天数
+			const maxDay = this.days.length
+			const newDayIndex = Math.min(dayIndex, maxDay - 1)
+			this.selectedDay = this.days[newDayIndex]
+			
+			// 更新选择器值
+			this.pickerValue = [yearIndex, monthIndex, newDayIndex]
+			
+			// 更新当前选中的日期显示
+			this.updateSelectedDate()
+		},
+		
+		/**
+		 * 更新日期列表
+		 */
+		updateDays() {
+			const daysInMonth = this.getDaysInMonth(this.selectedYear, this.selectedMonth)
+			const days = []
+			for (let i = 1; i <= daysInMonth; i++) {
+				days.push(i)
+			}
+			this.days = days
+			
+			// 如果当前选中的日期超过新月份的最大天数,调整为最大天数
+			if (this.selectedDay > daysInMonth) {
+				this.selectedDay = daysInMonth
+				const dayIndex = this.days.indexOf(this.selectedDay)
+				this.pickerValue[2] = dayIndex >= 0 ? dayIndex : 0
+			}
+		},
+		
+		/**
+		 * 更新选中的日期显示
+		 */
+		updateSelectedDate() {
+			const dateStr = `${this.selectedYear}年${this.selectedMonth}月${this.selectedDay}号`
+			if (this.activeDateType === 'start') {
+				this.startDate = dateStr
+			} else {
+				this.endDate = dateStr
+			}
+		},
+		
+		/**
+		 * 解析日期字符串
+		 */
+		parseDate(dateStr) {
+			// 格式:2024年10月9号
+			const match = dateStr.match(/(\d{4})年(\d{1,2})月(\d{1,2})号/)
+			if (match) {
+				return {
+					year: parseInt(match[1]),
+					month: parseInt(match[2]),
+					day: parseInt(match[3])
+				}
+			}
+			return null
+		},
+		
+		/**
+		 * 处理弹窗状态变化
+		 */
+		handlePopupChange(e) {
+			if (e.show) {
+				// 弹窗打开时,初始化选择器
+				this.initPickerValue()
+			}
+		},
+		
+		/**
+		 * 打开弹窗
+		 */
+		open() {
+			this.$refs.popup.open()
+		},
+		
+		/**
+		 * 关闭弹窗
+		 */
+		close() {
+			this.$refs.popup.close()
+		},
+		handleCancel() {
+			this.close()
+		},
+		
+		/**
+		 * 重置
+		 */
+		handleReset() {
+			this.startDate = ''
+			this.endDate = ''
+			this.activeDateType = 'start'
+			this.initPickerValue()
+		},
+		
+		/**
+		 * 确定
+		 */
+		handleConfirm() {
+			if(this.startDate && this.endDate){
+				this.$emit('confirmOrder', {
+					startDate: this.startDate,
+					endDate: this.endDate
+				})
+				this.close()
+			}else{
+				uni.showToast({
+					title:'请输入完整格式',
+					icon:'none'
+				})
+			}
+			
+		}
+	}
+}
+</script>
+
+<style scoped>
+.filter-popup {
+	background-color: #FFFFFF;
+	border-radius: 24rpx 24rpx 0 0;
+	box-shadow: 0 -10rpx 40rpx rgba(0, 0, 0, 0.06);
+	padding-bottom: env(safe-area-inset-bottom);
+	min-height: 60vh;
+	display: flex;
+	flex-direction: column;
+}
+
+/* 标题栏 */
+.filter-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding: 32rpx 36rpx 24rpx;
+	border-bottom: 1px solid #F2F2F2;
+}
+
+.filter-title {
+	font-size: 34rpx;
+	font-weight: 600;
+	color: #323232;
+	flex: 1;
+	text-align: center;
+}
+
+.filter-cancel {
+	font-size: 28rpx;
+	color: #C0C0C0;
+	padding: 8rpx 16rpx;
+}
+
+/* 日期范围输入 */
+.date-range-section {
+	display: flex;
+	justify-content: space-around;
+	padding: 16px 26px 8px;
+	/* gap: 49px; */
+	border-bottom: 1px solid #F2F2F2;
+}
+
+.date-input {
+	display: flex;
+	flex-direction: column;
+	gap: 6px;
+	padding: 6px 0 13px;
+	align-items: center;
+	position: relative;
+	justify-content: center;
+}
+
+.date-label {
+	font-size: 26rpx;
+	color: #999999;
+}
+
+.date-value {
+	font-size: 30rpx;
+	color: #3475E7;
+	line-height: 38rpx;
+}
+
+.date-value.placeholder {
+	color: #999999;
+}
+
+.date-input.active .date-value {
+	color: #3475E7;
+	font-weight: 500;
+}
+
+.date-underline {
+	position: absolute;
+	bottom: 0;
+	width: 57rpx;
+	height: 8rpx;
+	background-color: transparent;
+	border-radius: 4rpx;
+	transition: background-color 0.2s;
+}
+
+.date-input.active .date-underline {
+	background-color: #3475E7;
+}
+
+/* 日期选择器 */
+.date-picker-section {
+	flex: 1;
+	padding: 8rpx 40rpx 0;
+	position: relative;
+	min-height: 400rpx;
+}
+
+.picker-wrapper {
+	position: relative;
+	height: 420rpx;
+	width: 100%;
+}
+
+.date-picker-view {
+	height: 100%;
+	width: 100%;
+	position: relative;
+	z-index: 2;
+}
+
+.picker-item {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	height: 50px;
+	font-size: 30rpx;
+	color: #323232;
+}
+
+/* 选中行指示器 - 模拟选中效果 */
+.picker-indicator {
+	position: absolute;
+	top: 50%;
+	left: 0;
+	right: 0;
+	height: 50px;
+	transform: translateY(-50%);
+	background-color: rgba(52, 117, 231, 0.14);
+	pointer-events: none;
+	border-radius: 24rpx;
+	z-index: 1;
+}
+
+/* 选中项的样式 */
+.date-picker-section ::v-deep .uni-picker-view-column-item-selected {
+	color: #3475E7 !important;
+	font-weight: 500;
+}
+
+/* 底部按钮 */
+.filter-footer {
+	display: flex;
+	padding: 30rpx 36rpx 40rpx;
+	gap: 24rpx;
+	border-top: 1px solid #F5F5F5;
+}
+
+.btn-reset,
+.btn-confirm {
+	flex: 1;
+	height: 88rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	border-radius: 15rpx;
+	font-size: 32rpx;
+	font-weight: 500;
+}
+
+.btn-reset {
+	background-color: #FFFFFF;
+	border: 2rpx solid #3475E7;
+	color: #3475E7;
+	box-shadow: 0 6rpx 18rpx rgba(52, 117, 231, 0.08);
+}
+
+.btn-confirm {
+	background: linear-gradient(90deg, #2E6CFB 0%, #3E82FF 100%);
+	color: #FFFFFF;
+	box-shadow: 0 8rpx 24rpx rgba(62, 130, 255, 0.35);
+}
+</style>

+ 272 - 274
pages/indexOrder/index.vue

@@ -1,295 +1,293 @@
 <template>
-  <view class="page">
-    <!-- 搜索和筛选区域 -->
-    <view class="search-section">
-      <view class="search-box">
-        <uni-icons type="search" size="18" color="#999999"></uni-icons>
-        <input 
-          class="search-input" 
-          placeholder="搜客户姓名" 
-          placeholder-style="color: #999999"
-          v-model="searchKeyword"
-          @input="handleSearch"
-        />
-        <text class="search-box-text">搜索</text>
-      </view>
-      <view class="filter-btn" @click="handleFilter">
-        <uni-icons type="settings" size="18" color="#323232"></uni-icons>
-        <text class="filter-text">筛选</text>
-      </view>
-    </view>
+	<view class="page">
+		<!-- 搜索和筛选区域 -->
+		<view class="search-section">
+			<view class="search-box">
+				<uni-icons type="search" size="18" color="#999999"></uni-icons>
+				<input class="search-input" placeholder="搜客户姓名" placeholder-style="color: #999999"
+					v-model="searchKeyword" @input="handleSearch" />
+				<text class="search-box-text">搜索</text>
+			</view>
+			<view class="filter-btn" @click="handleFilter">
+				<uni-icons type="settings" size="18" color="#323232"></uni-icons>
+				<text class="filter-text">筛选</text>
+			</view>
+		</view>
+		<!-- 订单标签页 -->
+		<view class="order-tabs">
+			<view v-for="tab in tabList" :key="tab.key" class="tab-item" :class="{ 'active': activeTab === tab.key }"
+				@click="switchTab(tab.key)">
+				<text class="tab-text">{{ tab.label }}({{ tab.count }})</text>
+			</view>
+		</view>
+		<!-- 订单列表-->
+		<order-list :orders="filteredOrders" :order-info-fields="orderInfoFields" @delete="handleDelete"
+			@message="handleMessage"></order-list>
+		<!-- 订单筛选弹窗 -->
+		<orderFilter ref="orderFilter" @confirmOrder="confirmOrder"></orderFilter>
+		<!-- 底部导航栏 -->
+		<bar-navigasi-handap></bar-navigasi-handap>
+	</view>
+</template>
 
-    <!-- 订单标签页 -->
-    <view class="order-tabs">
-      <view 
-        v-for="tab in tabList" 
-        :key="tab.key"
-        class="tab-item" 
-        :class="{ 'active': activeTab === tab.key }"
-        @click="switchTab(tab.key)"
-      >
-        <text class="tab-text">{{ tab.label }}({{ tab.count }})</text>
-      </view>
-    </view>
+<script>
+	import BarNavigasiHandap from "@/components/barNavigasiHandap.vue"
+	import OrderList from "./components/order.vue"
+	// 订单筛选弹窗
+	import orderFilter from "./components/orderFilter.vue"
+	export default {
+		components: {
+			BarNavigasiHandap,
+			OrderList,
+			orderFilter
+		},
+		data() {
+			return {
+				activeTab: 'all', // 当前选中的标签页
+				searchKeyword: '', // 搜索关键词
+				// 标签页配置
+				tabList: [{
+						key: 'all',
+						label: '全部订单',
+						count: 2
+					},
+					{
+						key: 'progress',
+						label: '进行中',
+						count: 0
+					},
+					{
+						key: 'completed',
+						label: '已完成',
+						count: 0
+					}
+				],
+				// 订单信息字段配置
+				orderInfoFields: [{
+						key: 'orderNo',
+						label: '订单编号'
+					},
+					{
+						key: 'phone',
+						label: '联系电话'
+					},
+					{
+						key: 'serviceFee',
+						label: '服务费用'
+					},
+					{
+						key: 'orderTime',
+						label: '下单时间'
+					},
+					{
+						key: 'payTime',
+						label: '支付时间'
+					},
+					{
+						key: 'commissionRate',
+						label: '佣金比例'
+					}
+				],
+				// 订单列表数据
+				orders: [{
+						id: 1,
+						customerName: '张明明',
+						avatar: '/static/images/profile.jpg',
+						validDate: '2025-11-07',
+						status: 'progress',
+						orderNo: 'LAW2023071500123',
+						phone: '13877092066',
+						serviceFee: '¥200/次',
+						orderTime: '2025-11-11 11:11:11',
+						payTime: '2025-11-11 11:11:11',
+						commissionRate: '3%',
+						revenue: 280
+					},
+					{
+						id: 2,
+						customerName: '张明明',
+						avatar: '/static/images/profile.jpg',
+						validDate: '2025-11-07',
+						status: 'completed',
+						orderNo: 'LAW2023071500123',
+						phone: '13877092066',
+						serviceFee: '¥200/次',
+						orderTime: '2025-11-11 11:11:11',
+						payTime: '2025-11-11 11:11:11',
+						commissionRate: '3%',
+						revenue: 280
+					},
+					{
+						id: 3,
+						customerName: '张明明',
+						avatar: '/static/images/profile.jpg',
+						validDate: '2025-11-07',
+						status: 'completed',
+						orderNo: 'LAW2023071500123',
+						phone: '13877092066',
+						serviceFee: '¥200/次',
+						orderTime: '2025-11-11 11:11:11',
+						payTime: '2025-11-11 11:11:11',
+						commissionRate: '3%',
+						revenue: 280
+					}
+				]
+			}
+		},
+		computed: {
+			/**
+			 * 过滤后的订单列表
+			 */
+			filteredOrders() {
+				let result = this.orders
 
-    <!-- 订单列表组件 -->
-    <order-list 
-      :orders="filteredOrders"
-      :order-info-fields="orderInfoFields"
-      @delete="handleDelete"
-      @message="handleMessage"
-    ></order-list>
+				// 根据标签页筛选
+				if (this.activeTab !== 'all') {
+					result = result.filter(order => order.status === this.activeTab)
+				}
 
-    <!-- 底部导航栏 -->
-    <bar-navigasi-handap></bar-navigasi-handap>
-  </view>
-</template>
+				// 根据搜索关键词筛选
+				if (this.searchKeyword.trim()) {
+					const keyword = this.searchKeyword.trim().toLowerCase()
+					result = result.filter(order =>
+						order.customerName.toLowerCase().includes(keyword) ||
+						order.orderNo.toLowerCase().includes(keyword) ||
+						order.phone.includes(keyword)
+					)
+				}
 
-<script>
-import BarNavigasiHandap from "@/components/barNavigasiHandap.vue"
-import OrderList from "./components/order.vue"
+				return result
+			}
+		},
+		methods: {
+			/**
+			 * 切换标签页
+			 */
+			switchTab(tab) {
+				if (this.activeTab === tab) return
+				this.activeTab = tab
+				this.updateTabCount()
+			},
+
+			/**
+			 * 更新标签页数量
+			 */
+			updateTabCount() {
+				this.tabList.forEach(tab => {
+					if (tab.key === 'all') {
+						tab.count = this.orders.length
+					} else {
+						tab.count = this.orders.filter(order => order.status === tab.key).length
+					}
+				})
+			},
+			handleSearch() {
+				// 搜索逻辑已在 computed 中处理
+			},
+			// 打开日期筛选弹窗
+			handleFilter() {
+				this.$refs.orderFilter.open()
+			},
+			handleMessage(order) {
 
-export default {
-  name: 'Index',
-  components: {
-    BarNavigasiHandap,
-    OrderList
-  },
-  data() {
-    return {
-      activeTab: 'all', // 当前选中的标签页
-      searchKeyword: '', // 搜索关键词
-      // 标签页配置
-      tabList: [
-        { key: 'all', label: '全部订单', count: 2 },
-        { key: 'progress', label: '进行中', count: 0 },
-        { key: 'completed', label: '已完成', count: 0 }
-      ],
-      // 订单信息字段配置
-      orderInfoFields: [
-        { key: 'orderNo', label: '订单编号' },
-        { key: 'phone', label: '联系电话' },
-        { key: 'serviceFee', label: '服务费用' },
-        { key: 'orderTime', label: '下单时间' },
-        { key: 'payTime', label: '支付时间' },
-        { key: 'commissionRate', label: '佣金比例' }
-      ],
-      // 订单列表数据
-      orders: [
-        {
-          id: 1,
-          customerName: '张明明',
-          avatar: '/static/images/profile.jpg',
-          validDate: '2025-11-07',
-          status: 'progress',
-          orderNo: 'LAW2023071500123',
-          phone: '13877092066',
-          serviceFee: '¥200/次',
-          orderTime: '2025-11-11 11:11:11',
-          payTime: '2025-11-11 11:11:11',
-          commissionRate: '3%',
-          revenue: 280
-        },
-        {
-          id: 2,
-          customerName: '张明明',
-          avatar: '/static/images/profile.jpg',
-          validDate: '2025-11-07',
-          status: 'completed',
-          orderNo: 'LAW2023071500123',
-          phone: '13877092066',
-          serviceFee: '¥200/次',
-          orderTime: '2025-11-11 11:11:11',
-          payTime: '2025-11-11 11:11:11',
-          commissionRate: '3%',
-          revenue: 280
-        },
-        {
-          id: 3,
-          customerName: '张明明',
-          avatar: '/static/images/profile.jpg',
-          validDate: '2025-11-07',
-          status: 'completed',
-          orderNo: 'LAW2023071500123',
-          phone: '13877092066',
-          serviceFee: '¥200/次',
-          orderTime: '2025-11-11 11:11:11',
-          payTime: '2025-11-11 11:11:11',
-          commissionRate: '3%',
-          revenue: 280
-        }
-      ]
-    }
-  },
-  computed: {
-    /**
-     * 过滤后的订单列表
-     */
-    filteredOrders() {
-      let result = this.orders
-      
-      // 根据标签页筛选
-      if (this.activeTab !== 'all') {
-        result = result.filter(order => order.status === this.activeTab)
-      }
-      
-      // 根据搜索关键词筛选
-      if (this.searchKeyword.trim()) {
-        const keyword = this.searchKeyword.trim().toLowerCase()
-        result = result.filter(order => 
-          order.customerName.toLowerCase().includes(keyword) ||
-          order.orderNo.toLowerCase().includes(keyword) ||
-          order.phone.includes(keyword)
-        )
-      }
-      
-      return result
-    }
-  },
-  methods: {
-    /**
-     * 切换标签页
-     */
-    switchTab(tab) {
-      if (this.activeTab === tab) return
-      this.activeTab = tab
-      this.updateTabCount()
-    },
-    
-    /**
-     * 更新标签页数量
-     */
-    updateTabCount() {
-      this.tabList.forEach(tab => {
-        if (tab.key === 'all') {
-          tab.count = this.orders.length
-        } else {
-          tab.count = this.orders.filter(order => order.status === tab.key).length
-        }
-      })
-    },
-    
-    /**
-     * 处理搜索
-     */
-    handleSearch() {
-      // 搜索逻辑已在 computed 中处理
-    },
-    
-    /**
-     * 处理筛选
-     */
-    handleFilter() {
-      uni.showToast({
-        title: '筛选功能开发中',
-        icon: 'none'
-      })
-    },
-    
-    /**
-     * 处理发消息(从子组件触发)
-     */
-    handleMessage(order) {
-      // TODO: 实现跳转到消息页面
-    },
-    
-    /**
-     * 处理删除(从子组件触发)
-     */
-    handleDelete(order) {
-      const index = this.orders.findIndex(item => item.id === order.id)
-      if (index > -1) {
-        this.orders.splice(index, 1)
-        this.updateTabCount()
-        uni.showToast({
-          title: '删除成功',
-          icon: 'success'
-        })
-      }
-    }
-  },
-  onLoad() {
-    // 页面加载时更新标签页数量
-    this.updateTabCount()
-  }
-}
+			},
+			handleDelete(order) {
+				const index = this.orders.findIndex(item => item.id === order.id)
+				if (index > -1) {
+					this.orders.splice(index, 1)
+					this.updateTabCount()
+					uni.showToast({
+						title: '删除成功',
+						icon: 'success'
+					})
+				}
+			},
+			confirmOrder(data) {
+				console.log(data, '筛选日期')
+			}
+		},
+		onLoad() {
+			// 页面加载时更新标签页数量
+			this.updateTabCount()
+		}
+	}
 </script>
 
 <style scoped>
-.page {
-  padding-top: calc(var(--status-bar-height) + 20rpx);
-  padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
-  background: linear-gradient(180deg, rgba(40, 86, 199, 0.3) 0%, rgba(255, 255, 255, 0) 100%);
-  min-height: 100vh;
-  box-sizing: border-box;
-}
+	.page {
+		padding-top: calc(var(--status-bar-height) + 20rpx);
+		padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
+		background: linear-gradient(180deg, rgba(40, 86, 199, 0.3) 0%, rgba(255, 255, 255, 0) 100%);
+		min-height: 100vh;
+		box-sizing: border-box;
+	}
 
-/* 搜索区域 */
-.search-section {
-  display: flex;
-  align-items: center;
-  padding: 0 30rpx 24rpx;
-  gap: 20rpx;
-}
+	/* 搜索区域 */
+	.search-section {
+		display: flex;
+		align-items: center;
+		padding: 0 30rpx 24rpx;
+		gap: 20rpx;
+	}
 
-.search-box {
-  flex: 1;
-  display: flex;
-  align-items: center;
-  background-color: #F5F5F5;
-  border-radius: 38rpx;
-  padding: 20rpx 24rpx;
-  gap: 12rpx;
-}
+	.search-box {
+		flex: 1;
+		display: flex;
+		align-items: center;
+		background-color: #F5F5F5;
+		border-radius: 38rpx;
+		padding: 20rpx 24rpx;
+		gap: 12rpx;
+	}
 
-.search-input {
-  flex: 1;
-  font-size: 28rpx;
-  color: #323232;
-}
+	.search-input {
+		flex: 1;
+		font-size: 28rpx;
+		color: #323232;
+	}
 
-.search-box-text {
-  font-weight: 400;
-  font-size: 27rpx;
-  color: #151515;
-}
+	.search-box-text {
+		font-weight: 400;
+		font-size: 27rpx;
+		color: #151515;
+	}
 
-.filter-btn {
-  display: flex;
-  align-items: center;
-  gap: 8rpx;
-  padding: 20rpx 24rpx;
-}
+	.filter-btn {
+		display: flex;
+		align-items: center;
+		gap: 8rpx;
+		padding: 20rpx 24rpx;
+	}
 
-.filter-text {
-  font-size: 28rpx;
-  color: #323232;
-}
+	.filter-text {
+		font-size: 28rpx;
+		color: #323232;
+	}
 
-/* 订单标签页 */
-.order-tabs {
-  display: flex;
-  justify-content: space-around;
-  width: 100%;
-}
+	/* 订单标签页 */
+	.order-tabs {
+		display: flex;
+		justify-content: space-around;
+		width: 100%;
+	}
 
-.tab-item {
-  padding: 24rpx 0;
-  position: relative;
-  cursor: pointer;
-}
+	.tab-item {
+		padding: 24rpx 0;
+		position: relative;
+		cursor: pointer;
+	}
 
-.tab-item.active {
-  font-weight: 600;
-}
+	.tab-item.active {
+		font-weight: 600;
+	}
 
-.tab-text {
-  font-size: 28rpx;
-  color: #8D8D8D;
-  transition: color 0.3s;
-}
+	.tab-text {
+		font-size: 28rpx;
+		color: #8D8D8D;
+		transition: color 0.3s;
+	}
 
-.tab-item.active .tab-text {
-  color: #323232;
-}
+	.tab-item.active .tab-text {
+		color: #323232;
+	}
 </style>

+ 447 - 171
pages/login.vue

@@ -1,210 +1,486 @@
 <template>
-  <view class="normal-login-container">
-    <view class="logo-content align-center justify-center flex">
-      <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
-      </image>
-      <text class="title">若依移动端登录</text>
+  <view class="login-container">
+
+    <!-- 背景装饰 -->
+    <view class="background-decoration"> </view>
+
+    <!-- 返回按钮 -->
+    <view class="back-btn" @click="showInterruptLoginModal = true" v-if="step === 2">
+      <image src="@/static/images/login/back.png" mode="widthFix" style="width: 50rpx;height: 50rpx;"></image>
     </view>
-    <view class="login-form-content">
-      <view class="input-item flex align-center">
-        <view class="iconfont icon-user icon"></view>
-        <input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
-      </view>
-      <view class="input-item flex align-center">
-        <view class="iconfont icon-password icon"></view>
-        <input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
+
+    <!-- 主内容区 -->
+    <view class="login-content">
+      <!-- 标题 -->
+      <view class="title">登录律师账号</view>
+      <view class="subtitle">请使用手机号接收验证码进行登录</view>
+
+      <!-- 第一步:输入手机号 -->
+      <view class="form-section" v-if="step === 1">
+        <view class="input-label">手机号码</view>
+        <view class="input-wrapper">
+          <input v-model="phone" type="number" class="phone-input" placeholder="请输入手机号码" maxlength="11" />
+        </view>
+        <view class="resend-code-btn" @click="handleGetCode"> 获取验证码</view>
       </view>
-      <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
-        <view class="iconfont icon-code icon"></view>
-        <input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
-        <view class="login-code"> 
-          <image :src="codeUrl" @click="getCode" class="login-code-img"></image>
+
+      <!-- 第二步:输入验证码 -->
+      <view class="form-section" v-if="step === 2">
+        <view class="input-label">验证码</view>
+        <view class="input-wrapper">
+          <input v-model="code" type="number" class="code-input" placeholder="请输入验证码" maxlength="6"
+            @input="handleInputCode" />
         </view>
+
+        <button class="resend-code-btn" @click="handleResendCode">
+          {{ countdown > 0 ? `重新获取 (${countdown}s)` : '重新获取' }}
+        </button>
+        <!-- <button 
+          class="login-btn" 
+          :disabled="!canLogin"
+          @click="handleLogin"
+        >
+          登录
+        </button> -->
       </view>
-      <view class="action-btn">
-        <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button>
+
+      <!-- 用户协议 -->
+      <view class="agreement-section">
+        <view class="checkbox-wrapper" @click="toggleAgreement">
+          <view class="checkbox" :class="{ 'checked': agreed }">
+            <text class="check-icon" v-if="agreed">✓</text>
+          </view>
+          <text class="agreement-text">
+            我已阅读并同意
+            <text class="link-text" @click.stop="handleUserAgrement">《用户协议》</text>
+            和
+            <text class="link-text" @click.stop="handlePrivacy">《隐私政策》</text>
+          </text>
+        </view>
       </view>
-      <view class="reg text-center" v-if="register">
-        <text class="text-grey1">没有账号?</text>
-        <text @click="handleUserRegister" class="text-blue">立即注册</text>
+    </view>
+
+    <!-- 用户协议弹窗 -->
+    <view class="modal-overlay" v-if="showAgreementModal" @click="showAgreementModal = false">
+      <view class="modal-content" @click.stop>
+        <view class="modal-title">用户协议及隐私政策</view>
+        <view class="modal-text">
+          为了更好的保障您的合法权益,请您阅读并同意以下协议
+          <text class="link-text" @click="handleUserAgrement">《用户协议》</text>
+          和
+          <text class="link-text" @click="handlePrivacy">《隐私政策》</text>
+        </view>
+        <view class="modal-buttons">
+          <button class="modal-btn reject-btn" @click="handleReject">拒绝</button>
+          <button class="modal-btn agree-btn" @click="handleAgree">同意</button>
+        </view>
       </view>
-      <view class="xieyi text-center">
-        <text class="text-grey1">登录即代表同意</text>
-        <text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
-        <text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
+    </view>
+
+    <!-- 中断登录弹窗 -->
+    <view class="modal-overlay" v-if="showInterruptLoginModal">
+      <view class="modal-content" @click.stop>
+        <view class="modal-title" style="margin-bottom: 60rpx;">
+          返回将中断登录,确定返回?
+        </view>
+        <view class="modal-buttons">
+          <button class="modal-btn reject-btn" @click="showInterruptLoginModal = false">取消</button>
+          <button class="modal-btn agree-btn" @click="interruptLogin">确定</button>
+        </view>
       </view>
     </view>
-     
   </view>
 </template>
 
 <script>
-  import { getCodeImg } from '@/api/login'
-  import { getToken } from '@/utils/auth'
-
-  export default {
-    data() {
-      return {
-        codeUrl: "",
-        captchaEnabled: true,
-        // 用户注册开关
-        register: false,
-        globalConfig: getApp().globalData.config,
-        loginForm: {
-          username: "admin",
-          password: "admin123",
-          code: "",
-          uuid: ""
+import { sendSmsCode } from '@/api/login'
+import { getToken } from '@/utils/auth'
+
+export default {
+  data() {
+    return {
+      step: 1, // 1: 输入手机号, 2: 输入验证码
+      phone: '',
+      code: '',
+      countdown: 0,
+      agreed: false,
+      showAgreementModal: false,
+      globalConfig: getApp().globalData.config,
+      timer: null,
+      showInterruptLoginModal: false
+    }
+  },
+  computed: {
+    canGetCode() {
+      return /^1[3-9]\d{9}$/.test(this.phone) && this.agreed
+    },
+    canLogin() {
+      return this.code.length >= 4 && this.agreed
+    }
+  },
+  onLoad() {
+    //#ifdef H5
+    if (getToken()) {
+      this.$tab.reLaunch('/pages/index')
+    }
+    //#endif
+    // 首次进入显示协议弹窗
+    this.showAgreementModal = true
+  },
+  onUnload() {
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    interruptLogin() {
+      this.showInterruptLoginModal = false
+      this.step = 1
+      this.code = ''
+    },
+    toggleAgreement() {
+      this.agreed = !this.agreed
+    },
+    handleGetCode() {
+      if (!this.canGetCode) {
+        if (!/^1[3-9]\d{9}$/.test(this.phone)) {
+          this.$modal.msgError('请输入正确的手机号码')
+        } else if (!this.agreed) {
+          this.$modal.msgError('请先同意用户协议和隐私政策')
         }
+        return
       }
+
+      this.$modal.loading('发送中...')
+      sendSmsCode(this.phone).then(() => {
+        this.$modal.closeLoading()
+        this.$modal.msgSuccess('验证码已发送')
+        this.step = 2
+        this.startCountdown()
+      }).catch(() => {
+        this.$modal.closeLoading()
+      })
     },
-    created() {
-      this.getCode()
+    handleResendCode() {
+      if (this.countdown > 0) return
+      this.handleGetCode()
     },
-    onLoad() {
-      //#ifdef H5
-      if (getToken()) {
-        this.$tab.reLaunch('/pages/indexOrder/index')
+    startCountdown() {
+      this.countdown = 60
+      if (this.timer) {
+        clearInterval(this.timer)
       }
-      //#endif
+      this.timer = setInterval(() => {
+        this.countdown--
+        if (this.countdown <= 0) {
+          clearInterval(this.timer)
+          this.timer = null
+        }
+      }, 1000)
     },
-    methods: {
-      // 用户注册
-      handleUserRegister() {
-        this.$tab.redirectTo(`/pages/register`)
-      },
-      // 隐私协议
-      handlePrivacy() {
-        let site = this.globalConfig.appInfo.agreements[0]
-        this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
-      },
-      // 用户协议
-      handleUserAgrement() {
-        let site = this.globalConfig.appInfo.agreements[1]
-        this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
-      },
-      // 获取图形验证码
-      getCode() {
-        getCodeImg().then(res => {
-          this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
-          if (this.captchaEnabled) {
-            this.codeUrl = 'data:image/gif;base64,' + res.img
-            this.loginForm.uuid = res.uuid
-          }
-        })
-      },
-      // 登录方法
-      async handleLogin() {
-        if (this.loginForm.username === "") {
-          this.$modal.msgError("请输入账号")
-        } else if (this.loginForm.password === "") {
-          this.$modal.msgError("请输入密码")
-        } else if (this.loginForm.code === "" && this.captchaEnabled) {
-          this.$modal.msgError("请输入验证码")
-        } else {
-          this.$modal.loading("登录中,请耐心等待...")
-          this.pwdLogin()
+    handleInputCode() {
+      if (this.code.length >= 6) {
+        this.handleLogin()
+      }
+    },
+    async handleLogin() {
+      if (!this.canLogin) {
+        if (this.code.length < 4) {
+          this.$modal.msgError('请输入验证码')
+        } else if (!this.agreed) {
+          this.$modal.msgError('请先同意用户协议和隐私政策')
         }
-      },
-      // 密码登录
-      async pwdLogin() {
-        this.$store.dispatch('Login', this.loginForm).then(() => {
-          this.$modal.closeLoading()
-          this.loginSuccess()
-        }).catch(() => {
-          if (this.captchaEnabled) {
-            this.getCode()
-          }
-        })
-      },
-      // 登录成功后,处理函数
-      loginSuccess(result) {
-        // 设置用户信息
-        this.$store.dispatch('GetInfo').then(res => {
-          this.$tab.reLaunch('/pages/indexOrder/index')
+        return
+      }
+
+      this.$modal.loading('登录中,请耐心等待...')
+
+      this.$modal.closeLoading()
+      this.loginSuccess()
+
+      try {
+        await this.$store.dispatch('LoginBySms', {
+          phone: this.phone,
+          code: this.code
         })
+        this.$modal.closeLoading()
+        this.loginSuccess()
+      } catch (error) {
+        this.$modal.closeLoading()
       }
+
+    },
+    loginSuccess() {
+      // this.$store.dispatch('GetInfo').then(res => {
+        this.$tab.reLaunch('/pages/setUserInfo')
+      // })
+    },
+    handleUserAgrement() {
+      let site = this.globalConfig.appInfo.agreements[1]
+      this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
+    },
+    handlePrivacy() {
+      let site = this.globalConfig.appInfo.agreements[0]
+      this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
+    },
+    handleReject() {
+      this.showAgreementModal = false
+      this.agreed = false
+    },
+    handleAgree() {
+      this.showAgreementModal = false
+      this.agreed = true
     }
   }
+}
 </script>
 
 <style lang="scss" scoped>
-  page {
-    background-color: #ffffff;
+page {
+  background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf0 100%);
+  min-height: 100vh;
+}
+
+.login-container {
+  position: relative;
+  width: 100%;
+  min-height: 100vh;
+  padding: 0 60rpx;
+  padding-top: 120rpx;
+  overflow: hidden;
+  background-image: url('@/static/images/login/bg1.png');
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
+.background-decoration {
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 100%;
+  height: 80%;
+  background-image: url('@/static/images/login/bg2.png');
+  background-size: cover;
+}
+
+.back-btn {
+  position: absolute;
+  top: 100rpx;
+  left: 40rpx;
+  width: 60rpx;
+  height: 60rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 10;
+
+  .back-icon {
+    font-size: 40rpx;
+    color: #333;
+    font-weight: bold;
   }
+}
 
-  .normal-login-container {
-    width: 100%;
 
-    .logo-content {
-      width: 100%;
-      font-size: 21px;
-      text-align: center;
-      padding-top: 15%;
+.login-content {
+  position: relative;
+  z-index: 1;
+  top: 260rpx;
+}
 
-      image {
-        border-radius: 4px;
-      }
+.title {
+  font-size: 56rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 20rpx;
+  text-align: left;
+}
 
-      .title {
-        margin-left: 10px;
-      }
-    }
+.subtitle {
+  font-size: 28rpx;
+  color: #666;
+  margin-bottom: 80rpx;
+  text-align: left;
+}
 
-    .login-form-content {
-      text-align: center;
-      margin: 20px auto;
-      margin-top: 15%;
-      width: 80%;
-
-      .input-item {
-        margin: 20px auto;
-        background-color: #f5f6f7;
-        height: 45px;
-        border-radius: 20px;
-
-        .icon {
-          font-size: 38rpx;
-          margin-left: 10px;
-          color: #999;
-        }
+.form-section {
+  margin-bottom: 60rpx;
+}
 
-        .input {
-          width: 100%;
-          font-size: 14px;
-          line-height: 20px;
-          text-align: left;
-          padding-left: 15px;
-        }
+.input-label {
+  font-size: 28rpx;
+  color: #333;
+  margin-bottom: 20rpx;
+  text-align: left;
+}
 
-      }
+.input-wrapper {
+  background-color: #f8f9fa;
+  border-radius: 16rpx;
+  padding: 24rpx 30rpx;
+  margin-bottom: 40rpx;
+}
 
-      .login-btn {
-        margin-top: 40px;
-        height: 45px;
-      }
-      
-      .reg {
-        margin-top: 15px;
-      }
-      
-      .xieyi {
-        color: #333;
-        margin-top: 20px;
-      }
-      
-      .login-code {
-        height: 38px;
-        float: right;
-      
-        .login-code-img {
-          height: 38px;
-          position: absolute;
-          margin-left: 10px;
-          width: 200rpx;
-        }
-      }
+.phone-input,
+.code-input {
+  width: 100%;
+  font-size: 32rpx;
+  color: #333;
+  background: transparent;
+  border: none;
+}
+
+.get-code-btn,
+.resend-code-btn {
+  width: 100%;
+  height: 88rpx;
+  background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
+  color: #fff;
+  font-size: 32rpx;
+  border-radius: 16rpx;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 40rpx;
+
+  &[disabled] {
+    background: #d0d0d0;
+    color: #999;
+  }
+}
+
+.login-btn {
+  width: 100%;
+  height: 88rpx;
+  background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
+  color: #fff;
+  font-size: 32rpx;
+  border-radius: 16rpx;
+  border: none;
+  margin-top: 40rpx;
+
+  &[disabled] {
+    background: #d0d0d0;
+    color: #999;
+  }
+}
+
+.agreement-section {
+  position: fixed;
+  bottom: 60rpx;
+  left: 0;
+  right: 0;
+  padding: 0 60rpx;
+  z-index: 2;
+}
+
+.checkbox-wrapper {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.checkbox {
+  width: 36rpx;
+  height: 36rpx;
+  border: 2rpx solid #ddd;
+  border-radius: 50%;
+  margin-right: 16rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+
+  &.checked {
+    background: #4a90e2;
+    border-color: #4a90e2;
+
+    .check-icon {
+      color: #fff;
+      font-size: 24rpx;
+      font-weight: bold;
     }
   }
+}
+
+.agreement-text {
+  font-size: 24rpx;
+  color: #666;
+  line-height: 1.6;
+}
+
+.link-text {
+  color: #4a90e2;
+}
+
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  width: 600rpx;
+  background: #fff;
+  border-radius: 24rpx;
+  padding: 60rpx 40rpx 0 40rpx;
+  margin: 0 40rpx;
+}
+
+.modal-title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 30rpx;
+  text-align: center;
+}
+
+.modal-text {
+  font-size: 28rpx;
+  color: #666;
+  line-height: 1.8;
+  margin-bottom: 50rpx;
+  text-align: left;
+}
+
+.modal-buttons {
+  display: flex;
+  border-top: 1rpx solid #eee;
+  // padding-top: 30rpx;
+
+}
+
+.modal-btn {
+  flex: 1;
+  height: 100rpx;
+  font-size: 32rpx;
+  border: none;
+  background: transparent;
+  border-radius: 12rpx;
+  padding: 10rpx;
+
+  &.reject-btn {
+    color: #999;
+    margin-right: 20rpx;
+    border-right: 1rpx solid #eee;
+  }
+
+  &.agree-btn {
+    color: #4a90e2;
+    font-weight: bold;
+  }
+}
 
-</style>
+uni-button:after {
+  border: none !important;
+}
+</style>

+ 852 - 0
pages/setUserInfo.vue

@@ -0,0 +1,852 @@
+<template>
+    <view class="set-user-info-container">
+        <!-- 标题 -->
+        <view class="page-title">完善个人信息</view>
+
+        <scroll-view class="form-scroll" scroll-y>
+            <!-- 头像上传 -->
+            <view class="avatar-section">
+                <view class="avatar-wrapper" @click="chooseAvatar">
+                    <image v-if="formData.avatar" :src="formData.avatar" class="avatar-image" mode="aspectFill" />
+                    <view v-else class="avatar-placeholder">
+                         <image src="/static/images/login/user.png" class="avatar-image" mode="aspectFill" style="width: 80%; height: 80%;" />
+                    </view>
+                </view>
+                <view class="avatar-tip">
+                    <text class="tip-text">点击上传头像</text>
+                    <text class="required-mark">*</text>
+                </view>
+                <view v-if="errors.avatar" class="error-tip">{{ errors.avatar }}</view>
+            </view>
+
+            <!-- 表单字段 -->
+            <view class="form-section">
+                <!-- 真实姓名 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>真实姓名</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <input v-model="formData.realName" class="form-input" placeholder="请输入真实姓名"
+                        @blur="validateField('realName')" />
+                    <view v-if="errors.realName" class="error-tip">{{ errors.realName }}</view>
+                </view>
+
+                <!-- 从业时间 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>从业时间</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <picker mode="date" :value="formData.practiceYear" :start="startDate" :end="endDate"
+                        @change="onPracticeYearChange">
+                        <view class="picker-view">
+                            <text :class="formData.practiceYear ? 'picker-text' : 'picker-placeholder'">
+                                {{ formData.practiceYear ? formatDate(formData.practiceYear) : '请选择从业时间' }}
+                            </text>
+                            <text class="picker-arrow">›</text>
+                        </view>
+                    </picker>
+                    <view v-if="errors.practiceYear" class="error-tip">{{ errors.practiceYear }}</view>
+                </view>
+
+                <!-- 专业领域 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>专业领域</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <picker mode="selector" :range="professionalFields" :value="professionalFieldIndex"
+                        @change="onProfessionalFieldChange">
+                        <view class="picker-view">
+                            <text :class="formData.professionalField ? 'picker-text' : 'picker-placeholder'">
+                                {{ formData.professionalField || '请选择专业领域' }}
+                            </text>
+                            <text class="picker-arrow">›</text>
+                        </view>
+                    </picker>
+                    <view v-if="errors.professionalField" class="error-tip">{{ errors.professionalField }}</view>
+                </view>
+
+                <!-- 法律场景 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>法律场景</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <view class="picker-view" @click="showLegalScenarioModal = true">
+                        <view class="picker-text-ellipsis">
+                            <text :class="formData.legalScenarios && formData.legalScenarios.length > 0 ? 'picker-text' : 'picker-placeholder'">
+                                {{ getLegalScenarioText() || '请选择法律场景' }}
+                            </text>
+                        </view>
+                        <text class="picker-arrow">›</text>
+                    </view>
+                    <view v-if="errors.legalScenario" class="error-tip">{{ errors.legalScenario }}</view>
+                </view>
+
+                <!-- 联系地址 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>联系地址</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <input v-model="formData.address" class="form-input" placeholder="请输入常用联系地址"
+                        @blur="validateField('address')" />
+                    <view v-if="errors.address" class="error-tip">{{ errors.address }}</view>
+                </view>
+
+                <!-- 律师事务所名称 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>律师事务所名称</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <picker 
+                        mode="selector" 
+                        :range="firmList" 
+                        range-key="firmName"
+                        :value="lawFirmIndex"
+                        @change="onLawFirmChange"
+                    >
+                        <view class="picker-view">
+                            <text :class="formData.lawFirmName ? 'picker-text' : 'picker-placeholder'">
+                                {{ formData.lawFirmName || '请选择律师事务所名称' }}
+                            </text>
+                            <text class="picker-arrow">›</text>
+                        </view>
+                    </picker>
+                    <view v-if="errors.lawFirmName" class="error-tip">{{ errors.lawFirmName }}</view>
+                </view>
+
+                <!-- 律师事务所收款账号 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>律师事务所收款账号</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <picker 
+                        mode="selector" 
+                        :range="paymentAccountList" 
+                        :value="paymentAccountIndex"
+                        @change="onPaymentAccountChange"
+                    >
+                        <view class="picker-view">
+                            <text :class="formData.paymentAccount ? 'picker-text' : 'picker-placeholder'">
+                                {{ formData.paymentAccount || '请选择律师事务所收款账号' }}
+                            </text>
+                            <text class="picker-arrow">›</text>
+                        </view>
+                    </picker>
+                    <view v-if="errors.paymentAccount" class="error-tip">{{ errors.paymentAccount }}</view>
+                </view>
+
+                
+
+                <!-- 律师资格证 -->
+                <view class="form-item">
+                    <view class="form-label">
+                        <text>律师资格证</text>
+                        <text class="required-mark">*</text>
+                    </view>
+                    <view class="certificate-upload" @click="chooseCertificate">
+                        <image v-if="formData.certificate" :src="formData.certificate" class="certificate-image"
+                            mode="aspectFit" />
+                        <view v-else class="certificate-placeholder">
+                            <text class="certificate-icon">🏔️</text>
+                            <text class="certificate-text">点击上传图片</text>
+                        </view>
+                    </view>
+                    <view v-if="errors.certificate" class="error-tip">{{ errors.certificate }}</view>
+                </view>
+            </view>
+        </scroll-view>
+
+        <!-- 提交按钮 -->
+        <view class="submit-section">
+            <button class="submit-btn" @click="handleSubmit">提交信息</button>
+        </view>
+        
+        <!-- 法律场景多选弹窗 -->
+        <view class="modal-overlay" v-if="showLegalScenarioModal" @click="showLegalScenarioModal = false">
+            <view class="legal-scenario-modal" @click.stop>
+                <view class="modal-header">
+                    <view class="modal-title">选择您擅长的法律场景</view>
+                    <text class="cancel-btn" @click="showLegalScenarioModal = false">取消</text>
+                </view>
+                <view class="scenario-tags">
+                    <view 
+                        v-for="(scenario, index) in legalScenarios" 
+                        :key="index"
+                        class="scenario-tag"
+                        :class="{ 'selected': isLegalScenarioSelected(scenario) }"
+                        @click="toggleLegalScenario(scenario)"
+                    >
+                        {{ scenario }}
+                    </view>
+                </view>
+                <button class="confirm-btn" @click="confirmLegalScenarios">选好了</button>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import upload from '@/utils/upload'
+import { updateUserProfile, uploadAvatar } from '@/api/system/user'
+import { getFirmList, getLegalProblemScenarioList, getExpertiseAreaList } from '@/api/setUserInfo'
+import { getToken } from '@/utils/auth'
+import config from '@/config'
+
+export default {
+    data() {
+        return {
+            formData: {
+                avatar: '',
+                realName: '',
+                practiceYear: '',
+                professionalField: '',
+                legalScenarios: [], // 改为数组支持多选
+                address: '',
+                paymentAccount: '',
+                lawFirmName: '',
+                certificate: ''
+            },
+            errors: {},
+            startDate: '1950-01-01', // 最早可选日期
+            endDate: '', // 最晚可选日期(今天)
+            professionalFields: ['刑事法律', '民事法律', '商事法律', '行政法律', '知识产权', '劳动法律', '其他'],
+            professionalFieldIndex: -1,
+            legalScenarios: ['家庭生活', '职场工作', '邻里与社区', '网络与数字', '交通出行', '居住与物业', '消费与服务'],
+            showLegalScenarioModal: false,
+            firmList: [], // 律师事务所列表
+            lawFirmIndex: -1,
+            paymentAccountList: [], // 收款账号列表
+            paymentAccountIndex: -1,
+            baseUrl: config.baseUrl
+        }
+    },
+    onLoad() {
+        // 设置最晚可选日期为今天
+        const today = new Date()
+        const year = today.getFullYear()
+        const month = String(today.getMonth() + 1).padStart(2, '0')
+        const day = String(today.getDate()).padStart(2, '0')
+        this.endDate = `${year}-${month}-${day}`
+        // 加载律师事务所列表
+        // this.getPageInfo()
+    },
+    methods: {
+        getPageInfo() {
+            getFirmList().then(res => {
+                if (res.data && res.data.length > 0) {
+                    this.firmList = res.data
+                    // 提取收款账号列表(假设每个律师事务所都有收款账号字段)
+                    this.paymentAccountList = res.data.map(item => item.paymentAccount || item.account || '').filter(account => account)
+                }
+            }).catch(() => {
+                // 如果接口失败,使用默认数据
+                this.firmList = []
+                this.paymentAccountList = []
+            })
+        },
+        
+        // 律师事务所选择
+        onLawFirmChange(e) {
+            this.lawFirmIndex = e.detail.value
+            const selectedFirm = this.firmList[e.detail.value]
+            if (selectedFirm) {
+                this.formData.lawFirmName = selectedFirm.firmName || selectedFirm.name || ''
+                // 如果选择的律师事务所有收款账号,自动填充
+                if (selectedFirm.paymentAccount || selectedFirm.account) {
+                    this.formData.paymentAccount = selectedFirm.paymentAccount || selectedFirm.account
+                    // 找到对应的收款账号索引
+                    const accountIndex = this.paymentAccountList.indexOf(this.formData.paymentAccount)
+                    if (accountIndex > -1) {
+                        this.paymentAccountIndex = accountIndex
+                    }
+                }
+                this.errors.lawFirmName = ''
+            }
+        },
+        
+        // 收款账号选择
+        onPaymentAccountChange(e) {
+            this.paymentAccountIndex = e.detail.value
+            this.formData.paymentAccount = this.paymentAccountList[e.detail.value] || ''
+            this.errors.paymentAccount = ''
+        },
+        // 选择头像
+        chooseAvatar() {
+            uni.chooseImage({
+                count: 1,
+                sizeType: ['compressed'],
+                sourceType: ['album', 'camera'],
+                success: (res) => {
+                    const tempFilePath = res.tempFilePaths[0]
+                    this.uploadAvatarFile(tempFilePath)
+                }
+            })
+        },
+
+        // 上传头像
+        uploadAvatarFile(filePath) {
+            this.$modal.loading('上传中...')
+            uni.uploadFile({
+                url: 'http://192.168.2.54:8899/file/upload',
+                filePath: filePath,
+                name: 'avatarfile',
+                header: {
+                    'Authorization': 'Bearer ' + (getToken() || '')
+                },
+                success: (res) => {
+                    try {
+                        const result = JSON.parse(res.data)
+                        if (result.code === 200) {
+                            this.$modal.closeLoading()
+                            this.formData.avatar = this.baseUrl + result.imgUrl
+                            this.errors.avatar = ''
+                        } else {
+                            this.$modal.closeLoading()
+                            this.$modal.msgError(result.msg || '上传失败')
+                        }
+                    } catch (e) {
+                        this.$modal.closeLoading()
+                        this.$modal.msgError('上传失败')
+                    }
+                },
+                fail: (error) => {
+                    this.$modal.closeLoading()
+                    this.$modal.msgError('上传失败')
+                }
+            })
+        },
+
+        // 选择律师资格证
+        chooseCertificate() {
+            uni.chooseImage({
+                count: 1,
+                sizeType: ['compressed'],
+                sourceType: ['album', 'camera'],
+                success: (res) => {
+                    const tempFilePath = res.tempFilePaths[0]
+                    this.uploadCertificateFile(tempFilePath)
+                }
+            })
+        },
+
+        // 上传资格证
+        uploadCertificateFile(filePath) {
+            this.$modal.loading('上传中...')
+            upload({
+                url: '/system/user/profile/certificate',
+                name: 'certificate',
+                filePath: filePath
+            }).then(res => {
+                this.$modal.closeLoading()
+                this.formData.certificate = this.baseUrl + res.imgUrl
+                this.errors.certificate = ''
+            }).catch(() => {
+                this.$modal.closeLoading()
+            })
+        },
+
+        // 从业时间选择
+        onPracticeYearChange(e) {
+            this.formData.practiceYear = e.detail.value
+            this.errors.practiceYear = ''
+        },
+        
+        // 格式化日期显示
+        formatDate(dateStr) {
+            if (!dateStr) return ''
+            const date = new Date(dateStr)
+            const year = date.getFullYear()
+            const month = String(date.getMonth() + 1).padStart(2, '0')
+            const day = String(date.getDate()).padStart(2, '0')
+            return `${year}年${month}月${day}日`
+        },
+
+        // 专业领域选择
+        onProfessionalFieldChange(e) {
+            this.professionalFieldIndex = e.detail.value
+            this.formData.professionalField = this.professionalFields[e.detail.value]
+            this.errors.professionalField = ''
+        },
+
+        // 获取法律场景显示文本
+        getLegalScenarioText() {
+            if (!this.formData.legalScenarios || this.formData.legalScenarios.length === 0) {
+                return ''
+            }
+            return this.formData.legalScenarios.join('、')
+        },
+        
+        // 判断法律场景是否已选中
+        isLegalScenarioSelected(scenario) {
+            return this.formData.legalScenarios && this.formData.legalScenarios.includes(scenario)
+        },
+        
+        // 切换法律场景选择状态
+        toggleLegalScenario(scenario) {
+            if (!this.formData.legalScenarios) {
+                this.formData.legalScenarios = []
+            }
+            const index = this.formData.legalScenarios.indexOf(scenario)
+            if (index > -1) {
+                // 已选中,取消选择
+                this.formData.legalScenarios.splice(index, 1)
+            } else {
+                // 未选中,添加选择
+                this.formData.legalScenarios.push(scenario)
+            }
+        },
+        
+        // 确认法律场景选择
+        confirmLegalScenarios() {
+            if (this.formData.legalScenarios && this.formData.legalScenarios.length > 0) {
+                this.errors.legalScenario = ''
+            }
+            this.showLegalScenarioModal = false
+        },
+
+        // 验证单个字段
+        validateField(field) {
+            this.errors[field] = ''
+            const value = this.formData[field]
+
+            if (!value || value.trim() === '') {
+                switch (field) {
+                    case 'realName':
+                        this.errors.realName = '请填写真实姓名'
+                        break
+                    case 'address':
+                        this.errors.address = '请填写联系地址'
+                        break
+                    case 'paymentAccount':
+                        this.errors.paymentAccount = '请选择律师事务所收款账号'
+                        break
+                    case 'lawFirmName':
+                        this.errors.lawFirmName = '请选择律师事务所名称'
+                        break
+                }
+            }
+        },
+
+        // 验证所有字段
+        validateForm() {
+            this.errors = {}
+            let isValid = true
+
+            if (!this.formData.avatar) {
+                this.errors.avatar = '请上传头像'
+                isValid = false
+            }
+
+            if (!this.formData.realName || this.formData.realName.trim() === '') {
+                this.errors.realName = '请填写真实姓名'
+                isValid = false
+            }
+
+            if (!this.formData.practiceYear) {
+                this.errors.practiceYear = '请选择从业时间'
+                isValid = false
+            }
+
+            if (!this.formData.professionalField) {
+                this.errors.professionalField = '请选择专业领域'
+                isValid = false
+            }
+
+            if (!this.formData.legalScenarios || this.formData.legalScenarios.length === 0) {
+                this.errors.legalScenario = '请选择法律场景'
+                isValid = false
+            }
+
+            if (!this.formData.address || this.formData.address.trim() === '') {
+                this.errors.address = '请填写联系地址'
+                isValid = false
+            }
+
+            if (!this.formData.paymentAccount || this.formData.paymentAccount.trim() === '') {
+                this.errors.paymentAccount = '请选择律师事务所收款账号'
+                isValid = false
+            }
+
+            if (!this.formData.lawFirmName || this.formData.lawFirmName.trim() === '') {
+                this.errors.lawFirmName = '请选择律师事务所名称'
+                isValid = false
+            }
+
+            if (!this.formData.certificate) {
+                this.errors.certificate = '请上传律师资格证'
+                isValid = false
+            }
+
+            return isValid
+        },
+
+        // 提交表单
+        handleSubmit() {
+            if (!this.validateForm()) {
+                this.$modal.msgError('请完善所有必填信息')
+                return
+            }
+
+            this.$modal.loading('提交中...')
+            updateUserProfile(this.formData).then(() => {
+                this.$modal.closeLoading()
+                this.$modal.msgSuccess('提交成功')
+                setTimeout(() => {
+                    uni.navigateBack()
+                }, 1500)
+            }).catch(() => {
+                this.$modal.closeLoading()
+            })
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+page {
+    background-color: #F9FAFC;
+}
+
+input,.picker-view {
+    background-color: #fff !important;
+    width: 676rpx;
+    height: 103rpx;
+    background: #FFFFFF;
+    box-shadow: 0rpx 2rpx 11rpx 0rpx rgba(0, 0, 0, 0.06);
+    border-radius: 23rpx 23rpx 23rpx 23rpx;
+}
+
+.set-user-info-container {
+    min-height: 100vh;
+    padding-bottom: 120rpx;
+}
+
+.page-title {
+    font-size: 36rpx;
+    font-weight: bold;
+    color: #333;
+    text-align: center;
+    padding: 40rpx 0 30rpx;
+    // background-color: #fff;
+}
+
+.form-scroll {
+    height: calc(100vh - 200rpx);
+    padding: 0 30rpx;
+}
+
+.avatar-section {
+    // background-color: #F9FAFC;
+    padding: 40rpx 0;
+    margin-bottom: 20rpx;
+    border-radius: 16rpx;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.avatar-wrapper {
+    position: relative;
+    width: 160rpx;
+    height: 160rpx;
+    border-radius: 50%;
+    overflow: hidden;
+    // background-color: #f0f0f0;
+    margin-bottom: 20rpx;
+}
+
+.avatar-image {
+    width: 100%;
+    height: 100%;
+}
+
+.avatar-placeholder {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    // background-color: #f0f0f0;
+}
+
+.avatar-icon {
+    font-size: 80rpx;
+    color: #ccc;
+}
+
+.camera-icon {
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    width: 48rpx;
+    height: 48rpx;
+    background-color: #4a90e2;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 3rpx solid #fff;
+}
+
+.camera-text {
+    font-size: 24rpx;
+}
+
+.avatar-tip {
+    display: flex;
+    align-items: center;
+    font-size: 28rpx;
+    color: #4a90e2;
+}
+
+.tip-text {
+    margin-right: 4rpx;
+}
+
+.required-mark {
+    color: #ff4d4f;
+    font-size: 28rpx;
+}
+
+.form-section {
+    // background-color: #fff;
+    border-radius: 16rpx;
+    padding: 30rpx;
+    margin-bottom: 20rpx;
+}
+
+.form-item {
+    margin-bottom: 40rpx;
+
+    &:last-child {
+        margin-bottom: 0;
+    }
+}
+
+.form-label {
+    font-size: 28rpx;
+    color: #333;
+    margin-bottom: 20rpx;
+    display: flex;
+    align-items: center;
+}
+
+.form-input {
+    width: 100%;
+    height: 80rpx;
+    background-color: #f8f9fa;
+    border-radius: 12rpx;
+    padding: 0 24rpx;
+    font-size: 28rpx;
+    color: #333;
+    box-sizing: border-box;
+}
+
+.picker-view {
+    width: 100%;
+    height: 80rpx;
+    background-color: #f8f9fa;
+    border-radius: 12rpx;
+    padding: 0 24rpx;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    box-sizing: border-box;
+}
+
+.picker-text {
+    font-size: 28rpx;
+    color: #333;
+}
+
+.picker-placeholder {
+    font-size: 28rpx;
+    color: #999;
+}
+
+.picker-text-ellipsis {
+    flex: 1;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    margin-right: 20rpx;
+}
+
+.picker-arrow {
+    font-size: 40rpx;
+    color: #999;
+    font-weight: 300;
+}
+
+.certificate-upload {
+    width: 100%;
+    height: 300rpx;
+    border: 2rpx dashed #ddd;
+    border-radius: 12rpx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #fafafa;
+    box-sizing: border-box;
+}
+
+.certificate-image {
+    width: 100%;
+    height: 100%;
+    border-radius: 12rpx;
+}
+
+.certificate-placeholder {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+}
+
+.certificate-icon {
+    font-size: 80rpx;
+    margin-bottom: 20rpx;
+}
+
+.certificate-text {
+    font-size: 28rpx;
+    color: #999;
+}
+
+.error-tip {
+    font-size: 24rpx;
+    color: #ff4d4f;
+    margin-top: 10rpx;
+    padding: 8rpx 16rpx;
+    background-color: #fff2f0;
+    border-radius: 8rpx;
+    display: inline-block;
+}
+
+.submit-section {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 20rpx 30rpx;
+    padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
+    background-color: #fff;
+    box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
+}
+
+.submit-btn {
+    width: 100%;
+    height: 88rpx;
+    background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
+    color: #fff;
+    font-size: 32rpx;
+    border-radius: 16rpx;
+    border: none;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+ uni-button:after {
+     border: none !important;
+ }
+
+ .modal-overlay {
+     position: fixed;
+     top: 0;
+     left: 0;
+     right: 0;
+     bottom: 0;
+     background: rgba(0, 0, 0, 0.5);
+    //  display: flex;
+    //  align-items: center;
+    //  justify-content: center;
+     z-index: 1000;
+ }
+
+ .legal-scenario-modal {
+     width: 100%;
+     background: #fff;
+     border-radius: 24rpx 24rpx 0 0;
+     padding: 40rpx 30rpx 30rpx;
+     max-height: 80vh;
+     display: flex;
+     flex-direction: column;
+     position: fixed;
+     left: 0;
+     bottom: 0;
+ }
+
+ .modal-header {
+     position: relative;
+     display: flex;
+     justify-content: center;
+     align-items: center;
+     margin-bottom: 40rpx;
+     padding: 0 60rpx;
+ }
+
+ .modal-title {
+     font-size: 32rpx;
+     font-weight: bold;
+     color: #333;
+     text-align: center;
+ }
+
+ .cancel-btn {
+     font-size: 28rpx;
+     color: #999;
+     position: absolute;
+     right: 30rpx;
+     top: 50%;
+     transform: translateY(-50%);
+ }
+
+ .scenario-tags {
+     display: flex;
+     flex-wrap: wrap;
+     gap: 20rpx;
+     margin-bottom: 40rpx;
+     max-height: 50vh;
+     overflow-y: auto;
+ }
+
+ .scenario-tag {
+     min-width: 200rpx;
+     height: 70rpx;
+     background-color: #f5f5f5;
+     border-radius: 45rpx;
+     display: flex;
+     align-items: center;
+     justify-content: center;
+     font-size: 28rpx;
+     color: #666;
+     flex: 0 0 calc(33.333% - 14rpx);
+     box-sizing: border-box;
+     transition: all 0.3s;
+ }
+
+ .scenario-tag.selected {
+     background:#ECF1FE;
+     color: #2652C2;
+ }
+
+ .confirm-btn {
+     width: 100%;
+     height: 88rpx;
+     background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
+     color: #fff;
+     font-size: 32rpx;
+     border-radius: 16rpx;
+     border: none;
+     display: flex;
+     align-items: center;
+     justify-content: center;
+ }
+ </style>

BIN
static/images/login/back.png


BIN
static/images/login/bg1.png


BIN
static/images/login/bg2.png


BIN
static/images/login/user.png


+ 19 - 1
store/modules/user.js

@@ -2,7 +2,7 @@ import config from '@/config'
 import storage from '@/utils/storage'
 import constant from '@/utils/constant'
 import { isHttp, isEmpty } from "@/utils/validate"
-import { login, logout, getInfo } from '@/api/login'
+import { login, logout, getInfo  } from '@/api/login'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 import defAva from '@/static/images/profile.jpg'
 
@@ -61,6 +61,24 @@ const user = {
         })
       })
     },
+    
+    // 手机号验证码登录
+    LoginBySms({ commit }, userInfo) {
+      const phone = userInfo.phone.trim()
+      const code = userInfo.code
+      return new Promise((resolve, reject) => {
+        setToken('22222')
+        commit('SET_TOKEN', '22222')
+        resolve()
+        // loginBySms(phone, code).then(res => {
+        //   setToken(res.token)
+        //   commit('SET_TOKEN', res.token)
+        //   resolve()
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    },
 
     // 获取用户信息
     GetInfo({ commit, state }) {