From c8d12c37b3f78e41aafef1ccb3e380573308c34a Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期二, 04 八月 2026 17:41:46 +0800
Subject: [PATCH] feat(admin): 添加商户登录密码修改功能并完善优惠券金额验证

---
 talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java      |    2 
 rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue                                             |    8 +
 rencaika_merchant/manifest.json                                                                              |    2 
 rencaika_merchant/pages/verification-detail/verification-detail.uvue                                         |    8 -
 talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java              |   11 ++
 rencaika_merchant/config/api.uts                                                                             |    9 +
 rencaika_merchant/pages/orders/orders.uvue                                                                   |   21 ---
 talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponUpdateRequest.java               |    3 
 talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantUpdateRequest.java             |    3 
 talent-card-admin/src/views/MerchantCreateView.vue                                                           |   37 +++++-
 talent-card-server/src/main/resources/application.yml                                                        |   31 ++---
 rencaika_merchant/pages/withdrawal/withdrawal.uvue                                                           |    5 
 rencaika_merchant/pages/order-detail/order-detail.uvue                                                       |   72 +++----------
 rencaika_merchant/services/settlement.uts                                                                    |    4 
 talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponCreateRequest.java               |    3 
 talent-card-server/src/main/java/com/talentcard/server/business/merchant/HuifuMerchantWithdrawalService.java |   15 ++
 talent-card-admin/src/style.css                                                                              |   30 ++++++
 rencaika_merchant/pages/merchant/merchant.uvue                                                               |   17 ---
 talent-card-admin/src/views/MerchantSettlementView.vue                                                       |    6 
 19 files changed, 149 insertions(+), 138 deletions(-)

diff --git a/rencaika_merchant/config/api.uts b/rencaika_merchant/config/api.uts
index 8b9a674..7c423f4 100644
--- a/rencaika_merchant/config/api.uts
+++ b/rencaika_merchant/config/api.uts
@@ -9,13 +9,14 @@
 
 // Toggle homepage mock metrics independently from the login bypass.
 // When disabled, the dashboard requests the authenticated merchant summary API.
-export const useDashboardDemoDataInDevelopment = true
+export const useDashboardDemoDataInDevelopment = false
 
-// 商户中心、商品与营业时间的演示数据开关,与登录跳过和首页经营数据开关相互独立。
-export const useMerchantManagementDemoDataInDevelopment = true
+// Toggle merchant-center, product, and business-hour demo data independently from login bypass and dashboard demo data.
+export const useMerchantManagementDemoDataInDevelopment = false
 
 // 后台提供微信小程序合法 HTTPS 域名后,在对应环境填写完整基础地址。
-const developmentBaseUrl = 'http://192.168.110.13:8080'
+//const developmentBaseUrl = 'http://192.168.110.13:8080'
+const developmentBaseUrl = 'http://221.182.45.100:11451'
 const stagingBaseUrl = ''
 const productionBaseUrl = ''
 
diff --git a/rencaika_merchant/manifest.json b/rencaika_merchant/manifest.json
index b8b7add..aad0f3f 100644
--- a/rencaika_merchant/manifest.json
+++ b/rencaika_merchant/manifest.json
@@ -9,7 +9,7 @@
 	"quickapp": {},
 	/* 小程序特有相关 */
 	"mp-weixin": {
-		"appid": "wxfb87c6ef164c2922",
+		"appid": "wxe91f1af7638aa5dd",
 		"setting": {
 			"urlCheck": false
 		},
diff --git a/rencaika_merchant/pages/merchant/merchant.uvue b/rencaika_merchant/pages/merchant/merchant.uvue
index 35c0496..5fdb03f 100644
--- a/rencaika_merchant/pages/merchant/merchant.uvue
+++ b/rencaika_merchant/pages/merchant/merchant.uvue
@@ -37,12 +37,10 @@
 </template>
 
 <script setup lang="uts">
-	import { apiEnvironment, useMerchantManagementDemoDataInDevelopment } from '../../config/api.uts'
 	import { hasActiveSession } from '../../services/session.uts'
-	import { MerchantProfile, loadDemoMerchantProfile, loadMerchantProfile, updateDemoMerchantBusinessStatus, updateMerchantBusinessStatus } from '../../services/merchant-management.uts'
+	import { MerchantProfile, loadMerchantProfile, updateMerchantBusinessStatus } from '../../services/merchant-management.uts'
 
-	const useDemoData = apiEnvironment == 'development' && useMerchantManagementDemoDataInDevelopment
-	const merchant = ref<MerchantProfile>(loadDemoMerchantProfile())
+	const merchant = ref<MerchantProfile>({ merchantId: '', storeId: '', merchantName: '', storeName: '', address: '', coverUrl: '', businessStatus: '', onlineProductCount: 0 })
 	const loadState = ref('loading')
 	const traceId = ref('')
 	const businessUpdating = ref(false)
@@ -56,11 +54,6 @@
 		}
 		loadState.value = 'loading'
 		traceId.value = ''
-		if (useDemoData) {
-			merchant.value = loadDemoMerchantProfile()
-			loadState.value = 'success'
-			return
-		}
 		if (!hasActiveSession()) {
 			loadState.value = 'error'
 			return
@@ -81,12 +74,6 @@
 		if (businessUpdating.value || loadState.value != 'success') return
 		const nextStatus = isBusinessOpen.value ? 'closed' : 'open'
 		businessUpdating.value = true
-		if (useDemoData) {
-			merchant.value = updateDemoMerchantBusinessStatus(nextStatus)
-			businessUpdating.value = false
-			uni.showToast({ title: nextStatus == 'open' ? '已切换为营业中' : '已切换为休息中', icon: 'none' })
-			return
-		}
 		updateMerchantBusinessStatus(nextStatus, (result: MerchantProfile, _traceId: string) => {
 			merchant.value.businessStatus = result.businessStatus
 			businessUpdating.value = false
diff --git a/rencaika_merchant/pages/order-detail/order-detail.uvue b/rencaika_merchant/pages/order-detail/order-detail.uvue
index d69d7f6..8b1b86c 100644
--- a/rencaika_merchant/pages/order-detail/order-detail.uvue
+++ b/rencaika_merchant/pages/order-detail/order-detail.uvue
@@ -37,8 +37,6 @@
 <script setup lang="uts">
 	import { revokeOrderVerification } from '../../services/orders.uts'
 	import { loadMerchantOrderDetail, MerchantOrderDetail } from '../../services/orders.uts'
-	import { apiEnvironment } from '../../config/api.uts'
-	import { getLocalOrderDetail } from '../../config/order-demo-data.uts'
 	import { formatErrorMessage } from '../../services/diagnostics.uts'
 
 	const orderId = ref('')
@@ -47,20 +45,19 @@
 	const canRevokeVerification = ref(false)
 	const revokeExpiredMessage = ref('已过可撤销时间')
 	const revokeSubmitting = ref(false)
-	const statusTitle = ref('待支付')
-	const statusDesc = ref('订单已生成,等待用户完成支付后即可继续核销。')
+	const statusTitle = ref('订单加载中')
+	const statusDesc = ref('正在获取订单详情。')
 	const statusIcon = ref('/static/icons/lucide/clock-3.svg')
-	const orderNo = ref('155464871234')
-	const productAmount = ref('¥256.00')
-	const talentDiscount = ref('-¥128.00')
-	const productDiscount = ref('-¥0.00')
-	const paidAmount = ref('¥128.00')
-	const subsidyAmount = ref('¥128.00')
-	const createdAt = ref('2026-07-27 10:26:15')
-	const verificationAt = ref('待核销')
-	const customerName = ref('刘先生')
-	const customerPhone = ref('183***4568')
-	const useDemoData = (): boolean => apiEnvironment == 'development' && uni.getStorageSync('merchant-orders-demo-data') != false
+	const orderNo = ref('')
+	const productAmount = ref('')
+	const talentDiscount = ref('')
+	const productDiscount = ref('')
+	const paidAmount = ref('')
+	const subsidyAmount = ref('')
+	const createdAt = ref('')
+	const verificationAt = ref('')
+	const customerName = ref('')
+	const customerPhone = ref('')
 	const formatCents = (value: number): string => '¥' + (value / 100).toFixed(2)
 
 	const applyRemoteOrder = (detail: MerchantOrderDetail) => {
@@ -86,33 +83,15 @@
 	onLoad((options: any) => {
 		orderId.value = options.id != null ? options.id as string : ''
 		orderNo.value = options.orderNo != null ? options.orderNo as string : orderNo.value
-		if (!useDemoData() && orderNo.value.length > 0) {
-			loadMerchantOrderDetail(orderNo.value, (detail: MerchantOrderDetail, _traceId: string) => applyRemoteOrder(detail), (error: any) => {
-				uni.showToast({ title: error.message != null ? error.message : '订单详情加载失败', icon: 'none' })
-			})
+		if (orderNo.value.length == 0) {
+			uni.showToast({ title: '订单参数缺失', icon: 'none' })
 			return
 		}
-		const detail = getLocalOrderDetail(orderId.value)
-		isStoreCompleted.value = detail.category == 'store' && detail.status == 'completed'
-		isCompleted.value = detail.status == 'completed'
-		orderNo.value = detail.orderNo
-		productAmount.value = detail.productAmount
-		talentDiscount.value = detail.talentDiscount
-		productDiscount.value = detail.productDiscount
-		paidAmount.value = detail.paidAmount
-		subsidyAmount.value = detail.subsidyAmount
-		createdAt.value = detail.createdAt
-		verificationAt.value = detail.verificationAt
-		customerName.value = detail.customerName
-		customerPhone.value = detail.customerPhone
-		canRevokeVerification.value = detail.canRevoke
-		if (detail.revokeReason.length > 0) revokeExpiredMessage.value = detail.revokeReason
-
-		if (isCompleted.value) {
-			statusTitle.value = '已完成'
-			statusDesc.value = '订单已完成核销,相关权益已结算。'
-			statusIcon.value = '/static/icons/lucide/badge-check.svg'
-		}
+		loadMerchantOrderDetail(orderNo.value, (detail: MerchantOrderDetail, _traceId: string) => applyRemoteOrder(detail), (error: any) => {
+			statusTitle.value = '订单加载失败'
+			statusDesc.value = error.message != null ? error.message : '请返回订单列表后重试。'
+			uni.showToast({ title: error.message != null ? error.message : '订单详情加载失败', icon: 'none' })
+		})
 	})
 
 	const goBack = () => {
@@ -132,19 +111,6 @@
 	const submitRevokeVerification = () => {
 		if (revokeSubmitting.value) return
 		revokeSubmitting.value = true
-		if (useDemoData()) {
-			setTimeout(() => {
-				revokeSubmitting.value = false
-				isCompleted.value = false
-				canRevokeVerification.value = false
-				statusTitle.value = '待核销'
-				statusDesc.value = '核销已撤销,订单已退回待核销状态。'
-				statusIcon.value = '/static/icons/lucide/clock-3.svg'
-				verificationAt.value = '待核销'
-				uni.showToast({ title: '撤销成功', icon: 'success' })
-			}, 300)
-			return
-		}
 		const idempotencyKey = 'revoke-verification-' + orderId.value + '-' + Date.now()
 		revokeOrderVerification(orderId.value, idempotencyKey, (result: any, traceId: string) => {
 			revokeSubmitting.value = false
diff --git a/rencaika_merchant/pages/orders/orders.uvue b/rencaika_merchant/pages/orders/orders.uvue
index c9c7912..db08743 100644
--- a/rencaika_merchant/pages/orders/orders.uvue
+++ b/rencaika_merchant/pages/orders/orders.uvue
@@ -2,7 +2,7 @@
 	<view class="page">
 		<view class="header">
 			<view class="status-safe-space"></view>
-			<view class="title-row"><text class="page-title">订单管理</text><view v-if="isDevelopment" class="demo-control"><text class="demo-control-text">演示数据</text><switch class="demo-switch" :checked="demoDataEnabled" color="#FF7924" @change="toggleDemoData"></switch></view></view>
+			<view class="title-row"><text class="page-title">订单管理</text></view>
 			<view class="category-tabs">
 				<view class="category-tab" :class="activeCategory == 'group' ? 'active' : ''" @tap="selectCategory('group')"><text>团购</text></view>
 				<view class="category-tab" :class="activeCategory == 'store' ? 'active' : ''" @tap="selectCategory('store')"><text>到店消费</text></view>
@@ -146,8 +146,7 @@
 
 <script setup lang="uts">
 	import { getOrderStatusText, getPendingStatusByCategory } from '../../config/order.uts'
-	import { loadDemoMerchantOrders, loadMerchantBusinessDate, loadMerchantOrders, MerchantOrder, MerchantOrderPage, MerchantOrderQuery } from '../../services/orders.uts'
-	import { apiEnvironment } from '../../config/api.uts'
+	import { loadMerchantBusinessDate, loadMerchantOrders, MerchantOrder, MerchantOrderPage, MerchantOrderQuery } from '../../services/orders.uts'
 	import { hasActiveSession } from '../../services/session.uts'
 
 	const activeCategory = ref('group')
@@ -164,8 +163,6 @@
 	const currentPage = ref(1)
 	const loadMoreStep = ref(0)
 	const orders = ref<Array<MerchantOrder>>([])
-	const isDevelopment = apiEnvironment == 'development'
-	const demoDataEnabled = ref(isDevelopment && uni.getStorageSync('merchant-orders-demo-data') != false)
 	const dateFilterApplied = ref(false)
 	const pageSize = 3
 	let cancelOrderRequest: (() => void) | null = null
@@ -262,12 +259,6 @@
 			loadMoreState.value = 'loading'
 		}
 		const query = buildOrderQuery(page)
-		if (demoDataEnabled.value) {
-			setTimeout(() => {
-				applyOrderPage(loadDemoMerchantOrders(query), append)
-			}, 180)
-			return
-		}
 		if (!hasActiveSession()) {
 			showOrderError('请登录后加载真实订单', '', append)
 			return
@@ -282,12 +273,6 @@
 	}
 
 	const reloadOrders = () => requestOrders(1, false)
-
-	const toggleDemoData = (event: any) => {
-		demoDataEnabled.value = event.detail != null && event.detail.value == true
-		uni.setStorageSync('merchant-orders-demo-data', demoDataEnabled.value)
-		reloadOrders()
-	}
 
 	const formatAmount = (amount: number): string => (amount / 100).toFixed(2)
 	const formatDateTime = (value: string): string => value.length > 0 ? value.replace('T', ' ') : '—'
@@ -503,7 +488,7 @@
 	}
 
 	onLoad(() => {
-		if (!demoDataEnabled.value && hasActiveSession()) loadMerchantBusinessDate((value: string) => applyBusinessDate(value), () => {})
+		if (hasActiveSession()) loadMerchantBusinessDate((value: string) => applyBusinessDate(value), () => {})
 		reloadOrders()
 	})
 
diff --git a/rencaika_merchant/pages/verification-detail/verification-detail.uvue b/rencaika_merchant/pages/verification-detail/verification-detail.uvue
index bee5b2e..ea08b6a 100644
--- a/rencaika_merchant/pages/verification-detail/verification-detail.uvue
+++ b/rencaika_merchant/pages/verification-detail/verification-detail.uvue
@@ -26,8 +26,6 @@
 </template>
 
 <script setup lang="uts">
-	import { apiEnvironment } from '../../config/api.uts'
-	import { getLocalOrderDetail } from '../../config/order-demo-data.uts'
 	import { confirmMerchantOrderVerification, loadMerchantOrderDetail, MerchantOrderDetail } from '../../services/orders.uts'
 
 	const orderId = ref('')
@@ -46,7 +44,6 @@
 	const submitting = ref(false)
 	const loadState = ref('loading')
 	const loadError = ref('订单详情加载失败')
-	const useDemoData = (): boolean => apiEnvironment == 'development' && uni.getStorageSync('merchant-orders-demo-data') != false
 
 	const formatAmount = (amount: number): string => (amount / 100).toFixed(2)
 	const formatDateTime = (value: string): string => value.length > 0 ? value.replace('T', ' ') : '—'
@@ -70,11 +67,6 @@
 
 	const loadOrder = () => {
 		loadState.value = 'loading'
-		if (useDemoData()) {
-			const detail = getLocalOrderDetail(orderId.value)
-			applyOrder({ id: orderId.value, orderNo: detail.orderNo, category: detail.category, status: detail.status, statusText: detail.status == 'completed' ? '已完成' : '待核销', title: '特色酸菜鱼', customerName: detail.customerName, customerMobile: detail.customerPhone, cardLevel: '卓越人才卡', orderAmount: Number(detail.productAmount.replace(/[^0-9.]/g, '')) * 100, payAmount: Number(detail.paidAmount.replace(/[^0-9.]/g, '')) * 100, subsidyAmount: Number(detail.subsidyAmount.replace(/[^0-9.]/g, '')) * 100, createdAt: detail.createdAt, verifyTime: detail.status == 'completed' ? detail.verificationAt : '', benefitName: '人才专属权益', merchantName: '', canRevoke: false, revokeDeadline: '', revokeReason: '' })
-			return
-		}
 		if (orderNo.value.length == 0) { loadError.value = '订单参数缺失'; loadState.value = 'error'; return }
 		loadMerchantOrderDetail(orderNo.value, (order: MerchantOrderDetail, _traceId: string) => applyOrder(order), (error: any) => { loadError.value = error.message != null ? error.message : '订单详情加载失败'; loadState.value = 'error' })
 	}
diff --git a/rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue b/rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue
index 879b320..837db3d 100644
--- a/rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue
+++ b/rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue
@@ -23,11 +23,12 @@
 	const selectedId = ref('')
 	const error = ref('')
 	const submitting = ref(false)
+	const requestKey = ref('')
 	const availableText = computed(() => (available.value / 100).toFixed(2))
 	const selected = computed(() => cards.value.find((item) => item.id == selectedId.value) || null)
 	const goBack = () => uni.navigateBack()
-	const clearError = () => { error.value = '' }
-	const chooseBank = () => uni.navigateTo({ url: '/pages/bank-card-select/bank-card-select?selected=' + encodeURIComponent(selectedId.value) })
+	const clearError = () => { error.value = ''; requestKey.value = '' }
+	const chooseBank = () => { requestKey.value = ''; uni.navigateTo({ url: '/pages/bank-card-select/bank-card-select?selected=' + encodeURIComponent(selectedId.value) }) }
 	const load = () => {
 		loadWithdrawalSummary((data: any) => { available.value = Number(data.availableAmountCents || 0) }, () => { error.value = '可提金额加载失败,请稍后重试' })
 		loadBankCards((items: Array<SettlementBankCard>) => { cards.value = items }, () => { error.value = '银行卡加载失败,请稍后重试' })
@@ -45,7 +46,8 @@
 		uni.showModal({ title: '确认提现', content: '确认提现 ¥' + (cents / 100).toFixed(2) + ' 至' + selectedCard.bankName + '吗?', confirmText: '确认提现', confirmColor: '#FF6B2C', success: (result: any) => {
 			if (!result.confirm) return
 			submitting.value = true
-			createWithdrawal(selectedCard.id, cents, 'withdrawal-' + Date.now(), () => { submitting.value = false; uni.redirectTo({ url: '/pages/withdrawal-success/withdrawal-success' }) }, (requestError: any) => { submitting.value = false; error.value = requestError.message || '提现提交失败,请重试' })
+			if (requestKey.value.length == 0) requestKey.value = 'withdrawal-' + selectedCard.id + '-' + cents + '-' + Date.now()
+			createWithdrawal(selectedCard.id, cents, requestKey.value, (created: any) => { submitting.value = false; requestKey.value = ''; uni.redirectTo({ url: '/pages/withdrawal-success/withdrawal-success?withdrawalNo=' + encodeURIComponent(created.withdrawalNo) }) }, (requestError: any) => { submitting.value = false; error.value = requestError.message || '提现提交失败,请重试' })
 		} })
 	}
 	onShow(() => load())
diff --git a/rencaika_merchant/pages/withdrawal/withdrawal.uvue b/rencaika_merchant/pages/withdrawal/withdrawal.uvue
index ba93a8c..2e5636a 100644
--- a/rencaika_merchant/pages/withdrawal/withdrawal.uvue
+++ b/rencaika_merchant/pages/withdrawal/withdrawal.uvue
@@ -1,11 +1,12 @@
 <template>
-  <view class="page"><view class="nav"><view @tap="goBack">返回</view><text>商户提现</text><view></view></view><view class="balance"><text>当前可提</text><text class="amount">¥{{amount}}</text><view class="button" @tap="startWithdrawal">提现</view></view><view class="heading"><text>提现记录</text><text>共 {{records.length}} 条</text></view><scroll-view class="scroll" scroll-y="true"><view v-if="loading" class="state">正在加载</view><view v-else-if="records.length == 0" class="state">暂无提现记录</view><view v-for="item in records" :key="item.id" class="record"><view><text>提现</text><text class="money">¥{{format(item.amountCents)}}</text></view><view class="record-bottom"><text>{{formatTime(item.createdAt)}} {{item.cardMasked}}</text><text :class="'status ' + item.status">{{statusText(item.status)}}</text></view><text v-if="item.reason.length > 0" class="reason">{{item.reason}}</text></view></scroll-view></view>
+  <view class="page"><view class="nav"><view @tap="goBack">返回</view><text>商户提现</text><view></view></view><view class="balance"><text>当前可提</text><text class="amount">¥{{amount}}</text><view class="button" @tap="startWithdrawal">提现</view></view><view class="heading"><text>提现记录</text><text>共 {{records.length}} 条</text></view><scroll-view class="scroll" scroll-y="true"><view v-if="loading" class="state">正在加载</view><view v-else-if="records.length == 0" class="state">暂无提现记录</view><view v-for="item in records" :key="item.id" class="record"><view><text>提现</text><text class="money">¥{{format(item.amountCents)}}</text></view><view class="record-bottom"><text>{{displayTime(item)}} {{item.cardMasked}}</text><text :class="'status ' + item.status">{{statusText(item.status)}}</text></view><text v-if="item.reason.length > 0" class="reason">{{item.reason}}</text></view></scroll-view></view>
 </template>
 <script setup lang="uts">
 import { loadOnboardingStatus, loadWithdrawalSummary, loadWithdrawals, SettlementWithdrawal } from '../../services/settlement.uts'
 const loading = ref(true); const available = ref(0); const onboardingStatus = ref('unsubmitted'); const records = ref<Array<SettlementWithdrawal>>([])
 const amount = computed(() => (available.value / 100).toFixed(2)); const format = (cents: number): string => (cents / 100).toFixed(2); const formatTime = (value: string): string => value.replace('T', ' ')
-const statusText = (value: string): string => value == 'paid' ? '已到账' : value == 'rejected' ? '已驳回' : value == 'failed' ? '提现失败' : '审核中'
+const statusText = (value: string): string => value == 'paid' ? '已到账' : value == 'processing' ? '到账处理中' : value == 'rejected' ? '已驳回' : value == 'failed' ? '提现失败' : '待审核'
+const displayTime = (item: SettlementWithdrawal): string => item.status == 'paid' && item.paidAt.length > 0 ? '到账 ' + formatTime(item.paidAt) : formatTime(item.createdAt)
 const goBack = () => uni.navigateBack()
 const startWithdrawal = () => { if (onboardingStatus.value == 'approved') { uni.navigateTo({ url: '/pages/withdrawal-detail/withdrawal-detail' }); return }; if (onboardingStatus.value == 'pending') { uni.navigateTo({ url: '/pages/merchant-onboarding-pending/merchant-onboarding-pending' }); return }; uni.navigateTo({ url: '/pages/merchant-onboarding/merchant-onboarding' }) }
 const load = () => { loading.value = true; loadOnboardingStatus((item) => { onboardingStatus.value = item.status }, () => {}); loadWithdrawalSummary((data: any) => { available.value = Number(data.availableAmountCents || 0) }, () => {}); loadWithdrawals(1, 50, (data) => { records.value = data.records; loading.value = false }, (error: any) => { loading.value = false; uni.showToast({ title: error.message || '提现记录加载失败', icon: 'none' }) }) }
diff --git a/rencaika_merchant/services/settlement.uts b/rencaika_merchant/services/settlement.uts
index 204ff6e..f19b626 100644
--- a/rencaika_merchant/services/settlement.uts
+++ b/rencaika_merchant/services/settlement.uts
@@ -3,14 +3,14 @@
 
 export type SettlementOnboarding = { id: string, applicationNo: string, status: string, reason: string, submittedAt: string }
 export type SettlementBankCard = { id: string, bankName: string, branchName: string, cardMasked: string, status: string, reason: string, createdAt: string }
-export type SettlementWithdrawal = { id: string, withdrawalNo: string, amountCents: number, status: string, reason: string, bankName: string, cardMasked: string, createdAt: string }
+export type SettlementWithdrawal = { id: string, withdrawalNo: string, amountCents: number, status: string, reason: string, bankName: string, cardMasked: string, createdAt: string, reviewedAt: string, paidAt: string }
 export type SettlementPage<T> = { records: Array<T>, page: number, size: number, total: number }
 
 const stringValue = (value: any): string => value == null ? '' : '' + value
 const numberValue = (value: any): number => value == null ? 0 : Number(value)
 const onboarding = (value: any): SettlementOnboarding => ({ id: stringValue(value != null ? value.id : ''), applicationNo: stringValue(value != null ? value.applicationNo : ''), status: stringValue(value != null ? value.status : 'unsubmitted'), reason: stringValue(value != null ? value.reason : ''), submittedAt: stringValue(value != null ? value.submittedAt : '') })
 const bankCard = (value: any): SettlementBankCard => ({ id: stringValue(value != null ? value.id : ''), bankName: stringValue(value != null ? value.bankName : ''), branchName: stringValue(value != null ? value.branchName : ''), cardMasked: stringValue(value != null ? value.cardMasked : ''), status: stringValue(value != null ? value.status : 'pending'), reason: stringValue(value != null ? value.reason : ''), createdAt: stringValue(value != null ? value.createdAt : '') })
-const withdrawal = (value: any): SettlementWithdrawal => ({ id: stringValue(value != null ? value.id : ''), withdrawalNo: stringValue(value != null ? value.withdrawalNo : ''), amountCents: numberValue(value != null ? value.amountCents : 0), status: stringValue(value != null ? value.status : 'pending'), reason: stringValue(value != null ? value.reason : ''), bankName: stringValue(value != null ? value.bankName : ''), cardMasked: stringValue(value != null ? value.cardMasked : ''), createdAt: stringValue(value != null ? value.createdAt : '') })
+const withdrawal = (value: any): SettlementWithdrawal => ({ id: stringValue(value != null ? value.id : ''), withdrawalNo: stringValue(value != null ? value.withdrawalNo : ''), amountCents: numberValue(value != null ? value.amountCents : 0), status: stringValue(value != null ? value.status : 'pending'), reason: stringValue(value != null ? value.reason : ''), bankName: stringValue(value != null ? value.bankName : ''), cardMasked: stringValue(value != null ? value.cardMasked : ''), createdAt: stringValue(value != null ? value.createdAt : ''), reviewedAt: stringValue(value != null ? value.reviewedAt : ''), paidAt: stringValue(value != null ? value.paidAt : '') })
 
 export const loadOnboardingStatus = (success: (value: SettlementOnboarding) => void, error: (value: HttpError) => void): (() => void) => request<any>({ path: getApiEndpoint('merchantOnboardingStatus') }, (data: any) => success(onboarding(data)), error)
 export const submitOnboarding = (payload: any, key: string, success: (value: SettlementOnboarding) => void, error: (value: HttpError) => void): (() => void) => request<any>({ path: getApiEndpoint('merchantOnboarding'), method: 'POST', data: payload, idempotencyKey: key }, (data: any) => success(onboarding(data)), error)
diff --git a/talent-card-admin/src/style.css b/talent-card-admin/src/style.css
index a19bb8b..dc33b48 100644
--- a/talent-card-admin/src/style.css
+++ b/talent-card-admin/src/style.css
@@ -1185,6 +1185,20 @@
 .merchant-coupon-edit-form .el-select__wrapper,
 .merchant-coupon-edit-form .el-range-editor.el-input__wrapper {
   background: #ffffff;
+  box-shadow: 0 0 0 1px #d9dee8 inset;
+}
+
+.merchant-coupons-filter .el-input__wrapper:hover,
+.merchant-coupons-filter .el-input__wrapper.is-focus,
+.merchant-coupons-filter .el-select__wrapper:hover,
+.merchant-coupons-filter .el-select__wrapper.is-focused,
+.merchant-coupon-edit-form .el-input__wrapper:hover,
+.merchant-coupon-edit-form .el-input__wrapper.is-focus,
+.merchant-coupon-edit-form .el-select__wrapper:hover,
+.merchant-coupon-edit-form .el-select__wrapper.is-focused,
+.merchant-coupon-edit-form .el-date-editor.el-input__wrapper:hover,
+.merchant-coupon-edit-form .el-date-editor.el-input__wrapper.is-focus {
+  box-shadow: 0 0 0 1px #b8c2d1 inset;
 }
 
 .merchant-coupons-filter .coupon-created-time-picker {
@@ -1561,6 +1575,22 @@
   width: 200px;
 }
 
+.coupon-amount-control {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.coupon-amount-control .el-input-number {
+  width: 200px;
+}
+
+.coupon-amount-control > span {
+  color: #334155;
+  line-height: 28px;
+  white-space: nowrap;
+}
+
 .merchant-coupon-edit-form .coupon-valid-time-picker {
   width: 300px;
 }
diff --git a/talent-card-admin/src/views/MerchantCreateView.vue b/talent-card-admin/src/views/MerchantCreateView.vue
index d8e2764..53d438a 100644
--- a/talent-card-admin/src/views/MerchantCreateView.vue
+++ b/talent-card-admin/src/views/MerchantCreateView.vue
@@ -959,6 +959,11 @@
     ElMessage.warning('请输入优惠券名称')
     return
   }
+  const couponAmount = Number(couponEditForm.couponAmount)
+  if (couponEditForm.couponAmount === '' || !Number.isFinite(couponAmount) || couponAmount <= 0) {
+    ElMessage.warning('请输入大于0的优惠券金额')
+    return
+  }
   if (couponEditForm.useRequirement === 'full' && couponEditForm.fullAmount === '') {
     ElMessage.warning('请输入使用门槛')
     return
@@ -1016,7 +1021,18 @@
 		ElMessage.warning('请输入排序')
 		return
 	}
-	if (requiresMerchantOperator.value) {
+  const updatingMerchantPassword = isEditMode.value && accountForm.loginPassword.length > 0
+	if (updatingMerchantPassword) {
+		if (accountForm.loginPassword.length < 6 || accountForm.loginPassword.length > 64) {
+			ElMessage.warning('登录密码长度须为6至64位')
+			return
+		}
+		if (!accountForm.confirmPassword) {
+			ElMessage.warning('请输入确认密码')
+			return
+		}
+	}
+  if (requiresMerchantOperator.value) {
 		if (!accountForm.loginAccount.trim()) {
 			ElMessage.warning('请输入登录账号')
 			return
@@ -1039,7 +1055,7 @@
 			return
 		}
 	}
-  if (accountForm.loginPassword !== accountForm.confirmPassword) {
+	if ((requiresMerchantOperator.value || updatingMerchantPassword) && accountForm.loginPassword !== accountForm.confirmPassword) {
     ElMessage.warning('两次输入的密码不一致')
     return
   }
@@ -1058,7 +1074,7 @@
 		latitude: Number(form.latitude || 0) || undefined,
 		canLoginMerchantApp: requiresMerchantOperator.value ? 1 : Number(form.canLoginMerchantApp ?? 1),
 		loginAccount: !isEditMode.value ? accountForm.loginAccount : undefined,
-		loginPassword: !isEditMode.value ? accountForm.loginPassword : undefined,
+		loginPassword: !isEditMode.value || updatingMerchantPassword ? accountForm.loginPassword : undefined,
 		groupBuyingEnabled: form.groupBuyingEnabled,
 		usageInstructions: form.usageInstructions,
 		rightsText: form.rightsText,
@@ -1279,13 +1295,13 @@
             <el-switch v-model="form.canLoginMerchantApp" :active-value="1" :inactive-value="0" />
           </el-form-item>
           <el-form-item label="登录账号" :error="accountTaken ? '登录账号已存在,请更换' : ''">
-            <el-input v-model="accountForm.loginAccount" maxlength="32" :readonly="isEditMode" :placeholder="isEditMode ? '未配置登录账号' : '仅支持英文和数字'" @input="normalizeLoginAccount" @blur="checkLoginAccountAvailable" />
+            <el-input v-model="accountForm.loginAccount" maxlength="32" :disabled="isEditMode" :placeholder="isEditMode ? '未配置登录账号' : '仅支持英文和数字'" @input="normalizeLoginAccount" @blur="checkLoginAccountAvailable" />
           </el-form-item>
-          <el-form-item v-if="!isEditMode" label="登录密码">
-            <el-input v-model="accountForm.loginPassword" type="password" show-password />
+          <el-form-item label="登录密码">
+            <el-input v-model="accountForm.loginPassword" type="password" show-password :placeholder="isEditMode ? '留空则不修改,6至64位' : ''" />
           </el-form-item>
-          <el-form-item v-if="!isEditMode" label="确认密码">
-            <el-input v-model="accountForm.confirmPassword" type="password" show-password />
+          <el-form-item label="确认密码">
+            <el-input v-model="accountForm.confirmPassword" type="password" show-password :placeholder="isEditMode ? '再次输入新密码' : ''" />
           </el-form-item>
         </el-form>
       </section>
@@ -1762,6 +1778,11 @@
               <el-input v-model="couponEditForm.couponName" placeholder="请输入优惠券名称" />
             </div>
 
+            <div class="coupon-edit-row coupon-amount-row">
+              <label>优惠券金额</label>
+              <div class="coupon-amount-control"><el-input-number v-model="couponEditForm.couponAmount" :min="0.01" :precision="2" :step="1" controls-position="right" placeholder="请输入优惠券金额" /><span>元</span></div>
+            </div>
+
             <div class="coupon-edit-row coupon-requirement-row">
               <label>使用要求</label>
               <el-radio-group v-model="couponEditForm.useRequirement">
diff --git a/talent-card-admin/src/views/MerchantSettlementView.vue b/talent-card-admin/src/views/MerchantSettlementView.vue
index e6a50cb..c01c918 100644
--- a/talent-card-admin/src/views/MerchantSettlementView.vue
+++ b/talent-card-admin/src/views/MerchantSettlementView.vue
@@ -197,7 +197,7 @@
     <section class="table-panel">
       <el-table v-loading="loading" :data="rows" border class="settlement-table" empty-text="暂无数据">
         <template v-if="kind === 'withdrawals'">
-          <el-table-column prop="withdrawalNo" label="提现Id" min-width="156" />
+          <el-table-column prop="withdrawalNo" label="提现id" min-width="156" />
           <el-table-column prop="merchantName" label="商家名称" min-width="130" show-overflow-tooltip />
           <el-table-column prop="contactMobile" label="联系方式" min-width="118" />
           <el-table-column prop="merchantType" label="商家类型" min-width="110" />
@@ -211,7 +211,7 @@
           <el-table-column prop="cardMasked" label="提现卡号" min-width="150" />
         </template>
         <template v-else-if="kind === 'onboardings'">
-          <el-table-column prop="applicationNo" label="进件申请Id" min-width="156" />
+          <el-table-column prop="applicationNo" label="进件id" min-width="156" />
           <el-table-column prop="merchantName" label="商家名称" min-width="150" show-overflow-tooltip />
           <el-table-column prop="contactMobile" label="联系方式" min-width="118" />
           <el-table-column prop="merchantType" label="商家类型" min-width="110" />
@@ -219,7 +219,7 @@
           <el-table-column prop="subjectType" label="主体类型" min-width="105" />
         </template>
         <template v-else>
-          <el-table-column prop="id" label="申请Id" min-width="100" />
+          <el-table-column prop="id" label="申请id" min-width="100" />
           <el-table-column prop="merchantName" label="商家名称" min-width="150" show-overflow-tooltip />
           <el-table-column prop="contactMobile" label="联系方式" min-width="118" />
           <el-table-column prop="merchantType" label="商家类型" min-width="110" />
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
index 43bdb0c..186a531 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
@@ -459,6 +459,17 @@
 		ensureUpdated(updated);
 		Long storeId = findOrCreateDefaultStore(id, request.merchantName(), request.address());
 		syncMerchantBusinessHours(id, storeId, request.businessHours());
+		if (request.loginPassword() != null && !request.loginPassword().isBlank()) {
+			if (request.loginPassword().length() < 6 || request.loginPassword().length() > 64) {
+				throw new BusinessException(ErrorCode.BAD_REQUEST, "商户登录密码长度须为6至64位");
+			}
+			int passwordUpdated = jdbcTemplate.update("""
+					update merchant_operator
+					set password_hash = ?
+					where merchant_id = ? and role_code = 'owner' and deleted = 0
+					""", MerchantPasswordHasher.encode(request.loginPassword()), id);
+			if (passwordUpdated == 0) throw new BusinessException(ErrorCode.CONFLICT, "该商家未配置商户端登录账号");
+		}
 		return merchant(id);
 	}
 
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponCreateRequest.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponCreateRequest.java
index 36cf118..c450ad0 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponCreateRequest.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponCreateRequest.java
@@ -4,6 +4,7 @@
 import java.util.List;
 
 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.DecimalMin;
 import jakarta.validation.constraints.NotNull;
 import jakarta.validation.constraints.Size;
 
@@ -16,6 +17,8 @@
 		@NotBlank
 		String conditionType,
 		BigDecimal conditionAmount,
+		@NotNull
+		@DecimalMin(value = "0.01")
 		BigDecimal couponAmount,
 		List<String> talentLevels,
 		String validStart,
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponUpdateRequest.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponUpdateRequest.java
index 7bffa56..f68890a 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponUpdateRequest.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/CouponUpdateRequest.java
@@ -4,6 +4,7 @@
 import java.util.List;
 
 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.DecimalMin;
 import jakarta.validation.constraints.NotNull;
 import jakarta.validation.constraints.Size;
 
@@ -16,6 +17,8 @@
 		@NotBlank
 		String conditionType,
 		BigDecimal conditionAmount,
+		@NotNull
+		@DecimalMin(value = "0.01")
 		BigDecimal couponAmount,
 		List<String> talentLevels,
 		String validStart,
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantUpdateRequest.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantUpdateRequest.java
index ea1b01d..9a4ab96 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantUpdateRequest.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantUpdateRequest.java
@@ -35,6 +35,7 @@
 		@Size(max = 64)
 		String serviceLabel,
 		List<@Valid MerchantBusinessHourRequest> businessHours,
-		Byte canLoginMerchantApp
+		Byte canLoginMerchantApp,
+		@Size(max = 64) String loginPassword
 ) {
 }
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/HuifuMerchantWithdrawalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/HuifuMerchantWithdrawalService.java
index a95b015..411d0b7 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/HuifuMerchantWithdrawalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/HuifuMerchantWithdrawalService.java
@@ -1,6 +1,7 @@
 package com.talentcard.server.business.merchant;
 
 import com.talentcard.server.business.DatabaseRows;
+import com.alibaba.fastjson.JSON;
 import com.talentcard.server.business.payment.huifu.HuifuPaymentGatewayException;
 import com.talentcard.server.business.payment.huifu.HuifuWithdrawalCommand;
 import com.talentcard.server.business.payment.huifu.HuifuWithdrawalGateway;
@@ -68,7 +69,19 @@
     private long number(Object v) { return v instanceof Number n ? n.longValue() : 0; }
     private record PreparedWithdrawal(String withdrawalNo, long amountCents, String huifuId, String tokenNo) {}
     @SuppressWarnings("unchecked") private record ProviderResult(boolean success, boolean failed, String code, String message, String providerNo) {
-        static ProviderResult from(Map<String, Object> response) { Map<String,Object> d=response.get("data") instanceof Map<?,?> map?(Map<String,Object>)map:response; String code=value(d,"sub_resp_code","resp_code","code"), status=value(d,"trans_status","trans_stat"), message=value(d,"sub_resp_desc","resp_desc","message"), no=value(d,"hf_seq_id"); boolean accepted="00000000".equals(code)||"10000".equals(code)||"0".equals(code); boolean ok=accepted&&("S".equalsIgnoreCase(status)||"SUCCESS".equalsIgnoreCase(status)); boolean pending="P".equalsIgnoreCase(status)||"PROCESSING".equalsIgnoreCase(status)||status.isBlank(); return new ProviderResult(ok,!ok&&!pending,code,message,no); }
+        static ProviderResult from(Map<String, Object> response) {
+            Object raw = response.get("data");
+            Map<String, Object> d = raw instanceof Map<?, ?> map ? (Map<String, Object>) map
+                    : raw instanceof String json && !json.isBlank() ? JSON.parseObject(json, Map.class) : response;
+            String code = value(d, "sub_resp_code", "resp_code", "code");
+            String status = value(d, "trans_stat", "trans_status");
+            String message = value(d, "sub_resp_desc", "resp_desc", "message");
+            String no = value(d, "hf_seq_id", "bank_order_no");
+            boolean accepted = "00000000".equals(code) || "10000".equals(code) || "0".equals(code) || "SUCCESS".equalsIgnoreCase(code);
+            boolean ok = accepted && ("S".equalsIgnoreCase(status) || "SUCCESS".equalsIgnoreCase(status) || "PAID".equalsIgnoreCase(status));
+            boolean pending = "P".equalsIgnoreCase(status) || "PROCESSING".equalsIgnoreCase(status) || "PENDING".equalsIgnoreCase(status) || status.isBlank();
+            return new ProviderResult(ok, !ok && !pending, code, message, no);
+        }
         static String value(Map<String,Object> data,String...keys){for(String key:keys)if(data.get(key)!=null)return String.valueOf(data.get(key)).trim();return "";}
     }
 }
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
index 66ef75b..50f2981 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
@@ -112,7 +112,7 @@
     private void store(MerchantPrincipal principal) { if (rows("select id from merchant_store where id = ? and merchant_id = ? and status = 1 and deleted = 0", principal.storeId(), principal.merchantId()).isEmpty()) throw new BusinessException(ErrorCode.FORBIDDEN, "当前门店不可操作"); }
     private Map<String, Object> onboarding(Map<String, Object> row) { return Map.of("id", String.valueOf(row.get("id")), "applicationNo", row.get("applicationNo"), "status", row.get("status"), "reason", clean(row.get("rejectReason")), "submittedAt", String.valueOf(row.get("createdAt"))); }
     private Map<String, Object> bankCard(Map<String, Object> row) { return Map.of("id", String.valueOf(row.get("id")), "bankName", row.get("bankName"), "branchName", row.get("branchName"), "cardMasked", row.get("cardMasked"), "status", row.get("status"), "reason", clean(row.get("rejectReason")), "createdAt", String.valueOf(row.get("createdAt"))); }
-    private Map<String, Object> withdrawal(Map<String, Object> row) { Map<String, Object> value = new LinkedHashMap<>(); value.put("id", String.valueOf(row.get("id"))); value.put("withdrawalNo", row.get("withdrawalNo")); value.put("amountCents", row.get("amountCents")); value.put("status", row.get("status")); value.put("reason", clean(row.get("failureReason"))); value.put("bankName", clean(row.get("bankName"))); value.put("cardMasked", clean(row.get("cardMasked"))); value.put("createdAt", String.valueOf(row.get("createdAt"))); return value; }
+    private Map<String, Object> withdrawal(Map<String, Object> row) { Map<String, Object> value = new LinkedHashMap<>(); value.put("id", String.valueOf(row.get("id"))); value.put("withdrawalNo", row.get("withdrawalNo")); value.put("amountCents", row.get("amountCents")); value.put("status", row.get("status")); value.put("reason", clean(row.get("failureReason"))); value.put("bankName", clean(row.get("bankName"))); value.put("cardMasked", clean(row.get("cardMasked"))); value.put("createdAt", String.valueOf(row.get("createdAt"))); value.put("reviewedAt", clean(row.get("reviewedAt"))); value.put("paidAt", clean(row.get("paidAt"))); return value; }
     private Map<String, Object> branch(String id, String branchName, String bankName) { return Map.of("id", id, "branchName", branchName, "bankName", bankName); }
     private List<Map<String, Object>> rows(String sql, Object... args) { return DatabaseRows.normalize(jdbc.queryForList(sql, args)); }
     private Long number(String value) { try { return Long.valueOf(value); } catch (Exception ignored) { throw new BusinessException(ErrorCode.BAD_REQUEST, "编号无效"); } }
diff --git a/talent-card-server/src/main/resources/application.yml b/talent-card-server/src/main/resources/application.yml
index e702e92..9516b0e 100644
--- a/talent-card-server/src/main/resources/application.yml
+++ b/talent-card-server/src/main/resources/application.yml
@@ -52,29 +52,24 @@
   payment:
     huifu:
       # Keep disabled until the Huifu test/production product, merchant and keys are provisioned.
-      enabled: ${HUIFU_ENABLED:false}
-      environment: ${HUIFU_ENVIRONMENT:test}
-      system-id: ${HUIFU_SYSTEM_ID:}
-      product-id: ${HUIFU_PRODUCT_ID:}
-      merchant-id: ${HUIFU_MERCHANT_ID:}
-      mini-program-app-id: ${HUIFU_MINI_PROGRAM_APP_ID:}
-      private-key: ${HUIFU_PRIVATE_KEY:}
-      platform-public-key: ${HUIFU_PLATFORM_PUBLIC_KEY:}
-      notify-url: ${HUIFU_NOTIFY_URL:}
-      withdrawal-product-id: ${HUIFU_WITHDRAWAL_PRODUCT_ID:}
-      withdrawal-notify-url: ${HUIFU_WITHDRAWAL_NOTIFY_URL:}
-      withdrawal-into-account-date-type: ${HUIFU_WITHDRAWAL_INTO_ACCOUNT_DATE_TYPE:D0}
+      enabled: true
+      environment: prod
+      system-id: 6666000212191071
+      product-id: KAZX
+      merchant-id: 6666000212191071
+      mini-program-app-id: wx6ae2cadfea28fce1
+      private-key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCcsR3R3nUFCv/4l6vczGk6j4UgZhuMm/fTs2MQQqFkIuoISd38TOiIMaLS3KLYL+D+qhUCps56svOK/3M/kdyXfPsBphJyXB5Ar7il8pJ6BDa38StzTrlRm+IXX+4diJvqxUimetjpx0OfnqRkNYQWc/ZVeoEdQbITqLyxogy0R3rkR/wnOTwxHBbkCYsDCxSon4W0SoM5fLs3o947INbPUbUsf0vL5l6NiqlV9YsZ3qAWvvPoPX4HI1s5maMiVKfUwe27P3ARW9n6n3tadBzbB6lrmAEcFoihXpZjNN9UaRKjYfYjTS9JRkDqRyYGhz5cHp9GthEksMvhLP84oEanAgMBAAECggEAKV6d5+Ya8TzpPiIVTxNtCPgRhu9OgL5BHVS0Z/ufjselEJEoGc/YaPTp71AvcnKZrcMMDwopY73RjTZKoFMLcbeesd296xGlLyD12GKGB88K/1+eQDBdv00v0UoTnRqPR9nUh5fRo09n7EG/V3HFsQPm2sSgSDArKwOW5jNJtWLsGIVCW8gg3RQ9YlZ5HW85neBnjBFnrMA9S/hxwZD336M8CiViIa0v9o5CS7qxAqXMzzoOC7Vr3hZ/X0i/5GrSH9DRO7ougSmP4F/zCEc2dViA0rOJ6m3OuS0osh5FulihOBOjI5uLETEt4K/7PuV9xOd4oAz0OBpJ2bhPf3YpGQKBgQDQdEcmnlULa3jTSrbr0vYA3iMpcls/8F8+I/QymMXHAUeVyc8XKuGzblx+/n3x8ZoAvdVg1ZAO5wgLh/P0BEL74iWhfHedjt8xcdk2R5U0RuOnx1TUTKrmLKRZ5gStNFnGlK4yVwpiNqHn/cr+gYYeZSPARFVi00WdXbqVbEEf2wKBgQDAbmo4uHrmHN5GYvt8lVmT9aha1IpKOOLenjd+Y/vKGJcvHzOVCHnOh8OGO/4p7CxOq0sshER713jW2cFGO3xpFEFpIc45pDQ8Ut0XuSoOjKtwPzid8vKX7A1If6FDLMNy7bYR1qqnIJNJnN/f3lsksX+es7QTuRShhA0X0mnEJQKBgBE5OlPHi1FZPO+AYeLUWH0z3YXkLAP5cXUp9Vhk5RqPUYHf3duVMHbp7HyVvIRMKSRciw/oNXH1xuVlA1QrMfmr8t4H8b4z+t8UABWLDpn2LYNEZg7wksJX9/Bxn/tLswtEZ6xDItmAmBoaDza+Lv2975lITCHRQRRClVMZUbw3AoGAVFrSs6SjM2aqRZ60ccuipgrFT3PmX10Kjt46o2w+/zvCYoTB/u3lP5UiMCDybPw7/Ax4+r3Mq6EsNrrkT95ZzlJzzhtkpL4Hq/4DL5gbCJ+/s4fzUMIkeFahCAvy7FieIS51ZuJ8kqDkEBv1w9RcjfxFXpOWOCMlGRyjBLNXbAUCgYEAjcTEuXctlGEjtO1MBaHc4hkkpiPG7gxV/Bq1XXLszv4LTaOfDEpjGGBpVYtb3URYrif/HzX8T1KHELvPziuqP2ghaJQzbztep1TGQ48A5VpOvHdA/w/+k4JJl0PyKBPrFXiHIw1if7rnvOLt27TymwXSaJquSz7Sz2+wXFxzKJk=
+      platform-public-key: ${HUIFU_PLATFORM_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgxOuXt1UEdZNPk6sntqiIlcs7e+0fZ3CVgKMV2Qv4ixwKmha5etL5WyIONmjoGEHePHpanYkXvm0kHkbbDkjpyHDFdEshuP1eGx5tRUTISRvXY/iFuD3xyeWSsvvjW6hS29OvqVCPcnBUC7jcRj15dJS2IpYR0iDGNS+/M0TyOFwRQME07At+qO+MSjKu4aRIjlglukjD7YbE2s35uV066nsBUCZUNpGPuju1pieUW4zyoIW6K70dyXCQy61oRI6JmA4JRCOJV1BE80N3GrLI4Pbq1C3ZBTgOPi5RWYNq1hfu807BDkPLc3dJKYt22Ea1jPJsg6e/B9Xbzh6JaUNAQIDAQAB}
+      notify-url: ${HUIFU_NOTIFY_URL:http://221.182.45.100:11451/api/payments/huifu/notify}
+      withdrawal-product-id: ${HUIFU_WITHDRAWAL_PRODUCT_ID:KAZX}
+      withdrawal-notify-url: ${HUIFU_WITHDRAWAL_NOTIFY_URL:http://221.182.45.100:11451/api/payments/huifu/withdrawal-notify}
       delay-account: ${HUIFU_DELAY_ACCOUNT:false}
-      reconciliation:
-        enabled: ${HUIFU_RECONCILIATION_ENABLED:false}
-        fixed-delay-ms: ${HUIFU_RECONCILIATION_FIXED_DELAY_MS:300000}
-        pending-after-minutes: ${HUIFU_RECONCILIATION_PENDING_AFTER_MINUTES:5}
   wechat:
     mini-program:
       # The app id must be the same mini-program that invokes uni.login and uni.requestPayment.
-      app-id: ${WECHAT_MINI_PROGRAM_APP_ID:}
+      app-id: ${WECHAT_MINI_PROGRAM_APP_ID:wx6ae2cadfea28fce1}
       # Keep this only in the deployment environment. It is required to exchange a wx.login code for an OpenID.
-      app-secret: ${WECHAT_MINI_PROGRAM_APP_SECRET:}
+      app-secret: ${WECHAT_MINI_PROGRAM_APP_SECRET:7bf743b066523bbb2d6de80decabc15b}
 
 management:
   endpoints:

--
Gitblit v1.7.1