```json
{
"summary": "设计并实现了一个「设备抵扣记录」uni-app Vue2 移动端页面,以橘红色/橙色为主色调,蓝绿为辅色。采用卡片式布局展示抵扣记录,查询区域带阴影突出显示,使用 Font Awesome 6.4.0 SVG 图标,SCSS 嵌套样式,兼容微信小程序。包含设备号输入(仅字母数字)、picker 状态选择、模拟查询、复制设备号、卡片数据展示及跳转详情等功能。",
"widget": {
"type": "full-html",
"html": "<template>\n <view class=\"deduction-record\">\n <!-- 顶部导航 -->\n <view class=\"deduction-record__navbar\">\n <view class=\"navbar__left\" @click=\"onBack\">\n <image src=\"/static/icons/angle-left.svg\" class=\"icon icon--nav\" />\n </view>\n <text class=\"navbar__title\">设备抵扣记录</text>\n <view class=\"navbar__right\">\n <image src=\"/static/icons/search.svg\" class=\"icon icon--nav\" @click=\"onSearch\" />\n </view>\n </view>\n\n <!-- 主内容区 -->\n <scroll-view class=\"deduction-record__body\" scroll-y>\n <!-- 查询条件卡片 -->\n <view class=\"search-card\">\n <view class=\"search-card__header\">\n <image src=\"/static/icons/filter.svg\" class=\"icon icon--title\" />\n <text class=\"search-card__title\">查询条件</text>\n </view>\n\n <view class=\"search-card__form\">\n <!-- 设备号 -->\n <view class=\"form-group\">\n <view class=\"form-group__label-wrap\">\n <image src=\"/static/icons/barcode.svg\" class=\"icon icon--label\" />\n <text class=\"form-group__label\">设备号</text>\n </view>\n <view class=\"form-group__input-wrap\">\n <input\n class=\"form-group__input\"\n v-model=\"queryForm.deviceNo\"\n type=\"text\"\n maxlength=\"64\"\n placeholder=\"请输入设备机身号\"\n placeholder-class=\"input-placeholder\"\n @input=\"onDeviceNoInput\"\n />\n <view\n class=\"form-group__clear\"\n v-if=\"queryForm.deviceNo.length > 0\"\n @click=\"queryForm.deviceNo = ''\"\n >\n <image src=\"/static/icons/xmark.svg\" class=\"icon icon--clear\" />\n </view>\n </view>\n </view>\n\n <!-- 抵扣状态 -->\n <view class=\"form-group\">\n <view class=\"form-group__label-wrap\">\n <image src=\"/static/icons/list-dropdown.svg\" class=\"icon icon--label\" />\n <text class=\"form-group__label\">抵扣状态</text>\n </view>\n <picker\n mode=\"selector\"\n :range=\"statusOptions\"\n :value=\"queryForm.statusIndex\"\n @change=\"onStatusChange\"\n >\n <view class=\"form-group__picker\">\n <text class=\"form-group__picker-text\" :class=\"{ 'is-active': queryForm.statusIndex > 0 }\">\n {{ statusOptions[queryForm.statusIndex] }}\n </text>\n <image src=\"/static/icons/angle-down.svg\" class=\"icon icon--arrow\" />\n </view>\n </picker>\n </view>\n\n <!-- 查询按钮 -->\n <button class=\"form-group__btn\" @click=\"onQuery\">\n <image src=\"/static/icons/magnifying-glass.svg\" class=\"icon icon--btn\" />\n <text>查 询</text>\n </button>\n </view>\n </view>\n\n <!-- 统计信息 -->\n <view class=\"stat-bar\">\n <text class=\"stat-bar__text\">共 <text class=\"stat-bar__num\">{{ filteredList.length }}</text> 条抵扣记录</text>\n </view>\n\n <!-- 列表结果 -->\n <view class=\"list-section\" v-if=\"filteredList.length > 0\">\n <view\n class=\"record-card\"\n v-for=\"(item, index) in filteredList\"\n :key=\"index\"\n >\n <!-- 设备号 + 复制 -->\n <view class=\"record-card__device\">\n <view class=\"device__left\">\n <image src=\"/static/icons/qrcode.svg\" class=\"icon icon--device\" />\n <text class=\"device__number\">{{ item.deviceNo }}</text>\n </view>\n <view class=\"device__copy\" @click=\"onCopy(item.deviceNo)\">\n <image src=\"/static/icons/copy.svg\" class=\"icon icon--copy\" />\n <text class=\"device__copy-text\">复制</text>\n </view>\n </view>\n\n <!-- 分割线 -->\n <view class=\"record-card__divider\"></view>\n\n <!-- 平台 -->\n <view class=\"record-card__row\">\n <view class=\"row__left\">\n <image src=\"/static/icons/store.svg\" class=\"icon icon--row\" />\n <text class=\"row__label\">平台</text>\n </view>\n <text class=\"row__value\">{{ item.platform }}</text>\n </view>\n\n <!-- 抵扣状态 -->\n <view class=\"record-card__row\">\n <view class=\"row__left\">\n <image src=\"/static/icons/circle-info.svg\" class=\"icon icon--row\" />\n <text class=\"row__label\">抵扣状态</text>\n </view>\n <view class=\"row__status\" :class=\"'status--' + item.statusKey\">\n <image\n :src=\"'/static/icons/' + item.statusIcon + '.svg'\"\n class=\"icon icon--status\"\n />\n <text class=\"status__text\">{{ item.statusText }}</text>\n </view>\n </view>\n\n <!-- 抵扣时间 -->\n <view class=\"record-card__row\">\n <view class=\"row__left\">\n <image src=\"/static/icons/clock.svg\" class=\"icon icon--row\" />\n <text class=\"row__label\">抵扣时间</text>\n </view>\n <text class=\"row__value row__value--time\">{{ item.deductionTime }}</text>\n </view>\n\n <!-- 抵扣金额 -->\n <view class=\"record-card__row\">\n <view class=\"row__left\">\n <image src=\"/static/icons/coins.svg\" class=\"icon icon--row\" />\n <text class=\"row__label\">抵扣金额</text>\n </view>\n <text class=\"row__value row__value--amount\">¥{{ item.amount }}</text>\n </view>\n\n <!-- 商户号 -->\n <view class=\"record-card__row record-card__row--last\">\n <view class=\"row__left\">\n <image src=\"/static/icons/building.svg\" class=\"icon icon--row\" />\n <text class=\"row__label\">商户号</text>\n </view>\n <text class=\"row__value row__value--merchant\">{{ item.merchantNo }}</text>\n </view>\n\n <!-- 更多按钮 -->\n <view class=\"record-card__more\" @click=\"onGoDetail(item)\">\n <text class=\"more__text\">查看更多</text>\n <image src=\"/static/icons/angle-right.svg\" class=\"icon icon--more\" />\n </view>\n </view>\n </view>\n\n <!-- 空状态 -->\n <view class=\"empty-state\" v-else>\n <view class=\"empty-state__icon-wrap\">\n <image src=\"/static/icons/box-open.svg\" class=\"icon icon--empty\" />\n </view>\n <text class=\"empty-state__title\">暂无抵扣记录</text>\n <text class=\"empty-state__desc\">请调整查询条件后重新搜索</text>\n </view>\n\n <view class=\"deduction-record__footer\"></view>\n </scroll-view>\n </view>\n</template>\n\n<script>\nexport default {\n data() {\n return {\n queryForm: {\n deviceNo: '',\n statusIndex: 0\n },\n statusOptions: ['所有状态', '等待扣除', '已扣除', '已取消', '已撤销扣除'],\n recordList: [\n {\n deviceNo: 'SN2024A78001',\n platform: '微信支付',\n statusKey: 'pending',\n statusIcon: 'clock',\n statusText: '等待扣除',\n deductionTime: '2024-12-18 14:30',\n amount: '1280.50',\n merchantNo: 'M20241218001'\n },\n {\n deviceNo: 'SN2024B89002',\n platform: '支付宝',\n statusKey: 'completed',\n statusIcon: 'circle-check',\n statusText: '已扣除',\n deductionTime: '2024-12-20 09:15',\n amount: '3560.00',\n merchantNo: 'M20241220002'\n },\n {\n deviceNo: 'SN2024C67003',\n platform: '银联商务',\n statusKey: 'cancelled',\n statusIcon: 'circle-xmark',\n statusText: '已取消',\n deductionTime: '2024-12-22 16:45',\n amount: '890.32',\n merchantNo: 'M20241222003'\n },\n {\n deviceNo: 'SN2024D56004',\n platform: '微信支付',\n statusKey: 'revoked',\n statusIcon: 'rotate-left',\n statusText: '已撤销扣除',\n deductionTime: '2024-12-25 11:20',\n amount: '2450.78',\n merchantNo: 'M20241225004'\n },\n {\n deviceNo: 'SN2024E34005',\n platform: '拉卡拉',\n statusKey: 'pending',\n statusIcon: 'clock',\n statusText: '等待扣除',\n deductionTime: '2024-12-28 08:00',\n amount: '5120.66',\n merchantNo: 'M20241228005'\n }\n ]\n }\n },\n computed: {\n filteredList() {\n let list = [...this.recordList]\n const deviceNo = this.queryForm.deviceNo.trim().toUpperCase()\n if (deviceNo) {\n list = list.filter(item =>\n item.deviceNo.toUpperCase().includes(deviceNo)\n )\n }\n const idx = parseInt(this.queryForm.statusIndex)\n if (idx > 0) {\n const keyMap = ['', 'pending', 'completed', 'cancelled', 'revoked']\n list = list.filter(item => item.statusKey === keyMap[idx])\n }\n return list\n }\n },\n methods: {\n onDeviceNoInput(e) {\n let val = e.detail.value\n val = val.replace(/[^a-zA-Z0-9]/g, '')\n this.queryForm.deviceNo = val\n },\n onStatusChange(e) {\n this.queryForm.statusIndex = parseInt(e.detail.value)\n },\n onQuery() {\n uni.showToast({\n title: `查询完成,共 ${this.filteredList.length} 条记录`,\n icon: 'none',\n duration: 2000\n })\n },\n onCopy(deviceNo) {\n uni.setClipboardData({\n data: deviceNo,\n success: () => {\n uni.showToast({\n title: '设备号已复制',\n icon: 'success',\n duration: 1500\n })\n },\n fail: () => {\n uni.showToast({\n title: '复制失败',\n icon: 'none',\n duration: 1500\n })\n }\n })\n },\n onGoDetail(item) {\n uni.navigateTo({\n url: `/pages/deduction-detail/deduction-detail?deviceNo=${item.deviceNo}&merchantNo=${item.merchantNo}`\n })\n },\n onBack() {\n uni.navigateBack()\n },\n onSearch() {\n this.onQuery()\n }\n }\n}\n</script>\n\n<style lang=\"scss\">\n// ============================================\n// 设计系统变量\n// ============================================\n$color-primary: #FF5A1F;\n$color-primary-dark: #E04A0E;\n$color-primary-light: #FF7A4A;\n$color-primary-gradient: linear-gradient(135deg, #FF5A1F 0%, #FF8C00 100%);\n$color-secondary: #FF8C00;\n$color-accent-blue: #2196F3;\n$color-accent-green: #4CAF50;\n$color-accent-red: #F44336;\n\n$color-bg: #FFF5F0;\n$color-card: #FFFFFF;\n$color-text: #2D1B14;\n$color-text-secondary: #8C7A72;\n$color-text-muted: #B8A8A0;\n$color-border: #E5E5E5;\n$color-shadow: rgba(255, 90, 31, 0.10);\n\n$radius-sm: 8rpx;\n$radius-md: 16rpx;\n$radius-lg: 24rpx;\n$radius-xl: 32rpx;\n\n// ============================================\n// 全局样式\n// ============================================\npage {\n background-color: $color-bg;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif;\n color: $color-text;\n}\n\n// ============================================\n// 图标基础\n// ============================================\n.icon {\n width: 32rpx;\n height: 32rpx;\n display: inline-block;\n vertical-align: middle;\n flex-shrink: 0;\n\n &--nav {\n width: 40rpx;\n height: 40rpx;\n padding: 12rpx;\n }\n &--title {\n width: 36rpx;\n height: 36rpx;\n margin-right: 10rpx;\n }\n &--label {\n width: 28rpx;\n height: 28rpx;\n margin-right: 8rpx;\n opacity: 0.7;\n }\n &--arrow {\n width: 28rpx;\n height: 28rpx;\n transition: transform 0.3s ease;\n }\n &--btn {\n width: 32rpx;\n height: 32rpx;\n margin-right: 8rpx;\n filter: brightness(0) invert(1);\n }\n &--clear {\n width: 28rpx;\n height: 28rpx;\n opacity: 0.4;\n }\n &--device {\n width: 32rpx;\n height: 32rpx;\n margin-right: 10rpx;\n }\n &--copy {\n width: 28rpx;\n height: 28rpx;\n margin-right: 4rpx;\n }\n &--row {\n width: 28rpx;\n height: 28rpx;\n margin-right: 10rpx;\n opacity: 0.55;\n }\n &--status {\n width: 28rpx;\n height: 28rpx;\n margin-right: 6rpx;\n }\n &--more {\n width: 28rpx;\n height: 28rpx;\n margin-left: 6rpx;\n opacity: 0.6;\n transition: transform 0.3s ease;\n }\n &--empty {\n width: 120rpx;\n height: 120rpx;\n opacity: 0.25;\n }\n}\n\n.input-placeholder {\n color: #C8B8B0;\n font-size: 26rpx;\n}\n\n// ============================================\n// 页面容器\n// ============================================\n.deduction-record {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n\n // ==========================================\n // 顶部导航栏\n // ==========================================\n &__navbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: 88rpx;\n padding: 0 20rpx;\n padding-top: var(--status-bar-height, 44px);\n height: calc(88rpx + var(--status-bar-height, 44px));\n background: $color-primary-gradient;\n position: relative;\n z-index: 100;\n\n &::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n bottom: -12rpx;\n height: 24rpx;\n background: $color-primary-gradient;\n filter: blur(12rpx);\n opacity: 0.4;\n z-index: -1;\n }\n }\n\n .navbar {\n &__left {\n display: flex;\n align-items: center;\n padding: 10rpx;\n }\n &__title {\n font-size: 34rpx;\n font-weight: 700;\n color: #FFFFFF;\n letter-spacing: 2rpx;\n text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);\n }\n &__right {\n display: flex;\n align-items: center;\n padding: 10rpx;\n }\n }\n\n // ==========================================\n // 滚动内容区\n // ==========================================\n &__body {\n flex: 1;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n padding: 0 24rpx;\n }\n\n &__footer {\n height: 40rpx;\n }\n}\n\n// ============================================\n// 查询卡片\n// ============================================\n.search-card {\n background: $color-card;\n border-radius: $radius-xl;\n padding: 32rpx 30rpx 30rpx;\n margin: 24rpx 0 20rpx;\n box-shadow: 0 8rpx 40rpx $color-shadow,\n 0 2rpx 8rpx rgba(0, 0, 0, 0.04);\n position: relative;\n overflow: hidden;\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 4rpx;\n background: $color-primary-gradient;\n }\n\n &__header {\n display: flex;\n align-items: center;\n margin-bottom: 28rpx;\n padding-bottom: 20rpx;\n border-bottom: 1rpx solid #FFF0E8;\n }\n\n &__title {\n font-size: 30rpx;\n font-weight: 600;\n color: $color-text;\n letter-spacing: 1rpx;\n }\n\n &__form {\n display: flex;\n flex-direction: column;\n gap: 24rpx;\n }\n}\n\n// ============================================\n// 表单组\n// ============================================\n.form-group {\n display: flex;\n flex-direction: column;\n gap: 12rpx;\n\n &__label-wrap {\n display: flex;\n align-items: center;\n }\n\n &__label {\n font-size: 26rpx;\n font-weight: 500;\n color: $color-text-secondary;\n letter-spacing: 1rpx;\n }\n\n &__input-wrap {\n display: flex;\n align-items: center;\n background: #FFF8F5;\n border: 2rpx solid #FFE8DC;\n border-radius: $radius-md;\n padding: 0 24rpx;\n height: 72rpx;\n transition: all 0.3s ease;\n\n &:focus-within {\n border-color: $color-primary;\n background: #FFFBF8;\n box-shadow: 0 0 0 4rpx rgba(255, 90, 31, 0.08);\n }\n }\n\n &__input {\n flex: 1;\n height: 72rpx;\n font-size: 28rpx;\n color: $color-text;\n background: transparent;\n border: none;\n outline: none;\n }\n\n &__clear {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 8rpx;\n }\n\n &__picker {\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: #FFF8F5;\n border: 2rpx solid #FFE8DC;\n border-radius: $radius-md;\n padding: 0 24rpx;\n height: 72rpx;\n transition: all 0.3s ease;\n\n &:active {\n border-color: $color-primary;\n background: #FFFBF8;\n }\n }\n\n &__picker-text {\n font-size: 28rpx;\n color: #C8B8B0;\n transition: color 0.3s ease;\n\n &.is-active {\n color: $color-text;\n font-weight: 500;\n }\n }\n\n &__btn {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 80rpx;\n margin-top: 8rpx;\n background: $color-primary-gradient;\n border-radius: $radius-md;\n font-size: 30rpx;\n font-weight: 600;\n color: #FFFFFF;\n letter-spacing: 4rpx;\n border: none;\n outline: none;\n box-shadow: 0 6rpx 24rpx rgba(255, 90, 31, 0.35);\n transition: all 0.3s ease;\n\n &::after {\n display: none;\n }\n\n &:active {\n transform: scale(0.97);\n box-shadow: 0 3rpx 12rpx rgba(255, 90, 31, 0.25);\n opacity: 0.92;\n }\n }\n}\n\n// ============================================\n// 统计条\n// ============================================\n.stat-bar {\n display: flex;\n align-items: center;\n padding: 12rpx 8rpx;\n margin-bottom: 12rpx;\n\n &__text {\n font-size: 24rpx;\n color: $color-text-muted;\n letter-spacing: 1rpx;\n }\n\n &__num {\n color: $color-primary;\n font-weight: 700;\n font-size: 28rpx;\n }\n}\n\n// ============================================\n// 记录卡片\n// ============================================\n.list-section {\n display: flex;\n flex-direction: column;\n gap: 24rpx;\n}\n\n.record-card {\n background: $color-card;\n border-radius: $radius-xl;\n padding: 28rpx 30rpx 0;\n box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04),\n 0 1rpx 4rpx rgba(0, 0, 0, 0.02);\n position: relative;\n overflow: hidden;\n transition: all 0.3s ease;\n\n &:active {\n transform: scale(0.99);\n box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);\n }\n\n // 顶部设备号栏 - 彩色装饰\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n width: 6rpx;\n height: 100%;\n background: $color-primary-gradient;\n border-radius: 0 3rpx 3rpx 0;\n }\n\n // 设备号\n &__device {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4rpx 0 20rpx;\n }\n\n .device {\n &__left {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n }\n\n &__number {\n font-size: 30rpx;\n font-weight: 700;\n color: $color-text;\n letter-spacing: 1rpx;\n font-family: 'Courier New', Courier, monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__copy {\n display: flex;\n align-items: center;\n background: linear-gradient(135deg, #FFF0E8, #FFE8DC);\n border: 1rpx solid #FFD8C8;\n border-radius: $radius-sm;\n padding: 6rpx 14rpx;\n margin-left: 16rpx;\n flex-shrink: 0;\n transition: all 0.25s ease;\n\n &:active {\n background: $color-primary;\n border-color: $color-primary;\n\n .icon--copy {\n filter: brightness(0) invert(1);\n }\n\n .device__copy-text {\n color: #FFFFFF;\n }\n }\n }\n\n &__copy-text {\n font-size: 22rpx;\n color: $color-primary;\n font-weight: 500;\n transition: color 0.25s ease;\n }\n }\n\n // 分割线\n &__divider {\n height: 1rpx;\n background-color: #E5E5E5;\n margin-bottom: 6rpx;\n }\n\n // 数据行\n &__row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14rpx 0;\n min-height: 52rpx;\n\n &--last {\n padding-bottom: 18rpx;\n }\n }\n\n .row {\n &__left {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n &__label {\n font-size: 26rpx;\n color: $color-text-muted;\n letter-spacing: 0.5rpx;\n }\n\n &__value {\n font-size: 26rpx;\n color: $color-text;\n font-weight: 500;\n text-align: right;\n max-width: 55%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &--time {\n color: $color-text-secondary;\n font-weight: 400;\n font-family: 'Courier New', Courier, monospace;\n font-size: 24rpx;\n }\n\n &--amount {\n font-size: 30rpx;\n font-weight: 700;\n color: $color-primary;\n }\n\n &--merchant {\n font-family: 'Courier New', Courier, monospace;\n font-size: 24rpx;\n color: $color-text-secondary;\n }\n }\n\n &__status {\n display: inline-flex;\n align-items: center;\n padding: 4rpx 14rpx;\n border-radius: 20rpx;\n font-size: 24rpx;\n font-weight: 500;\n\n &.status {\n &--pending {\n background: linear-gradient(135deg, #FFF3E0, #FFE0B2);\n color: #E65100;\n .icon--status {\n opacity: 0.8;\n }\n }\n &--completed {\n background: linear-gradient(135deg, #E8F5E9, #C8E6C9);\n color: #2E7D32;\n }\n &--cancelled {\n background: linear-gradient(135deg, #FFF3E0, #FFCCBC);\n color: #BF360C;\n }\n &--revoked {\n background: linear-gradient(135deg, #E3F2FD, #BBDEFB);\n color: #1565C0;\n }\n }\n }\n }\n\n // 更多按钮\n &__more {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 22rpx 0;\n border-top: 1rpx solid #FFF0E8;\n margin: 0 -30rpx;\n transition: all 0.3s ease;\n\n &:active {\n background: #FFF8F5;\n\n .more__text {\n color: $color-primary;\n }\n\n .icon--more {\n transform: translateX(4rpx);\n opacity: 1;\n }\n }\n }\n\n .more {\n &__text {\n font-size: 26rpx;\n color: $color-text-muted;\n font-weight: 500;\n transition: color 0.3s ease;\n }\n }\n}\n\n// ============================================\n// 空状态\n// ============================================\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 120rpx 40rpx 80rpx;\n\n &__icon-wrap {\n width: 160rpx;\n height: 160rpx;\n border-radius: 50%;\n background: #FFF0E8;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 32rpx;\n }\n\n &__title {\n font-size: 30rpx;\n font-weight: 600;\n color: $color-text-secondary;\n margin-bottom: 12rpx;\n }\n\n &__desc {\n font-size: 26rpx;\n color: $color-text-muted;\n letter-spacing: 1rpx;\n }\n}\n</style>"
},
"next": [
"添加下拉刷新",
"分页加载更多",
"状态筛选动效",
"数据导出功能",
"详情页联动"
],
"breakpoint": "xs"
}
```
推理
The user wants a "设备抵扣记录" (Device Deduction Record) page for a uni-app Vue2 project that's compatible with WeChat Mini Program. Let me analyze the requirements carefully:
1. **Search/Query Section**:
- Block layout with shadow
- Device number input (alphanumeric only, max 64 chars)
- Deduction status picker (using uni-app `<picker>` component)
- Search button (simulate query)
2. **Data Display Section**:
- Card layout with spacing between cards
- Each card shows:
- Device number (left-right layout with copy button)
- Divider line (1rpx, #e5e5e5)
- Platform (left-right layout)
- Deduction status (left-right layout)
- Deduction time (year-month-day hour:minute)
- Deduction amount (format: 1234.56)
- Merchant number (format: 1234567890)
- "More" button (navigate to detail page)
3. **Design Requirements**:
- Theme colors:橘红色 (orange-red) and orange为主, blue and green as secondary
- High-contrast, vibrant colors
- Mobile-first (phone)
- Use SCSS with nested styles
- uni-app Vue2 code compatible with WeChat Mini Program
- Use <view>, <text>, <image> tags
- Font Awesome icons from /static/icons directory (SVG format)
Let me first get the design system recommendations and assets.
Let me think about the design direction:
- Theme: Vibrant orange-red and orange tones
- Device: Mobile (uni-app + WeChat Mini Program compatible)
- Style: Modern, clean card-based UI with bold colors
Let me get the design system first.Now I have some design system info. Let me now design the page according to the user's requirements.
The user wants:
1. A uni-app Vue2 page compatible with WeChat Mini Program
2. Orange-red and orange theme colors, with blue and green as complementary
3. Font Awesome icons from /static/icons (SVG format)
4. SCSS styling with nesting
5. Mobile-first (phone only)
Let me now create the complete code.
For the Font Awesome icons, the user mentioned they're SVG files located at /static/icons directory. So I need to use <image> tags to reference these SVGs.
Common Font Awesome icons I might need:
- copy / clone: for copy button
- search / magnifying-glass: for search
- chevron-right / angle-right: for more
- Maybe some status icons
Let me think about the icon mappings:
- copy: /static/icons/copy.svg or /static/icons/clone.svg
- search: /static/icons/magnifying-glass.svg or /static/icons/search.svg
- angle-right: /static/icons/angle-right.svg
- filter: /static/icons/filter.svg
- clock: /static/icons/clock.svg
- money-bill: /static/icons/money-bill.svg
- store: /static/icons/store.svg
- check: /static/icons/check.svg
- times: /static/icons/times.svg or /static/icons/xmark.svg
- circle-check: /static/icons/circle-check.svg
- circle-xmark: /static/icons/circle-xmark.svg
- spinner: /static/icons/spinner.svg
Actually, for Font Awesome 6.4.0, the SVG file names would typically be kebab-case versions of the icon names. Let me use some common ones.
Let me design the page:
**Color Palette:**
- Primary: #FF6B35 (orange-red)
- Secondary: #FF8C00 (orange)
- Accent blue: #2563EB (blue)
- Accent green: #10B981 (green)
- Background: #F8F6F3 (warm light)
- Card background: #FFFFFF
- Text primary: #1A1A2E
- Text secondary: #6B7280
Let me think about the structure:
```
<template>
<view class="device-deduction-record">
<!-- Header -->
<view class="header">
<text class="header-title">设备抵扣记录</text>
</view>
<!-- Search/Query Section -->
<view class="search-section">
<view class="search-card">
<view class="form-group">
<text class="form-label">设备号</text>
<input ... />
</view>
<view class="form-group">
<text class="form-label">抵扣状态</text>
<picker ...>
<view class="picker-value">{{ statusText }}</view>
</picker>
</view>
<button class="search-btn">查询</button>
</view>
</view>
<!-- Data Display -->
<view class="data-section">
<view class="card" v-for="item in list" :key="item.id">
<!-- Device number with copy -->
<view class="card-row">
<text class="device-number">{{ item.deviceNo }}</text>
<image class="icon" src="/static/icons/copy.svg" @click="copy" />
</view>
<!-- Divider -->
<view class="divider"></view>
<!-- Platform -->
<view class="card-row">
<text class="label">平台</text>
<text class="value">{{ item.platform }}</text>
</view>
<!-- Status -->
<view class="card-row">
<text class="label">抵扣状态</text>
<text class="value">{{ item.status }}</text>
</view>
<!-- Time -->
<view class="card-row">
<text class="label">抵扣时间</text>
<text class="value">{{ item.time }}</text>
</view>
<!-- Amount -->
<view class="card-row">
<text class="label">抵扣金额</text>
<text class="value">{{ item.amount }}</text>
</view>
<!-- Merchant -->
<view class="card-row">
<text class="label">商户号</text>
<text class="value">{{ item.merchantNo }}</text>
</view>
<!-- More button -->
<view class="more-btn" @click="goToDetail(item)">
<text>更多</text>
<image class="icon-sm" src="/static/icons/angle-right.svg" />
</view>
</view>
</view>
</view>
</template>
```
Wait, let me re-read the requirements more carefully:
1. **抵扣状态** labels are wrong in my draft - the user said:
- 抵扣状态: 左右布局, 左侧展示 **平台**, 右侧展示具体的**平台名称**
Wait, that seems like a copy-paste error in the user's requirements. Let me re-read:
"抵扣状态: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称"
I think this might be a typo in the user's request. They probably mean left side shows "抵扣状态" (label) and right side shows the status value. But let me look at the original:
- 平台: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称
- 抵扣状态: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称
The second one seems like a copy-paste error. Given the context, for "抵扣状态", the left should show "抵扣状态" and the right should show the status value. Let me correct this.
Actually, looking again carefully at the user's request:
- 平台: 左右布局, 左侧展示"平台", 右侧展示具体的平台名称
- 抵扣状态: 左右布局, 左侧展示"抵扣状态", 右侧展示具体的状态名称
The user accidentally copied the wrong text for 抵扣状态. I'll use the correct labels.
Now, let me also think about the mock data. I need to create some sample records.
For the icons from Font Awesome 6.4.0, common SVG file names:
- copy.svg (or clone.svg / regular.svg) - for copy button
- angle-right.svg (or chevron-right.svg) - for more button
- search.svg (or magnifying-glass.svg) - for search
Let me check what Font Awesome 6.4.0 SVG file names look like... In Font Awesome 6, the SVGs are typically named like:
- `copy.svg`
- `angle-right.svg`
- `chevron-right.svg`
- `magnifying-glass.svg`
- `clock.svg`
- `circle-check.svg`
- `circle-xmark.svg`
- `filter.svg`
I'll use these common ones.
Now let me write the complete code. I need to use SCSS with nesting, uni-app Vue2 compatible with WeChat Mini Program.
Let me write the code now:
```vue
<template>
<view class="device-deduction-record">
<!-- 顶部导航 -->
<view class="nav-bar">
<view class="nav-back">
<image src="/static/icons/angle-left.svg" class="icon-nav" />
</view>
<text class="nav-title">设备抵扣记录</text>
<view class="nav-placeholder"></view>
</view>
<!-- 查询条件 -->
<view class="search-section">
<view class="search-card">
<view class="form-item">
<view class="form-item-header">
<image src="/static/icons/barcode.svg" class="icon-form" />
<text class="form-label">设备号</text>
</view>
<input
class="form-input"
v-model="queryParams.deviceNo"
placeholder="请输入设备号"
maxlength="64"
@input="onDeviceNoInput"
/>
</view>
<view class="form-item">
<view class="form-item-header">
<image src="/static/icons/filter.svg" class="icon-form" />
<text class="form-label">抵扣状态</text>
</view>
<picker mode="selector" :range="statusOptions" @change="onStatusChange">
<view class="picker-value">
<text>{{ statusOptions[queryParams.statusIndex] }}</text>
<image src="/static/icons/angle-down.svg" class="icon-arrow-down" />
</view>
</picker>
</view>
<button class="search-btn" @click="onSearch">查询</button>
</view>
</view>
<!-- 数据列表 -->
<view class="data-section">
<view class="card" v-for="(item, index) in recordList" :key="index">
<!-- 设备号 + 复制 -->
<view class="card-row device-row">
<text class="device-number">{{ item.deviceNo }}</text>
<image src="/static/icons/copy.svg" class="icon-copy" @click="onCopy(item.deviceNo)" />
</view>
<!-- 分割线 -->
<view class="divider"></view>
<!-- 平台 -->
<view class="card-row">
<text class="row-label">平台</text>
<text class="row-value">{{ item.platform }}</text>
</view>
<!-- 抵扣状态 -->
<view class="card-row">
<text class="row-label">抵扣状态</text>
<text class="row-value status-text" :class="'status-' + item.statusKey">{{ item.statusText }}</text>
</view>
<!-- 抵扣时间 -->
<view class="card-row">
<text class="row-label">抵扣时间</text>
<text class="row-value">{{ item.deductionTime }}</text>
</view>
<!-- 抵扣金额 -->
<view class="card-row">
<text class="row-label">抵扣金额</text>
<text class="row-value amount-text">¥{{ item.amount }}</text>
</view>
<!-- 商户号 -->
<view class="card-row">
<text class="row-label">商户号</text>
<text class="row-value">{{ item.merchantNo }}</text>
</view>
<!-- 更多 -->
<view class="more-btn" @click="onGoDetail(item)">
<text class="more-text">查看更多</text>
<image src="/static/icons/angle-right.svg" class="icon-more" />
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="recordList.length === 0">
<image src="/static/icons/inbox.svg" class="icon-empty" />
<text class="empty-text">暂无抵扣记录</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
queryParams: {
deviceNo: '',
statusIndex: 0
},
statusOptions: ['所有状态', '等待扣除', '已扣除', '已取消', '已撤销扣除'],
recordList: [],
mockData: [
{
deviceNo: 'SN20240101001',
platform: '微信支付',
statusKey: 'pending',
statusText: '等待扣除',
deductionTime: '2024-01-15 14:30',
amount: '1280.50',
merchantNo: 'M20240101001'
},
{
deviceNo: 'SN20240101002',
platform: '支付宝',
statusKey: 'completed',
statusText: '已扣除',
deductionTime: '2024-01-16 09:15',
amount: '2560.00',
merchantNo: 'M20240101002'
},
{
deviceNo: 'SN20240101003',
platform: '银联支付',
statusKey: 'cancelled',
statusText: '已取消',
deductionTime: '2024-01-17 16:45',
amount: '890.32',
merchantNo: 'M20240101003'
},
{
deviceNo: 'SN20240101004',
platform: '微信支付',
statusKey: 'revoked',
statusText: '已撤销扣除',
deductionTime: '2024-01-18 11:20',
amount: '3450.78',
merchantNo: 'M20240101004'
}
]
}
},
onLoad() {
this.recordList = [...this.mockData]
},
methods: {
onDeviceNoInput(e) {
// 仅允许字母和数字
let value = e.detail.value
value = value.replace(/[^a-zA-Z0-9]/g, '')
this.queryParams.deviceNo = value
},
onStatusChange(e) {
this.queryParams.statusIndex = e.detail.value
},
onSearch() {
// 模拟查询
let list = [...this.mockData]
if (this.queryParams.deviceNo) {
list = list.filter(item => item.deviceNo.includes(this.queryParams.deviceNo))
}
const statusIndex = parseInt(this.queryParams.statusIndex)
if (statusIndex > 0) {
const statusMap = ['', 'pending', 'completed', 'cancelled', 'revoked']
list = list.filter(item => item.statusKey === statusMap[statusIndex])
}
this.recordList = list
uni.showToast({
title: '查询完成',
icon: 'none',
duration: 1500
})
},
onCopy(deviceNo) {
uni.setClipboardData({
data: deviceNo,
success: () => {
uni.showToast({
title: '已复制',
icon: 'success',
duration: 1500
})
}
})
},
onGoDetail(item) {
uni.navigateTo({
url: `/pages/deduction-detail/deduction-detail?deviceNo=${item.deviceNo}`
})
}
}
}
</script>
<style lang="scss">
// ...styles
</style>
```
Wait, I need to reconsider the icons. The user said all icons are from fontawesome-free-6.4.0-web and placed at /static/icons. Let me use common Font Awesome 6 icon names.
In Font Awesome 6.4.0, the SVG file structure typically uses kebab-case names. Some common ones:
- `angle-left.svg`
- `angle-right.svg`
- `angle-down.svg`
- `copy.svg` (or `clone.svg`)
- `barcode.svg` (for device number)
- `filter.svg`
- `inbox.svg` (for empty state)
- `search.svg` (for search)
Actually, Font Awesome 6.4.0 SVG files are typically named with the icon name + .svg. Let me use realistic names.
Let me finalize the design and write the full code now.
Color scheme I'll go with:
- Primary (橘红色): `#FF5A1F` - vibrant orange-red
- Secondary (橙色): `#FF8C00`
- Blue accent: `#2B6CB0`
- Green accent: `#38A169`
- Warm background: `#FFF8F5`
- Card: `#FFFFFF`
- Text: `#1A202C`
- Secondary text: `#718096`
Let me finalize the complete code now.
Actually, let me also think about the format more carefully for icons. In uni-app with Mini Program compatibility, using `<image>` is the right approach for SVGs. But I need to be careful - some Mini Programs handle SVGs differently.
Let me create the full implementation now.Looks like there's some existing content but not directly relevant. Let me now build the complete page based on the user's requirements.
Let me think about the Font Awesome 6.4.0 SVG file names more carefully. In the Font Awesome Free 6.4.0 package, SVGs are organized by style (solid, regular, brands) and the filenames are the icon names in kebab-case.
Common icon names I'll use:
- `angle-left.svg` - back button
- `angle-right.svg` - more button
- `angle-down.svg` - dropdown arrow
- `copy.svg` - copy button
- `barcode.svg` - device number icon
- `filter.svg` - filter/status icon
- `inbox.svg` - empty state
Actually, the user said they placed "所有图标" from fontawesome-free-6.4.0-web in /static/icons. So the paths would be like:
- /static/icons/angle-left.svg
- /static/icons/angle-right.svg
- /static/icons/copy.svg
- etc.
These are solid style icons (the default in the free package's svg-icons directory).
Let me now write the complete code. I need to be careful about:
1. uni-app Vue2 syntax
2. WeChat Mini Program compatible tags (view, text, image, input, picker, button)
3. SCSS with nesting
4. Theme: orange-red and orange primary, blue and green accent
5. Mobile phone only (not responsive)
Let me design a really nice looking page with vibrant colors.
Color scheme:
- Primary: #FF5A1F (vibrant orange-red)
- Primary dark: #E04A0E
- Primary light: #FF7A4A
- Secondary (orange): #FF8C00
- Blue accent: #2196F3
- Green accent: #4CAF50
- Background: #FFF5F0 (warm light)
- Card: #FFFFFF
- Card shadow: rgba(255, 90, 31, 0.12)
- Text primary: #2D1B14
- Text secondary: #8C7A72
- Divider: #E5E5E5
Let me create the complete implementation now.The images don't really fit the device deduction record page. I'll proceed without them since this is a data-heavy page that doesn't need decorative images.
Now let me write the complete code. I'll focus on creating a beautiful, functional uni-app Vue2 page with:
- Vibrant orange-red / orange theme
- SCSS nesting
- Card-based layout
- Proper icons from /static/icons
- All the required functionality
Let me finalize and write the code.Now I have enough information. Let me build the complete page. I'll create a stunning, vibrant orange-red themed device deduction record page for uni-app Vue2.
Let me finalize the complete code now. I need to be careful about:
1. Uni-app Vue2 syntax - no Composition API
2. WeChat Mini Program compatible - use view, text, image, input, picker, button, scroll-view
3. SCSS with nested styles
4. Font Awesome 6.4.0 icons from /static/icons
5. Mobile-only (no responsive)
Let me write the final code:Good. Now let me create the complete page code. Let me write the full implementation:
I'll design a visually striking mobile page with:
- A gradient header with orange-red tones
- A white search card with prominent shadow
- Beautiful cards for each record with orange-red accent elements
- Color-coded status badges
- Clean iconography from Font Awesome
Here's my complete plan for the code:
```vue
<template>
<view class="deduction-record">
<!-- 顶部导航栏 -->
<view class="header">
<view class="header__back">
<image src="/static/icons/angle-left.svg" class="icon icon--back" />
</view>
<text class="header__title">设备抵扣记录</text>
<view class="header__right" />
</view>
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-card">
<view class="form-group">
<view class="form-group__label">
<image src="/static/icons/barcode.svg" class="icon icon--form" />
<text>设备号</text>
</view>
<input ... />
</view>
<view class="form-group">
<view class="form-group__label">
<image src="/static/icons/filter.svg" class="icon icon--form" />
<text>抵扣状态</text>
</view>
<picker ...>
...
</picker>
</view>
<button class="search-btn">查询</button>
</view>
</view>
<!-- 记录列表 -->
<scroll-view class="list-section">
<view class="card" v-for="...">
...
</view>
</scroll-view>
</view>
</template>
```
Let me write the complete code now with all the details.Now let me write the final complete code. I have all the information I need. Let me craft the complete uni-app Vue2 page.
Key design decisions:
1. **Color Palette** - Orange-red (#FF5A1F) dominant, orange (#FF8C00) secondary, blue (#2196F3) and green (#4CAF50) as accents
2. **Font** - Use a unique Chinese-friendly font
3. **Layout** - Sticky header, scrollable content, card-based records
4. **Icons** - Font Awesome 6.4.0 SVG from /static/icons
Let me write the complete code now.OK, I have enough context. Let me now write the complete uni-app Vue2 page code. Let me create a visually stunning, vibrant orange-red themed page.
Let me think about the specific Font Awesome icon SVG file names I'll use. In Font Awesome 6.4.0 Free, the SVG filenames in the `svgs/solid` directory would be:
- `angle-left.svg`
- `angle-right.svg`
- `angle-down.svg`
- `copy.svg`
- `magnifying-glass.svg` (search)
- `filter.svg`
- `clock.svg`
- `building.svg` (merchant)
- `tags.svg` (amount/tags)
- `circle-check.svg` (completed status)
- `circle-xmark.svg` (cancelled status)
- `circle-pause.svg` or `clock.svg` (pending)
- `rotate-left.svg` (revoked)
- `chevron-right.svg` (more)
Wait, in Font Awesome 6.4.0, the actual file structure has folders like `svgs/solid/`, `svgs/regular/`, `svgs/brands/`. The user said they placed "所有图标" in /static/icons. So I'll reference them directly as `/static/icons/filename.svg`.
Common icon SVG files I can use:
- angle-left.svg ✓
- angle-right.svg ✓
- angle-down.svg ✓
- copy.svg ✓
- search.svg ✓ (or magnifying-glass.svg)
- filter.svg ✓
- barcode.svg ✓ (for device number)
- store.svg ✓ (for platform/merchant)
- circle-check.svg ✓
- circle-xmark.svg ✓
- clock.svg ✓
- circle-info.svg ✓
- chevron-right.svg ✓
Let me now write the final code. I'll use BEM-like naming convention with SCSS nesting.
Actually wait, let me re-check - in Font Awesome 6.4.0 free web package, the SVG file names in the `sprites` or `svgs` directory - they should be the icon names in kebab-case. Let me use commonly available ones.
Now writing the complete code:
1. **Search/Query Section**:
- Block layout with shadow
- Device number input (alphanumeric only, max 64 chars)
- Deduction status picker (using uni-app `<picker>` component)
- Search button (simulate query)
2. **Data Display Section**:
- Card layout with spacing between cards
- Each card shows:
- Device number (left-right layout with copy button)
- Divider line (1rpx, #e5e5e5)
- Platform (left-right layout)
- Deduction status (left-right layout)
- Deduction time (year-month-day hour:minute)
- Deduction amount (format: 1234.56)
- Merchant number (format: 1234567890)
- "More" button (navigate to detail page)
3. **Design Requirements**:
- Theme colors:橘红色 (orange-red) and orange为主, blue and green as secondary
- High-contrast, vibrant colors
- Mobile-first (phone)
- Use SCSS with nested styles
- uni-app Vue2 code compatible with WeChat Mini Program
- Use <view>, <text>, <image> tags
- Font Awesome icons from /static/icons directory (SVG format)
Let me first get the design system recommendations and assets.
Let me think about the design direction:
- Theme: Vibrant orange-red and orange tones
- Device: Mobile (uni-app + WeChat Mini Program compatible)
- Style: Modern, clean card-based UI with bold colors
Let me get the design system first.Now I have some design system info. Let me now design the page according to the user's requirements.
The user wants:
1. A uni-app Vue2 page compatible with WeChat Mini Program
2. Orange-red and orange theme colors, with blue and green as complementary
3. Font Awesome icons from /static/icons (SVG format)
4. SCSS styling with nesting
5. Mobile-first (phone only)
Let me now create the complete code.
For the Font Awesome icons, the user mentioned they're SVG files located at /static/icons directory. So I need to use <image> tags to reference these SVGs.
Common Font Awesome icons I might need:
- copy / clone: for copy button
- search / magnifying-glass: for search
- chevron-right / angle-right: for more
- Maybe some status icons
Let me think about the icon mappings:
- copy: /static/icons/copy.svg or /static/icons/clone.svg
- search: /static/icons/magnifying-glass.svg or /static/icons/search.svg
- angle-right: /static/icons/angle-right.svg
- filter: /static/icons/filter.svg
- clock: /static/icons/clock.svg
- money-bill: /static/icons/money-bill.svg
- store: /static/icons/store.svg
- check: /static/icons/check.svg
- times: /static/icons/times.svg or /static/icons/xmark.svg
- circle-check: /static/icons/circle-check.svg
- circle-xmark: /static/icons/circle-xmark.svg
- spinner: /static/icons/spinner.svg
Actually, for Font Awesome 6.4.0, the SVG file names would typically be kebab-case versions of the icon names. Let me use some common ones.
Let me design the page:
**Color Palette:**
- Primary: #FF6B35 (orange-red)
- Secondary: #FF8C00 (orange)
- Accent blue: #2563EB (blue)
- Accent green: #10B981 (green)
- Background: #F8F6F3 (warm light)
- Card background: #FFFFFF
- Text primary: #1A1A2E
- Text secondary: #6B7280
Let me think about the structure:
```
<template>
<view class="device-deduction-record">
<!-- Header -->
<view class="header">
<text class="header-title">设备抵扣记录</text>
</view>
<!-- Search/Query Section -->
<view class="search-section">
<view class="search-card">
<view class="form-group">
<text class="form-label">设备号</text>
<input ... />
</view>
<view class="form-group">
<text class="form-label">抵扣状态</text>
<picker ...>
<view class="picker-value">{{ statusText }}</view>
</picker>
</view>
<button class="search-btn">查询</button>
</view>
</view>
<!-- Data Display -->
<view class="data-section">
<view class="card" v-for="item in list" :key="item.id">
<!-- Device number with copy -->
<view class="card-row">
<text class="device-number">{{ item.deviceNo }}</text>
<image class="icon" src="/static/icons/copy.svg" @click="copy" />
</view>
<!-- Divider -->
<view class="divider"></view>
<!-- Platform -->
<view class="card-row">
<text class="label">平台</text>
<text class="value">{{ item.platform }}</text>
</view>
<!-- Status -->
<view class="card-row">
<text class="label">抵扣状态</text>
<text class="value">{{ item.status }}</text>
</view>
<!-- Time -->
<view class="card-row">
<text class="label">抵扣时间</text>
<text class="value">{{ item.time }}</text>
</view>
<!-- Amount -->
<view class="card-row">
<text class="label">抵扣金额</text>
<text class="value">{{ item.amount }}</text>
</view>
<!-- Merchant -->
<view class="card-row">
<text class="label">商户号</text>
<text class="value">{{ item.merchantNo }}</text>
</view>
<!-- More button -->
<view class="more-btn" @click="goToDetail(item)">
<text>更多</text>
<image class="icon-sm" src="/static/icons/angle-right.svg" />
</view>
</view>
</view>
</view>
</template>
```
Wait, let me re-read the requirements more carefully:
1. **抵扣状态** labels are wrong in my draft - the user said:
- 抵扣状态: 左右布局, 左侧展示 **平台**, 右侧展示具体的**平台名称**
Wait, that seems like a copy-paste error in the user's requirements. Let me re-read:
"抵扣状态: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称"
I think this might be a typo in the user's request. They probably mean left side shows "抵扣状态" (label) and right side shows the status value. But let me look at the original:
- 平台: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称
- 抵扣状态: 左右布局, 左侧展示 平台, 右侧展示具体的平台名称
The second one seems like a copy-paste error. Given the context, for "抵扣状态", the left should show "抵扣状态" and the right should show the status value. Let me correct this.
Actually, looking again carefully at the user's request:
- 平台: 左右布局, 左侧展示"平台", 右侧展示具体的平台名称
- 抵扣状态: 左右布局, 左侧展示"抵扣状态", 右侧展示具体的状态名称
The user accidentally copied the wrong text for 抵扣状态. I'll use the correct labels.
Now, let me also think about the mock data. I need to create some sample records.
For the icons from Font Awesome 6.4.0, common SVG file names:
- copy.svg (or clone.svg / regular.svg) - for copy button
- angle-right.svg (or chevron-right.svg) - for more button
- search.svg (or magnifying-glass.svg) - for search
Let me check what Font Awesome 6.4.0 SVG file names look like... In Font Awesome 6, the SVGs are typically named like:
- `copy.svg`
- `angle-right.svg`
- `chevron-right.svg`
- `magnifying-glass.svg`
- `clock.svg`
- `circle-check.svg`
- `circle-xmark.svg`
- `filter.svg`
I'll use these common ones.
Now let me write the complete code. I need to use SCSS with nesting, uni-app Vue2 compatible with WeChat Mini Program.
Let me write the code now:
```vue
<template>
<view class="device-deduction-record">
<!-- 顶部导航 -->
<view class="nav-bar">
<view class="nav-back">
<image src="/static/icons/angle-left.svg" class="icon-nav" />
</view>
<text class="nav-title">设备抵扣记录</text>
<view class="nav-placeholder"></view>
</view>
<!-- 查询条件 -->
<view class="search-section">
<view class="search-card">
<view class="form-item">
<view class="form-item-header">
<image src="/static/icons/barcode.svg" class="icon-form" />
<text class="form-label">设备号</text>
</view>
<input
class="form-input"
v-model="queryParams.deviceNo"
placeholder="请输入设备号"
maxlength="64"
@input="onDeviceNoInput"
/>
</view>
<view class="form-item">
<view class="form-item-header">
<image src="/static/icons/filter.svg" class="icon-form" />
<text class="form-label">抵扣状态</text>
</view>
<picker mode="selector" :range="statusOptions" @change="onStatusChange">
<view class="picker-value">
<text>{{ statusOptions[queryParams.statusIndex] }}</text>
<image src="/static/icons/angle-down.svg" class="icon-arrow-down" />
</view>
</picker>
</view>
<button class="search-btn" @click="onSearch">查询</button>
</view>
</view>
<!-- 数据列表 -->
<view class="data-section">
<view class="card" v-for="(item, index) in recordList" :key="index">
<!-- 设备号 + 复制 -->
<view class="card-row device-row">
<text class="device-number">{{ item.deviceNo }}</text>
<image src="/static/icons/copy.svg" class="icon-copy" @click="onCopy(item.deviceNo)" />
</view>
<!-- 分割线 -->
<view class="divider"></view>
<!-- 平台 -->
<view class="card-row">
<text class="row-label">平台</text>
<text class="row-value">{{ item.platform }}</text>
</view>
<!-- 抵扣状态 -->
<view class="card-row">
<text class="row-label">抵扣状态</text>
<text class="row-value status-text" :class="'status-' + item.statusKey">{{ item.statusText }}</text>
</view>
<!-- 抵扣时间 -->
<view class="card-row">
<text class="row-label">抵扣时间</text>
<text class="row-value">{{ item.deductionTime }}</text>
</view>
<!-- 抵扣金额 -->
<view class="card-row">
<text class="row-label">抵扣金额</text>
<text class="row-value amount-text">¥{{ item.amount }}</text>
</view>
<!-- 商户号 -->
<view class="card-row">
<text class="row-label">商户号</text>
<text class="row-value">{{ item.merchantNo }}</text>
</view>
<!-- 更多 -->
<view class="more-btn" @click="onGoDetail(item)">
<text class="more-text">查看更多</text>
<image src="/static/icons/angle-right.svg" class="icon-more" />
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="recordList.length === 0">
<image src="/static/icons/inbox.svg" class="icon-empty" />
<text class="empty-text">暂无抵扣记录</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
queryParams: {
deviceNo: '',
statusIndex: 0
},
statusOptions: ['所有状态', '等待扣除', '已扣除', '已取消', '已撤销扣除'],
recordList: [],
mockData: [
{
deviceNo: 'SN20240101001',
platform: '微信支付',
statusKey: 'pending',
statusText: '等待扣除',
deductionTime: '2024-01-15 14:30',
amount: '1280.50',
merchantNo: 'M20240101001'
},
{
deviceNo: 'SN20240101002',
platform: '支付宝',
statusKey: 'completed',
statusText: '已扣除',
deductionTime: '2024-01-16 09:15',
amount: '2560.00',
merchantNo: 'M20240101002'
},
{
deviceNo: 'SN20240101003',
platform: '银联支付',
statusKey: 'cancelled',
statusText: '已取消',
deductionTime: '2024-01-17 16:45',
amount: '890.32',
merchantNo: 'M20240101003'
},
{
deviceNo: 'SN20240101004',
platform: '微信支付',
statusKey: 'revoked',
statusText: '已撤销扣除',
deductionTime: '2024-01-18 11:20',
amount: '3450.78',
merchantNo: 'M20240101004'
}
]
}
},
onLoad() {
this.recordList = [...this.mockData]
},
methods: {
onDeviceNoInput(e) {
// 仅允许字母和数字
let value = e.detail.value
value = value.replace(/[^a-zA-Z0-9]/g, '')
this.queryParams.deviceNo = value
},
onStatusChange(e) {
this.queryParams.statusIndex = e.detail.value
},
onSearch() {
// 模拟查询
let list = [...this.mockData]
if (this.queryParams.deviceNo) {
list = list.filter(item => item.deviceNo.includes(this.queryParams.deviceNo))
}
const statusIndex = parseInt(this.queryParams.statusIndex)
if (statusIndex > 0) {
const statusMap = ['', 'pending', 'completed', 'cancelled', 'revoked']
list = list.filter(item => item.statusKey === statusMap[statusIndex])
}
this.recordList = list
uni.showToast({
title: '查询完成',
icon: 'none',
duration: 1500
})
},
onCopy(deviceNo) {
uni.setClipboardData({
data: deviceNo,
success: () => {
uni.showToast({
title: '已复制',
icon: 'success',
duration: 1500
})
}
})
},
onGoDetail(item) {
uni.navigateTo({
url: `/pages/deduction-detail/deduction-detail?deviceNo=${item.deviceNo}`
})
}
}
}
</script>
<style lang="scss">
// ...styles
</style>
```
Wait, I need to reconsider the icons. The user said all icons are from fontawesome-free-6.4.0-web and placed at /static/icons. Let me use common Font Awesome 6 icon names.
In Font Awesome 6.4.0, the SVG file structure typically uses kebab-case names. Some common ones:
- `angle-left.svg`
- `angle-right.svg`
- `angle-down.svg`
- `copy.svg` (or `clone.svg`)
- `barcode.svg` (for device number)
- `filter.svg`
- `inbox.svg` (for empty state)
- `search.svg` (for search)
Actually, Font Awesome 6.4.0 SVG files are typically named with the icon name + .svg. Let me use realistic names.
Let me finalize the design and write the full code now.
Color scheme I'll go with:
- Primary (橘红色): `#FF5A1F` - vibrant orange-red
- Secondary (橙色): `#FF8C00`
- Blue accent: `#2B6CB0`
- Green accent: `#38A169`
- Warm background: `#FFF8F5`
- Card: `#FFFFFF`
- Text: `#1A202C`
- Secondary text: `#718096`
Let me finalize the complete code now.
Actually, let me also think about the format more carefully for icons. In uni-app with Mini Program compatibility, using `<image>` is the right approach for SVGs. But I need to be careful - some Mini Programs handle SVGs differently.
Let me create the full implementation now.Looks like there's some existing content but not directly relevant. Let me now build the complete page based on the user's requirements.
Let me think about the Font Awesome 6.4.0 SVG file names more carefully. In the Font Awesome Free 6.4.0 package, SVGs are organized by style (solid, regular, brands) and the filenames are the icon names in kebab-case.
Common icon names I'll use:
- `angle-left.svg` - back button
- `angle-right.svg` - more button
- `angle-down.svg` - dropdown arrow
- `copy.svg` - copy button
- `barcode.svg` - device number icon
- `filter.svg` - filter/status icon
- `inbox.svg` - empty state
Actually, the user said they placed "所有图标" from fontawesome-free-6.4.0-web in /static/icons. So the paths would be like:
- /static/icons/angle-left.svg
- /static/icons/angle-right.svg
- /static/icons/copy.svg
- etc.
These are solid style icons (the default in the free package's svg-icons directory).
Let me now write the complete code. I need to be careful about:
1. uni-app Vue2 syntax
2. WeChat Mini Program compatible tags (view, text, image, input, picker, button)
3. SCSS with nesting
4. Theme: orange-red and orange primary, blue and green accent
5. Mobile phone only (not responsive)
Let me design a really nice looking page with vibrant colors.
Color scheme:
- Primary: #FF5A1F (vibrant orange-red)
- Primary dark: #E04A0E
- Primary light: #FF7A4A
- Secondary (orange): #FF8C00
- Blue accent: #2196F3
- Green accent: #4CAF50
- Background: #FFF5F0 (warm light)
- Card: #FFFFFF
- Card shadow: rgba(255, 90, 31, 0.12)
- Text primary: #2D1B14
- Text secondary: #8C7A72
- Divider: #E5E5E5
Let me create the complete implementation now.The images don't really fit the device deduction record page. I'll proceed without them since this is a data-heavy page that doesn't need decorative images.
Now let me write the complete code. I'll focus on creating a beautiful, functional uni-app Vue2 page with:
- Vibrant orange-red / orange theme
- SCSS nesting
- Card-based layout
- Proper icons from /static/icons
- All the required functionality
Let me finalize and write the code.Now I have enough information. Let me build the complete page. I'll create a stunning, vibrant orange-red themed device deduction record page for uni-app Vue2.
Let me finalize the complete code now. I need to be careful about:
1. Uni-app Vue2 syntax - no Composition API
2. WeChat Mini Program compatible - use view, text, image, input, picker, button, scroll-view
3. SCSS with nested styles
4. Font Awesome 6.4.0 icons from /static/icons
5. Mobile-only (no responsive)
Let me write the final code:Good. Now let me create the complete page code. Let me write the full implementation:
I'll design a visually striking mobile page with:
- A gradient header with orange-red tones
- A white search card with prominent shadow
- Beautiful cards for each record with orange-red accent elements
- Color-coded status badges
- Clean iconography from Font Awesome
Here's my complete plan for the code:
```vue
<template>
<view class="deduction-record">
<!-- 顶部导航栏 -->
<view class="header">
<view class="header__back">
<image src="/static/icons/angle-left.svg" class="icon icon--back" />
</view>
<text class="header__title">设备抵扣记录</text>
<view class="header__right" />
</view>
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-card">
<view class="form-group">
<view class="form-group__label">
<image src="/static/icons/barcode.svg" class="icon icon--form" />
<text>设备号</text>
</view>
<input ... />
</view>
<view class="form-group">
<view class="form-group__label">
<image src="/static/icons/filter.svg" class="icon icon--form" />
<text>抵扣状态</text>
</view>
<picker ...>
...
</picker>
</view>
<button class="search-btn">查询</button>
</view>
</view>
<!-- 记录列表 -->
<scroll-view class="list-section">
<view class="card" v-for="...">
...
</view>
</scroll-view>
</view>
</template>
```
Let me write the complete code now with all the details.Now let me write the final complete code. I have all the information I need. Let me craft the complete uni-app Vue2 page.
Key design decisions:
1. **Color Palette** - Orange-red (#FF5A1F) dominant, orange (#FF8C00) secondary, blue (#2196F3) and green (#4CAF50) as accents
2. **Font** - Use a unique Chinese-friendly font
3. **Layout** - Sticky header, scrollable content, card-based records
4. **Icons** - Font Awesome 6.4.0 SVG from /static/icons
Let me write the complete code now.OK, I have enough context. Let me now write the complete uni-app Vue2 page code. Let me create a visually stunning, vibrant orange-red themed page.
Let me think about the specific Font Awesome icon SVG file names I'll use. In Font Awesome 6.4.0 Free, the SVG filenames in the `svgs/solid` directory would be:
- `angle-left.svg`
- `angle-right.svg`
- `angle-down.svg`
- `copy.svg`
- `magnifying-glass.svg` (search)
- `filter.svg`
- `clock.svg`
- `building.svg` (merchant)
- `tags.svg` (amount/tags)
- `circle-check.svg` (completed status)
- `circle-xmark.svg` (cancelled status)
- `circle-pause.svg` or `clock.svg` (pending)
- `rotate-left.svg` (revoked)
- `chevron-right.svg` (more)
Wait, in Font Awesome 6.4.0, the actual file structure has folders like `svgs/solid/`, `svgs/regular/`, `svgs/brands/`. The user said they placed "所有图标" in /static/icons. So I'll reference them directly as `/static/icons/filename.svg`.
Common icon SVG files I can use:
- angle-left.svg ✓
- angle-right.svg ✓
- angle-down.svg ✓
- copy.svg ✓
- search.svg ✓ (or magnifying-glass.svg)
- filter.svg ✓
- barcode.svg ✓ (for device number)
- store.svg ✓ (for platform/merchant)
- circle-check.svg ✓
- circle-xmark.svg ✓
- clock.svg ✓
- circle-info.svg ✓
- chevron-right.svg ✓
Let me now write the final code. I'll use BEM-like naming convention with SCSS nesting.
Actually wait, let me re-check - in Font Awesome 6.4.0 free web package, the SVG file names in the `sprites` or `svgs` directory - they should be the icon names in kebab-case. Let me use commonly available ones.
Now writing the complete code:
角色
assistant
content
total_tokens
23998
summary
设计并实现了一个「设备抵扣记录」uni-app Vue2 移动端页面,以橘红色/橙色为主色调,蓝绿为辅色。采用卡片式布局展示抵扣记录,查询区域带阴影突出显示,使用 Font Awesome 6.4.0 SVG 图标,SCSS 嵌套样式,兼容微信小程序。包含设备号输入(仅字母数字)、picker 状态选择、模拟查询、复制设备号、卡片数据展示及跳转详情等功能。
uiParsing
关闭