完整项目初始化
This commit is contained in:
commit
cddf85b760
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
unpackage/
|
||||
.hbuilderx/
|
||||
.DS_Store
|
||||
133
App.vue
Normal file
133
App.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<script>
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ====== 全局设计系统 ====== */
|
||||
page {
|
||||
/* 主色 - 仅用于交互元素 */
|
||||
--color-primary: #409eff;
|
||||
--color-primary-light: #ecf5ff;
|
||||
--color-primary-disabled: #a0cfff;
|
||||
|
||||
/* 背景色 - 以白色为主 */
|
||||
--bg-page: #f5f6fa;
|
||||
--bg-card: #ffffff;
|
||||
--bg-secondary: #f5f7fa;
|
||||
--bg-tertiary: #f0f2f5;
|
||||
|
||||
/* 文字色 - 中性灰阶 */
|
||||
--text-primary: #1d2129;
|
||||
--text-regular: #4e5969;
|
||||
--text-secondary: #86909c;
|
||||
--text-placeholder: #c9cdd4;
|
||||
--text-disabled: #e5e6eb;
|
||||
|
||||
/* 边框 */
|
||||
--border-color: #e5e6eb;
|
||||
--border-light: #f2f3f5;
|
||||
|
||||
/* 语义色 - 极简使用 */
|
||||
--color-danger: #f77234;
|
||||
--color-success: #00b42a;
|
||||
--color-warning: #ff7d00;
|
||||
|
||||
/* 阴影 - 更柔和 */
|
||||
--shadow-sm: 0 1rpx 4rpx rgba(0,0,0,0.04);
|
||||
--shadow-md: 0 2rpx 8rpx rgba(0,0,0,0.06);
|
||||
--shadow-lg: 0 4rpx 16rpx rgba(0,0,0,0.08);
|
||||
|
||||
/* 圆角 */
|
||||
--radius-sm: 8rpx;
|
||||
--radius-md: 12rpx;
|
||||
--radius-lg: 16rpx;
|
||||
--radius-xl: 20rpx;
|
||||
|
||||
/* 间距 */
|
||||
--spacing-page: 28rpx;
|
||||
--spacing-card: 24rpx;
|
||||
--spacing-section: 20rpx;
|
||||
|
||||
background: var(--bg-page);
|
||||
font-size: 28rpx;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 全局重置 */
|
||||
view, text, input, button, scroll-view {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 通用卡片样式 */
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* 主按钮 */
|
||||
.btn-primary {
|
||||
background: var(--color-primary);
|
||||
color: #ffffff;
|
||||
border-radius: var(--radius-md);
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
}
|
||||
.btn-primary:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
.btn-primary[disabled] {
|
||||
background: var(--color-primary-disabled);
|
||||
color: rgba(255,255,255,0.7);
|
||||
}
|
||||
|
||||
/* 输入框统一风格 */
|
||||
.field-input, input[type="text"], input[type="password"] {
|
||||
background: var(--bg-secondary);
|
||||
border: 2rpx solid transparent;
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 20rpx 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--text-primary);
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.field-input:focus, input:focus {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* 页面标题 */
|
||||
.page-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 状态标签 */
|
||||
.tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 6rpx;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.tag-blue { background: var(--color-primary-light); color: var(--color-primary); }
|
||||
.tag-green { background: #e8ffea; color: var(--color-success); }
|
||||
.tag-orange { background: #fff3e8; color: var(--color-warning); }
|
||||
.tag-red { background: #fff1e8; color: var(--color-danger); }
|
||||
.tag-gray { background: var(--bg-tertiary); color: var(--text-secondary); }
|
||||
</style>
|
||||
20
index.html
Normal file
20
index.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
22
main.js
Normal file
22
main.js
Normal file
@ -0,0 +1,22 @@
|
||||
import App from './App'
|
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import './uni.promisify.adaptor'
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
const app = new Vue({
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { createSSRApp } from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
72
manifest.json
Normal file
72
manifest.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"name" : "scanBook",
|
||||
"appid" : "",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "2"
|
||||
}
|
||||
18
package-lock.json
generated
Normal file
18
package-lock.json
generated
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "scanBook",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"blueimp-md5": "^2.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/blueimp-md5": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz",
|
||||
"integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"blueimp-md5": "^2.19.0"
|
||||
}
|
||||
}
|
||||
65
pages.json
Normal file
65
pages.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/entry/entry",
|
||||
"style": {
|
||||
"navigationBarTitleText": "功能入口"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/warehouse/warehouse",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择仓库"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/home",
|
||||
"style": {
|
||||
"navigationBarTitleText": "入库助手"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order",
|
||||
"style": {
|
||||
"navigationBarTitleText": "仓库订单"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/vip/vip",
|
||||
"style": {
|
||||
"navigationBarTitleText": "会员等级选择"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/record/record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上书记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/upload/upload",
|
||||
"style": {
|
||||
"navigationBarTitleText": "图书上传"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "入库助手",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"backgroundColor": "#f5f7fa"
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
||||
262
pages/entry/entry.vue
Normal file
262
pages/entry/entry.vue
Normal file
@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<view class="entry-container">
|
||||
<!-- 页面标题 -->
|
||||
<view class="header">
|
||||
<text class="title">请选择您要使用的功能</text>
|
||||
</view>
|
||||
|
||||
<!-- 功能入口列表 -->
|
||||
<view class="entry-list">
|
||||
<!-- 小程序上书 -->
|
||||
<view class="entry-item" @click="handleEntry('upload')">
|
||||
<view class="entry-icon upload-icon">
|
||||
<view class="icon-book"></view>
|
||||
<view class="icon-arrow"></view>
|
||||
</view>
|
||||
<view class="entry-content">
|
||||
<text class="entry-title">小程序上书</text>
|
||||
<text class="entry-desc">进入仓库后选择上书</text>
|
||||
</view>
|
||||
<view class="entry-arrow">
|
||||
<text class="arrow-icon">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 孔网商品翻新 -->
|
||||
<view class="entry-item" @click="handleEntry('refresh')">
|
||||
<view class="entry-icon refresh-icon">
|
||||
<view class="icon-refresh-circle"></view>
|
||||
<view class="icon-refresh-arrow"></view>
|
||||
</view>
|
||||
<view class="entry-content">
|
||||
<text class="entry-title">孔网商品翻新</text>
|
||||
<text class="entry-desc">会员功能、支持商品翻新</text>
|
||||
</view>
|
||||
<view class="entry-arrow">
|
||||
<text class="arrow-icon">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 仓库订单 -->
|
||||
<view class="entry-item" @click="handleEntry('order')">
|
||||
<view class="entry-icon order-icon">
|
||||
<view class="icon-order-box"></view>
|
||||
<view class="icon-order-lines">
|
||||
<view class="line line-1"></view>
|
||||
<view class="line line-2"></view>
|
||||
<view class="line line-3"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="entry-content">
|
||||
<text class="entry-title">仓库订单</text>
|
||||
<text class="entry-desc">显示仓库订单</text>
|
||||
</view>
|
||||
<view class="entry-arrow">
|
||||
<text class="arrow-icon">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({
|
||||
title: '功能入口'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleEntry(type) {
|
||||
switch (type) {
|
||||
case 'upload':
|
||||
uni.navigateTo({
|
||||
url: '/pages/warehouse/warehouse'
|
||||
})
|
||||
break
|
||||
case 'refresh':
|
||||
uni.showToast({
|
||||
title: '孔网商品翻新',
|
||||
icon: 'none'
|
||||
})
|
||||
// TODO: 跳转到翻新页面
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/refresh/refresh'
|
||||
// })
|
||||
break
|
||||
case 'order':
|
||||
uni.navigateTo({
|
||||
url: '/pages/order/order'
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.entry-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding: 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 页面标题 */
|
||||
.header {
|
||||
padding: 40rpx 0 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 功能入口列表 */
|
||||
.entry-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.entry-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* 图标区域 */
|
||||
.entry-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
margin-right: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 上书图标 - 书本 */
|
||||
.upload-icon {
|
||||
background: #f5f6fa;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.icon-book {
|
||||
width: 28rpx;
|
||||
height: 32rpx;
|
||||
border: 2rpx solid #86909c;
|
||||
border-radius: 2rpx 6rpx 2rpx 2rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-book::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4rpx;
|
||||
top: 4rpx;
|
||||
width: 2rpx;
|
||||
height: 24rpx;
|
||||
background: #86909c;
|
||||
}
|
||||
|
||||
/* 翻新图标 - 刷新圆圈 */
|
||||
.refresh-icon {
|
||||
background: #f5f6fa;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.icon-refresh-circle {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border: 2rpx solid #86909c;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.icon-refresh-arrow {
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-top: 2rpx solid #86909c;
|
||||
border-right: 2rpx solid #86909c;
|
||||
position: absolute;
|
||||
top: 12rpx;
|
||||
right: 14rpx;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
/* 订单图标 - 订单盒子 */
|
||||
.order-icon {
|
||||
background: #f5f6fa;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.icon-order-box {
|
||||
width: 28rpx;
|
||||
height: 24rpx;
|
||||
border: 2rpx solid #86909c;
|
||||
border-radius: 4rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-order-lines {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 16rpx;
|
||||
height: 2rpx;
|
||||
background: #86909c;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.line-1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
.entry-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.entry-title {
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.entry-desc {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* 箭头 */
|
||||
.entry-arrow {
|
||||
width: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
font-size: 36rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
</style>
|
||||
517
pages/home/home.vue
Normal file
517
pages/home/home.vue
Normal file
@ -0,0 +1,517 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- 首页内容 -->
|
||||
<view class="home-content" v-if="currentTab === 'home'">
|
||||
<!-- 页面标题 -->
|
||||
<view class="header">
|
||||
<text class="title">请选择上传方式</text>
|
||||
</view>
|
||||
|
||||
<!-- 上传方式列表 -->
|
||||
<view class="upload-list">
|
||||
<!-- ISBN上传 -->
|
||||
<view class="upload-card" @click="handleISBNUpload">
|
||||
<view class="upload-icon isbn-icon">
|
||||
<text class="icon-emoji">📚</text>
|
||||
</view>
|
||||
<view class="upload-info">
|
||||
<text class="upload-title">ISBN上传</text>
|
||||
<text class="upload-desc">扫描或输入ISBN快速上架</text>
|
||||
</view>
|
||||
<view class="upload-arrow">
|
||||
<text class="arrow-text">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无ISBN上传 -->
|
||||
<view class="upload-card" @click="handleNoISBNUpload">
|
||||
<view class="upload-icon no-isbn-icon">
|
||||
<text class="icon-emoji">📷</text>
|
||||
</view>
|
||||
<view class="upload-info">
|
||||
<text class="upload-title">无ISBN上传</text>
|
||||
<text class="upload-desc">拍照识别无书籍信息上架</text>
|
||||
</view>
|
||||
<view class="upload-arrow">
|
||||
<text class="arrow-text">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的页面内容 -->
|
||||
<view class="mine-content" v-if="currentTab === 'mine'">
|
||||
<!-- 页面标题 -->
|
||||
<view class="header">
|
||||
<text class="title">个人中心</text>
|
||||
</view>
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-card">
|
||||
<view class="user-avatar">
|
||||
<text class="avatar-emoji">👤</text>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="user-name">用户名</text>
|
||||
<text class="version-text">系统版本:v1.0.0</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能列表 -->
|
||||
<view class="menu-card">
|
||||
<view class="menu-item" @click="handleMenu('vip')">
|
||||
<text class="menu-icon">⭐</text>
|
||||
<text class="menu-title">开通会员</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-item" @click="handleMenu('offline')">
|
||||
<text class="menu-icon">📋</text>
|
||||
<text class="menu-title">线下订单管理</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-item" @click="handleMenu('shelf')">
|
||||
<text class="menu-icon">📦</text>
|
||||
<text class="menu-title">货架管理</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-item" @click="handleMenu('refresh')">
|
||||
<text class="menu-icon">🔄</text>
|
||||
<text class="menu-title">孔网商品翻新</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-item" @click="handleMenu('record')">
|
||||
<text class="menu-icon">📝</text>
|
||||
<text class="menu-title">上书记录</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-item" @click="handleMenu('order')">
|
||||
<text class="menu-icon">📄</text>
|
||||
<text class="menu-title">仓库订单查询</text>
|
||||
<view class="menu-arrow-wrap">
|
||||
<text class="menu-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<view class="logout-btn" @click="handleLogout">
|
||||
<text class="logout-text">退出登录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 返回功能入口 -->
|
||||
<view class="back-entry" @click="goBackToEntry">
|
||||
<text class="back-entry-icon">‹</text>
|
||||
<text class="back-entry-text">返回功能入口</text>
|
||||
</view>
|
||||
|
||||
<!-- 底部导航栏 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item" :class="{ active: currentTab === 'home' }" @click="switchTab('home')">
|
||||
<text class="tab-icon">🏠</text>
|
||||
<text class="tab-text">首页</text>
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: currentTab === 'mine' }" @click="switchTab('mine')">
|
||||
<text class="tab-icon">👤</text>
|
||||
<text class="tab-text">我的</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentTab: 'home'
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
uni.setNavigationBarTitle({
|
||||
title: '入库助手'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 切换Tab
|
||||
switchTab(tab) {
|
||||
this.currentTab = tab
|
||||
uni.setNavigationBarTitle({
|
||||
title: tab === 'home' ? '入库助手' : '我的'
|
||||
})
|
||||
},
|
||||
|
||||
// ISBN上传
|
||||
handleISBNUpload() {
|
||||
const data = uni.getStorageSync('selectedWarehouseData')
|
||||
let params = 'tab=isbn'
|
||||
if (data && data.warehouseName && data.locationCode) {
|
||||
const encode = encodeURIComponent
|
||||
params += `&whName=${encode(data.warehouseName)}&whCode=${encode(data.warehouseCode)}&whId=${encode(data.warehouseId)}`
|
||||
params += `&locCode=${encode(data.locationCode)}&locName=${encode(data.locationName)}&locId=${encode(data.locationId)}`
|
||||
}
|
||||
uni.navigateTo({ url: `/pages/upload/upload?${params}` })
|
||||
},
|
||||
|
||||
// 无ISBN上传
|
||||
handleNoISBNUpload() {
|
||||
const data = uni.getStorageSync('selectedWarehouseData')
|
||||
let params = 'tab=no-isbn'
|
||||
if (data && data.warehouseName && data.locationCode) {
|
||||
const encode = encodeURIComponent
|
||||
params += `&whName=${encode(data.warehouseName)}&whCode=${encode(data.warehouseCode)}&whId=${encode(data.warehouseId)}`
|
||||
params += `&locCode=${encode(data.locationCode)}&locName=${encode(data.locationName)}&locId=${encode(data.locationId)}`
|
||||
}
|
||||
uni.navigateTo({ url: `/pages/upload/upload?${params}` })
|
||||
},
|
||||
|
||||
// 菜单点击
|
||||
handleMenu(type) {
|
||||
const menuNames = {
|
||||
vip: '开通会员',
|
||||
offline: '线下订单管理',
|
||||
shelf: '货架管理',
|
||||
refresh: '孔网商品翻新',
|
||||
record: '上书记录',
|
||||
order: '仓库订单查询'
|
||||
}
|
||||
|
||||
// 开通会员跳转到VIP页面
|
||||
if (type === 'vip') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/vip/vip'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 上书记录跳转到记录页面
|
||||
if (type === 'record') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/record/record'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 仓库订单查询跳转到订单页面
|
||||
if (type === 'order') {
|
||||
uni.navigateTo({
|
||||
url: '/pages/order/order'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: menuNames[type],
|
||||
icon: 'none'
|
||||
})
|
||||
// TODO: 跳转到对应页面
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
handleLogout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.removeStorageSync('token')
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 返回功能入口页面
|
||||
goBackToEntry() {
|
||||
uni.redirectTo({ url: '/pages/entry/entry' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding-bottom: 100rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ====== 页面标题 ====== */
|
||||
.header {
|
||||
padding: 40rpx 0 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ====== 上传列表 ====== */
|
||||
.home-content {
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.upload-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.upload-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.upload-card:active {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.isbn-icon {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.no-isbn-icon {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.icon-emoji {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.upload-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.upload-title {
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-desc {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.upload-arrow {
|
||||
width: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.arrow-text {
|
||||
font-size: 36rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* ====== 我的页面 ====== */
|
||||
.mine-content {
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-emoji {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 32rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.version-text {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* 功能列表 */
|
||||
.menu-card {
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 28rpx;
|
||||
border-bottom: 1rpx solid #f0f2f5;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 30rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.menu-arrow-wrap {
|
||||
width: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 32rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* 退出登录 */
|
||||
.logout-btn {
|
||||
margin-top: 32rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.logout-btn:active {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.logout-text {
|
||||
font-size: 28rpx;
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 返回功能入口 */
|
||||
.back-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx 0;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.back-entry-icon {
|
||||
font-size: 28rpx;
|
||||
color: #c9cdd4;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.back-entry-text {
|
||||
font-size: 24rpx;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.back-entry:active {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* ====== 底部导航栏 ====== */
|
||||
.tab-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100rpx;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
border-top: 1rpx solid #f0f2f5;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
font-size: 36rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 22rpx;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
.tab-item.active .tab-text {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
52
pages/index/index.vue
Normal file
52
pages/index/index.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<image class="logo" src="/static/logo.png"></image>
|
||||
<view class="text-area">
|
||||
<text class="title">{{title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: 'Hello'
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 200rpx;
|
||||
width: 200rpx;
|
||||
margin-top: 200rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
color: #8f8f94;
|
||||
}
|
||||
</style>
|
||||
693
pages/login/login.vue
Normal file
693
pages/login/login.vue
Normal file
@ -0,0 +1,693 @@
|
||||
<template>
|
||||
<view class="login-container">
|
||||
<!-- 加载状态遮罩 -->
|
||||
<view class="loading-mask" v-if="isCheckingLogin">
|
||||
<view class="loading-spinner"></view>
|
||||
</view>
|
||||
|
||||
<!-- Logo区域 -->
|
||||
<view class="logo-area" v-if="!isCheckingLogin">
|
||||
<image class="logo" src="/static/logo.png" mode="aspectFit"></image>
|
||||
<text class="app-name">扫码图书</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="login-form" v-if="!isCheckingLogin">
|
||||
<!-- 账号输入 -->
|
||||
<view class="form-item">
|
||||
<view class="icon-box">
|
||||
<view class="icon-user-head"></view>
|
||||
<view class="icon-user-body"></view>
|
||||
</view>
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
v-model="formData.account"
|
||||
placeholder="请输入账号"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<view class="form-item">
|
||||
<view class="icon-box">
|
||||
<view class="icon-lock-body"></view>
|
||||
<view class="icon-lock-top"></view>
|
||||
</view>
|
||||
<input
|
||||
class="input"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
v-model="formData.password"
|
||||
placeholder="请输入密码"
|
||||
maxlength="20"
|
||||
/>
|
||||
<view class="icon-eye-box" @click="togglePassword">
|
||||
<view class="icon-eye-outer"></view>
|
||||
<view class="icon-eye-inner"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 记住密码 -->
|
||||
<view class="remember-row">
|
||||
<view class="checkbox-wrapper" @click="toggleRemember">
|
||||
<view :class="['checkbox', { checked: formData.remember }]">
|
||||
<text v-if="formData.remember" class="check-mark">✓</text>
|
||||
</view>
|
||||
<text class="checkbox-label">记住密码</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 隐私协议同意 -->
|
||||
<view class="agreement-row">
|
||||
<view class="checkbox-wrapper" @click="toggleAgreement">
|
||||
<view :class="['checkbox', { checked: formData.agreed }]">
|
||||
<text v-if="formData.agreed" class="check-mark">✓</text>
|
||||
</view>
|
||||
<text class="checkbox-label">我已阅读并同意</text>
|
||||
</view>
|
||||
<text class="link" @click="showPrivacyPolicy">《隐私协议》</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button class="login-btn" :disabled="!canLogin" @click="handleLogin">
|
||||
登录
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 隐私协议弹窗 -->
|
||||
<view class="modal-mask" v-if="showModal" @click="closeModal">
|
||||
<view class="modal-content" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">隐私协议</text>
|
||||
<text class="close-btn" @click="closeModal">✕</text>
|
||||
</view>
|
||||
<scroll-view class="modal-body" scroll-y>
|
||||
<view class="policy-content">
|
||||
<text class="policy-title">入库助手-大商道小程序隐私协议</text>
|
||||
<view class="policy-intro">
|
||||
<text>本指引是入库助手-大商道小程序开发者"沈阳大商道商贸有限公司"(以下简称"开发者")为处理你的个人信息而制定。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">开发者处理的信息</text>
|
||||
<text class="section-item">· 为了用户注册用户账号,开发者将在获取你的明示同意后,收集你的手机号。</text>
|
||||
<text class="section-item">· 为了用户注册用户账号,开发者将在获取你的明示同意后,收集你的微信昵称、头像。</text>
|
||||
<text class="section-item">· 为了客户跟商家沟通会发送图片,开发者将在获取你的明示同意后,访问你的摄像头。</text>
|
||||
<text class="section-item">· 为了用于保存商城图片,开发者将在获取你的明示同意后,使用你的相册(仅写入)权限。</text>
|
||||
<text class="section-item">· 为了用于下单快速录入地址,开发者将在获取你的明示同意后,收集你的位置信息。</text>
|
||||
<text class="section-item">· 开发者收集你的地址,用于下单快速录入地址。</text>
|
||||
<text class="section-item">· 开发者收集你的设备信息,用于判断客户身份,如果恶意请求则限制设备。</text>
|
||||
<text class="section-item">· 开发者收集你选中的照片或视频信息,用于客户跟商家沟通会发送图片。</text>
|
||||
<text class="section-item">· 开发者收集你的操作日志,用于记录用户操作信息,方便分析问题、故障。</text>
|
||||
<text class="section-item">· 开发者收集你选中的文件,用于与商家沟通退货时的上传凭证。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">未成年人保护</text>
|
||||
<text class="section-text">根据相关法律法规的规定,若你是14周岁以下的未成年人,你需要和你的监护人共同仔细阅读本指引,并在征得监护人明示同意后继续使用小程序服务。</text>
|
||||
<text class="section-text">开发者将根据相关法律法规的规定及本指引内容,处理经监护人同意而收集的未成年人用户信息,并通过本指引你的权益部分披露的内容保障未成年人在个人信息处理活动中的各项权利。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">你的权益</text>
|
||||
<text class="section-text">关于访问你的摄像头,你可以通过以下路径:小程序主页右上角"..."—"设置"—点击特定信息—点击"不允许",撤回对开发者的授权。</text>
|
||||
<text class="section-text">关于你的个人信息,你可以通过以下方式与开发者联系,行使查阅、复制、更正、删除等法定权利。</text>
|
||||
<text class="section-text">若你在小程序中注册了账号,你可以通过以下方式与开发者联系,申请注销你在小程序中使用的账号。在受理你的申请后,开发者承诺在十五个工作日内完成核查和处理,并按照法律法规要求处理你的相关信息。</text>
|
||||
<text class="section-text">邮箱: admin@qinsilk.com</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">开发者对信息的存储</text>
|
||||
<text class="section-text">开发者承诺,除法律法规另有规定外,开发者对你的信息的保存期限应当为实现处理目的所必要的最短时间。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">信息的使用规则</text>
|
||||
<text class="section-text">开发者将会在本指引所明示的用途内使用收集的信息。</text>
|
||||
<text class="section-text">如开发者使用你的信息超出本指引目的或合理范围,开发者必须在变更使用目的或范围前,再次以通过公告方式告知并征得你的明示同意。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">信息对外提供</text>
|
||||
<text class="section-text">开发者承诺,不会主动共享或转让你的信息至任何第三方,如存在确需共享或转让时,开发者应当直接征得或确认第三方征得你的单独同意。</text>
|
||||
<text class="section-text">开发者承诺,不会对外公开披露你的信息,如必须公开披露时,开发者应当向你告知公开披露的目的、披露信息的类型及可能涉及的信息,并征得你的单独同意。</text>
|
||||
</view>
|
||||
|
||||
<view class="policy-section">
|
||||
<text class="section-title">联系我们</text>
|
||||
<text class="section-text">若你认为开发者未遵守上述约定,或有其他的投诉建议、或未成年人个人信息保护相关问题,可通过以下方式与开发者联系;或者向微信进行投诉。</text>
|
||||
<text class="section-text">邮箱: admin@qinsilk.com</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="modal-footer">
|
||||
<button class="confirm-btn" @click="confirmRead">我已阅读</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isCheckingLogin: true,
|
||||
formData: {
|
||||
account: '',
|
||||
password: '',
|
||||
remember: false,
|
||||
agreed: false
|
||||
},
|
||||
showPassword: false,
|
||||
showModal: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
canLogin() {
|
||||
return this.formData.account.trim() !== '' &&
|
||||
this.formData.password.trim() !== '' &&
|
||||
this.formData.agreed
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 已登录则直接跳转首页
|
||||
const token = uni.getStorageSync('token')
|
||||
if (token) {
|
||||
uni.redirectTo({ url: '/pages/home/home' })
|
||||
return
|
||||
}
|
||||
// 未登录,显示登录页
|
||||
this.isCheckingLogin = false
|
||||
// 页面加载时读取记住的账号密码
|
||||
this.loadRememberedCredentials()
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 切换密码显示
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword
|
||||
},
|
||||
|
||||
// 切换记住密码
|
||||
toggleRemember() {
|
||||
this.formData.remember = !this.formData.remember
|
||||
},
|
||||
|
||||
// 切换协议同意
|
||||
toggleAgreement() {
|
||||
this.formData.agreed = !this.formData.agreed
|
||||
},
|
||||
|
||||
// 显示隐私协议
|
||||
showPrivacyPolicy() {
|
||||
this.showModal = true
|
||||
},
|
||||
|
||||
// 关闭弹窗
|
||||
closeModal() {
|
||||
this.showModal = false
|
||||
},
|
||||
|
||||
// 确认已阅读隐私协议
|
||||
confirmRead() {
|
||||
this.formData.agreed = true
|
||||
this.showModal = false
|
||||
},
|
||||
|
||||
// 登录处理
|
||||
handleLogin() {
|
||||
if (!this.canLogin) {
|
||||
uni.showToast({
|
||||
title: '请填写完整信息并同意隐私协议',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 保存或清除记住的密码
|
||||
if (this.formData.remember) {
|
||||
this.saveCredentials()
|
||||
} else {
|
||||
this.clearCredentials()
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: '登录中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 构建登录参数(form-data格式)
|
||||
const loginData = {
|
||||
clientId: 'cec96a240989d1c6bcd55f86fca702b7',
|
||||
phoneNumber: this.formData.account,
|
||||
password: this.formData.password
|
||||
}
|
||||
|
||||
// 调用登录API
|
||||
uni.request({
|
||||
url: 'https://api.buzhiyushu.cn/auth/interFaceLogin',
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Authorization': 'Basic ZWxhc3RpYzo1bVJESVVnNTJWQzBmcDE0bnctRg=='
|
||||
},
|
||||
data: loginData,
|
||||
success: (res) => {
|
||||
uni.hideLoading()
|
||||
const response = res.data
|
||||
|
||||
// 新接口返回结构:{ code: 200, msg: "操作成功", data: { access_token, userId, ... } }
|
||||
if (response && response.code === 200 && response.data && response.data.access_token) {
|
||||
const data = response.data
|
||||
// 登录成功,保存数据
|
||||
uni.setStorageSync('token', data.access_token)
|
||||
uni.setStorageSync('openId', data.openid || '')
|
||||
uni.setStorageSync('userId', data.userId || '')
|
||||
uni.setStorageSync('phoneNumber', data.phoneNumber || this.formData.account)
|
||||
uni.setStorageSync('nickName', data.nickName || '')
|
||||
uni.setStorageSync('lastSubmitTime', Date.now())
|
||||
uni.setStorageSync('agreedPrivacy', true)
|
||||
|
||||
// 调用商户记录接口
|
||||
if (data.userId) {
|
||||
uni.request({
|
||||
url: `https://go.order.service.buzhiyushu.cn/api/user/insertRecbusinessByUserId?userId=${data.userId}&sort=1`,
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转到功能入口页面
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/entry/entry'
|
||||
})
|
||||
}, 1500)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: response.msg || response.message || '登录失败,请检查账号密码',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '网络请求失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 保存账号密码到本地
|
||||
saveCredentials() {
|
||||
uni.setStorageSync('remembered_account', this.formData.account)
|
||||
uni.setStorageSync('remembered_password', this.formData.password)
|
||||
uni.setStorageSync('remember_flag', true)
|
||||
},
|
||||
|
||||
// 清除保存的账号密码
|
||||
clearCredentials() {
|
||||
uni.removeStorageSync('remembered_account')
|
||||
uni.removeStorageSync('remembered_password')
|
||||
uni.setStorageSync('remember_flag', false)
|
||||
},
|
||||
|
||||
// 加载记住的账号密码
|
||||
loadRememberedCredentials() {
|
||||
const rememberFlag = uni.getStorageSync('remember_flag')
|
||||
if (rememberFlag) {
|
||||
this.formData.account = uni.getStorageSync('remembered_account') || ''
|
||||
this.formData.password = uni.getStorageSync('remembered_password') || ''
|
||||
this.formData.remember = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
background: #ffffff;
|
||||
padding: 0 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 加载遮罩 */
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 3rpx solid #e0e0e0;
|
||||
border-top-color: #409eff;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Logo区域 */
|
||||
.logo-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 100rpx;
|
||||
padding-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
font-size: 40rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
/* 登录表单 */
|
||||
.login-form {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f7fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx 20rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
/* 图标容器 */
|
||||
.icon-box {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 用户图标 - 头部 */
|
||||
.icon-user-head {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border: 2rpx solid #909399;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
}
|
||||
|
||||
/* 用户图标 - 身体 */
|
||||
.icon-user-body {
|
||||
width: 28rpx;
|
||||
height: 12rpx;
|
||||
border: 2rpx solid #909399;
|
||||
border-bottom: none;
|
||||
border-radius: 14rpx 14rpx 0 0;
|
||||
position: absolute;
|
||||
bottom: 2rpx;
|
||||
}
|
||||
|
||||
/* 锁图标 - 锁身 */
|
||||
.icon-lock-body {
|
||||
width: 24rpx;
|
||||
height: 20rpx;
|
||||
border: 2rpx solid #909399;
|
||||
border-radius: 4rpx;
|
||||
position: absolute;
|
||||
bottom: 2rpx;
|
||||
}
|
||||
|
||||
/* 锁图标 - 锁环 */
|
||||
.icon-lock-top {
|
||||
width: 14rpx;
|
||||
height: 10rpx;
|
||||
border: 2rpx solid #909399;
|
||||
border-bottom: none;
|
||||
border-radius: 7rpx 7rpx 0 0;
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
/* 眼睛图标容器 */
|
||||
.icon-eye-box {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
padding: 8rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 眼睛图标 - 外框 */
|
||||
.icon-eye-outer {
|
||||
width: 22rpx;
|
||||
height: 12rpx;
|
||||
border: 2rpx solid #909399;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* 眼睛图标 - 眼珠 */
|
||||
.icon-eye-inner {
|
||||
width: 4rpx;
|
||||
height: 4rpx;
|
||||
background: #909399;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.input {
|
||||
flex: 1;
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* 记住密码 */
|
||||
.remember-row {
|
||||
margin-top: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
/* 隐私协议 */
|
||||
.agreement-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 8rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border: 2rpx solid #dcdfe6;
|
||||
border-radius: 4rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background: #409eff;
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.check-mark {
|
||||
color: #ffffff;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: 26rpx;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
.link {
|
||||
font-size: 26rpx;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
/* 登录按钮 */
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #409eff;
|
||||
border-radius: 12rpx;
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.login-btn[disabled] {
|
||||
background: #a0cfff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 92%;
|
||||
max-height: 80vh;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 24rpx;
|
||||
border-bottom: 1rpx solid #ebeef5;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 36rpx;
|
||||
color: #86909c;
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
flex: 1;
|
||||
max-height: 60vh;
|
||||
padding: 20rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.policy-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.policy-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 16rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.policy-intro {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.policy-intro text {
|
||||
font-size: 24rpx;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.policy-section {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section-item {
|
||||
font-size: 24rpx;
|
||||
color: #606266;
|
||||
line-height: 1.7;
|
||||
display: block;
|
||||
margin-bottom: 6rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.section-text {
|
||||
font-size: 24rpx;
|
||||
color: #606266;
|
||||
line-height: 1.7;
|
||||
display: block;
|
||||
margin-bottom: 6rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 28rpx 36rpx;
|
||||
border-top: 1rpx solid #ebeef5;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 76rpx;
|
||||
background: #409eff;
|
||||
border-radius: 12rpx;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
888
pages/order/order.vue
Normal file
888
pages/order/order.vue
Normal file
@ -0,0 +1,888 @@
|
||||
<template>
|
||||
<view class="order-container">
|
||||
<!-- 统计栏 -->
|
||||
<view class="stats-bar">
|
||||
<text class="stats-text">订单总数:{{ totalCount }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 订单列表 -->
|
||||
<scroll-view class="order-list" scroll-y @scrolltolower="loadMore">
|
||||
<view
|
||||
class="order-item"
|
||||
v-for="(item, index) in orderList"
|
||||
:key="index"
|
||||
@click="handleItemClick(item, index)"
|
||||
>
|
||||
<!-- 多选框 -->
|
||||
<view class="checkbox-wrapper" v-if="showBatchMode" @click.stop="toggleSelect(index)">
|
||||
<view :class="['checkbox', { checked: selectedItems.includes(index) }]">
|
||||
<text v-if="selectedItems.includes(index)" class="check-mark">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品图片 -->
|
||||
<image class="order-image" :src="item.image" mode="aspectFill"></image>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-info">
|
||||
<text class="order-name">{{ item.name }}</text>
|
||||
<view class="order-tags">
|
||||
<text class="tag new-code">新:{{ item.newCode }}</text>
|
||||
<text class="tag old-code">原:{{ item.oldCode }}</text>
|
||||
</view>
|
||||
<text class="order-isbn">ISBN: {{ item.isbn }}</text>
|
||||
<view class="status-row">
|
||||
<text :class="['status-tag', 'ship-' + item.shipStatus]">{{ item.shipStatusText }}</text>
|
||||
<text :class="['status-tag', 'out-' + item.outStatus]">{{ item.outStatusText }}</text>
|
||||
</view>
|
||||
<view class="time-row">
|
||||
<text class="ship-time">发货: {{ item.shipTime }}</text>
|
||||
<text class="create-time">{{ item.createTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="load-more" v-if="loading">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar" v-if="!showBatchMode">
|
||||
<view class="btn filter-btn" @click="showFilter = true">
|
||||
<text class="btn-icon">🔍</text>
|
||||
<text class="btn-text">筛选</text>
|
||||
</view>
|
||||
<view class="btn batch-btn" @click="enterBatchMode">
|
||||
<text class="btn-icon">📦</text>
|
||||
<text class="btn-text">批量出库</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 批量操作栏 -->
|
||||
<view class="batch-bar" v-if="showBatchMode">
|
||||
<view class="batch-info">
|
||||
<text class="batch-count">已选择 {{ selectedItems.length }} 项</text>
|
||||
</view>
|
||||
<view class="batch-actions">
|
||||
<view class="btn cancel-btn" @click="cancelBatch">取消</view>
|
||||
<view class="btn confirm-btn" @click="confirmBatch">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选弹窗 -->
|
||||
<view class="filter-mask" v-if="showFilter" @click="showFilter = false">
|
||||
<view class="filter-panel" @click.stop>
|
||||
<view class="filter-header">
|
||||
<text class="filter-title">筛选条件</text>
|
||||
<text class="close-btn" @click="showFilter = false">✕</text>
|
||||
</view>
|
||||
|
||||
<scroll-view class="filter-body" scroll-y>
|
||||
<!-- 订单编号 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">订单编号</text>
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="filterForm.orderNo"
|
||||
placeholder="请输入订单编号"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 店铺类型 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">店铺类型</text>
|
||||
<picker class="filter-picker" :value="filterForm.shopType" :range="shopTypeOptions" @change="onShopTypeChange">
|
||||
<view class="picker-value">
|
||||
<text>{{ shopTypeOptions[filterForm.shopType] || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 时间范围 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">时间范围</text>
|
||||
<picker class="filter-picker" :value="filterForm.timeRange" :range="timeRangeOptions" @change="onTimeRangeChange">
|
||||
<view class="picker-value">
|
||||
<text>{{ timeRangeOptions[filterForm.timeRange] || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 出库状态 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">出库状态</text>
|
||||
<picker class="filter-picker" :value="filterForm.outStatus" :range="outStatusOptions" @change="onOutStatusChange">
|
||||
<view class="picker-value">
|
||||
<text>{{ outStatusOptions[filterForm.outStatus] || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 发货状态 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">发货状态</text>
|
||||
<picker class="filter-picker" :value="filterForm.shipStatus" :range="shipStatusOptions" @change="onShipStatusChange">
|
||||
<view class="picker-value">
|
||||
<text>{{ shipStatusOptions[filterForm.shipStatus] || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 货号 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">货号</text>
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="filterForm.code"
|
||||
placeholder="请输入货号"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 原货号 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">原货号</text>
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="filterForm.oldCode"
|
||||
placeholder="请输入原货号"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- ISBN -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">ISBN</text>
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="filterForm.isbn"
|
||||
placeholder="请输入ISBN"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 排序方式 -->
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">排序方式</text>
|
||||
<picker class="filter-picker" :value="filterForm.sortType" :range="sortTypeOptions" @change="onSortTypeChange">
|
||||
<view class="picker-value">
|
||||
<text>{{ sortTypeOptions[filterForm.sortType] || '请选择' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="filter-footer">
|
||||
<view class="btn filter-cancel" @click="showFilter = false">取消</view>
|
||||
<view class="btn filter-reset" @click="resetFilter">重置</view>
|
||||
<view class="btn filter-confirm" @click="confirmFilter">查询</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
totalCount: 128,
|
||||
loading: false,
|
||||
showBatchMode: false,
|
||||
selectedItems: [],
|
||||
showFilter: false,
|
||||
|
||||
// 筛选选项
|
||||
shopTypeOptions: ['孔夫子', '闲鱼', '拼多多'],
|
||||
timeRangeOptions: ['24小时内', '48小时内', '48小时外'],
|
||||
outStatusOptions: ['全部', '未出库', '已出库'],
|
||||
shipStatusOptions: ['全部', '到付款', '待发货', '已发货待签收', '交易完成', '已退款', '交易关闭', '售后预处理'],
|
||||
sortTypeOptions: ['时间排序', '货号排序'],
|
||||
|
||||
// 筛选表单
|
||||
filterForm: {
|
||||
orderNo: '',
|
||||
shopType: '',
|
||||
timeRange: '',
|
||||
outStatus: '',
|
||||
shipStatus: '',
|
||||
code: '',
|
||||
oldCode: '',
|
||||
isbn: '',
|
||||
sortType: ''
|
||||
},
|
||||
|
||||
// 模拟订单数据
|
||||
orderList: [
|
||||
{
|
||||
image: '/static/books/book1.jpg',
|
||||
name: '红楼梦(精装版)',
|
||||
newCode: 'BK2024001',
|
||||
oldCode: 'OLD001',
|
||||
isbn: '978-7-101-00001-1',
|
||||
shipStatus: 'pending',
|
||||
shipStatusText: '待发货',
|
||||
outStatus: 'not_out',
|
||||
outStatusText: '未出库',
|
||||
shipTime: '24小时内',
|
||||
createTime: '刚刚'
|
||||
},
|
||||
{
|
||||
image: '/static/books/book2.jpg',
|
||||
name: '西游记(全四册)',
|
||||
newCode: 'BK2024002',
|
||||
oldCode: 'OLD002',
|
||||
isbn: '978-7-101-00002-2',
|
||||
shipStatus: 'shipped',
|
||||
shipStatusText: '已发货待签收',
|
||||
outStatus: 'out',
|
||||
outStatusText: '已出库',
|
||||
shipTime: '36小时内',
|
||||
createTime: '5分钟前'
|
||||
},
|
||||
{
|
||||
image: '/static/books/book3.jpg',
|
||||
name: '水浒传(上下册)',
|
||||
newCode: 'BK2024003',
|
||||
oldCode: 'OLD003',
|
||||
isbn: '978-7-101-00003-3',
|
||||
shipStatus: 'completed',
|
||||
shipStatusText: '交易完成',
|
||||
outStatus: 'out',
|
||||
outStatusText: '已出库',
|
||||
shipTime: '48小时内',
|
||||
createTime: '一天前'
|
||||
},
|
||||
{
|
||||
image: '/static/books/book4.jpg',
|
||||
name: '三国演义(珍藏版)',
|
||||
newCode: 'BK2024004',
|
||||
oldCode: 'OLD004',
|
||||
isbn: '978-7-101-00004-4',
|
||||
shipStatus: 'cod',
|
||||
shipStatusText: '到付款',
|
||||
outStatus: 'not_out',
|
||||
outStatusText: '未出库',
|
||||
shipTime: '24小时内',
|
||||
createTime: '2天前'
|
||||
},
|
||||
{
|
||||
image: '/static/books/book5.jpg',
|
||||
name: '论语译注',
|
||||
newCode: 'BK2024005',
|
||||
oldCode: 'OLD005',
|
||||
isbn: '978-7-101-00005-5',
|
||||
shipStatus: 'refunded',
|
||||
shipStatusText: '已退款',
|
||||
outStatus: 'out',
|
||||
outStatusText: '已出库',
|
||||
shipTime: '48小时内',
|
||||
createTime: '3个月前'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
uni.setNavigationBarTitle({
|
||||
title: '仓库订单'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 进入批量模式
|
||||
enterBatchMode() {
|
||||
this.showBatchMode = true
|
||||
this.selectedItems = []
|
||||
},
|
||||
|
||||
// 取消批量
|
||||
cancelBatch() {
|
||||
this.showBatchMode = false
|
||||
this.selectedItems = []
|
||||
},
|
||||
|
||||
// 确认批量出库
|
||||
confirmBatch() {
|
||||
if (this.selectedItems.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择订单',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.showModal({
|
||||
title: '确认出库',
|
||||
content: `确定要出库选中的 ${this.selectedItems.length} 个订单吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showToast({
|
||||
title: '出库成功',
|
||||
icon: 'success'
|
||||
})
|
||||
this.cancelBatch()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 切换选中
|
||||
toggleSelect(index) {
|
||||
const pos = this.selectedItems.indexOf(index)
|
||||
if (pos > -1) {
|
||||
this.selectedItems.splice(pos, 1)
|
||||
} else {
|
||||
this.selectedItems.push(index)
|
||||
}
|
||||
},
|
||||
|
||||
// 点击订单项
|
||||
handleItemClick(item, index) {
|
||||
if (this.showBatchMode) {
|
||||
this.toggleSelect(index)
|
||||
} else {
|
||||
// 查看订单详情
|
||||
uni.showToast({
|
||||
title: '查看订单: ' + item.name,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 筛选器变更
|
||||
onShopTypeChange(e) {
|
||||
this.filterForm.shopType = e.detail.value
|
||||
},
|
||||
onTimeRangeChange(e) {
|
||||
this.filterForm.timeRange = e.detail.value
|
||||
},
|
||||
onOutStatusChange(e) {
|
||||
this.filterForm.outStatus = e.detail.value
|
||||
},
|
||||
onShipStatusChange(e) {
|
||||
this.filterForm.shipStatus = e.detail.value
|
||||
},
|
||||
onSortTypeChange(e) {
|
||||
this.filterForm.sortType = e.detail.value
|
||||
},
|
||||
|
||||
// 重置筛选
|
||||
resetFilter() {
|
||||
this.filterForm = {
|
||||
orderNo: '',
|
||||
shopType: '',
|
||||
timeRange: '',
|
||||
outStatus: '',
|
||||
shipStatus: '',
|
||||
code: '',
|
||||
oldCode: '',
|
||||
isbn: '',
|
||||
sortType: ''
|
||||
}
|
||||
},
|
||||
|
||||
// 确认筛选
|
||||
confirmFilter() {
|
||||
uni.showToast({
|
||||
title: '筛选查询中...',
|
||||
icon: 'none'
|
||||
})
|
||||
this.showFilter = false
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
loadMore() {
|
||||
if (this.loading) return
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.order-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding-bottom: 140rpx;
|
||||
}
|
||||
|
||||
/* 统计栏 */
|
||||
.stats-bar {
|
||||
background: #ffffff;
|
||||
padding: 32rpx;
|
||||
margin: 24rpx 24rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.stats-text {
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 订单列表 */
|
||||
.order-list {
|
||||
height: calc(100vh - 280rpx);
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.order-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background: #ffffff;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.order-item:active {
|
||||
box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
/* 多选框 */
|
||||
.checkbox-wrapper {
|
||||
padding-right: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border: 3rpx solid #dcdfe6;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background: #409eff;
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.check-mark {
|
||||
color: #ffffff;
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 商品图片 */
|
||||
.order-image {
|
||||
width: 130rpx;
|
||||
height: 130rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 24rpx;
|
||||
background: #f0f2f5;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
/* 订单信息 */
|
||||
.order-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.order-name {
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16rpx;
|
||||
line-height: 1.4;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.order-tags {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.new-code {
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.old-code {
|
||||
background: #f0f9eb;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.order-isbn {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 400;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.ship-pending { background: #fdf6ec; color: #e6a23c; }
|
||||
.ship-shipped { background: #ecf5ff; color: #409eff; }
|
||||
.ship-completed { background: #f0f9eb; color: #67c23a; }
|
||||
.ship-cod { background: #f4f4f5; color: #606266; }
|
||||
.ship-refunded { background: #fef0f0; color: #f56c6c; }
|
||||
|
||||
.out-not_out { background: #fdf6ec; color: #e6a23c; }
|
||||
.out-out { background: #f0f9eb; color: #67c23a; }
|
||||
|
||||
.time-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 8rpx;
|
||||
border-top: 1rpx solid #e5e6eb;
|
||||
}
|
||||
|
||||
.ship-time {
|
||||
font-size: 24rpx;
|
||||
color: #e6a23c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.create-time {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 110rpx;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
border-top: 1rpx solid #e5e6eb;
|
||||
}
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
background: #f0f2f5;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 30rpx;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
border-right: 1rpx solid #e5e6eb;
|
||||
}
|
||||
|
||||
.batch-btn .btn-text {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
/* 批量操作栏 */
|
||||
.batch-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #ffffff;
|
||||
border-top: 1rpx solid #e5e6eb;
|
||||
padding: 24rpx 32rpx;
|
||||
}
|
||||
|
||||
.batch-info {
|
||||
text-align: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.batch-count {
|
||||
font-size: 30rpx;
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.batch-actions {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 12rpx;
|
||||
font-size: 30rpx;
|
||||
color: #4e5969;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.cancel-btn:active {
|
||||
background: #e5e6eb;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
background: #409eff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.confirm-btn:active {
|
||||
background: #3a8ee6;
|
||||
}
|
||||
|
||||
/* 筛选弹窗 */
|
||||
.filter-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.filter-panel {
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
max-height: 85vh;
|
||||
background: #ffffff;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.filter-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx;
|
||||
border-bottom: 1rpx solid #e5e6eb;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 40rpx;
|
||||
color: #909399;
|
||||
padding: 12rpx;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.close-btn:active {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.filter-body {
|
||||
flex: 1;
|
||||
max-height: 65vh;
|
||||
padding: 20rpx 24rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
margin-bottom: 20rpx;
|
||||
background: #ffffff;
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 28rpx;
|
||||
color: #4e5969;
|
||||
margin-bottom: 16rpx;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
height: 72rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 10rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-input:focus {
|
||||
border-color: #409eff;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-picker {
|
||||
height: 72rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 10rpx;
|
||||
padding: 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filter-picker:active {
|
||||
background: #e5e6eb;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.picker-value text:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
font-size: 36rpx;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.filter-footer {
|
||||
display: flex;
|
||||
padding: 20rpx 24rpx;
|
||||
border-top: 1rpx solid #e5e6eb;
|
||||
gap: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-cancel {
|
||||
flex: 1;
|
||||
height: 84rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 16rpx;
|
||||
font-size: 30rpx;
|
||||
color: #4e5969;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.filter-cancel:active {
|
||||
background: #e5e6eb;
|
||||
}
|
||||
|
||||
.filter-reset {
|
||||
flex: 1;
|
||||
height: 84rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 16rpx;
|
||||
font-size: 30rpx;
|
||||
color: #4e5969;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.filter-reset:active {
|
||||
background: #e5e6eb;
|
||||
}
|
||||
|
||||
.filter-confirm {
|
||||
flex: 1;
|
||||
height: 84rpx;
|
||||
background: #409eff;
|
||||
border-radius: 16rpx;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.filter-confirm:active {
|
||||
background: #3a8ee6;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
color: #86909c;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
567
pages/record/record.vue
Normal file
567
pages/record/record.vue
Normal file
@ -0,0 +1,567 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- 筛选区域 -->
|
||||
<view class="filter-section">
|
||||
<view class="filter-card">
|
||||
<view class="filter-row">
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">账号</text>
|
||||
<picker class="filter-picker" @change="handleAccountChange" :value="accountIndex" :range="accountList">
|
||||
<view class="picker-value">
|
||||
<text class="picker-text">{{ accountList[accountIndex] }}</text>
|
||||
<text class="picker-arrow">▼</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">店铺</text>
|
||||
<picker class="filter-picker" @change="handleShopChange" :value="shopIndex" :range="shopList">
|
||||
<view class="picker-value">
|
||||
<text class="picker-text">{{ shopList[shopIndex] }}</text>
|
||||
<text class="picker-arrow">▼</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-row">
|
||||
<view class="filter-item full-width">
|
||||
<text class="filter-label">日期</text>
|
||||
<picker class="filter-picker" mode="date" @change="handleDateChange" :value="selectedDate">
|
||||
<view class="picker-value">
|
||||
<text class="picker-text">{{ selectedDate }}</text>
|
||||
<text class="picker-arrow">▼</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<view class="stats-section">
|
||||
<view class="stats-card">
|
||||
<text class="stats-icon">📊</text>
|
||||
<text class="stats-label">总记录数</text>
|
||||
<text class="stats-value">{{ recordList.length }} 条</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 记录列表 -->
|
||||
<view class="record-list">
|
||||
<view class="record-item" v-for="(item, index) in recordList" :key="index">
|
||||
<view class="record-main">
|
||||
<!-- 图片 -->
|
||||
<view class="record-image" @click="previewImage(item.image)">
|
||||
<image class="book-image" :src="item.image" mode="aspectFill"></image>
|
||||
<view class="image-overlay">
|
||||
<text class="zoom-icon">🔍</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 基本信息 -->
|
||||
<view class="record-info">
|
||||
<view class="info-row">
|
||||
<text class="book-name">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">ISBN:</text>
|
||||
<text class="info-value">{{ item.isbn }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">品相:</text>
|
||||
<text class="condition-badge" :class="getConditionClass(item.condition)">{{ item.condition }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">上书时间:</text>
|
||||
<text class="info-value">{{ item.uploadTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 价格和库存 -->
|
||||
<view class="record-detail">
|
||||
<view class="detail-row">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">库存</text>
|
||||
<text class="detail-value">{{ item.stock }}本</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">价格</text>
|
||||
<text class="detail-value price">¥{{ item.price }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 发布状态 -->
|
||||
<view class="publish-status">
|
||||
<view class="status-row">
|
||||
<view class="status-item" :class="{ published: item.pddPublished }">
|
||||
<text class="status-icon">{{ item.pddPublished ? '✓' : '✗' }}</text>
|
||||
<text class="status-text">拼多多:{{ item.pddPublished ? '已发布' : '未发布' }}</text>
|
||||
</view>
|
||||
<view class="status-item" :class="{ published: item.kfzPublished }">
|
||||
<text class="status-icon">{{ item.kfzPublished ? '✓' : '✗' }}</text>
|
||||
<text class="status-text">孔夫子:{{ item.kfzPublished ? '已发布' : '未发布' }}</text>
|
||||
</view>
|
||||
<view class="status-item" :class="{ published: item.xianyuPublished }">
|
||||
<text class="status-icon">{{ item.xianyuPublished ? '✓' : '✗' }}</text>
|
||||
<text class="status-text">闲鱼:{{ item.xianyuPublished ? '已发布' : '未发布' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="recordList.length === 0">
|
||||
<text class="empty-icon">📭</text>
|
||||
<text class="empty-text">暂无上书记录</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 筛选条件
|
||||
accountIndex: 0,
|
||||
accountList: ['全部账号', '账号A', '账号B', '账号C'],
|
||||
shopIndex: 0,
|
||||
shopList: ['全部店铺', '店铺1', '店铺2', '店铺3'],
|
||||
selectedDate: this.getTodayDate(),
|
||||
|
||||
// 记录列表
|
||||
recordList: [
|
||||
{
|
||||
image: 'https://picsum.photos/200/280?random=1',
|
||||
name: '红楼梦',
|
||||
isbn: '9787020002207',
|
||||
condition: '全新',
|
||||
uploadTime: '2024-01-15 14:30',
|
||||
stock: 5,
|
||||
price: '45.00',
|
||||
pddPublished: true,
|
||||
kfzPublished: true,
|
||||
xianyuPublished: false
|
||||
},
|
||||
{
|
||||
image: 'https://picsum.photos/200/280?random=2',
|
||||
name: '西游记',
|
||||
isbn: '9787020002214',
|
||||
condition: '九成新',
|
||||
uploadTime: '2024-01-15 15:20',
|
||||
stock: 3,
|
||||
price: '38.00',
|
||||
pddPublished: true,
|
||||
kfzPublished: false,
|
||||
xianyuPublished: true
|
||||
},
|
||||
{
|
||||
image: 'https://picsum.photos/200/280?random=3',
|
||||
name: '水浒传',
|
||||
isbn: '9787020002221',
|
||||
condition: '八成新',
|
||||
uploadTime: '2024-01-15 16:45',
|
||||
stock: 2,
|
||||
price: '32.00',
|
||||
pddPublished: false,
|
||||
kfzPublished: true,
|
||||
xianyuPublished: true
|
||||
},
|
||||
{
|
||||
image: 'https://picsum.photos/200/280?random=4',
|
||||
name: '三国演义',
|
||||
isbn: '9787020002238',
|
||||
condition: '全新',
|
||||
uploadTime: '2024-01-15 17:10',
|
||||
stock: 8,
|
||||
price: '52.00',
|
||||
pddPublished: true,
|
||||
kfzPublished: true,
|
||||
xianyuPublished: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
uni.setNavigationBarTitle({
|
||||
title: '上书记录'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 获取今天日期
|
||||
getTodayDate() {
|
||||
const today = new Date()
|
||||
const year = today.getFullYear()
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(today.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
},
|
||||
|
||||
// 账号筛选变化
|
||||
handleAccountChange(e) {
|
||||
this.accountIndex = e.detail.value
|
||||
this.filterRecords()
|
||||
},
|
||||
|
||||
// 店铺筛选变化
|
||||
handleShopChange(e) {
|
||||
this.shopIndex = e.detail.value
|
||||
this.filterRecords()
|
||||
},
|
||||
|
||||
// 日期筛选变化
|
||||
handleDateChange(e) {
|
||||
this.selectedDate = e.detail.value
|
||||
this.filterRecords()
|
||||
},
|
||||
|
||||
// 筛选记录
|
||||
filterRecords() {
|
||||
// TODO: 根据筛选条件调用接口获取数据
|
||||
uni.showToast({
|
||||
title: '筛选条件已更新',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
// 获取品相样式类
|
||||
getConditionClass(condition) {
|
||||
const classMap = {
|
||||
'全新': 'condition-new',
|
||||
'九成新': 'condition-good',
|
||||
'八成新': 'condition-fair',
|
||||
'七成新': 'condition-poor'
|
||||
}
|
||||
return classMap[condition] || 'condition-default'
|
||||
},
|
||||
|
||||
// 预览图片
|
||||
previewImage(imageUrl) {
|
||||
uni.previewImage({
|
||||
urls: [imageUrl],
|
||||
current: imageUrl,
|
||||
longPressActions: {
|
||||
itemList: ['发送给朋友', '保存图片', '收藏']
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding: 24rpx 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 筛选区域 */
|
||||
.filter-section {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.filter-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.filter-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.filter-item.full-width {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 26rpx;
|
||||
color: #4e5969;
|
||||
margin-right: 12rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.filter-picker {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f5f7fa;
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
font-size: 26rpx;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
font-size: 20rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* 统计信息 */
|
||||
.stats-section {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.stats-icon {
|
||||
font-size: 40rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 28rpx;
|
||||
color: #4e5969;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 36rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 记录列表 */
|
||||
.record-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.record-main {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 图片区域 */
|
||||
.record-image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.book-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 60rpx;
|
||||
background: linear-gradient(transparent, rgba(0, 0, 0, 0.5));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.record-image:active .image-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.zoom-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 基本信息 */
|
||||
.record-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.book-name {
|
||||
font-size: 32rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 24rpx;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
.condition-badge {
|
||||
font-size: 22rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.condition-new {
|
||||
background: #e1f3d8;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.condition-good {
|
||||
background: #d9ecff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.condition-fair {
|
||||
background: #faecd8;
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.condition-poor {
|
||||
background: #fde2e2;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.condition-default {
|
||||
background: #f4f4f5;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* 价格和库存 */
|
||||
.record-detail {
|
||||
background: #f5f6fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-value.price {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
/* 发布状态 */
|
||||
.publish-status {
|
||||
border-top: 1rpx solid #ebeef5;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
font-size: 20rpx;
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 50%;
|
||||
background: #c0c4cc;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.status-item.published .status-icon {
|
||||
background: #67c23a;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.status-item.published .status-text {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
</style>
|
||||
2195
pages/upload/upload.vue
Normal file
2195
pages/upload/upload.vue
Normal file
File diff suppressed because it is too large
Load Diff
282
pages/upload/upload_noisbn_new.vue
Normal file
282
pages/upload/upload_noisbn_new.vue
Normal file
@ -0,0 +1,282 @@
|
||||
<swiper-item>
|
||||
<view class="tab-content">
|
||||
<scroll-view class="content-scroll" scroll-y="true">
|
||||
<!-- 货区选择 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📍</text>
|
||||
<text class="title-text">货区选择</text>
|
||||
</view>
|
||||
<picker @change="handleNoIsbnAreaChange" :value="noIsbnAreaIndex" :range="areaList">
|
||||
<view class="picker-box">
|
||||
<text class="picker-value">{{ areaList[noIsbnAreaIndex] }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 印刷时间 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📅</text>
|
||||
<text class="title-text">印刷时间</text>
|
||||
</view>
|
||||
<view class="input-with-btn">
|
||||
<input
|
||||
class="form-input-flex"
|
||||
v-model="noIsbnPrintTime"
|
||||
placeholder="请输入印刷时间"
|
||||
/>
|
||||
<view class="action-btn primary" @click="recognizeImage">
|
||||
<text class="btn-icon">📷</text>
|
||||
<text class="btn-text">识图</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 书名 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📚</text>
|
||||
<text class="title-text">书名</text>
|
||||
</view>
|
||||
<view class="input-with-btn">
|
||||
<input
|
||||
class="form-input-flex"
|
||||
v-model="noIsbnBookName"
|
||||
placeholder="请输入书名"
|
||||
/>
|
||||
<view class="action-btn" @click="searchBookName">
|
||||
<text class="btn-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 出版社 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">🏢</text>
|
||||
<text class="title-text">出版社</text>
|
||||
</view>
|
||||
<picker @change="handleNoIsbnPublisherChange" :value="noIsbnPublisherIndex" :range="publisherList">
|
||||
<view class="picker-box">
|
||||
<text class="picker-value">{{ publisherList[noIsbnPublisherIndex] }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 图书分类 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📂</text>
|
||||
<text class="title-text">图书分类</text>
|
||||
</view>
|
||||
<view class="category-select" @click="showCategoryPopup = true">
|
||||
<text class="category-value">{{ noIsbnSelectedCategory || '请选择分类' }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 开本 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📐</text>
|
||||
<text class="title-text">开本</text>
|
||||
</view>
|
||||
<picker @change="handleNoIsbnFormatChange" :value="noIsbnFormatIndex" :range="formatList">
|
||||
<view class="picker-box">
|
||||
<text class="picker-value">{{ formatList[noIsbnFormatIndex] }}</text>
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 书号 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">🔢</text>
|
||||
<text class="title-text">书号</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="noIsbnBookNumber"
|
||||
placeholder="请输入书号"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 定价 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">💵</text>
|
||||
<text class="title-text">定价</text>
|
||||
</view>
|
||||
<view class="price-input-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<input
|
||||
class="price-input"
|
||||
v-model="noIsbnOriginalPrice"
|
||||
placeholder="请输入定价"
|
||||
type="digit"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 字数 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📝</text>
|
||||
<text class="title-text">字数</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="noIsbnWordCount"
|
||||
placeholder="请输入字数"
|
||||
type="number"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- ISBN -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📖</text>
|
||||
<text class="title-text">ISBN</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="noIsbnIsbn"
|
||||
placeholder="请输入ISBN(纯数字)"
|
||||
type="number"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 品相选择 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">⭐</text>
|
||||
<text class="title-text">品相</text>
|
||||
</view>
|
||||
<view class="condition-list">
|
||||
<view
|
||||
class="condition-item"
|
||||
v-for="(item, index) in conditionList"
|
||||
:key="index"
|
||||
:class="{ active: noIsbnSelectedCondition === item }"
|
||||
@click="selectNoIsbnCondition(item)"
|
||||
>
|
||||
<text class="condition-text">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 价格 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">💰</text>
|
||||
<text class="title-text">价格</text>
|
||||
</view>
|
||||
<view class="price-input-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<input
|
||||
class="price-input"
|
||||
v-model="noIsbnPrice"
|
||||
placeholder="请输入价格"
|
||||
type="digit"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 库存 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📦</text>
|
||||
<text class="title-text">库存</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="noIsbnStock"
|
||||
placeholder="请输入库存数量"
|
||||
type="number"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 拍照 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📷</text>
|
||||
<text class="title-text">拍照</text>
|
||||
<text class="photo-count">已拍{{ noIsbnPhotoList.length }}/9张</text>
|
||||
</view>
|
||||
<view class="photo-section">
|
||||
<view class="photo-list">
|
||||
<view class="photo-item" v-for="(photo, index) in noIsbnPhotoList" :key="index">
|
||||
<image class="photo-image" :src="photo" mode="aspectFill" @click="previewNoIsbnPhoto(photo, index)"></image>
|
||||
<view class="photo-index-badge">
|
||||
<text class="photo-index-badge-text">{{ index + 1 }}</text>
|
||||
</view>
|
||||
<view class="photo-delete" @click="deleteNoIsbnPhoto(index)">
|
||||
<text class="delete-icon">✕</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="photo-add" @click="takePhotoNoIsbn" v-if="noIsbnPhotoList.length < 9">
|
||||
<text class="add-icon">+</text>
|
||||
<text class="add-text">拍照</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 在售商品 -->
|
||||
<view class="form-section">
|
||||
<view class="section-header-row">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">🛒</text>
|
||||
<text class="title-text">在售商品</text>
|
||||
</view>
|
||||
<view class="compare-toggle">
|
||||
<text class="toggle-btn" :class="{ active: compareType === 'isbn' }" @click="switchCompare('isbn')">ISBN比价</text>
|
||||
<text class="toggle-btn" :class="{ active: compareType === 'name' }" @click="switchCompare('name')">书名比价</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="product-grid">
|
||||
<view class="grid-item" v-for="(item, index) in productList.slice(0, 12)" :key="index">
|
||||
<image class="grid-image" :src="item.image" mode="aspectFill" @click="previewProductImage(index)"></image>
|
||||
<text class="grid-name">{{ item.name }}</text>
|
||||
<text class="grid-condition">{{ item.condition }}</text>
|
||||
<text class="grid-price">¥{{ item.price }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上书记录 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">📝</text>
|
||||
<text class="title-text">上书记录</text>
|
||||
</view>
|
||||
<view class="history-list">
|
||||
<view class="history-item" v-for="(item, index) in historyList" :key="index">
|
||||
<view class="history-row">
|
||||
<text class="history-date">{{ item.date }}</text>
|
||||
<text class="history-condition">{{ item.condition }}</text>
|
||||
</view>
|
||||
<view class="history-row">
|
||||
<text class="history-price">¥{{ item.price }}</text>
|
||||
<text class="history-stock">库存{{ item.stock }}本</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-placeholder"></view>
|
||||
</scroll-view>
|
||||
<!-- 图片预览遮罩 -->
|
||||
<view class="photo-preview-mask" v-if="previewVisible" @click="closePreview">
|
||||
<swiper class="photo-preview-swiper" :current="previewIndex" @change="onPreviewSwiperChange" circular="true">
|
||||
<swiper-item v-for="(photo, idx) in noIsbnPhotoList" :key="idx">
|
||||
<image class="photo-preview-img" :src="photo" mode="widthFix" @click.stop></image>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
710
pages/vip/vip.vue
Normal file
710
pages/vip/vip.vue
Normal file
@ -0,0 +1,710 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- 页面标题 -->
|
||||
<view class="header-section">
|
||||
<view class="header-card">
|
||||
<text class="header-icon">👑</text>
|
||||
<text class="header-title">选择适合您的会员等级</text>
|
||||
<text class="header-desc">享受到更多专属权益</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已开通会员 -->
|
||||
<view class="active-vip-section" v-if="hasActiveVip">
|
||||
<view class="section-header-row">
|
||||
<text class="section-icon-small">✨</text>
|
||||
<text class="section-title">已开通会员</text>
|
||||
</view>
|
||||
|
||||
<!-- 手机版上书会员 -->
|
||||
<view class="active-card mobile-active" v-if="activeMobileVip">
|
||||
<view class="active-header">
|
||||
<view class="active-name-row">
|
||||
<text class="active-icon">📱</text>
|
||||
<text class="active-name">手机版上书会员</text>
|
||||
</view>
|
||||
<text class="active-badge">已开通</text>
|
||||
</view>
|
||||
<view class="active-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">已上书本数</text>
|
||||
<text class="info-value">{{ activeMobileVip.uploadCount }}本</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">到期时间</text>
|
||||
<text class="info-value">{{ activeMobileVip.expireDate }}</text>
|
||||
</view>
|
||||
<view class="info-row highlight">
|
||||
<text class="info-label">剩余天数</text>
|
||||
<text class="info-value days">{{ activeMobileVip.remainingDays }}天</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 孔网翻新会员 -->
|
||||
<view class="active-card refresh-active" v-if="activeRefreshVip">
|
||||
<view class="active-header">
|
||||
<view class="active-name-row">
|
||||
<text class="active-icon">🔄</text>
|
||||
<text class="active-name">孔网翻新会员</text>
|
||||
</view>
|
||||
<text class="active-badge">已开通</text>
|
||||
</view>
|
||||
<view class="active-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">到期时间</text>
|
||||
<text class="info-value">{{ activeRefreshVip.expireDate }}</text>
|
||||
</view>
|
||||
<view class="info-row highlight">
|
||||
<text class="info-label">剩余天数</text>
|
||||
<text class="info-value days">{{ activeRefreshVip.remainingDays }}天</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 会员选择 -->
|
||||
<view class="vip-options">
|
||||
<view class="section-header-row">
|
||||
<text class="section-icon-small">💎</text>
|
||||
<text class="section-title">选择会员</text>
|
||||
</view>
|
||||
|
||||
<!-- 手机版上书会员 -->
|
||||
<view class="vip-section">
|
||||
<view class="section-header">
|
||||
<text class="section-icon">📱</text>
|
||||
<view class="section-name-box">
|
||||
<text class="section-name">手机版上书会员</text>
|
||||
<text class="section-desc">适合经常上架书籍的用户</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="vip-cards">
|
||||
<!-- 月付会员 -->
|
||||
<view
|
||||
class="vip-card"
|
||||
:class="{ selected: selectedVip === 'mobile-month' }"
|
||||
@click="selectVip('mobile-month')"
|
||||
>
|
||||
<view class="card-header">
|
||||
<view class="card-title-box">
|
||||
<text class="card-title">月付会员</text>
|
||||
<text class="card-period">/月</text>
|
||||
</view>
|
||||
<view class="price-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="card-price">29.9</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-features">
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">每月上传书籍数量增加</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">优先展示您的商品</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">专属客服服务</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">月度VIP标识</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="select-indicator" v-if="selectedVip === 'mobile-month'">
|
||||
<text class="indicator-icon">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 年度会员 -->
|
||||
<view
|
||||
class="vip-card recommended"
|
||||
:class="{ selected: selectedVip === 'mobile-year' }"
|
||||
@click="selectVip('mobile-year')"
|
||||
>
|
||||
<view class="card-header">
|
||||
<view class="card-title-box">
|
||||
<text class="card-title">年度会员</text>
|
||||
<text class="recommend-badge-inline">
|
||||
<text class="badge-icon">🔥</text>
|
||||
<text class="badge-text">推荐</text>
|
||||
</text>
|
||||
<text class="card-period">/年</text>
|
||||
</view>
|
||||
<view class="price-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="card-price">299</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="save-badge">省¥59.8</view>
|
||||
<view class="card-features">
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text highlight">无限制上传书籍数量</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">优先展示您的商品</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">24小时专属客服服务</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">年度专属VIP标识</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">更多增值服务特权</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="select-indicator" v-if="selectedVip === 'mobile-year'">
|
||||
<text class="indicator-icon">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 孔网翻新会员 -->
|
||||
<view class="vip-section">
|
||||
<view class="section-header">
|
||||
<text class="section-icon">🔄</text>
|
||||
<view class="section-name-box">
|
||||
<text class="section-name">孔网翻新会员</text>
|
||||
<text class="section-desc">适合批量处理商品的用户</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="vip-cards">
|
||||
<view
|
||||
class="vip-card"
|
||||
:class="{ selected: selectedVip === 'refresh-month' }"
|
||||
@click="selectVip('refresh-month')"
|
||||
>
|
||||
<view class="card-header">
|
||||
<view class="card-title-box">
|
||||
<text class="card-title">翻新会员</text>
|
||||
<text class="card-period">/月</text>
|
||||
</view>
|
||||
<view class="price-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="card-price">49.9</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-features">
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text highlight">无限制使用翻新功能</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">批量处理商品信息</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<text class="feature-dot">✓</text>
|
||||
<text class="feature-text">优先获得新功能体验</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="select-indicator" v-if="selectedVip === 'refresh-month'">
|
||||
<text class="indicator-icon">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部支付按钮 -->
|
||||
<view class="pay-section">
|
||||
<view class="pay-btn" :class="{ disabled: !selectedVip }" @click="handlePay">
|
||||
<text class="pay-text">{{ selectedVip ? '立即支付' : '请选择会员类型' }}</text>
|
||||
<text class="pay-price" v-if="selectedVip">{{ getSelectedPrice }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectedVip: '',
|
||||
// 模拟已开通会员数据
|
||||
hasActiveVip: true,
|
||||
activeMobileVip: {
|
||||
uploadCount: 128,
|
||||
expireDate: '2024-12-31',
|
||||
remainingDays: 180
|
||||
},
|
||||
activeRefreshVip: {
|
||||
expireDate: '2024-08-15',
|
||||
remainingDays: 45
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
getSelectedPrice() {
|
||||
const prices = {
|
||||
'mobile-month': '¥29.9',
|
||||
'mobile-year': '¥299',
|
||||
'refresh-month': '¥49.9'
|
||||
}
|
||||
return prices[this.selectedVip] || ''
|
||||
},
|
||||
|
||||
getSelectedVipInfo() {
|
||||
const vipInfo = {
|
||||
'mobile-month': { name: '手机版上书会员 - 月付会员', price: '¥29.9' },
|
||||
'mobile-year': { name: '手机版上书会员 - 年度会员', price: '¥299' },
|
||||
'refresh-month': { name: '孔网翻新会员 - 月付会员', price: '¥49.9' }
|
||||
}
|
||||
return vipInfo[this.selectedVip] || { name: '', price: '' }
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
uni.setNavigationBarTitle({
|
||||
title: '会员等级选择'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectVip(type) {
|
||||
this.selectedVip = type
|
||||
},
|
||||
|
||||
handlePay() {
|
||||
if (!this.selectedVip) {
|
||||
uni.showToast({
|
||||
title: '请选择会员类型',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const vipInfo = this.getSelectedVipInfo
|
||||
uni.showModal({
|
||||
title: '确认支付',
|
||||
content: `会员类型:${vipInfo.name}\n支付金额:${vipInfo.price}`,
|
||||
confirmText: '确认支付',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding: 24rpx 28rpx 160rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 页面标题 */
|
||||
.header-section {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.header-card {
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 36rpx 28rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
font-size: 48rpx;
|
||||
display: block;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 34rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.header-desc {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* 区块标题 */
|
||||
.section-header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 0 4rpx;
|
||||
}
|
||||
|
||||
.section-icon-small {
|
||||
font-size: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 30rpx;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 已开通会员 */
|
||||
.active-vip-section {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.active-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
border-left: 6rpx solid #409eff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.active-card.refresh-active {
|
||||
border-left-color: #67c23a;
|
||||
}
|
||||
|
||||
.active-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.active-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.active-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.active-name {
|
||||
font-size: 30rpx;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.active-badge {
|
||||
background: #67c23a;
|
||||
color: #ffffff;
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.active-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 26rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-value.days {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.info-row.highlight .info-label {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
/* 会员选择 */
|
||||
.vip-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.vip-section {
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 2rpx solid #f0f2f5;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
font-size: 40rpx;
|
||||
margin-right: 16rpx;
|
||||
background: #f0f5ff;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.section-name-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-name {
|
||||
font-size: 32rpx;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.vip-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.vip-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
border: 3rpx solid #ebeef5;
|
||||
transition: all 0.25s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vip-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.vip-card.selected {
|
||||
border-color: #409eff;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.vip-card.recommended {
|
||||
background: #ffffff;
|
||||
border-color: #ebeef5;
|
||||
}
|
||||
|
||||
.vip-card.recommended.selected {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.recommend-badge-inline {
|
||||
background: #e6a23c;
|
||||
color: #ffffff;
|
||||
font-size: 18rpx;
|
||||
padding: 4rpx 10rpx;
|
||||
border-radius: 12rpx;
|
||||
font-weight: 500;
|
||||
margin-left: 8rpx;
|
||||
margin-right: 4rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.badge-icon {
|
||||
font-size: 18rpx;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.card-title-box {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-period {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.price-box {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.price-symbol {
|
||||
font-size: 24rpx;
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-price {
|
||||
font-size: 44rpx;
|
||||
color: #f56c6c;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.save-badge {
|
||||
display: inline-block;
|
||||
background: #f56c6c;
|
||||
color: #ffffff;
|
||||
font-size: 20rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 12rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.card-features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.feature-dot {
|
||||
font-size: 22rpx;
|
||||
color: #67c23a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.feature-text.highlight {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.select-indicator {
|
||||
position: absolute;
|
||||
bottom: 16rpx;
|
||||
right: 16rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: #409eff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.vip-card.recommended .select-indicator {
|
||||
background: #409eff;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.indicator-icon {
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 底部支付 */
|
||||
.pay-section {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #ffffff;
|
||||
padding: 24rpx 28rpx;
|
||||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||||
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
background: #409eff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.pay-btn.disabled {
|
||||
background: #c0c4cc;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.pay-btn:active:not(.disabled) {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.pay-text {
|
||||
font-size: 32rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pay-price {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
</style>
|
||||
705
pages/warehouse/warehouse.vue
Normal file
705
pages/warehouse/warehouse.vue
Normal file
@ -0,0 +1,705 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- Element 风格 Tabs 标签栏 -->
|
||||
<view class="wh-tabs-wrapper">
|
||||
<scroll-view scroll-x class="wh-tabs-scroll" :show-scrollbar="false">
|
||||
<view class="wh-tabs">
|
||||
<!-- 加载中 -->
|
||||
<view class="wh-tabs-loading" v-if="isLoadingWarehouse">
|
||||
<view class="mini-spinner"></view>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view
|
||||
class="wh-tab"
|
||||
v-for="item in warehouseList"
|
||||
:key="item.id"
|
||||
:class="{ active: selectedWarehouse && selectedWarehouse.id === item.id }"
|
||||
@click="selectWarehouse(item)"
|
||||
>
|
||||
<text class="wh-tab-text">{{ item.name }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="wh-tab-empty" v-if="!isLoadingWarehouse && warehouseList.length === 0">
|
||||
<text class="wh-tab-empty-text">暂无仓库</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<view class="wh-search-bar">
|
||||
<view class="wh-search-box">
|
||||
<text class="wh-search-icon">🔍</text>
|
||||
<input class="wh-search-input" v-model="searchKeyword" placeholder="搜索货位编号" @input="onSearchInput" confirm-type="search" @confirm="doSearch" />
|
||||
<text class="wh-search-clear" v-if="searchKeyword" @click="clearSearch">✕</text>
|
||||
<view class="wh-scan-btn" @click="handleScan">
|
||||
<text class="wh-scan-icon">📷</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区:货位列表 -->
|
||||
<view class="wh-location-scroll">
|
||||
<!-- 加载中 -->
|
||||
<view class="wh-loading-block" v-if="isLoadingLocation">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="wh-loading-text">加载货位...</text>
|
||||
</view>
|
||||
|
||||
<scroll-view
|
||||
v-if="!isLoadingLocation"
|
||||
class="wh-scroll-view"
|
||||
scroll-y
|
||||
@scrolltolower="loadMoreLocation"
|
||||
:show-scrollbar="false"
|
||||
:lower-threshold="50"
|
||||
refresher-enabled
|
||||
:refresher-triggered="isRefreshing"
|
||||
@refresherrefresh="onRefresh"
|
||||
>
|
||||
<view class="wh-location-grid">
|
||||
<view
|
||||
class="wh-location-cell"
|
||||
v-for="item in locationList"
|
||||
:key="item.id"
|
||||
@click="selectLocation(item)"
|
||||
>
|
||||
<view class="wh-cell-icon">
|
||||
<text class="wh-cell-emoji">📍</text>
|
||||
</view>
|
||||
<view class="wh-cell-info">
|
||||
<text class="wh-cell-code">{{ item.code }}</text>
|
||||
<text class="wh-cell-name">{{ item.name }}</text>
|
||||
</view>
|
||||
<text class="wh-cell-arrow">›</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="wh-load-more" v-if="isLoadingMore">
|
||||
<view class="mini-spinner"></view>
|
||||
<text class="wh-load-more-text">加载更多...</text>
|
||||
</view>
|
||||
|
||||
<!-- 没有更多 -->
|
||||
<view class="wh-load-more" v-if="!locationHasMore && locationList.length > 0">
|
||||
<text class="wh-no-more-text">— 已全部加载 —</text>
|
||||
</view>
|
||||
|
||||
<!-- 无货位 -->
|
||||
<view class="wh-empty-block" v-if="locationList.length === 0 && !isLoadingMore">
|
||||
<text class="wh-empty-text">该仓库暂无货位</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 扫码结果弹窗 -->
|
||||
<view class="wh-dialog-mask" v-if="showScanDialog" @click="showScanDialog = false">
|
||||
<view class="wh-dialog-box" @click.stop>
|
||||
<text class="wh-dialog-title">扫码识别结果</text>
|
||||
<view class="wh-dialog-body">
|
||||
<text class="wh-dialog-label">原始内容:</text>
|
||||
<text class="wh-dialog-value">{{ scanResult }}</text>
|
||||
</view>
|
||||
<view class="wh-dialog-footer">
|
||||
<text class="wh-dialog-btn cancel" @click="showScanDialog = false">关闭</text>
|
||||
<text class="wh-dialog-btn" @click="onScanConfirm">搜索货位</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getWarehouseList, getLocationList } from '@/utils/api.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectedWarehouse: null,
|
||||
warehouseList: [],
|
||||
locationList: [],
|
||||
isLoadingWarehouse: false,
|
||||
isLoadingLocation: false,
|
||||
locationPage: 1,
|
||||
locationPageSize: 20,
|
||||
locationHasMore: true,
|
||||
isLoadingMore: false,
|
||||
isRefreshing: false,
|
||||
searchKeyword: '',
|
||||
scanResult: '',
|
||||
showScanDialog: false
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
uni.setNavigationBarTitle({ title: '选择仓库货架' })
|
||||
this.loadWarehouseList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async loadWarehouseList() {
|
||||
this.isLoadingWarehouse = true
|
||||
try {
|
||||
const res = await getWarehouseList({ status: 1, page: 1, page_size: 100 })
|
||||
if (res.code === 0 && res.data && res.data.list) {
|
||||
this.warehouseList = res.data.list
|
||||
// 默认选中第一个仓库
|
||||
if (this.warehouseList.length > 0) {
|
||||
this.selectedWarehouse = this.warehouseList[0]
|
||||
this.loadLocationList(this.selectedWarehouse.id)
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '获取仓库列表失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '网络请求失败', icon: 'none' })
|
||||
} finally {
|
||||
this.isLoadingWarehouse = false
|
||||
}
|
||||
},
|
||||
|
||||
async loadLocationList(warehouseId, keyword) {
|
||||
this.isLoadingLocation = true
|
||||
this.locationPage = 1
|
||||
this.locationHasMore = true
|
||||
try {
|
||||
const params = {
|
||||
warehouse_id: warehouseId, type: 1, status: 1,
|
||||
page: 1, page_size: this.locationPageSize
|
||||
}
|
||||
if (keyword) params.code = keyword
|
||||
const res = await getLocationList(params)
|
||||
if (res.code === 0 && res.data && res.data.list) {
|
||||
this.locationList = res.data.list
|
||||
const total = res.data.total || 0
|
||||
this.locationHasMore = this.locationPage * this.locationPageSize < total
|
||||
} else {
|
||||
this.locationList = []
|
||||
this.locationHasMore = false
|
||||
}
|
||||
} catch (e) {
|
||||
this.locationList = []
|
||||
this.locationHasMore = false
|
||||
} finally {
|
||||
this.isLoadingLocation = false
|
||||
}
|
||||
},
|
||||
|
||||
async loadMoreLocation() {
|
||||
if (!this.selectedWarehouse || !this.locationHasMore || this.isLoadingMore) return
|
||||
this.isLoadingMore = true
|
||||
this.locationPage++
|
||||
try {
|
||||
const params = {
|
||||
warehouse_id: this.selectedWarehouse.id, type: 1, status: 1,
|
||||
page: this.locationPage, page_size: this.locationPageSize
|
||||
}
|
||||
if (this.searchKeyword) params.code = this.searchKeyword
|
||||
const res = await getLocationList(params)
|
||||
if (res.code === 0 && res.data && res.data.list) {
|
||||
const newList = res.data.list
|
||||
if (newList.length === 0) {
|
||||
this.locationHasMore = false
|
||||
} else {
|
||||
this.locationList = [...this.locationList, ...newList]
|
||||
const total = res.data.total || 0
|
||||
this.locationHasMore = this.locationPage * this.locationPageSize < total
|
||||
}
|
||||
} else {
|
||||
this.locationHasMore = false
|
||||
}
|
||||
} catch (e) {
|
||||
this.locationPage--
|
||||
} finally {
|
||||
this.isLoadingMore = false
|
||||
}
|
||||
},
|
||||
|
||||
selectWarehouse(item) {
|
||||
this.selectedWarehouse = item
|
||||
this.loadLocationList(item.id, this.searchKeyword)
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
async onRefresh() {
|
||||
this.isRefreshing = true
|
||||
this.locationPage = 1
|
||||
this.locationHasMore = true
|
||||
try {
|
||||
const params = {
|
||||
warehouse_id: this.selectedWarehouse.id, type: 1, status: 1,
|
||||
page: 1, page_size: this.locationPageSize
|
||||
}
|
||||
if (this.searchKeyword) params.code = this.searchKeyword
|
||||
const res = await getLocationList(params)
|
||||
if (res.code === 0 && res.data && res.data.list) {
|
||||
this.locationList = res.data.list
|
||||
const total = res.data.total || 0
|
||||
this.locationHasMore = this.locationPage * this.locationPageSize < total
|
||||
} else {
|
||||
this.locationList = []
|
||||
this.locationHasMore = false
|
||||
}
|
||||
} catch (e) {
|
||||
//
|
||||
} finally {
|
||||
this.isRefreshing = false
|
||||
}
|
||||
},
|
||||
|
||||
selectLocation(item) {
|
||||
const data = {
|
||||
warehouseId: this.selectedWarehouse.id,
|
||||
warehouseName: this.selectedWarehouse.name,
|
||||
warehouseCode: this.selectedWarehouse.code,
|
||||
locationId: item.id,
|
||||
locationName: item.name,
|
||||
locationCode: item.code
|
||||
}
|
||||
uni.setStorageSync('selectedWarehouseData', data)
|
||||
uni.redirectTo({ url: '/pages/home/home' })
|
||||
},
|
||||
|
||||
// 搜索输入(带防抖)
|
||||
onSearchInput(e) {
|
||||
if (this._searchTimer) clearTimeout(this._searchTimer)
|
||||
this._searchTimer = setTimeout(() => {
|
||||
this.doSearch()
|
||||
}, 400)
|
||||
},
|
||||
|
||||
// 执行搜索
|
||||
doSearch() {
|
||||
if (this.selectedWarehouse) {
|
||||
this.loadLocationList(this.selectedWarehouse.id, this.searchKeyword.trim())
|
||||
}
|
||||
},
|
||||
|
||||
// 清除搜索
|
||||
clearSearch() {
|
||||
this.searchKeyword = ''
|
||||
if (this.selectedWarehouse) {
|
||||
this.loadLocationList(this.selectedWarehouse.id)
|
||||
}
|
||||
},
|
||||
|
||||
// 扫码识别货位号
|
||||
handleScan() {
|
||||
uni.scanCode({
|
||||
onlyFromCamera: false,
|
||||
success: (res) => {
|
||||
this.scanResult = (res.result || '').trim()
|
||||
this.showScanDialog = true
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({ title: '扫码取消或失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 扫码确认搜索(提取##后的内容)
|
||||
onScanConfirm() {
|
||||
this.showScanDialog = false
|
||||
if (this.scanResult) {
|
||||
const parts = this.scanResult.split('##')
|
||||
const code = parts.length > 1 ? parts[parts.length - 1] : this.scanResult
|
||||
this.searchKeyword = code
|
||||
this.doSearch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page-container {
|
||||
height: 100vh;
|
||||
background: #f5f6fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ====== Element 风格 Tabs 标签栏 ====== */
|
||||
.wh-tabs-wrapper {
|
||||
background: #ffffff;
|
||||
border-bottom: 2rpx solid #e5e6eb;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wh-tabs-scroll {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wh-tabs {
|
||||
display: inline-flex;
|
||||
padding: 0 28rpx;
|
||||
}
|
||||
|
||||
.wh-tabs-loading {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.wh-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 88rpx;
|
||||
padding: 0 24rpx;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wh-tab::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 4rpx;
|
||||
background: #409eff;
|
||||
border-radius: 2rpx;
|
||||
transition: width 0.25s;
|
||||
}
|
||||
|
||||
.wh-tab.active::after {
|
||||
width: 48rpx;
|
||||
}
|
||||
|
||||
.wh-tab-text {
|
||||
font-size: 28rpx;
|
||||
color: #4e5969;
|
||||
white-space: nowrap;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.wh-tab.active .wh-tab-text {
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wh-tab-empty {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.wh-tab-empty-text {
|
||||
font-size: 26rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* ====== 搜索栏 ====== */
|
||||
.wh-search-bar {
|
||||
padding: 20rpx 28rpx 12rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wh-search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #e5e6eb;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 72rpx;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.wh-search-box:focus-within {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 4rpx rgba(64,158,255,0.08);
|
||||
}
|
||||
|
||||
.wh-search-icon {
|
||||
font-size: 28rpx;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.wh-search-box:focus-within .wh-search-icon {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.wh-search-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
background: transparent;
|
||||
border: none;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.wh-search-input::placeholder {
|
||||
color: #c9cdd4;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.wh-search-clear {
|
||||
font-size: 28rpx;
|
||||
color: #c9cdd4;
|
||||
padding: 8rpx 4rpx 8rpx 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wh-scan-btn {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 8rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #f5f6fa;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.wh-scan-btn:active {
|
||||
background: #e5e6eb;
|
||||
}
|
||||
|
||||
.wh-scan-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* ====== 扫码结果弹窗 ====== */
|
||||
.wh-dialog-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.wh-dialog-box {
|
||||
width: 560rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx 36rpx 32rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wh-dialog-title {
|
||||
font-size: 32rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.wh-dialog-body {
|
||||
width: 100%;
|
||||
background: #f5f6fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx 20rpx;
|
||||
margin-bottom: 32rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.wh-dialog-label {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.wh-dialog-value {
|
||||
font-size: 30rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
word-break: break-all;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wh-dialog-footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.wh-dialog-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
background: #409eff;
|
||||
color: #ffffff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.wh-dialog-btn.cancel {
|
||||
background: #f5f6fa;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
.wh-dialog-btn:active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* ====== 内容区 ====== */
|
||||
.wh-location-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wh-scroll-view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.wh-loading-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 160rpx 0;
|
||||
}
|
||||
|
||||
.wh-loading-text {
|
||||
font-size: 26rpx;
|
||||
color: #86909c;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.wh-location-grid {
|
||||
padding: 20rpx 28rpx 12rpx;
|
||||
}
|
||||
|
||||
/* ====== 货位单元格 ====== */
|
||||
.wh-location-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 22rpx 24rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
border: 2rpx solid #f0f2f5;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.wh-location-cell:active {
|
||||
background: #f5f6fa;
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.wh-cell-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
background: #f5f6fa;
|
||||
border-radius: 14rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 18rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wh-cell-emoji {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.wh-cell-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wh-cell-code {
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wh-cell-name {
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wh-cell-arrow {
|
||||
font-size: 32rpx;
|
||||
color: #c9cdd4;
|
||||
margin-left: 12rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ====== 加载更多 ====== */
|
||||
.wh-load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx 0 8rpx;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.wh-load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.wh-no-more-text {
|
||||
font-size: 22rpx;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
/* ====== 空状态 ====== */
|
||||
.wh-empty-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
}
|
||||
|
||||
.wh-empty-text {
|
||||
font-size: 26rpx;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
/* ====== 公用组件 ====== */
|
||||
.mini-spinner {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border: 3rpx solid #e4e7ed;
|
||||
border-top-color: #409eff;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border: 4rpx solid #e4e7ed;
|
||||
border-top-color: #409eff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
BIN
static/books/book1.jpg
Normal file
BIN
static/books/book1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 146 KiB |
BIN
static/books/book2.jpg
Normal file
BIN
static/books/book2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
BIN
static/books/book3.jpg
Normal file
BIN
static/books/book3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 304 KiB |
BIN
static/books/book4.jpg
Normal file
BIN
static/books/book4.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 247 KiB |
BIN
static/books/book5.jpg
Normal file
BIN
static/books/book5.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
BIN
static/logo.png
Normal file
BIN
static/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
13
uni.promisify.adaptor.js
Normal file
13
uni.promisify.adaptor.js
Normal file
@ -0,0 +1,13 @@
|
||||
uni.addInterceptor({
|
||||
returnValue (res) {
|
||||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
|
||||
return res;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
res.then((res) => {
|
||||
if (!res) return resolve(res)
|
||||
return res[0] ? reject(res[0]) : resolve(res[1])
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
76
uni.scss
Normal file
76
uni.scss
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color:#333;//基本色
|
||||
$uni-text-color-inverse:#fff;//反色
|
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable:#c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color:#ffffff;
|
||||
$uni-bg-color-grey:#f8f8f8;
|
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color:#c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm:12px;
|
||||
$uni-font-size-base:14px;
|
||||
$uni-font-size-lg:16px;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm:20px;
|
||||
$uni-img-size-base:26px;
|
||||
$uni-img-size-lg:40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2C405A; // 文章标题颜色
|
||||
$uni-font-size-title:20px;
|
||||
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
||||
212
utils/api.js
Normal file
212
utils/api.js
Normal file
@ -0,0 +1,212 @@
|
||||
/**
|
||||
* API 签名生成工具 - 用于 192.168.101.213:9090 接口
|
||||
*/
|
||||
|
||||
import md5 from 'blueimp-md5'
|
||||
|
||||
// 配置参数
|
||||
const APP_KEY = 'psi'
|
||||
const CLIENT_ID = 'psi'
|
||||
const APP_SECRET = 'psi_api_sign_secret'
|
||||
const SIGN_METHOD = 'md5'
|
||||
|
||||
// API基础地址
|
||||
const BASE_URL = 'https://psi.api.buzhiyushu.cn'
|
||||
|
||||
/**
|
||||
* 对参数键进行排序(与服务器Go代码 sortKeysWithIndex 完全一致)
|
||||
* Go代码使用 < 进行字符串比较(按字节字典序)
|
||||
*/
|
||||
function sortKeys(keys) {
|
||||
const indexPattern = /^(.+)\[(\d+)\](.*)$/
|
||||
keys.sort((keyI, keyJ) => {
|
||||
const ma = indexPattern.exec(keyI)
|
||||
const mb = indexPattern.exec(keyJ)
|
||||
if (ma && mb) {
|
||||
const [, preA, idxA, sufA] = ma
|
||||
const [, preB, idxB, sufB] = mb
|
||||
if (preA !== preB) return preA < preB ? -1 : 1
|
||||
const numA = parseInt(idxA, 10)
|
||||
const numB = parseInt(idxB, 10)
|
||||
if (numA !== numB) return numA - numB
|
||||
return sufA < sufB ? -1 : 1
|
||||
}
|
||||
// 至少有一个不是带索引的键,使用 < 比较(与Go一致)
|
||||
return keyI < keyJ ? -1 : (keyI > keyJ ? 1 : 0)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算签名(与服务器Go代码 calculateSign 一致)
|
||||
* 1. 收集所有参数(跳过sign)
|
||||
* 2. 按key排序
|
||||
* 3. 拼接 key1=value1&key2=value2...
|
||||
* 4. 前后加 secret
|
||||
* 5. MD5并转大写
|
||||
*/
|
||||
function calculateSign(params) {
|
||||
// 收集参数,跳过sign
|
||||
const entries = []
|
||||
for (const key in params) {
|
||||
if (key === 'sign') continue
|
||||
const value = params[key]
|
||||
if (value === undefined || value === null) continue
|
||||
entries.push({ key, value: String(value) })
|
||||
}
|
||||
|
||||
// 排序entries数组(按key)
|
||||
entries.sort((a, b) => {
|
||||
const indexPattern = /^(.+)\[(\d+)\](.*)$/
|
||||
const ma = indexPattern.exec(a.key)
|
||||
const mb = indexPattern.exec(b.key)
|
||||
if (ma && mb) {
|
||||
const [, preA, idxA, sufA] = ma
|
||||
const [, preB, idxB, sufB] = mb
|
||||
if (preA !== preB) return preA < preB ? -1 : 1
|
||||
const numA = parseInt(idxA, 10)
|
||||
const numB = parseInt(idxB, 10)
|
||||
if (numA !== numB) return numA - numB
|
||||
return sufA < sufB ? -1 : 1
|
||||
}
|
||||
return a.key < b.key ? -1 : (a.key > b.key ? 1 : 0)
|
||||
})
|
||||
|
||||
// 拼接签名字符串
|
||||
const signStr = entries.map(e => `${e.key}=${e.value}`).join('&')
|
||||
console.log('calculateSign 签名字符串:', signStr)
|
||||
|
||||
// 前后加secret
|
||||
const signWithSecret = APP_SECRET + signStr + APP_SECRET
|
||||
console.log('calculateSign 加secret后:', signWithSecret)
|
||||
|
||||
const sign = md5(signWithSecret).toUpperCase()
|
||||
console.log('calculateSign 生成的sign:', sign)
|
||||
|
||||
return sign
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带签名的URL(带系统参数:app_key, client_id, timestamp, sign_method)
|
||||
* 用于仓库列表等接口
|
||||
*/
|
||||
function generateSignedUrl(baseUrl, params = {}) {
|
||||
const timestamp = Math.floor(Date.now() / 1000).toString()
|
||||
|
||||
// 构建完整参数(业务参数 + 系统参数)
|
||||
const allParams = { ...params }
|
||||
delete allParams.sign
|
||||
allParams.app_key = APP_KEY
|
||||
allParams.client_id = CLIENT_ID
|
||||
allParams.timestamp = timestamp
|
||||
allParams.sign_method = SIGN_METHOD
|
||||
|
||||
// 计算签名
|
||||
const sign = calculateSign(allParams)
|
||||
|
||||
// 构建URL查询字符串(所有参数按key排序)
|
||||
const keys = Object.keys(allParams)
|
||||
sortKeys(keys)
|
||||
const queryParts = keys.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(allParams[key])}`)
|
||||
queryParts.push(`sign=${sign}`)
|
||||
|
||||
const separator = baseUrl.includes('?') ? '&' : '?'
|
||||
return `${baseUrl}${separator}${queryParts.join('&')}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成简单签名的URL(不带系统参数,只有业务参数签名)
|
||||
* 用于货位列表等接口
|
||||
*/
|
||||
function generateSimpleSignedUrl(baseUrl, params = {}) {
|
||||
// 只使用业务参数
|
||||
const allParams = { ...params }
|
||||
delete allParams.sign
|
||||
|
||||
// 计算签名(不带系统参数)
|
||||
const sign = calculateSign(allParams)
|
||||
|
||||
// 构建URL查询字符串(所有参数按key排序)
|
||||
const keys = Object.keys(allParams)
|
||||
sortKeys(keys)
|
||||
const queryParts = keys.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(allParams[key])}`)
|
||||
queryParts.push(`sign=${sign}`)
|
||||
|
||||
const separator = baseUrl.includes('?') ? '&' : '?'
|
||||
return `${baseUrl}${separator}${queryParts.join('&')}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token(从本地存储或登录接口)
|
||||
*/
|
||||
function getAuthToken() {
|
||||
// 优先从本地存储获取
|
||||
const token = uni.getStorageSync('psi_token')
|
||||
if (token) return token
|
||||
|
||||
// 使用curl中的固定token(临时方案)
|
||||
return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Miwicm9sZSI6MjU1LCJ1c2VybmFtZSI6IjE4OTA0MDU2ODAwIiwiYWJvdXRfaWQiOjE5NjUyNTQ3NzQzMjc1MzM1NzAsImlzcyI6InBzaS1zeXN0ZW0iLCJleHAiOjE3ODA0NjkxNzMsIm5iZiI6MTc4MDM4Mjc3MywiaWF0IjoxNzgwMzgyNzczfQ.FQkDiDzNj0tN3ct0RJCnL7s03vstf7uMmeXqqek8sME'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库列表
|
||||
*/
|
||||
export function getWarehouseList(params = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = generateSignedUrl(`${BASE_URL}/api/warehouse/list`, params)
|
||||
console.log('请求仓库列表URL:', url)
|
||||
uni.request({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': 'Bearer ' + getAuthToken()
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('仓库列表请求成功:', res.statusCode, res.data)
|
||||
if (res.statusCode === 200) {
|
||||
resolve(res.data)
|
||||
} else {
|
||||
reject(new Error(`请求失败: ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('仓库列表请求失败:', err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取货位列表
|
||||
*/
|
||||
export function getLocationList(params = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = generateSignedUrl(`${BASE_URL}/api/location/list`, params)
|
||||
console.log('请求货位列表URL:', url)
|
||||
uni.request({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': 'Bearer ' + getAuthToken()
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('货位列表请求成功:', res.statusCode, res.data)
|
||||
if (res.statusCode === 200) {
|
||||
resolve(res.data)
|
||||
} else {
|
||||
reject(new Error(`请求失败: ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('货位列表请求失败:', err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
getWarehouseList,
|
||||
getLocationList,
|
||||
generateSignedUrl
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user