Huanyi 1 тиждень тому
батько
коміт
a112234d0e

+ 2 - 1
components/erp-nav-bar.vue

@@ -25,7 +25,8 @@ export default {
 		return { statusBarHeight: 20 }
 	},
 	mounted() {
-		this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20;
+		const winInfo = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync();
+		this.statusBarHeight = winInfo.statusBarHeight || 20;
 	},
 	methods: {
 		handleBack() {

+ 1 - 1
manifest.json

@@ -1,6 +1,6 @@
 {
     "name" : "ERP下单",
-    "appid" : "__UNI__1AAB0CD",
+    "appid" : "__UNI__6B8F647",
     "description" : "",
     "versionName" : "1.0.0",
     "versionCode" : "100",

+ 2 - 1
pages/mine/agreement/index.vue

@@ -28,7 +28,8 @@ export default {
 		}
 	},
 	async onLoad() {
-		this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20;
+		const winInfo = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync();
+		this.statusBarHeight = winInfo.statusBarHeight || 20;
 		try {
 			const res = await getAgreement(1);
 			this.title = res.data.title;

+ 0 - 18
pages/mine/index.vue

@@ -19,9 +19,6 @@
 					</view>
 					<view class="info-box">
 						<text class="nickname">{{ customerInfo ? customerInfo.userName : '' }}</text>
-						<view class="tags-row" v-if="customerInfo">
-							<text class="customer-tag">授权客户: {{ customerInfo.authClientName || '无' }}</text>
-						</view>
 						<text class="phone-text">{{ customerInfo ? customerInfo.phone : '' }}</text>
 					</view>
 					<!-- 新增:右侧设置图标 -->
@@ -328,21 +325,6 @@ export default {
 	color: #333;
 }
 
-.tags-row {
-	display: flex;
-	align-items: center;
-	margin-bottom: 12rpx;
-}
-
-.customer-tag {
-	font-size: 24rpx;
-	color: #C1001C;
-	background: rgba(193, 0, 28, 0.1);
-	padding: 6rpx 16rpx;
-	border-radius: 8rpx;
-	font-weight: 500;
-}
-
 .phone-text {
 	font-size: 26rpx;
 	color: #999;

+ 2 - 1
pages/mine/privacy/index.vue

@@ -28,7 +28,8 @@ export default {
 		}
 	},
 	async onLoad() {
-		this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20;
+		const winInfo = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync();
+		this.statusBarHeight = winInfo.statusBarHeight || 20;
 		try {
 			const res = await getAgreement(2);
 			this.title = res.data.title;

+ 122 - 9
pages/mine/settings/index.vue

@@ -34,13 +34,29 @@
 					<text class="item-value readonly">{{ myInfo.phone }}</text>
 				</view>
 			</view>
-			<view class="item-row no-tap">
-				<text class="item-label">授权客户</text>
-				<view class="item-right">
-					<text class="item-value readonly">{{ myInfo.authClientName || myInfo.authClientRowId || '无'
-					}}</text>
+		</view>
+
+		<!-- 授权客户列表 -->
+		<view class="section-card" style="margin-top: 30rpx;">
+			<view class="section-header">
+				<text class="section-title">授权客户</text>
+				<text class="section-desc" v-if="myInfo.authClientList">共 {{ myInfo.authClientList.length }} 个</text>
+			</view>
+			<view v-if="myInfo.authClientList && myInfo.authClientList.length > 0" class="client-list">
+				<view class="client-item" v-for="(client, idx) in myInfo.authClientList" :key="idx">
+					<view class="client-index">{{ idx + 1 }}</view>
+					<view class="client-info">
+						<text class="client-name">{{ client.name || '-' }}</text>
+						<view class="client-meta">
+							<text class="client-class">{{ client.clientClass || '-' }}</text>
+							<text class="client-date" v-if="client.enterDate">{{ client.enterDate }}</text>
+						</view>
+					</view>
 				</view>
 			</view>
+			<view class="no-client" v-else>
+				<text class="no-client-text">暂无授权客户</text>
+			</view>
 		</view>
 
 		<view class="footer-bar">
@@ -64,8 +80,7 @@ export default {
 				userName: '',
 				phone: '',
 				avatar: null,
-				authClientRowId: '',
-				authClientName: ''
+				authClientList: []
 			}
 		}
 	},
@@ -84,8 +99,7 @@ export default {
 					userName: d.userName || '',
 					phone: d.phone || '',
 					avatar: d.avatar || null,
-					authClientRowId: d.authClientRowId || '',
-					authClientName: d.authClientName || ''
+					authClientList: d.authClientList || []
 				};
 				this.pendingAvatarOssId = null;
 			} catch (e) {
@@ -272,4 +286,103 @@ export default {
 	align-items: center;
 	justify-content: center;
 }
+
+.section-card {
+	background: #fff;
+	border-radius: 24rpx;
+	padding: 30rpx 40rpx;
+}
+
+.section-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	margin-bottom: 24rpx;
+}
+
+.section-title {
+	font-size: 32rpx;
+	font-weight: bold;
+	color: #333;
+}
+
+.section-desc {
+	font-size: 24rpx;
+	color: #999;
+}
+
+.client-list {
+	display: flex;
+	flex-direction: column;
+}
+
+.client-item {
+	display: flex;
+	align-items: center;
+	padding: 24rpx 0;
+	border-bottom: 1rpx solid #f5f6f7;
+}
+
+.client-item:last-child {
+	border-bottom: none;
+}
+
+.client-index {
+	width: 48rpx;
+	height: 48rpx;
+	border-radius: 50%;
+	background: #F5F7FA;
+	color: #666;
+	font-size: 24rpx;
+	font-weight: 600;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	margin-right: 24rpx;
+	flex-shrink: 0;
+}
+
+.client-info {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	gap: 8rpx;
+	min-width: 0;
+}
+
+.client-name {
+	font-size: 28rpx;
+	color: #333;
+	font-weight: 500;
+}
+
+.client-meta {
+	display: flex;
+	align-items: center;
+	gap: 16rpx;
+}
+
+.client-class {
+	font-size: 24rpx;
+	color: #C1001C;
+	background: rgba(193, 0, 28, 0.06);
+	padding: 2rpx 12rpx;
+	border-radius: 6rpx;
+}
+
+.client-date {
+	font-size: 22rpx;
+	color: #999;
+}
+
+.no-client {
+	display: flex;
+	justify-content: center;
+	padding: 40rpx 0;
+}
+
+.no-client-text {
+	font-size: 26rpx;
+	color: #ccc;
+}
 </style>

+ 130 - 32
pages/order/add-model/index.vue

@@ -128,6 +128,13 @@
 					<text class="popup-title">选择产品型号</text>
 					<text class="confirm-text" @click="confirmTypeSelect">确定</text>
 				</view>
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="typeSearchKey" placeholder="输入名称检索"
+							@input="onTypeSearch" />
+					</view>
+				</view>
 				<scroll-view scroll-y class="item-list" @scrolltolower="loadMoreType">
 					<view class="option-item" v-for="(item, index) in typeList" :key="index"
 						:class="{ active: tempSelectedIndex === index }" @click="selectTypeItem(index)">
@@ -153,6 +160,13 @@
 					<text class="popup-title">选择表面处理</text>
 					<text class="confirm-text" @click="confirmSurfaceSelect">确定</text>
 				</view>
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="surfaceSearchKey" placeholder="输入名称检索"
+							@input="onSurfaceSearch" />
+					</view>
+				</view>
 				<scroll-view scroll-y class="item-list" @scrolltolower="loadMoreSurface">
 					<view class="option-item" v-for="(item, index) in surfaceList" :key="index"
 						:class="{ active: tempSurfaceIndex === index }" @click="selectSurfaceItem(index)">
@@ -178,6 +192,13 @@
 					<text class="popup-title">选择包装方式</text>
 					<text class="confirm-text" @click="confirmPackageSelect">确定</text>
 				</view>
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="packageSearchKey" placeholder="输入名称检索"
+							@input="onPackageSearch" />
+					</view>
+				</view>
 				<scroll-view scroll-y class="item-list" @scrolltolower="loadMorePackage">
 					<view class="option-item" v-for="(item, index) in packageList" :key="index"
 						:class="{ active: tempPackageIndex === index }" @click="selectPackageItem(index)">
@@ -213,6 +234,10 @@ export default {
 			typeList: [],
 			surfaceList: [],
 			packageList: [],
+			// 搜索关键词
+			typeSearchKey: '', surfaceSearchKey: '', packageSearchKey: '',
+			// 防抖定时器
+			typeSearchTimer: null, surfaceSearchTimer: null, packageSearchTimer: null,
 			// 分页参数
 			typePageNum: 1, typePageSize: 20, typeHasMore: true, typeLoading: false,
 			surfacePageNum: 1, surfacePageSize: 20, surfaceHasMore: true, surfaceLoading: false,
@@ -232,13 +257,14 @@ export default {
 		]);
 	},
 	methods: {
-		async loadModels(pageNum = 1) {
+		async loadModels(pageNum = 1, keyword = '') {
 			if (this.typeLoading) return;
 			this.typeLoading = true;
 			try {
 				const res = await listPageModel({
 					pageNum: pageNum,
-					pageSize: this.typePageSize
+					pageSize: this.typePageSize,
+					name: keyword
 				});
 				const rows = res.rows || [];
 				const total = res.total || 0;
@@ -254,73 +280,107 @@ export default {
 				this.typeLoading = false;
 			}
 		},
-		async loadPackageMethods(pageNum = 1) {
-			if (this.packageLoading) return;
-			this.packageLoading = true;
+		async loadSurfaceKinds(pageNum = 1, keyword = '') {
+			if (this.surfaceLoading) return;
+			this.surfaceLoading = true;
 			try {
-				const res = await listPagePack({
+				const res = await listPageColor({
 					pageNum: pageNum,
-					pageSize: this.packagePageSize
+					pageSize: this.surfacePageSize,
+					name: keyword
 				});
-				const rows = res.rows || [];
+				let rows = res.rows || [];
 				const total = res.total || 0;
+				rows = rows.filter(item => item.name);
 				if (pageNum === 1) {
-					this.packageList = rows;
+					this.surfaceList = rows;
 				} else {
-					this.packageList = [...this.packageList, ...rows];
+					this.surfaceList = [...this.surfaceList, ...rows];
 				}
-				this.packageHasMore = this.packageList.length < total;
+				this.surfaceHasMore = this.surfaceList.length < total;
 			} catch (e) {
-				uni.showToast({ title: e || '加载包装方式失败', icon: 'none' });
+				uni.showToast({ title: e || '加载表面处理失败', icon: 'none' });
 			} finally {
-				this.packageLoading = false;
+				this.surfaceLoading = false;
 			}
 		},
-		async loadSurfaceKinds(pageNum = 1) {
-			if (this.surfaceLoading) return;
-			this.surfaceLoading = true;
+		async loadPackageMethods(pageNum = 1, keyword = '') {
+			if (this.packageLoading) return;
+			this.packageLoading = true;
 			try {
-				const res = await listPageColor({
+				const res = await listPagePack({
 					pageNum: pageNum,
-					pageSize: this.surfacePageSize
+					pageSize: this.packagePageSize,
+					name: keyword
 				});
-				let rows = res.rows || [];
+				const rows = res.rows || [];
 				const total = res.total || 0;
-				// 过滤未设置名称的非完整颜色数据
-				rows = rows.filter(item => item.name);
 				if (pageNum === 1) {
-					this.surfaceList = rows;
+					this.packageList = rows;
 				} else {
-					this.surfaceList = [...this.surfaceList, ...rows];
+					this.packageList = [...this.packageList, ...rows];
 				}
-				this.surfaceHasMore = this.surfaceList.length < total;
+				this.packageHasMore = this.packageList.length < total;
 			} catch (e) {
-				uni.showToast({ title: e || '加载表面处理失败', icon: 'none' });
+				uni.showToast({ title: e || '加载包装方式失败', icon: 'none' });
 			} finally {
-				this.surfaceLoading = false;
+				this.packageLoading = false;
 			}
 		},
 		loadMoreType() {
 			if (this.typeHasMore && !this.typeLoading) {
 				this.typePageNum++;
-				this.loadModels(this.typePageNum);
+				this.loadModels(this.typePageNum, this.typeSearchKey);
 			}
 		},
 		loadMoreSurface() {
 			if (this.surfaceHasMore && !this.surfaceLoading) {
 				this.surfacePageNum++;
-				this.loadSurfaceKinds(this.surfacePageNum);
+				this.loadSurfaceKinds(this.surfacePageNum, this.surfaceSearchKey);
 			}
 		},
 		loadMorePackage() {
 			if (this.packageHasMore && !this.packageLoading) {
 				this.packagePageNum++;
-				this.loadPackageMethods(this.packagePageNum);
+				this.loadPackageMethods(this.packagePageNum, this.packageSearchKey);
 			}
 		},
 		onScrollToLower() {
 			// 主页面滚动触底,可根据需要添加更多逻辑
 		},
+		/**
+		 * 型号搜索(防抖)
+		 * @Author: Antigravity
+		 */
+		onTypeSearch() {
+			if (this.typeSearchTimer) clearTimeout(this.typeSearchTimer);
+			this.typeSearchTimer = setTimeout(() => {
+				this.typePageNum = 1;
+				this.loadModels(1, this.typeSearchKey);
+			}, 300);
+		},
+		/**
+		 * 表面处理搜索(防抖)
+		 * @Author: Antigravity
+		 */
+		onSurfaceSearch() {
+			if (this.surfaceSearchTimer) clearTimeout(this.surfaceSearchTimer);
+			this.surfaceSearchTimer = setTimeout(() => {
+				this.surfacePageNum = 1;
+				this.loadSurfaceKinds(1, this.surfaceSearchKey);
+			}, 300);
+		},
+		/**
+		 * 包装方式搜索(防抖)
+		 * @Author: Antigravity
+		 */
+		onPackageSearch() {
+			if (this.packageSearchTimer) clearTimeout(this.packageSearchTimer);
+			this.packageSearchTimer = setTimeout(() => {
+				this.packagePageNum = 1;
+				this.loadPackageMethods(1, this.packageSearchKey);
+			}, 300);
+		},
 		openTypePicker() {
 			if (this.formData.type) {
 				this.tempSelectedIndex = this.typeList.findIndex(item => item.num === this.formData.type);
@@ -329,7 +389,11 @@ export default {
 			}
 			this.showTypePicker = true;
 		},
-		closeTypePicker() { this.showTypePicker = false; },
+		closeTypePicker() {
+			this.showTypePicker = false;
+			this.typeSearchKey = '';
+			this.typePageNum = 1;
+		},
 		selectTypeItem(index) { this.tempSelectedIndex = index; },
 		confirmTypeSelect() {
 			if (this.tempSelectedIndex === -1) return;
@@ -348,7 +412,11 @@ export default {
 			}
 			this.showSurfacePicker = true;
 		},
-		closeSurfacePicker() { this.showSurfacePicker = false; },
+		closeSurfacePicker() {
+			this.showSurfacePicker = false;
+			this.surfaceSearchKey = '';
+			this.surfacePageNum = 1;
+		},
 		selectSurfaceItem(index) { this.tempSurfaceIndex = index; },
 		confirmSurfaceSelect() {
 			if (this.tempSurfaceIndex === -1) return;
@@ -365,7 +433,11 @@ export default {
 			}
 			this.showPackagePicker = true;
 		},
-		closePackagePicker() { this.showPackagePicker = false; },
+		closePackagePicker() {
+			this.showPackagePicker = false;
+			this.packageSearchKey = '';
+			this.packagePageNum = 1;
+		},
 		selectPackageItem(index) { this.tempPackageIndex = index; },
 		confirmPackageSelect() {
 			if (this.tempPackageIndex === -1) return;
@@ -678,6 +750,32 @@ export default {
 	padding: 0 40rpx;
 }
 
+/* 搜索栏样式 */
+.search-bar {
+	padding: 16rpx 40rpx;
+	border-bottom: 1rpx solid #f0f0f0;
+}
+
+.search-input-wrap {
+	display: flex;
+	align-items: center;
+	background: #f5f6f8;
+	border-radius: 32rpx;
+	padding: 12rpx 24rpx;
+}
+
+.search-icon {
+	font-size: 28rpx;
+	margin-right: 12rpx;
+}
+
+.search-input {
+	flex: 1;
+	font-size: 26rpx;
+	color: #333;
+	height: 56rpx;
+}
+
 .option-item {
 	height: 110rpx;
 	display: flex;

+ 1 - 1
pages/order/detail/index.vue

@@ -114,7 +114,7 @@ export default {
 		scrollHeight() {
 			const info = uni.getSystemInfoSync();
 			const safeBottom = info.safeAreaInsets ? info.safeAreaInsets.bottom : 0;
-			const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20;
+			const statusBarHeight = info.statusBarHeight || 20;
 			return `calc(100vh - ${statusBarHeight + 164}px - ${80 + safeBottom}px)`;
 		}
 	},

+ 245 - 23
pages/order/edit-model/index.vue

@@ -128,10 +128,17 @@
 					<text class="popup-title">选择产品型号</text>
 					<text class="confirm-text" @click="confirmTypeSelect">确定</text>
 				</view>
-				<scroll-view scroll-y class="item-list">
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="typeSearchKey" placeholder="输入名称检索"
+							@input="onTypeSearch" />
+					</view>
+				</view>
+				<scroll-view scroll-y class="item-list" @scrolltolower="loadMoreType">
 					<view class="option-item" v-for="(item, index) in typeList" :key="index"
 						:class="{ active: tempSelectedIndex === index }" @click="selectTypeItem(index)">
-						<text>{{ item }}</text>
+						<text>{{ item.num }} - {{ item.name }}</text>
 						<icon type="success_no_circle" size="16" color="#C1001C" v-if="tempSelectedIndex === index">
 						</icon>
 					</view>
@@ -147,10 +154,17 @@
 					<text class="popup-title">选择表面处理</text>
 					<text class="confirm-text" @click="confirmSurfaceSelect">确定</text>
 				</view>
-				<scroll-view scroll-y class="item-list">
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="surfaceSearchKey" placeholder="输入名称检索"
+							@input="onSurfaceSearch" />
+					</view>
+				</view>
+				<scroll-view scroll-y class="item-list" @scrolltolower="loadMoreSurface">
 					<view class="option-item" v-for="(item, index) in surfaceList" :key="index"
 						:class="{ active: tempSurfaceIndex === index }" @click="selectSurfaceItem(index)">
-						<text>{{ item }}</text>
+						<text>{{ item.num }} - {{ item.name }}</text>
 						<icon type="success_no_circle" size="16" color="#C1001C" v-if="tempSurfaceIndex === index">
 						</icon>
 					</view>
@@ -166,10 +180,17 @@
 					<text class="popup-title">选择包装方式</text>
 					<text class="confirm-text" @click="confirmPackageSelect">确定</text>
 				</view>
-				<scroll-view scroll-y class="item-list">
+				<view class="search-bar">
+					<view class="search-input-wrap">
+						<text class="search-icon">🔍</text>
+						<input class="search-input" type="text" v-model="packageSearchKey" placeholder="输入名称检索"
+							@input="onPackageSearch" />
+					</view>
+				</view>
+				<scroll-view scroll-y class="item-list" @scrolltolower="loadMorePackage">
 					<view class="option-item" v-for="(item, index) in packageList" :key="index"
 						:class="{ active: tempPackageIndex === index }" @click="selectPackageItem(index)">
-						<text>{{ item }}</text>
+						<text>{{ item.num }} - {{ item.name }}</text>
 						<icon type="success_no_circle" size="16" color="#C1001C" v-if="tempPackageIndex === index">
 						</icon>
 					</view>
@@ -182,6 +203,10 @@
 
 <script>
 import ErpNavBar from '@/components/erp-nav-bar.vue';
+import { listPageColor } from '@/api/erp/color.js';
+import { listPagePack } from '@/api/erp/pack.js';
+import { listPageModel } from '@/api/erp/model.js';
+import { addOrderDetail } from '@/api/erp/orderDetail.js';
 export default {
 	components: { ErpNavBar },
 	data() {
@@ -189,40 +214,212 @@ export default {
 			itemIndex: -1,
 			showTypePicker: false, showSurfacePicker: false, showPackagePicker: false,
 			tempSelectedIndex: -1, tempSurfaceIndex: -1, tempPackageIndex: -1,
-			typeList: ['TY0018', 'TY0019', 'TY0020', 'TY0021', 'TY0022', 'TY0023', 'TY0024', 'TY0025', 'TY0026', 'TY0027', 'TY0028'],
-			surfaceList: ['PL坯料', '阳极氧化', '电泳涂漆', '粉末喷涂', '氟碳喷涂', '木纹转印'],
-			packageList: ['不贴膜+3点捆扎', '贴膜+纸箱', '气泡膜包装', '简易编织袋', '木托架包装'],
+			typeList: [],
+			surfaceList: [],
+			packageList: [],
+			// 搜索关键词
+			typeSearchKey: '', surfaceSearchKey: '', packageSearchKey: '',
+			// 防抖定时器
+			typeSearchTimer: null, surfaceSearchTimer: null, packageSearchTimer: null,
+			// 分页参数
+			typePageNum: 1, typePageSize: 20, typeHasMore: true, typeLoading: false,
+			surfacePageNum: 1, surfacePageSize: 20, surfaceHasMore: true, surfaceLoading: false,
+			packagePageNum: 1, packagePageSize: 20, packageHasMore: true, packageLoading: false,
 			formData: {
-				type: '', name: '', material: '',
-				surfaceName: '', packageMethod: '', length: '',
+				type: '', modelId: '', name: '', material: '',
+				surfaceName: '', surfaceId: '', packageMethod: '', packageId: '', length: '',
 				wallThickness: '', count: ''
 			}
 		}
 	},
-	onLoad(options) {
+	async onLoad(options) {
 		if (options.data) {
 			try {
 				const item = JSON.parse(decodeURIComponent(options.data));
-				this.formData = item;
+				this.formData.type = item.modelNum || '';
+				this.formData.modelId = item.modelId || '';
+				this.formData.name = item.modelName || '';
+				this.formData.material = item.material || '';
+				this.formData.surfaceName = item.surfaceName || '';
+				this.formData.surfaceId = item.surfaceId || '';
+				this.formData.packageMethod = item.packName || '';
+				this.formData.packageId = item.packId || '';
+				this.formData.length = item.length || '';
+				this.formData.wallThickness = item.wallThickness || '';
+				this.formData.count = item.count || '';
 				this.itemIndex = parseInt(options.index || -1);
 			} catch (e) {
 				console.error('Data parse error', e);
 			}
 		}
+		await Promise.all([
+			this.loadModels(),
+			this.loadSurfaceKinds(),
+			this.loadPackageMethods()
+		]);
 	},
 	methods: {
-		openTypePicker() { if (this.formData.type) this.tempSelectedIndex = this.typeList.indexOf(this.formData.type); this.showTypePicker = true; },
-		closeTypePicker() { this.showTypePicker = false; },
+		async loadModels(pageNum = 1, keyword = '') {
+			if (this.typeLoading) return;
+			this.typeLoading = true;
+			try {
+				const res = await listPageModel({ pageNum, pageSize: this.typePageSize, name: keyword });
+				const rows = res.rows || [];
+				const total = res.total || 0;
+				if (pageNum === 1) {
+					this.typeList = rows;
+				} else {
+					this.typeList = [...this.typeList, ...rows];
+				}
+				this.typeHasMore = this.typeList.length < total;
+			} catch (e) {
+				console.error('加载型号失败', e);
+			} finally {
+				this.typeLoading = false;
+			}
+		},
+		async loadSurfaceKinds(pageNum = 1, keyword = '') {
+			if (this.surfaceLoading) return;
+			this.surfaceLoading = true;
+			try {
+				const res = await listPageColor({ pageNum, pageSize: this.surfacePageSize, name: keyword });
+				let rows = (res.rows || []).filter(item => item.name);
+				const total = res.total || 0;
+				if (pageNum === 1) {
+					this.surfaceList = rows;
+				} else {
+					this.surfaceList = [...this.surfaceList, ...rows];
+				}
+				this.surfaceHasMore = this.surfaceList.length < total;
+			} catch (e) {
+				console.error('加载表面处理失败', e);
+			} finally {
+				this.surfaceLoading = false;
+			}
+		},
+		async loadPackageMethods(pageNum = 1, keyword = '') {
+			if (this.packageLoading) return;
+			this.packageLoading = true;
+			try {
+				const res = await listPagePack({ pageNum, pageSize: this.packagePageSize, name: keyword });
+				const rows = res.rows || [];
+				const total = res.total || 0;
+				if (pageNum === 1) {
+					this.packageList = rows;
+				} else {
+					this.packageList = [...this.packageList, ...rows];
+				}
+				this.packageHasMore = this.packageList.length < total;
+			} catch (e) {
+				console.error('加载包装方式失败', e);
+			} finally {
+				this.packageLoading = false;
+			}
+		},
+		loadMoreType() {
+			if (this.typeHasMore && !this.typeLoading) {
+				this.typePageNum++;
+				this.loadModels(this.typePageNum, this.typeSearchKey);
+			}
+		},
+		loadMoreSurface() {
+			if (this.surfaceHasMore && !this.surfaceLoading) {
+				this.surfacePageNum++;
+				this.loadSurfaceKinds(this.surfacePageNum, this.surfaceSearchKey);
+			}
+		},
+		loadMorePackage() {
+			if (this.packageHasMore && !this.packageLoading) {
+				this.packagePageNum++;
+				this.loadPackageMethods(this.packagePageNum, this.packageSearchKey);
+			}
+		},
+		onTypeSearch() {
+			if (this.typeSearchTimer) clearTimeout(this.typeSearchTimer);
+			this.typeSearchTimer = setTimeout(() => {
+				this.typePageNum = 1;
+				this.loadModels(1, this.typeSearchKey);
+			}, 300);
+		},
+		onSurfaceSearch() {
+			if (this.surfaceSearchTimer) clearTimeout(this.surfaceSearchTimer);
+			this.surfaceSearchTimer = setTimeout(() => {
+				this.surfacePageNum = 1;
+				this.loadSurfaceKinds(1, this.surfaceSearchKey);
+			}, 300);
+		},
+		onPackageSearch() {
+			if (this.packageSearchTimer) clearTimeout(this.packageSearchTimer);
+			this.packageSearchTimer = setTimeout(() => {
+				this.packagePageNum = 1;
+				this.loadPackageMethods(1, this.packageSearchKey);
+			}, 300);
+		},
+		openTypePicker() {
+			if (this.formData.type) {
+				this.tempSelectedIndex = this.typeList.findIndex(item => item.num === this.formData.type);
+			} else {
+				this.tempSelectedIndex = -1;
+			}
+			this.showTypePicker = true;
+		},
+		closeTypePicker() {
+			this.showTypePicker = false;
+			this.typeSearchKey = '';
+			this.typePageNum = 1;
+		},
 		selectTypeItem(index) { this.tempSelectedIndex = index; },
-		confirmTypeSelect() { if (this.tempSelectedIndex === -1) return; const val = this.typeList[this.tempSelectedIndex]; this.formData.type = val; this.formData.name = '工业铝材'; this.formData.material = (this.tempSelectedIndex % 2 === 0) ? '6063-T5' : '6061-T6'; this.closeTypePicker(); },
-		openSurfacePicker() { if (this.formData.surfaceName) this.tempSurfaceIndex = this.surfaceList.indexOf(this.formData.surfaceName); this.showSurfacePicker = true; },
-		closeSurfacePicker() { this.showSurfacePicker = false; },
+		confirmTypeSelect() {
+			if (this.tempSelectedIndex === -1) return;
+			const item = this.typeList[this.tempSelectedIndex];
+			this.formData.type = item.num;
+			this.formData.modelId = item.rowId;
+			this.formData.name = item.name;
+			this.formData.material = '6063-T5';
+			this.closeTypePicker();
+		},
+		openSurfacePicker() {
+			if (this.formData.surfaceName) {
+				this.tempSurfaceIndex = this.surfaceList.findIndex(item => item.name === this.formData.surfaceName);
+			} else {
+				this.tempSurfaceIndex = -1;
+			}
+			this.showSurfacePicker = true;
+		},
+		closeSurfacePicker() {
+			this.showSurfacePicker = false;
+			this.surfaceSearchKey = '';
+			this.surfacePageNum = 1;
+		},
 		selectSurfaceItem(index) { this.tempSurfaceIndex = index; },
-		confirmSurfaceSelect() { if (this.tempSurfaceIndex === -1) return; this.formData.surfaceName = this.surfaceList[this.tempSurfaceIndex]; this.closeSurfacePicker(); },
-		openPackagePicker() { if (this.formData.packageMethod) this.tempPackageIndex = this.packageList.indexOf(this.formData.packageMethod); this.showPackagePicker = true; },
-		closePackagePicker() { this.showPackagePicker = false; },
+		confirmSurfaceSelect() {
+			if (this.tempSurfaceIndex === -1) return;
+			const item = this.surfaceList[this.tempSurfaceIndex];
+			this.formData.surfaceName = item.name;
+			this.formData.surfaceId = item.rowId;
+			this.closeSurfacePicker();
+		},
+		openPackagePicker() {
+			if (this.formData.packageMethod) {
+				this.tempPackageIndex = this.packageList.findIndex(item => item.name === this.formData.packageMethod);
+			} else {
+				this.tempPackageIndex = -1;
+			}
+			this.showPackagePicker = true;
+		},
+		closePackagePicker() {
+			this.showPackagePicker = false;
+			this.packageSearchKey = '';
+			this.packagePageNum = 1;
+		},
 		selectPackageItem(index) { this.tempPackageIndex = index; },
-		confirmPackageSelect() { if (this.tempPackageIndex === -1) return; this.formData.packageMethod = this.packageList[this.tempPackageIndex]; this.closePackagePicker(); },
+		confirmPackageSelect() {
+			if (this.tempPackageIndex === -1) return;
+			const item = this.packageList[this.tempPackageIndex];
+			this.formData.packageMethod = item.name;
+			this.formData.packageId = item.rowId;
+			this.closePackagePicker();
+		},
 		saveEdit() {
 			const fields = [
 				{ key: 'type', label: '型号' },
@@ -238,7 +435,6 @@ export default {
 					return;
 				}
 			}
-
 			uni.$emit('update_order_item', {
 				index: this.itemIndex,
 				data: JSON.parse(JSON.stringify(this.formData))
@@ -505,6 +701,32 @@ export default {
 	padding: 0 40rpx;
 }
 
+/* 搜索栏样式 */
+.search-bar {
+	padding: 16rpx 40rpx;
+	border-bottom: 1rpx solid #f0f0f0;
+}
+
+.search-input-wrap {
+	display: flex;
+	align-items: center;
+	background: #f5f6f8;
+	border-radius: 32rpx;
+	padding: 12rpx 24rpx;
+}
+
+.search-icon {
+	font-size: 28rpx;
+	margin-right: 12rpx;
+}
+
+.search-input {
+	flex: 1;
+	font-size: 26rpx;
+	color: #333;
+	height: 56rpx;
+}
+
 .option-item {
 	height: 110rpx;
 	display: flex;

+ 77 - 3
pages/order/index.vue

@@ -39,6 +39,12 @@
 		<template v-else>
 			<scroll-view scroll-y class="order-scroll-list" :show-scrollbar="false" :enhanced="true">
 				<view class="list-wrapper">
+					<!-- 已选客户信息 -->
+					<view class="client-info-bar" v-if="selectedClientName">
+						<text class="client-label">下单客户:</text>
+						<text class="client-name-text">{{ selectedClientName }}</text>
+					</view>
+
 					<!-- 列表头部:仅在有数据时显示 -->
 					<view class="list-header" v-if="selectedModels.length > 0">
 						<text class="header-text">已选型号列表:</text>
@@ -117,7 +123,9 @@ export default {
 			isLoggedIn: false,
 			isLoading: true, // 初始为加载中
 			myInfo: {},
-			selectedModels: []
+			selectedModels: [],
+			selectedClientId: '',
+			selectedClientName: ''
 		}
 	},
 	computed: {
@@ -164,6 +172,9 @@ export default {
 			if (!token) {
 				this.isLoggedIn = false;
 				this.myInfo = {};
+				this.selectedClientId = '';
+				this.selectedClientName = '';
+				this.isLoading = false;
 				return;
 			}
 			try {
@@ -178,6 +189,8 @@ export default {
 				uni.removeStorageSync('isLogin');
 				this.isLoggedIn = false;
 				this.myInfo = {};
+				this.selectedClientId = '';
+				this.selectedClientName = '';
 				this.isLoading = false;
 			}
 		},
@@ -210,12 +223,51 @@ export default {
 		async submitFinalOrder() {
 			if (this.selectedModels.length === 0) return;
 
+			const clientList = this.myInfo.authClientList || [];
+			if (clientList.length === 0) {
+				uni.showToast({ title: '暂无授权客户,无法下单', icon: 'none' });
+				return;
+			}
+
+			// 单个授权客户:直接用
+			if (clientList.length === 1) {
+				this.selectedClientId = clientList[0].rowId;
+				this.selectedClientName = clientList[0].name;
+				this.doSubmitOrder();
+				return;
+			}
+
+			// 多个授权客户:弹出选择器
+			const clientNames = clientList.map(c => c.name);
+			const res = await new Promise((resolve) => {
+				uni.showActionSheet({
+					itemList: clientNames,
+					success: (r) => resolve(r),
+					fail: () => resolve(null)
+				});
+			});
+			if (res && res.tapIndex !== undefined) {
+				const chosen = clientList[res.tapIndex];
+				this.selectedClientId = chosen.rowId;
+				this.selectedClientName = chosen.name;
+				this.doSubmitOrder();
+			}
+		},
+		/**
+		 * 执行下单请求
+		 * @Author: Antigravity
+		 */
+		async doSubmitOrder() {
 			uni.showLoading({ title: '正在提交订单', mask: true });
 			try {
 				const detailIds = this.selectedModels.map(item => item.rowId);
-				const res = await addOrder({ detailIds });
+				const submitRes = await addOrder({
+					detailIds,
+					clientId: this.selectedClientId,
+					clientName: this.selectedClientName
+				});
 				uni.hideLoading();
-				const orderId = res.data;
+				const orderId = submitRes.data;
 				uni.showToast({ title: '下单成功', icon: 'success' });
 				setTimeout(() => {
 					uni.navigateTo({
@@ -681,4 +733,26 @@ export default {
 	color: #999;
 	letter-spacing: 2rpx;
 }
+
+/* 已选客户信息栏 */
+.client-info-bar {
+	display: flex;
+	align-items: center;
+	padding: 24rpx 32rpx;
+	margin-bottom: 20rpx;
+	background: linear-gradient(135deg, #FFF1F2 0%, #FFFFFF 100%);
+	border-radius: 16rpx;
+	border: 1rpx solid rgba(193, 0, 28, 0.1);
+}
+
+.client-label {
+	font-size: 26rpx;
+	color: #999;
+}
+
+.client-name-text {
+	font-size: 30rpx;
+	font-weight: bold;
+	color: #C1001C;
+}
 </style>

+ 3 - 4
pages/order/list/index.vue

@@ -108,10 +108,9 @@ export default {
 		}
 	},
 	onLoad(options) {
-		const info = uni.getSystemInfoSync();
-		this.statusBarHeight = info.statusBarHeight;
-		// 修正选项卡高度(单位px)
-		this.tabBarHeight = info.windowWidth / 750 * 110;
+		const winInfo = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync();
+		this.statusBarHeight = winInfo.statusBarHeight;
+		this.tabBarHeight = winInfo.windowWidth / 750 * 110;
 
 		if (options.tab) this.currentTab = parseInt(options.tab);
 		this.refresh();

+ 3 - 1
utils/request.js

@@ -1,4 +1,6 @@
-const BASE_URL = 'http://127.0.0.1:8080';
+// const BASE_URL = 'http://127.0.0.1:8080';
+// const BASE_URL = 'http://192.168.1.205:8080';
+const BASE_URL = 'https://app.jxhsal.com/api';
 
 const CLIENT_ID = 'e48ac397bff4f031b14d6e671eee49c3';