diff --git a/_codex_tabs_verify.png b/_codex_tabs_verify.png deleted file mode 100644 index 1f28e94..0000000 Binary files a/_codex_tabs_verify.png and /dev/null differ diff --git a/_codex_toolbox_verify.png b/_codex_toolbox_verify.png deleted file mode 100644 index 4da6469..0000000 Binary files a/_codex_toolbox_verify.png and /dev/null differ diff --git a/api/config.js b/api/config.js index fe6fd90..478537b 100644 --- a/api/config.js +++ b/api/config.js @@ -45,6 +45,11 @@ export default { INTERFACE_POINT_GET_LOG_LIST: '/point/loglist', // 点数账单流水 INTERFACE_POINT_POST_CREATE_ORDER: '/point/createorder', // 创建充值订单 INTERFACE_POINT_GET_ORDER_STATUS: '/point/orderstatus', // 订单状态轮询 + INTERFACE_POINT_GET_EARN_CONFIG: '/point/earnconfig', // 积分获取页配置(签到 + 邀请 + 看广告) + INTERFACE_POINT_POST_CHECKIN: '/point/checkin', // 每日签到领取积分 + INTERFACE_POINT_POST_AD_TICKET: '/point/adticket', // 看广告前领取一次性凭证 + INTERFACE_POINT_POST_AD_REWARD: '/point/adreward', // 看完广告发放积分 + INTERFACE_POINT_POST_AD_CANCEL: '/point/adcancel', // 广告未看完,作废凭证 INTERFACE_BILLING_GET_CONFIG: '/billing/config', // 产品计费配置 INTERFACE_BILLING_POST_QUOTE: '/billing/quote', // 产品计价 @@ -63,6 +68,25 @@ export default { INTERFACE_ANIME_GET_DETAIL: '/anime/getdetail', // 动漫头像详情 INTERFACE_ANIME_POST_DEL: '/anime/del', // 动漫头像删除 INTERFACE_ANIME_GET_STYLE_LIST: '/anime/getstylelist', // 动漫头像风格 + INTERFACE_IDPHOTO_GET_CONFIG: '/idphoto/config', + INTERFACE_IDPHOTO_POST_CREATE: '/idphoto/create', + INTERFACE_IDPHOTO_POST_RERENDER: '/idphoto/rerender', + INTERFACE_IDPHOTO_GET_DETAIL: '/idphoto/getdetail', + INTERFACE_IDPHOTO_POST_DEL: '/idphoto/del', + + // 形象照/职业照/写真(混元生图 3.0,一次可出多张) + INTERFACE_PORTRAIT_GET_CONFIG: '/portrait/config', + INTERFACE_PORTRAIT_POST_CREATE: '/portrait/create', + INTERFACE_PORTRAIT_GET_DETAIL: '/portrait/getdetail', + INTERFACE_PORTRAIT_GET_LIST: '/portrait/getlist', + INTERFACE_PORTRAIT_POST_DEL: '/portrait/del', + + // 老照片修复/上色(混元生图 3.0,异步任务 + 轮询) + INTERFACE_OLDPHOTO_GET_CONFIG: '/oldphoto/config', + INTERFACE_OLDPHOTO_POST_CREATE: '/oldphoto/create', + INTERFACE_OLDPHOTO_GET_DETAIL: '/oldphoto/getdetail', + INTERFACE_OLDPHOTO_GET_LIST: '/oldphoto/getlist', + INTERFACE_OLDPHOTO_POST_DEL: '/oldphoto/del', // 机器人/文本生成(旧项目 AI 写作/取名接口) INTERFACE_BOT_POST_EDIT: '/robot/edit', // 创建/编辑机器人 diff --git a/api/index.js b/api/index.js index b98a21f..304632b 100644 --- a/api/index.js +++ b/api/index.js @@ -66,7 +66,15 @@ export const pointApi = { // 创建充值订单(小程序返回虚拟支付参数) createOrder: (params) => request({ url: API.INTERFACE_POINT_POST_CREATE_ORDER, method: 'POST', params }), // 订单状态轮询 - getOrderStatus: (params) => request({ url: API.INTERFACE_POINT_GET_ORDER_STATUS, method: 'POST', params }) + getOrderStatus: (params) => request({ url: API.INTERFACE_POINT_GET_ORDER_STATUS, method: 'POST', params }), + // 积分获取页配置(签到、邀请、看广告配置与今日进度,免登录可调) + getEarnConfig: (params) => request({ url: API.INTERFACE_POINT_GET_EARN_CONFIG, method: 'POST', params }), + // 每日签到,服务端按用户与日期幂等发放 + checkin: (params) => request({ url: API.INTERFACE_POINT_POST_CHECKIN, method: 'POST', params }), + // 看广告:先取一次性凭证,看完再兑换积分,未看完则作废 + getAdTicket: (params) => request({ url: API.INTERFACE_POINT_POST_AD_TICKET, method: 'POST', params }), + getAdReward: (params) => request({ url: API.INTERFACE_POINT_POST_AD_REWARD, method: 'POST', params }), + cancelAdTicket: (params) => request({ url: API.INTERFACE_POINT_POST_AD_CANCEL, method: 'POST', params }) } export const billingApi = { @@ -74,6 +82,34 @@ export const billingApi = { quote: (params) => request({ url: API.INTERFACE_BILLING_POST_QUOTE, method: 'POST', params }) } +export const idPhotoApi = { + getConfig: (params) => request({ url: API.INTERFACE_IDPHOTO_GET_CONFIG, method: 'POST', params }), + getList: (params = {}) => request({ + url: API.INTERFACE_WORK_GET_LIST, + method: 'POST', + params: { ...params, type: 'photo' } + }), + rerender: (params) => request({ url: API.INTERFACE_IDPHOTO_POST_RERENDER, method: 'POST', params }), + getDetail: (params) => request({ url: API.INTERFACE_IDPHOTO_GET_DETAIL, method: 'POST', params }), + delete: (params) => request({ url: API.INTERFACE_IDPHOTO_POST_DEL, method: 'POST', params }) +} + +export const portraitApi = { + getConfig: (params) => request({ url: API.INTERFACE_PORTRAIT_GET_CONFIG, method: 'POST', params }), + getDetail: (params) => request({ url: API.INTERFACE_PORTRAIT_GET_DETAIL, method: 'POST', params }), + getList: (params) => request({ url: API.INTERFACE_PORTRAIT_GET_LIST, method: 'POST', params }), + delete: (params) => request({ url: API.INTERFACE_PORTRAIT_POST_DEL, method: 'POST', params }) + // create 走 multipart 直传,见 utils/upload.js 的 createPortrait +} + +export const oldPhotoApi = { + getConfig: (params) => request({ url: API.INTERFACE_OLDPHOTO_GET_CONFIG, method: 'POST', params }), + getDetail: (params) => request({ url: API.INTERFACE_OLDPHOTO_GET_DETAIL, method: 'POST', params }), + getList: (params) => request({ url: API.INTERFACE_OLDPHOTO_GET_LIST, method: 'POST', params }), + delete: (params) => request({ url: API.INTERFACE_OLDPHOTO_POST_DEL, method: 'POST', params }) + // create 走 multipart 直传,见 utils/upload.js 的 createOldPhoto +} + export const toolApi = { getMyWorkList: (params) => request({ url: API.INTERFACE_WORK_GET_LIST, method: 'POST', params }), getAppList: (params) => request({ url: API.INTERFACE_APP_GET_LIST, method: 'POST', params }), @@ -114,5 +150,8 @@ export default { vip: vipApi, point: pointApi, billing: billingApi, + idPhoto: idPhotoApi, + oldPhoto: oldPhotoApi, + portrait: portraitApi, tool: toolApi } diff --git a/pages.json b/pages.json index c0a96fc..a24c733 100644 --- a/pages.json +++ b/pages.json @@ -71,18 +71,54 @@ "navigationBarTitleText": "证件照" } }, + { + "path": "pages/tool/id-photo-history", + "style": { + "navigationBarTitleText": "证件照记录" + } + }, + { + "path": "pages/tool/id-photo-detail", + "style": { + "navigationBarTitleText": "证件照详情" + } + }, { "path": "pages/tool/portrait-photo", "style": { "navigationBarTitleText": "形象照/职业照/写真" } }, + { + "path": "pages/tool/portrait-history", + "style": { + "navigationBarTitleText": "生成记录" + } + }, + { + "path": "pages/tool/portrait-detail", + "style": { + "navigationBarTitleText": "形象照详情" + } + }, { "path": "pages/tool/old-photo", "style": { "navigationBarTitleText": "老照片修复/上色" } }, + { + "path": "pages/tool/old-photo-history", + "style": { + "navigationBarTitleText": "历史记录" + } + }, + { + "path": "pages/tool/old-photo-detail", + "style": { + "navigationBarTitleText": "老照片详情" + } + }, { "path": "pages/tool/work-detail", "style": { @@ -122,6 +158,36 @@ "backgroundColor": "#f3f7fb" } }, + { + "path": "pages/point/earn", + "style": { + "navigationBarTitleText": "获得点数" + } + }, + { + "path": "pages/my/wechat", + "style": { + "navigationBarTitleText": "关注公众号" + } + }, + { + "path": "pages/my/feedback", + "style": { + "navigationBarTitleText": "意见反馈" + } + }, + { + "path": "pages/my/contact", + "style": { + "navigationBarTitleText": "联系我们" + } + }, + { + "path": "pages/my/setting", + "style": { + "navigationBarTitleText": "设置" + } + }, { "path": "pages/invite/invite", "style": { diff --git a/pages/agreement/agreement.vue b/pages/agreement/agreement.vue index d0501b0..d9fa24b 100644 --- a/pages/agreement/agreement.vue +++ b/pages/agreement/agreement.vue @@ -1,45 +1,130 @@ diff --git a/pages/bill/bill.vue b/pages/bill/bill.vue index 6597d1c..29b677a 100644 --- a/pages/bill/bill.vue +++ b/pages/bill/bill.vue @@ -54,6 +54,11 @@ {{ item.type_text }} {{ item.time }} + + + 订单号 {{ orderNo(item) }} + 复制 + {{ formatAmount(item.amount) }} @@ -255,6 +260,24 @@ function formatAmount(value) { return num > 0 ? `+${num}` : String(num) } +/** + * 充值流水的订单号。 + * 后端 point_log.biz_no 在充值时存的就是 point_order.order_no(消费存的是计费流水号,不展示)。 + */ +function orderNo(item) { + if (!item || item.type !== 'recharge') return '' + return String(item.biz_no || '').trim() +} + +function copyOrderNo(value) { + if (!value) return + uni.setClipboardData({ + data: value, + success: () => toast('订单号已复制'), + fail: () => toast('复制失败,请长按选择') + }) +} + function getTypeMark(type) { return typeMark[type] || '记' } @@ -574,6 +597,30 @@ function goRecharge() { font-size: 22rpx; } +.ledger-order { + margin-top: 10rpx; + display: flex; + align-items: center; + gap: 10rpx; +} + +.ledger-order-text { + min-width: 0; + flex: 1; + color: #9aa4b2; + font-size: 21rpx; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.ledger-order-copy { + flex-shrink: 0; + color: #0b8cff; + font-size: 21rpx; + font-weight: 800; +} + .ledger-type { height: 34rpx; padding: 0 14rpx; diff --git a/pages/login/login.vue b/pages/login/login.vue index a63ea13..d202b09 100644 --- a/pages/login/login.vue +++ b/pages/login/login.vue @@ -3,10 +3,9 @@ - @@ -23,14 +22,14 @@ @getphonenumber="getPhoneNumber" @click="onPhoneLoginClick" > - + 手机号登录 @@ -69,6 +68,7 @@ import { userApi } from '@/api/index.js' import { useUserStore } from '@/store/user.js' import { useApp } from '@/utils/useApp.js' import { isInWechat } from '@/utils/util.js' +import { rememberLoginSource, returnAfterLogin } from '@/utils/login.js' import CONFIG from '@/utils/config.js' const userStore = useUserStore() @@ -89,9 +89,9 @@ onLoad((options = {}) => { type.value = options.type || '1' source.value = options.source || '' const redirect = options.redirect || options.url || '' + rememberLoginSource(redirect) // #ifdef H5 - if (redirect) uni.setStorageSync('login_redirect', decodeURIComponent(redirect)) if (options.code) postLogin(options.code) // 公众号授权回跳 // #endif @@ -260,10 +260,10 @@ function afterLogin(res) { if (inviteCode) uni.removeStorageSync('invite_code') - // 统一跳回首页 + // 返回发起登录的页面,navigateBack/reLaunch 都会触发目标页重新读取登录态 setTimeout(() => { - uni.switchTab({ url: '/pages/toolbox/toolbox' }) - }, 1200) + returnAfterLogin() + }, 800) } @@ -289,13 +289,6 @@ function afterLogin(res) { display: block; } -.login-tip { - margin-top: 24rpx; - color: #7f8896; - font-size: 26rpx; - line-height: 1.4; -} - .login-actions { margin-top: 92rpx; display: flex; @@ -329,14 +322,14 @@ function afterLogin(res) { &.wechat { color: #fff; - background: #46bb36; - box-shadow: 0 14rpx 28rpx rgba(70, 187, 54, 0.18); + background: #0b8cff; + box-shadow: 0 14rpx 28rpx rgba(11, 140, 255, 0.2); } &.phone { - color: #46bb36; + color: #0b8cff; background: #ffffff; - border: 2rpx solid rgba(70, 187, 54, 0.55); + border: 2rpx solid rgba(11, 140, 255, 0.48); } } @@ -396,8 +389,8 @@ function afterLogin(res) { flex-shrink: 0; &.checked { - background: #46bb36; - border-color: #46bb36; + background: #0b8cff; + border-color: #0b8cff; } } diff --git a/pages/login/phone.vue b/pages/login/phone.vue index a980a44..5bf1c2b 100644 --- a/pages/login/phone.vue +++ b/pages/login/phone.vue @@ -23,9 +23,11 @@ + + diff --git a/pages/my/feedback.vue b/pages/my/feedback.vue new file mode 100644 index 0000000..36f4def --- /dev/null +++ b/pages/my/feedback.vue @@ -0,0 +1,321 @@ + diff --git a/pages/tool/old-photo-detail.vue b/pages/tool/old-photo-detail.vue new file mode 100644 index 0000000..b47d2d6 --- /dev/null +++ b/pages/tool/old-photo-detail.vue @@ -0,0 +1,434 @@ + + + + + diff --git a/pages/tool/old-photo-history.vue b/pages/tool/old-photo-history.vue new file mode 100644 index 0000000..3e19227 --- /dev/null +++ b/pages/tool/old-photo-history.vue @@ -0,0 +1,393 @@ + + + + + diff --git a/pages/tool/old-photo.vue b/pages/tool/old-photo.vue index cca93bb..9f089c5 100644 --- a/pages/tool/old-photo.vue +++ b/pages/tool/old-photo.vue @@ -1,145 +1,270 @@