feat: initialize luobo printing WeChat mini program with full feature stack

- Add comprehensive project documentation (README.md) with tech stack, structure, and usage guide
- Implement API layer with modular services (auth, file, order, printer, price, pay)
- Add Redux Toolkit state management with slices for user, order, file, and printer
- Create complete page structure: index, login, user center, file management, order management, print settings
- Build reusable UI components (OrderCard, PriceTable) with consistent styling
- Establish design system with CSS variables, animations, and common styles
- Add TypeScript type definitions for all domain entities
- Implement utility functions for formatting, HTTP requests, and local storage
- Configure ESLint to use CommonJS format for compatibility
- Update dependencies: add Redux Toolkit, React Redux, and related packages
- Style pages with gradient backgrounds, card layouts, and smooth animations

BREAKING CHANGE: This is an initial project setup that replaces the previous Taro Hooks demo template with a complete printing service mini program
This commit is contained in:
Mikuisnotavailable
2026-03-30 23:22:30 +08:00
parent a424d06731
commit c9a70a139c
20 changed files with 4022 additions and 1697 deletions

View File

@@ -1,97 +1,140 @@
/* ============================================
登录页面样式 - 爱印通
登录页面样式 - 爱印通 Apple Liquid Glass 设计系统
大字体大控件版本 - 微信小程序优化
============================================ */
@import '../../styles/variables.css';
page {
background: linear-gradient(180deg, #e8f0fe 0%, #f0f5ff 30%, #fafbfc 100%);
background: var(--bg-page-gradient);
min-height: 100vh;
}
.login-page {
min-height: 100vh;
padding: 100px 32px 60px;
padding: 160rpx 48rpx 96rpx;
display: flex;
flex-direction: column;
position: relative;
}
/* 头部区域 */
/* ========== 头部区域 ========== */
.login-header {
text-align: center;
margin-bottom: 48px;
animation: fadeInDown 0.6s ease forwards;
margin-bottom: 80rpx;
animation: fadeInDown 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.login-logo {
width: 80px;
height: 80px;
width: 144rpx;
height: 144rpx;
background: var(--primary-gradient);
border-radius: 24px;
border-radius: var(--radius-xl);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 20px;
box-shadow: 0 8px 24px rgba(90, 147, 223, 0.3);
font-size: 40px;
margin: 0 auto 40rpx;
box-shadow: 0 16rpx 48rpx rgba(0, 122, 255, 0.25);
font-size: 72rpx;
position: relative;
overflow: hidden;
}
.login-logo::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%);
animation: logoShimmer 3s ease-in-out infinite;
}
@keyframes logoShimmer {
0%, 100% { left: -100%; }
50% { left: 100%; }
}
.login-title {
font-size: 40px;
font-size: 64rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 2px;
letter-spacing: -0.5px;
display: block;
margin-bottom: 8px;
margin-bottom: 16rpx;
line-height: 1.2;
}
.login-subtitle {
font-size: 24px;
font-size: 30rpx;
color: var(--text-tertiary);
display: block;
font-weight: 400;
}
/* 表单卡片 */
/* ========== 表单卡片 ========== */
.login-form {
background: rgba(255, 255, 255, 0.95);
border-radius: var(--radius-xl);
padding: 36px 28px;
box-shadow: var(--shadow-lg);
border: 1px solid rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
animation: slideUp 0.6s ease 0.2s forwards;
background: var(--bg-glass-heavy);
backdrop-filter: blur(48rpx) saturate(180%);
-webkit-backdrop-filter: blur(48rpx) saturate(180%);
border-radius: var(--radius-2xl);
padding: 64rpx 48rpx;
box-shadow: var(--shadow-xl);
border: 1px solid var(--glass-border);
animation: springUp 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 0.15s forwards;
opacity: 0;
}
@keyframes springUp {
0% {
opacity: 0;
transform: translateY(60rpx) scale(0.95);
}
50% {
transform: translateY(-10rpx) scale(1.01);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.form-item {
margin-bottom: 24px;
margin-bottom: 40rpx;
}
.form-label {
font-size: var(--font-size-base);
font-size: 28rpx;
color: var(--text-secondary);
font-weight: var(--font-weight-medium);
font-weight: 500;
display: block;
margin-bottom: 12px;
padding-left: 4px;
margin-bottom: 16rpx;
padding-left: 8rpx;
letter-spacing: 0.3px;
}
.form-input {
width: 100%;
height: 88px;
background: #f8f9fb;
height: 96rpx;
background: var(--glass-background);
backdrop-filter: blur(32rpx);
-webkit-backdrop-filter: blur(32rpx);
border-radius: var(--radius-md);
padding: 0 24px;
font-size: var(--font-size-base);
padding: 0 32rpx;
font-size: 32rpx;
color: var(--text-primary);
border: 1px solid var(--border-primary);
border: 2rpx solid var(--border-primary);
transition: all var(--transition-base);
outline: none;
}
.form-input:focus {
border-color: var(--primary-color);
background: #fff;
box-shadow: 0 0 0 4px rgba(90, 147, 223, 0.1);
border-color: var(--primary);
background: var(--bg-card-solid);
box-shadow: 0 0 0 6rpx var(--primary-opacity-20);
}
.form-input::placeholder {
@@ -99,17 +142,19 @@ page {
}
.form-error {
font-size: var(--font-size-xs);
color: var(--error-color);
margin-top: 8px;
font-size: 26rpx;
color: var(--error);
margin-top: 12rpx;
display: block;
padding-left: 4px;
padding-left: 8rpx;
font-weight: 400;
}
/* 验证码输入区域 */
/* ========== 验证码输入 ========== */
.code-input-wrapper {
display: flex;
gap: 16px;
gap: 24rpx;
}
.code-input {
@@ -117,212 +162,337 @@ page {
}
.code-btn {
width: 140px;
height: 88px;
background: var(--primary-gradient);
color: #fff;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
width: 220rpx;
height: 96rpx;
background: var(--primary);
color: var(--text-inverse);
font-size: 28rpx;
font-weight: 500;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all var(--transition-base);
transition: all var(--transition-scale);
white-space: nowrap;
}
.code-btn::after {
border: none;
cursor: pointer;
box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.2);
}
.code-btn:active {
transform: scale(0.96);
transform: scale(0.98);
opacity: 0.9;
}
.code-btn[disabled],
.code-btn.disabled {
background: linear-gradient(135deg, #c5cede 0%, #b0bccf 100%);
color: rgba(255, 255, 255, 0.7);
background: var(--border-primary);
color: var(--text-tertiary);
box-shadow: none;
}
/* 登录按钮 */
/* ========== 登录按钮 ========== */
.login-btn {
width: 100%;
height: 96px;
background: var(--primary-gradient);
color: #fff;
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
border-radius: 48px;
height: 88rpx;
background: var(--primary);
color: var(--text-inverse);
font-size: 32rpx;
font-weight: 700;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
margin-top: 32px;
box-shadow: 0 8px 24px rgba(90, 147, 223, 0.3);
transition: all var(--transition-base);
letter-spacing: 2px;
margin-top: 48rpx;
/* 增强的多层边框描边 */
border: 3rpx solid rgba(0, 122, 255, 0.5);
outline: 1rpx solid rgba(255, 255, 255, 0.3);
outline-offset: -3rpx;
/* 增强的阴影效果 */
box-shadow:
0 8rpx 32rpx rgba(0, 122, 255, 0.3),
0 2rpx 8rpx rgba(0, 0, 0, 0.1),
inset 0 1rpx 0 rgba(255, 255, 255, 0.3),
inset 0 -1rpx 0 rgba(0, 0, 0, 0.1);
transition: all var(--transition-scale);
letter-spacing: 1rpx;
cursor: pointer;
position: relative;
overflow: hidden;
}
.login-btn::after {
border: none;
/* 按钮内部光泽效果 */
.login-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%);
transition: left 0.5s ease;
}
.login-btn:active::before {
left: 100%;
}
.login-btn:active {
transform: scale(0.97);
box-shadow: 0 4px 12px rgba(90, 147, 223, 0.2);
transform: scale(0.98);
border-color: rgba(0, 122, 255, 0.7);
box-shadow:
0 4rpx 16rpx rgba(0, 122, 255, 0.2),
0 1rpx 4rpx rgba(0, 0, 0, 0.08),
inset 0 1rpx 0 rgba(255, 255, 255, 0.2);
}
.login-btn[disabled],
.login-btn.disabled {
background: linear-gradient(135deg, #c5cede 0%, #b0bccf 100%);
background: var(--border-primary);
color: var(--text-tertiary);
border-color: rgba(0, 0, 0, 0.1);
box-shadow: none;
outline: none;
}
/* 分割线 */
/* ========== 用户协议复选框 ========== */
.agreement-section {
display: flex;
align-items: flex-start;
margin-top: 40rpx;
padding: 24rpx;
background: rgba(0, 122, 255, 0.03);
border-radius: var(--radius-md);
border: 1px solid rgba(0, 122, 255, 0.08);
}
.agreement-checkbox {
display: flex;
align-items: center;
margin-right: 16rpx;
flex-shrink: 0;
}
.checkbox-input {
width: 40rpx;
height: 40rpx;
border: 3rpx solid var(--border-primary);
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition-base);
background: #fff;
}
.checkbox-input.checked {
background: var(--primary);
border-color: var(--primary);
}
.checkbox-icon {
width: 24rpx;
height: 24rpx;
color: #fff;
display: none;
}
.checkbox-input.checked .checkbox-icon {
display: flex;
align-items: center;
justify-content: center;
}
.agreement-text {
font-size: 24rpx;
color: var(--text-secondary);
line-height: 1.5;
}
.agreement-text .link {
color: var(--primary);
font-weight: 500;
text-decoration: none;
}
/* ========== 分割线 ========== */
.divider {
display: flex;
align-items: center;
margin: 36px 0;
margin: 48rpx 0;
}
.divider-line {
flex: 1;
height: 1px;
background: var(--border-primary);
height: 2rpx;
background: var(--border-separator);
}
.divider-text {
padding: 0 20px;
font-size: var(--font-size-xs);
padding: 0 32rpx;
font-size: 26rpx;
color: var(--text-tertiary);
white-space: nowrap;
}
/* 微信登录按钮 */
/* ========== 微信登录按钮 ========== */
.wechat-btn {
width: 100%;
height: 96px;
background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
color: #fff;
font-size: var(--font-size-lg);
font-weight: var(--font-weight-medium);
border-radius: 48px;
height: 88rpx;
background: #07C160;
color: #ffffff;
font-size: 32rpx;
font-weight: 600;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8px 24px rgba(7, 193, 96, 0.3);
transition: all var(--transition-base);
letter-spacing: 2px;
}
.wechat-btn::after {
box-shadow: 0 8rpx 32rpx rgba(7, 193, 96, 0.25);
transition: all var(--transition-scale);
letter-spacing: 1rpx;
border: none;
cursor: pointer;
}
.wechat-btn:active {
transform: scale(0.97);
transform: scale(0.98);
opacity: 0.95;
}
/* 底部链接 */
/* ========== 底部链接 ========== */
.login-footer {
display: flex;
justify-content: center;
align-items: center;
margin-top: 40px;
margin-top: 64rpx;
flex-wrap: wrap;
gap: 4px;
gap: 8rpx;
}
.footer-text {
font-size: var(--font-size-xs);
font-size: 28rpx;
color: var(--text-tertiary);
font-weight: 400;
}
.link-text {
font-size: var(--font-size-xs);
color: var(--primary-color);
font-weight: var(--font-weight-medium);
font-size: 28rpx;
color: var(--primary);
font-weight: 500;
text-decoration: none;
transition: opacity var(--transition-fast);
}
/* 昵称弹窗 */
.link-text:active {
opacity: 0.7;
}
/* ========== 昵称弹窗 ========== */
.nickname-modal {
background: rgba(255, 255, 255, 0.98);
border-radius: var(--radius-xl);
padding: 48px 32px;
margin-top: 100px;
background: var(--bg-glass-heavy);
backdrop-filter: blur(64rpx) saturate(180%);
-webkit-backdrop-filter: blur(64rpx) saturate(180%);
border-radius: var(--radius-2xl);
padding: 72rpx 56rpx;
margin-top: 160rpx;
box-shadow: var(--shadow-xl);
animation: modalIn 0.3s ease forwards;
border: 1px solid var(--glass-border);
animation: modalSpringIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes modalIn {
from {
@keyframes modalSpringIn {
0% {
opacity: 0;
transform: scale(0.9) translateY(20px);
transform: scale(0.9) translateY(40rpx);
}
to {
60% {
transform: scale(1.02) translateY(-10rpx);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.modal-title {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
font-size: 44rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
text-align: center;
margin-bottom: 12px;
margin-bottom: 16rpx;
letter-spacing: -0.3px;
}
.modal-subtitle {
font-size: var(--font-size-base);
font-size: 30rpx;
color: var(--text-tertiary);
display: block;
text-align: center;
margin-bottom: 32px;
margin-bottom: 56rpx;
font-weight: 400;
}
.nickname-input {
width: 100%;
height: 88px;
background: #f8f9fb;
height: 96rpx;
background: var(--glass-background);
backdrop-filter: blur(32rpx);
-webkit-backdrop-filter: blur(32rpx);
border-radius: var(--radius-md);
padding: 0 24px;
font-size: var(--font-size-base);
padding: 0 32rpx;
font-size: 32rpx;
color: var(--text-primary);
border: 1px solid var(--border-primary);
margin-bottom: 24px;
border: 2rpx solid var(--border-primary);
margin-bottom: 40rpx;
transition: all var(--transition-base);
outline: none;
}
.nickname-input:focus {
border-color: var(--primary-color);
background: #fff;
box-shadow: 0 0 0 4px rgba(90, 147, 223, 0.1);
border-color: var(--primary);
background: var(--bg-card-solid);
box-shadow: 0 0 0 6rpx var(--primary-opacity-20);
}
.nickname-input::placeholder {
color: var(--text-placeholder);
}
.submit-nickname-btn {
width: 100%;
height: 96px;
background: var(--primary-gradient);
color: #fff;
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
border-radius: 48px;
height: 88rpx;
background: var(--primary);
color: var(--text-inverse);
font-size: 32rpx;
font-weight: 600;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8px 24px rgba(90, 147, 223, 0.3);
}
.submit-nickname-btn::after {
box-shadow: 0 8rpx 32rpx rgba(0, 122, 255, 0.25);
border: none;
cursor: pointer;
transition: all var(--transition-scale);
}
/* 动画 */
.submit-nickname-btn:active {
transform: scale(0.98);
}
/* ========== 动画 ========== */
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
transform: translateY(-32rpx);
}
to {
opacity: 1;
@@ -330,38 +500,30 @@ page {
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ========== 装饰光晕 ========== */
/* 装饰元素 */
.login-page::before {
content: '';
position: fixed;
top: -100px;
right: -100px;
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(125, 179, 245, 0.15) 0%, transparent 70%);
top: -300rpx;
right: -300rpx;
width: 800rpx;
height: 800rpx;
background: radial-gradient(circle, rgba(0, 122, 255, 0.08) 0%, transparent 70%);
border-radius: 50%;
pointer-events: none;
z-index: 0;
}
.login-page::after {
content: '';
position: fixed;
bottom: -50px;
left: -50px;
width: 250px;
height: 250px;
background: radial-gradient(circle, rgba(125, 179, 245, 0.1) 0%, transparent 70%);
bottom: -200rpx;
left: -200rpx;
width: 700rpx;
height: 700rpx;
background: radial-gradient(circle, rgba(90, 200, 250, 0.06) 0%, transparent 70%);
border-radius: 50%;
pointer-events: none;
}
z-index: 0;
}