commit 4ad00dedd5de02c762449fe0dda3b16a90b04c1b Author: Jane Doe Date: Tue Mar 4 15:25:38 2025 +0800 first commit diff --git a/app.js b/app.js new file mode 100644 index 0000000..645ef58 --- /dev/null +++ b/app.js @@ -0,0 +1,393 @@ +// 引入封装加密包 +const aes = require('./utils/aes') +App({ + + onLaunch: function(e) { + var t = this; + const query = e.query + const inviter_nickname = query.uuid || '' + console.log("邀请人id", inviter_nickname) + wx.setStorageSync('inviter_nickname', inviter_nickname); + this.globalData.launchOptions = e, + this.getUserInfo().then(function() { + console.log(e) + }).catch(function(e) { + console.error("获取用户信息失败:", e); + }); +}, + getCurrentTabbar(selected, that) { + if (typeof that.getTabBar === 'function' && + that.getTabBar()) { + that.getTabBar().setData({ + selected: selected + }) + } + }, + onShow() { + console.log('执行app.jsonShow') + console.log(1) + }, + getPopupConfig() { + return new Promise((resolve, reject) => { + this.apiRequest({ + url: '/popup-config/', // 后端接口地址 + method: 'POST', + success: res => { + console.log(res) + if (res.data) { + const { is_enabled, popup_type, content } = res.data.data; + + // 存储到本地缓存 + wx.setStorageSync('popupEnabled', is_enabled); + wx.setStorageSync('popupType', popup_type); + wx.setStorageSync('popupContent', content); + + console.log('弹窗配置已成功获取'); + resolve(res.data.data); // 返回获取到的数据 + } else { + console.warn('弹窗数据获取失败'); + reject(new Error('弹窗数据获取失败')); + } + }, + fail: error => { + console.error('请求失败:', error); + reject(error); + } + }); + }); + }, + 广告(){ + wx.navigateTo({ + url: "/pages/details/details", + success() { + console.log('跳转成功'); + }, + fail(err) { + console.error('跳转失败:', err); + } + }); + }, + checkUpdateVersion() { + console.log('检查微信版本是否支持更新机制'); + if (wx.canIUse('getUpdateManager')) { + const updateManager = wx.getUpdateManager(); + updateManager.onCheckForUpdate(function (res) { + console.log('检查新版本', res); + if (res.hasUpdate) { + updateManager.onUpdateReady(function () { + console.log('新版本下载完成'); + wx.showModal({ + title: '更新提示', + content: '新版本已准备好,是否重启应用?', + success: (res) => { + if (res.confirm) { + console.log('用户确认更新'); + updateManager.applyUpdate(); + } + } + }); + }); + updateManager.onUpdateFailed(function () { + console.log('新版本下载失败'); + wx.showModal({ + title: '已经有新版本了~', + content: '新版本下载失败,请检查网络设置后重试。', + showCancel: false, + }); + }); + } else { + console.log('当前是最新版本'); + } + }); + } else { + wx.showModal({ + title: '温馨提示', + content: '当前微信版本过低,无法使用自动更新功能,请升级到最新微信版本后重试。', + showCancel: false, + }); + } + }, + /** + * 登陆并获取用户信息、token + * @param {*} callback + */ + getUserInfo: async function () { + wx.showLoading({ + title: '正在加载...' + }); + try { + let openid = wx.getStorageSync('openid'); + if (!openid) { + const loginRes = await this.login(); + openid = loginRes.data.userInfo.openid; + wx.setStorageSync('openid', openid); + this.globalData.hasUserInfo = true; + } + await this.getinfo(); // 调用 getinfo 方法获取用户信息 + wx.hideLoading(); + } catch (error) { + console.error('操作失败:', error); + wx.hideLoading(); + throw error; // 将错误向上抛出,让调用者可以捕获 + } + }, + + login: function () { + return new Promise((resolve, reject) => { + wx.login({ + success: res => { + const code = res.code; + this.apiRequest({ + url: '/myapp/login/', + method: 'POST', + data: { + code, + data: res.encryptedData, + iv: res.iv, + Options: this.globalData.launchOptions + }, + success: res => resolve(res), + fail: error => reject(error) + }); + }, + fail: error => reject(error) + }); + }); + }, + + getinfo: function () { + return new Promise((resolve, reject) => { + this.apiRequest({ + url: '/myapp/userinfo/', + method: 'POST', + data: { + 'openid': wx.getStorageSync('openid'), + }, + success: res => { + console.log('获取信息成功', res); + this.processUserInfo(res.data.userInfo, res.data.membershipTypeList); + resolve(); + }, + fail: error => { + console.error('获取信息失败:', error); + reject(error); + } + }); + }); + }, + + processUserInfo: function (userInfo, membershipTypeList) { + // 更新用户信息到本地存储 + wx.setStorageSync('userId', userInfo.nickname); + + + wx.setStorageSync('uuid', userInfo.nickname); + wx.setStorageSync('openid', userInfo.openid); + wx.setStorageSync('token', userInfo.token); + wx.setStorageSync('dailyVideoQuota', userInfo.daily_video_quota); + wx.setStorageSync('totalParseNum', userInfo.usage_count); + wx.setStorageSync('defaultDailyFreeParseNum', userInfo.coins); + wx.setStorageSync('isMember', userInfo.is_member); + wx.setStorageSync('startTime', userInfo.member_start_time); + wx.setStorageSync('endTime', userInfo.member_end_time); + wx.setStorageSync('cards', membershipTypeList); + wx.setStorageSync('invitees_count', userInfo.invitees_count); + wx.setStorageSync('balance', userInfo.balance); + // 检查会员状态 + this.checkMembershipExpiration(userInfo.member_end_time, userInfo.is_member); + }, + + checkMembershipExpiration: function (endTimeStr, isMember) { + if (endTimeStr && isMember) { + const currentTimeStamp = Date.now(); // 当前时间戳(毫秒) + + // 判断 endTimeStr 是时间戳还是日期字符串 + const endTime = typeof endTimeStr === "number" + ? endTimeStr * 1000 // 如果是秒时间戳,转换为毫秒 + : new Date(endTimeStr).getTime(); // 如果是字符串,解析为毫秒 + + // 验证时间是否有效 + if (isNaN(endTime)) { + console.error("无效的时间格式:", endTimeStr); + return; + } + + console.log("当前时间戳(毫秒):", currentTimeStamp); + console.log("会员到期时间戳(毫秒):", endTime); + + // 检查会员是否过期 + if (currentTimeStamp > endTime) { + wx.setStorageSync('isMember', false); + console.log('会员已过期,更新会员状态'); + } + } + }, + + +check_status: function() { + var e = this; + return new Promise(function(t, n) { + e.apiRequest({ + url: "/api/check_status/?param=0", + method: "GET", + success: function(e) { + t(e); + }, + fail: function(e) { + n(e); + } + }); + }); +}, + + globalData: { + selected: 0, + userInfo: null, + hasUserInfo: false, + // chatApiDomain: "https://chat.guimiaokeji.com", + chatApiDomain: "https://chat.guimiaokeji.com", + apiDomain: 'https://kuaiying.bytefunction.com', //生产 + downloadPrefix: 'https://kuaiying.bytefunction.com/proxy?url=', // 通过代理服务器中转(微信限制资源域名,不同平台cdn域名千变万化) + defaultDailyFreeParseNum: 0, //免费次数 + totalParseNum: 0, //总次数 + uuid: null, + isMember: true, // 假设默认为会员 + startTime: null, + endTime: null, + launchOptions:null //页面参数 + }, + //chat服务统一调用接口的方法 + chatApiRequest: function (options) { + const timestamp = Date.now(); + let t = timestamp + let x = aes.Encrypt(String(timestamp)) + return wx.request({ + url: this.globalData.chatApiDomain + options.url, + method: options.method ? options.method : 'GET', + enableChunked: options.enableChunked?options.enableChunked:false, + header: { + 'Authorization': 'Bearer ' + wx.getStorageSync('token'), + 'Accept': 'application/json', + 'x': x, + 't': t + }, + dataType: 'json', + data: options.data, + success: res => { + switch (res.statusCode) { + case 200: + options.success(res); + break; + case 401: + this.toLogin(); + break; + case 422: + break; + case 404: + wx.showToast({ + title: '请求地址不存在', + icon: 'none' + }) + break; + default: + wx.showToast({ + title: res.data.error, + icon: 'none' + }) + } + }, + fail: res => { + if (options.fail) { + options.fail(res); + } + }, + complete: res => { + if (options.complete) { + options.complete(res); + } + } + }); + }, + //全局统一调用接口的方法 + apiRequest: function (options) { + const timestamp = Date.now(); + let t = timestamp + let x = aes.Encrypt(String(timestamp)) + wx.request({ + url: this.globalData.apiDomain + options.url, + method: options.method ? options.method : 'GET', + header: { + 'Authorization': 'Bearer ' + wx.getStorageSync('token'), + 'Accept': 'application/json', + 'x': x, + 't': t + }, + dataType: 'json', + data: options.data, + success: res => { + switch (res.statusCode) { + case 200: + options.success(res); + break; + case 401: + this.toLogin(); + break; + case 422: + break; + case 404: + wx.showToast({ + title: '请求地址不存在', + icon: 'none' + }) + break; + default: + wx.showToast({ + title: res.data.message, + icon: 'none' + }) + } + }, + fail: res => { + if (options.fail) { + options.fail(res); + } + }, + complete: res => { + if (options.complete) { + options.complete(res); + } + } + }); + }, + // 上传图片 + uploadFile: function (filePath) { + return new Promise((resolve, reject) => { + wx.uploadFile({ + url: this.globalData.apiDomain + "/myapp/upload_image/", // 上传的服务器接口地址 + filePath: filePath, + name: 'image_file', + success: (res) => { + if (res.statusCode === 200) { + resolve(res.data) + } else { + reject(res) + } + + }, + fail: (err) => { + console.error('Upload failed:', err); + wx.showToast({ + title: '上传错误', + icon: 'error' + }); + } + }) + }) + }, + + // 生成视频额度是否为0 + noQuota: function(){ + let dailyVideoQuota = wx.getStorageSync('dailyVideoQuota') + return dailyVideoQuota < 1 + } +}); \ No newline at end of file diff --git a/app.json b/app.json new file mode 100644 index 0000000..e91ea85 --- /dev/null +++ b/app.json @@ -0,0 +1,60 @@ +{ + "pages": [ + "pages/index/index", + "pages/mine/mine", + "pages/video/video", + "pages/extract/extract", + "pages/users/users", + "pages/agent/agent", + "pages/invite/invite", + "pages/faq/faq", + "pages/vip_recharge/vip_recharge", + "pages/business_cooperation/business_cooperation", + "pages/invite_incentive/invite_incentive", + "pages/video_list/video_list", + "pages/aitools/aitools", + "pages/details/details", + "pages/bot-list/bot-list" + + ], + "window": { + "backgroundTextStyle": "light", + "navigationBarBackgroundColor": "#fff", + "navigationBarTitleText": "WeChat", + "navigationBarTextStyle": "black" + }, + "tabBar": { + "custom": true, + "color": "#bfbfbf", + "selectedColor": "#337AFF", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "list": [ + { + "pagePath": "pages/index/index", + "text": "首页", + "iconPath": "images/主页.png", + "selectedIconPath": "images/主页点击.png" + }, + { + "pagePath": "pages/aitools/aitools", + "text": "写文案", + "iconPath": "images/AI分析.png", + "selectedIconPath": "images/AI分析点击.png" + }, + { + "pagePath": "pages/video_list/video_list", + "text": "违规检测", + "iconPath": "images/文案库.png", + "selectedIconPath": "images/文案库点击.png" + }, + { + "pagePath": "pages/mine/mine", + "text": "我的", + "iconPath": "images/我的.png", + "selectedIconPath": "images/我的点击.png" + } + ] + }, + "sitemapLocation": "sitemap.json" +} diff --git a/app.wxss b/app.wxss new file mode 100644 index 0000000..06c6fc9 --- /dev/null +++ b/app.wxss @@ -0,0 +1,10 @@ +/**app.wxss**/ +.container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + padding: 200rpx 0; + box-sizing: border-box; +} diff --git a/custom-tab-bar/index.js b/custom-tab-bar/index.js new file mode 100644 index 0000000..5449f61 --- /dev/null +++ b/custom-tab-bar/index.js @@ -0,0 +1,44 @@ +Component({ + data: { + selected: 0, + color: "#bfbfbf", + selectedColor: "#337AFF", + list: [ + { + pagePath: "/pages/index/index", + iconPath: "/images/主页.png", + selectedIconPath: "/images/主页点击.png", + text: "首页" + }, + { + pagePath: "/pages/aitools/aitools", + iconPath: "/images/AI分析.png", + selectedIconPath: "/images/AI分析.png", + text: "写文案" + }, + { + pagePath: "/pages/video_list/video_list", + iconPath: "/images/文案库.png", + selectedIconPath: "/images/文案库点击.png", + text: "违规检测" + }, + { + pagePath: "/pages/mine/mine", + iconPath: "/images/my.png", + selectedIconPath: "/images/我的点击.png", + text: "我的" + } + ] + }, + attached() {}, + methods: { + switchTab(e) { + const data = e.currentTarget.dataset + const url = data.path + console.log(data) + wx.switchTab({ + url + }) + } + } +}); diff --git a/custom-tab-bar/index.json b/custom-tab-bar/index.json new file mode 100644 index 0000000..467ce29 --- /dev/null +++ b/custom-tab-bar/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/custom-tab-bar/index.wxml b/custom-tab-bar/index.wxml new file mode 100644 index 0000000..f91e6a0 --- /dev/null +++ b/custom-tab-bar/index.wxml @@ -0,0 +1,8 @@ + + + + + {{item.text}} + + + \ No newline at end of file diff --git a/custom-tab-bar/index.wxss b/custom-tab-bar/index.wxss new file mode 100644 index 0000000..e6167a2 --- /dev/null +++ b/custom-tab-bar/index.wxss @@ -0,0 +1,35 @@ +.tab-bar { + position: fixed; + bottom: 0; + width: 100%; + height: 60px; + background-color: #222238; + border-top:solid 1px rgba(233, 213, 213,0.5); + display: flex; + justify-content: space-around; + align-items: center; + z-index: 9999; /* 确保 z-index 足够高 */ +} + +.tab-bar-item { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; + + transition: all 0.3s; +} + + +.tab-bar-icon { + width: 24px; + height: 24px; + margin-bottom: 5px; +} + +.tab-bar-text { + margin-bottom: 10px; + font-size: 12px; + font-family: Arial, sans-serif; +} diff --git a/icons/back.png b/icons/back.png new file mode 100644 index 0000000..2620828 Binary files /dev/null and b/icons/back.png differ diff --git a/icons/file.png b/icons/file.png new file mode 100644 index 0000000..caf8fad Binary files /dev/null and b/icons/file.png differ diff --git a/icons/folder.png b/icons/folder.png new file mode 100644 index 0000000..e589b36 Binary files /dev/null and b/icons/folder.png differ diff --git a/icons/lw.png b/icons/lw.png new file mode 100644 index 0000000..91b9634 Binary files /dev/null and b/icons/lw.png differ diff --git a/images/1.jpg b/images/1.jpg new file mode 100644 index 0000000..8264985 Binary files /dev/null and b/images/1.jpg differ diff --git a/images/1.png b/images/1.png new file mode 100644 index 0000000..f6baa36 Binary files /dev/null and b/images/1.png differ diff --git a/images/2.jpg b/images/2.jpg new file mode 100644 index 0000000..a97e61c Binary files /dev/null and b/images/2.jpg differ diff --git a/images/2.png b/images/2.png new file mode 100644 index 0000000..80298a2 Binary files /dev/null and b/images/2.png differ diff --git a/images/3.jpg b/images/3.jpg new file mode 100644 index 0000000..a7aee99 Binary files /dev/null and b/images/3.jpg differ diff --git a/images/4.jpg b/images/4.jpg new file mode 100644 index 0000000..a60d7f1 Binary files /dev/null and b/images/4.jpg differ diff --git a/images/64dcf0661ce0234eaf713af1ebfecf1.jpg b/images/64dcf0661ce0234eaf713af1ebfecf1.jpg new file mode 100644 index 0000000..f4764c5 Binary files /dev/null and b/images/64dcf0661ce0234eaf713af1ebfecf1.jpg differ diff --git a/images/AI分析.png b/images/AI分析.png new file mode 100644 index 0000000..cef0015 Binary files /dev/null and b/images/AI分析.png differ diff --git a/images/AI分析点击.png b/images/AI分析点击.png new file mode 100644 index 0000000..e989b54 Binary files /dev/null and b/images/AI分析点击.png differ diff --git a/images/ChatGPT-copy.png b/images/ChatGPT-copy.png new file mode 100644 index 0000000..b772307 Binary files /dev/null and b/images/ChatGPT-copy.png differ diff --git a/images/Likee.png b/images/Likee.png new file mode 100644 index 0000000..cde69ac Binary files /dev/null and b/images/Likee.png differ diff --git a/images/Runwayml.png b/images/Runwayml.png new file mode 100644 index 0000000..b7815ff Binary files /dev/null and b/images/Runwayml.png differ diff --git a/images/Twitter.jpg b/images/Twitter.jpg new file mode 100644 index 0000000..a07efb6 Binary files /dev/null and b/images/Twitter.jpg differ diff --git a/images/VIP.png b/images/VIP.png new file mode 100644 index 0000000..7626976 Binary files /dev/null and b/images/VIP.png differ diff --git a/images/YouTube.jpg b/images/YouTube.jpg new file mode 100644 index 0000000..11b303a Binary files /dev/null and b/images/YouTube.jpg differ diff --git a/images/aws.png b/images/aws.png new file mode 100644 index 0000000..3992953 Binary files /dev/null and b/images/aws.png differ diff --git a/images/butterfly-icon.png b/images/butterfly-icon.png new file mode 100644 index 0000000..2945072 Binary files /dev/null and b/images/butterfly-icon.png differ diff --git a/images/delete.png b/images/delete.png new file mode 100644 index 0000000..9eb6af5 Binary files /dev/null and b/images/delete.png differ diff --git a/images/dianshu.png b/images/dianshu.png new file mode 100644 index 0000000..45bcfdc Binary files /dev/null and b/images/dianshu.png differ diff --git a/images/f.png b/images/f.png new file mode 100644 index 0000000..e8c7224 Binary files /dev/null and b/images/f.png differ diff --git a/images/header.jpg b/images/header.jpg new file mode 100644 index 0000000..95bd31c Binary files /dev/null and b/images/header.jpg differ diff --git a/images/huiyuan.png b/images/huiyuan.png new file mode 100644 index 0000000..648ea2c Binary files /dev/null and b/images/huiyuan.png differ diff --git a/images/icon-clear-active.png b/images/icon-clear-active.png new file mode 100644 index 0000000..4d8e34b Binary files /dev/null and b/images/icon-clear-active.png differ diff --git a/images/icon-clear.png b/images/icon-clear.png new file mode 100644 index 0000000..6aa9ea8 Binary files /dev/null and b/images/icon-clear.png differ diff --git a/images/icon-faq.png b/images/icon-faq.png new file mode 100644 index 0000000..260af68 Binary files /dev/null and b/images/icon-faq.png differ diff --git a/images/icon-home-selected.png b/images/icon-home-selected.png new file mode 100644 index 0000000..56ca649 Binary files /dev/null and b/images/icon-home-selected.png differ diff --git a/images/icon-home.png b/images/icon-home.png new file mode 100644 index 0000000..0d60ff3 Binary files /dev/null and b/images/icon-home.png differ diff --git a/images/icon-lock.png b/images/icon-lock.png new file mode 100644 index 0000000..475d944 Binary files /dev/null and b/images/icon-lock.png differ diff --git a/images/icon-me-selected.png b/images/icon-me-selected.png new file mode 100644 index 0000000..3b93fa9 Binary files /dev/null and b/images/icon-me-selected.png differ diff --git a/images/icon-me.png b/images/icon-me.png new file mode 100644 index 0000000..3a8bc65 Binary files /dev/null and b/images/icon-me.png differ diff --git a/images/icon-more.png b/images/icon-more.png new file mode 100644 index 0000000..da26641 Binary files /dev/null and b/images/icon-more.png differ diff --git a/images/icon-set.png b/images/icon-set.png new file mode 100644 index 0000000..f3a4aca Binary files /dev/null and b/images/icon-set.png differ diff --git a/images/icon-upload.png b/images/icon-upload.png new file mode 100644 index 0000000..58933fe Binary files /dev/null and b/images/icon-upload.png differ diff --git a/images/index.jpg b/images/index.jpg new file mode 100644 index 0000000..7afaf74 Binary files /dev/null and b/images/index.jpg differ diff --git a/images/index.png b/images/index.png new file mode 100644 index 0000000..694d537 Binary files /dev/null and b/images/index.png differ diff --git a/images/indexs.png b/images/indexs.png new file mode 100644 index 0000000..58e71b4 Binary files /dev/null and b/images/indexs.png differ diff --git a/images/instagram.png b/images/instagram.png new file mode 100644 index 0000000..2a97b39 Binary files /dev/null and b/images/instagram.png differ diff --git a/images/link_icon.png b/images/link_icon.png new file mode 100644 index 0000000..ed2241a Binary files /dev/null and b/images/link_icon.png differ diff --git a/images/loading.png b/images/loading.png new file mode 100644 index 0000000..9c73d4c Binary files /dev/null and b/images/loading.png differ diff --git a/images/logo-365yg.png b/images/logo-365yg.png new file mode 100644 index 0000000..5847c4d Binary files /dev/null and b/images/logo-365yg.png differ diff --git a/images/logo-douyin.png b/images/logo-douyin.png new file mode 100644 index 0000000..58c2edc Binary files /dev/null and b/images/logo-douyin.png differ diff --git a/images/logo-gitShow.png b/images/logo-gitShow.png new file mode 100644 index 0000000..9261269 Binary files /dev/null and b/images/logo-gitShow.png differ diff --git a/images/logo-meipai.png b/images/logo-meipai.png new file mode 100644 index 0000000..1eff4bb Binary files /dev/null and b/images/logo-meipai.png differ diff --git a/images/logo-miaopai.png b/images/logo-miaopai.png new file mode 100644 index 0000000..1419cca Binary files /dev/null and b/images/logo-miaopai.png differ diff --git a/images/logo-microview.png b/images/logo-microview.png new file mode 100644 index 0000000..55fc67e Binary files /dev/null and b/images/logo-microview.png differ diff --git a/images/me-bg.jpg b/images/me-bg.jpg new file mode 100644 index 0000000..87f42ee Binary files /dev/null and b/images/me-bg.jpg differ diff --git a/images/my.png b/images/my.png new file mode 100644 index 0000000..316e87b Binary files /dev/null and b/images/my.png differ diff --git a/images/mys.png b/images/mys.png new file mode 100644 index 0000000..aa87177 Binary files /dev/null and b/images/mys.png differ diff --git a/images/radar.png b/images/radar.png new file mode 100644 index 0000000..c47dc0c Binary files /dev/null and b/images/radar.png differ diff --git a/images/share.jpg b/images/share.jpg new file mode 100644 index 0000000..0261518 Binary files /dev/null and b/images/share.jpg differ diff --git a/images/submit_success.png b/images/submit_success.png new file mode 100644 index 0000000..6502407 Binary files /dev/null and b/images/submit_success.png differ diff --git a/images/t.jpg b/images/t.jpg new file mode 100644 index 0000000..5da6a17 Binary files /dev/null and b/images/t.jpg differ diff --git a/images/t.png b/images/t.png new file mode 100644 index 0000000..894405d Binary files /dev/null and b/images/t.png differ diff --git a/images/tiktok-logo.png b/images/tiktok-logo.png new file mode 100644 index 0000000..0ec0f02 Binary files /dev/null and b/images/tiktok-logo.png differ diff --git a/images/tiktok.png b/images/tiktok.png new file mode 100644 index 0000000..6942d60 Binary files /dev/null and b/images/tiktok.png differ diff --git a/images/timg.png b/images/timg.png new file mode 100644 index 0000000..2da06fd Binary files /dev/null and b/images/timg.png differ diff --git a/images/upload.png b/images/upload.png new file mode 100644 index 0000000..a9bc283 Binary files /dev/null and b/images/upload.png differ diff --git a/images/upload_icon.png b/images/upload_icon.png new file mode 100644 index 0000000..a202692 Binary files /dev/null and b/images/upload_icon.png differ diff --git a/images/y.png b/images/y.png new file mode 100644 index 0000000..ed0beee Binary files /dev/null and b/images/y.png differ diff --git a/images/youtube.png b/images/youtube.png new file mode 100644 index 0000000..25bff0d Binary files /dev/null and b/images/youtube.png differ diff --git a/images/主页.png b/images/主页.png new file mode 100644 index 0000000..df9074f Binary files /dev/null and b/images/主页.png differ diff --git a/images/主页点击.png b/images/主页点击.png new file mode 100644 index 0000000..5694e8b Binary files /dev/null and b/images/主页点击.png differ diff --git a/images/二维码.png b/images/二维码.png new file mode 100644 index 0000000..9ff6151 Binary files /dev/null and b/images/二维码.png differ diff --git a/images/人工智能机器人.png b/images/人工智能机器人.png new file mode 100644 index 0000000..71b7e62 Binary files /dev/null and b/images/人工智能机器人.png differ diff --git a/images/人民币.png b/images/人民币.png new file mode 100644 index 0000000..42a8ccc Binary files /dev/null and b/images/人民币.png differ diff --git a/images/代理商.png b/images/代理商.png new file mode 100644 index 0000000..1058193 Binary files /dev/null and b/images/代理商.png differ diff --git a/images/任务进程.png b/images/任务进程.png new file mode 100644 index 0000000..81a5dd6 Binary files /dev/null and b/images/任务进程.png differ diff --git a/images/会员、vip.png b/images/会员、vip.png new file mode 100644 index 0000000..f29362a Binary files /dev/null and b/images/会员、vip.png differ diff --git a/images/兑换码.png b/images/兑换码.png new file mode 100644 index 0000000..903541e Binary files /dev/null and b/images/兑换码.png differ diff --git a/images/公众号二维码.jpg b/images/公众号二维码.jpg new file mode 100644 index 0000000..edfa4b5 Binary files /dev/null and b/images/公众号二维码.jpg differ diff --git a/images/关闭.png b/images/关闭.png new file mode 100644 index 0000000..00738e4 Binary files /dev/null and b/images/关闭.png differ diff --git a/images/写作.png b/images/写作.png new file mode 100644 index 0000000..0ae6777 Binary files /dev/null and b/images/写作.png differ diff --git a/images/分享.png b/images/分享.png new file mode 100644 index 0000000..22c9907 Binary files /dev/null and b/images/分享.png differ diff --git a/images/分享2.png b/images/分享2.png new file mode 100644 index 0000000..2e566e9 Binary files /dev/null and b/images/分享2.png differ diff --git a/images/分支.png b/images/分支.png new file mode 100644 index 0000000..2758645 Binary files /dev/null and b/images/分支.png differ diff --git a/images/分类.png b/images/分类.png new file mode 100644 index 0000000..a0aaa9b Binary files /dev/null and b/images/分类.png differ diff --git a/images/切换角色.png b/images/切换角色.png new file mode 100644 index 0000000..6677be9 Binary files /dev/null and b/images/切换角色.png differ diff --git a/images/多素材.png b/images/多素材.png new file mode 100644 index 0000000..e0bdd06 Binary files /dev/null and b/images/多素材.png differ diff --git a/images/客服.png b/images/客服.png new file mode 100644 index 0000000..9bce0d0 Binary files /dev/null and b/images/客服.png differ diff --git a/images/客服二维码.jpg b/images/客服二维码.jpg new file mode 100644 index 0000000..5749047 Binary files /dev/null and b/images/客服二维码.jpg differ diff --git a/images/客服优先.png b/images/客服优先.png new file mode 100644 index 0000000..b18d8f8 Binary files /dev/null and b/images/客服优先.png differ diff --git a/images/帮助.png b/images/帮助.png new file mode 100644 index 0000000..369ecd3 Binary files /dev/null and b/images/帮助.png differ diff --git a/images/帮助2.png b/images/帮助2.png new file mode 100644 index 0000000..8de4066 Binary files /dev/null and b/images/帮助2.png differ diff --git a/images/平台.png b/images/平台.png new file mode 100644 index 0000000..13f5490 Binary files /dev/null and b/images/平台.png differ diff --git a/images/我的.png b/images/我的.png new file mode 100644 index 0000000..612aa72 Binary files /dev/null and b/images/我的.png differ diff --git a/images/我的点击.png b/images/我的点击.png new file mode 100644 index 0000000..44d206e Binary files /dev/null and b/images/我的点击.png differ diff --git a/images/手.png b/images/手.png new file mode 100644 index 0000000..f1356c4 Binary files /dev/null and b/images/手.png differ diff --git a/images/接口配置.png b/images/接口配置.png new file mode 100644 index 0000000..5844b54 Binary files /dev/null and b/images/接口配置.png differ diff --git a/images/搜索.png b/images/搜索.png new file mode 100644 index 0000000..cfe382b Binary files /dev/null and b/images/搜索.png differ diff --git a/images/文案库.png b/images/文案库.png new file mode 100644 index 0000000..c14f653 Binary files /dev/null and b/images/文案库.png differ diff --git a/images/文案库点击.png b/images/文案库点击.png new file mode 100644 index 0000000..4be2084 Binary files /dev/null and b/images/文案库点击.png differ diff --git a/images/文档.png b/images/文档.png new file mode 100644 index 0000000..dcc5c1a Binary files /dev/null and b/images/文档.png differ diff --git a/images/机器人二维码.jpg b/images/机器人二维码.jpg new file mode 100644 index 0000000..b740206 Binary files /dev/null and b/images/机器人二维码.jpg differ diff --git a/images/流转.png b/images/流转.png new file mode 100644 index 0000000..92c02fa Binary files /dev/null and b/images/流转.png differ diff --git a/images/用户.png b/images/用户.png new file mode 100644 index 0000000..e107dd4 Binary files /dev/null and b/images/用户.png differ diff --git a/images/真实可信.png b/images/真实可信.png new file mode 100644 index 0000000..3e2329f Binary files /dev/null and b/images/真实可信.png differ diff --git a/images/票据.png b/images/票据.png new file mode 100644 index 0000000..61592d5 Binary files /dev/null and b/images/票据.png differ diff --git a/images/积分.png b/images/积分.png new file mode 100644 index 0000000..915abb1 Binary files /dev/null and b/images/积分.png differ diff --git a/images/管理.png b/images/管理.png new file mode 100644 index 0000000..6f4aa44 Binary files /dev/null and b/images/管理.png differ diff --git a/images/网络.png b/images/网络.png new file mode 100644 index 0000000..48f3432 Binary files /dev/null and b/images/网络.png differ diff --git a/images/老师教师男人.png b/images/老师教师男人.png new file mode 100644 index 0000000..e1e14cf Binary files /dev/null and b/images/老师教师男人.png differ diff --git a/images/视频号.png b/images/视频号.png new file mode 100644 index 0000000..7a77ee3 Binary files /dev/null and b/images/视频号.png differ diff --git a/pages/agent/agent.js b/pages/agent/agent.js new file mode 100644 index 0000000..b9dfff7 --- /dev/null +++ b/pages/agent/agent.js @@ -0,0 +1,31 @@ +Page({ + data: {}, + onLoad: function(n) {}, + onReady: function() {}, + onShow: function() {}, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(n) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(n) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + } +}); \ No newline at end of file diff --git a/pages/agent/agent.json b/pages/agent/agent.json new file mode 100644 index 0000000..3928faa --- /dev/null +++ b/pages/agent/agent.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/agent/agent.wxml b/pages/agent/agent.wxml new file mode 100644 index 0000000..1928150 --- /dev/null +++ b/pages/agent/agent.wxml @@ -0,0 +1 @@ +pages/agent/agent.wxml diff --git a/pages/agent/agent.wxss b/pages/agent/agent.wxss new file mode 100644 index 0000000..e69de29 diff --git a/pages/aitools/aitools.js b/pages/aitools/aitools.js new file mode 100644 index 0000000..1f9cfaf --- /dev/null +++ b/pages/aitools/aitools.js @@ -0,0 +1,641 @@ +//index.js +const app = getApp() +import TextDecoder from '../../utils/miniprogram-text-decoder' +Page({ + data: { + currentTab: 'ToText', // 初始选择文生视频 + uploadedImage: '', + userInfo: {}, + videoUrl: '', + uuid: '', + inputValue: '', + charCount: 0, + picInputValue: '', + picCharCount: 0, + sizes: [{ + ratio: '1:1', + width: 1080, + height: 1080 + }, + { + ratio: '16:9', + width: 1920, + height: 1080 + }, + { + ratio: '9:16', + width: 1080, + height: 1920 + }, + { + ratio: '4:3', + width: 1440, + height: 1080 + }, + { + ratio: '3:4', + width: 1080, + height: 1440 + } + ], + selectedSize: '9:16', + selectedWidth: 1080, + selectedHeight: 1920, + styles: { + abandoned: '废弃', + abstract_sculpture: '抽象', + advertising: '广告', + anime: '动漫', + cine_lens: '电影镜头', + cinematic: '电影', + concept_art: '艺术', + forestpunk: '赛博朋克', + frost: '雪', + graphite: '石墨', + macro_photography: '宏观', + pixel_art: '像素艺术', + retro_photography: '复古', + sci_fi_art: '科幻', + thriller: '惊悚', + '35mm': '35mm', + vector: '矢量', + watercolor: '水彩' + }, + selectedStyle: '', + enhanceValue: 5, // 初始值设置为5 + picEnhanceValue: 5, + + ShowPicUrl: '', + tempImg: null, // 图片 + messages: {}, + messagesTemp: { + is_response: true, + content: '您好,我是智能AI助手,请问有什么可以帮助您的?' + }, + inputMessage: "", + toView: 'toBottom1', + showRoleDropdown: false, + currentRole: 9, // 默认角色 + currentRoleText: '选择角色', + roles: [] + + }, + + + // 文生视频提交 + textGenerateSubmit() { + if (this.data.inputValue === "") { + wx.showToast({ + title: '请输入视频描述', + icon: 'error' + }) + return + } + + let userId = wx.getStorageSync('userId') + const data = { + user_id: userId, + text_prompt: this.data.inputValue, + width: this.data.selectedWidth, + height: this.data.selectedHeight, + motion_score: this.data.enhanceValue, + style: this.data.selectedStyle + } + wx.showLoading({ + title: '任务提交中', + }) + app.apiRequest({ + url: "/myapp/generate_video/", + method: "POST", + data, + success: res => { + console.log('res', res); + if (res.data.success === false) { + wx.showModal({ + title: "文生视频", + content: "哎呀!创意点数不足, 请充值", + confirmColor: "#00B269", + cancelColor: "#858585", + success: function (e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }) + } else { + wx.navigateTo({ + url: '/pages/tips/tips', + }) + } + }, + fail: err => { + console.log('err', err); + }, + complete: () => { + wx.hideLoading() + } + }) + }, + // 图生视频提交 + async picGenerateSubmit() { + if (this.data.ShowPicUrl === "") { + wx.showToast({ + title: '请上传图片', + icon: 'error' + }) + return + } + if (this.data.picInputValue === "") { + wx.showToast({ + title: '请输入视频描述', + icon: 'error' + }) + return + } + + let imageUrl = '' + wx.showLoading({ + title: '任务提交中', + }) + try { + let res = await app.uploadFile(this.data.ShowPicUrl) + imageUrl = app.globalData.apiDomain + JSON.parse(res).file_url + } catch (error) { + console.log('error', error); + wx.hideLoading() + wx.showToast({ + title: '图片上传失败,请稍后重试~', + icon: 'error' + }); + return + } + let userId = wx.getStorageSync('userId') + const data = { + user_id: userId, + image_url: imageUrl, + text_prompt: this.data.picInputValue, + motion_score: this.data.picEnhanceValue + } + app.apiRequest({ + url: "/myapp/generate_image_video/", + method: "POST", + data, + success: res => { + console.log('res', res); + if (res.data.success === false) { + wx.showModal({ + title: "图生视频", + content: "哎呀!创意点数不足, 请充值", + confirmColor: "#00B269", + cancelColor: "#858585", + success: function (e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }) + } else { + wx.navigateTo({ + url: '/pages/tips/tips', + }) + + } + }, + fail: err => { + console.log('err', err); + }, + complete: () => { + wx.hideLoading() + } + }) + }, + // 点击上传图片 + uploadImage() { + let that = this + wx.chooseMedia({ + count: 1, + mediaType: ['image'], + sourceType: ['album'], + success(res) { + console.log(res) + let tempImg = res.tempFiles[0] + let pictureSize = tempImg.size + let ShowPicUrl = tempImg.tempFilePath + if (pictureSize > 1024 * 1024 * 10) { + wx.showToast({ + title: '图片大小不能超过10MB', + icon: 'error' + }) + return + } + that.setData({ + tempImg, + ShowPicUrl + }) + } + }) + }, + switchNav(e) { + const nav = e.currentTarget.dataset.nav; + console.log(nav) + this.setData({ + currentTab: nav + }); + }, + // 文生视频输入 + onInput(e) { + const value = e.detail.value; + this.setData({ + inputValue: value, + charCount: value.length + }); + }, + // 图生视频输入 + onPicInput(e) { + const value = e.detail.value; + this.setData({ + picInputValue: value, + picCharCount: value.length + }); + }, + optimizePrompt() { + // 优化提示词的逻辑 + console.log("优化提示词按钮被点击"); + // 可以在这里实现优化提示词的功能 + }, + // 文生视频运动增强 + onSliderChange(e) { + const value = e.detail.value; + this.setData({ + enhanceValue: value + }); + }, + // 图生视频运动增强 + onPicSliderChange(e) { + const value = e.detail.value; + this.setData({ + picEnhanceValue: value + }); + }, + selectStyle(e) { + const { + key + } = e.currentTarget.dataset; + this.setData({ + selectedStyle: key + }); + }, + selectSize(e) { + const { + ratio, + width, + height + } = e.currentTarget.dataset; + this.setData({ + selectedSize: ratio, + selectedWidth: width, + selectedHeight: height + }); + }, + onSliderChange(e) { + const value = e.detail.value; + this.setData({ + enhanceValue: value + }); + }, + onLoad: function (options) { + let uuid = options.uuid || '' + this.setData({ + uuid: uuid + }) + wx.showShareMenu({ + withShareTicket: true, + menus: ['shareAppMessage', 'shareTimeline'] + }) + + // 获取角色列表 + this.getRoles() + // 获取聊天记录 + this.getChatRecords() + }, + // 获取角色列表 + getRoles() { + let that = this + wx.showLoading({ + title: '加载中', + }) + app.chatApiRequest({ + url: "/chat/getRoles", + method: "GET", + success: res => { + console.log('res', res) + this.setData({ + roles: res.data.roles, + currentRole: 9 // 默认9 AI助手 + }) + }, + fail: err => { + console.log('err', err) + }, + complete: () => { + + } + }) + }, + // 获取聊天记录 + getChatRecords() { + let that = this + let userId = wx.getStorageSync('userId') + let openId = wx.getStorageSync('openid') + wx.showLoading({ + title: '加载中', + }) + app.chatApiRequest({ + url: '/chat/getRecord', + method: 'POST', + data: { + nickname: userId, + openid: openId, + role_id: this.data.currentRole + }, + success: (res) => { + let messages = this.data.messages + messages[that.data.currentRole] = res.data.records + that.setData({ + messages + }) + that.scrollToBottom() + }, + fail: (err) => { + console.log('err', err) + }, + complete: () => { + wx.hideLoading() + } + }) + }, + bindInput(e) { + this.setData({ + inputMessage: e.detail.value + }); + }, + + // 滚动条置底 + scrollToBottom() { + this.setData({ + toView: this.data.toView === 'toBottom1' ? 'toBottom2' : 'toBottom1' + }); + }, + + // 发送 + sendMessage() { + let that = this + let inputMessage = this.data.inputMessage + if (inputMessage === '') { + wx.showToast({ + title: '请输入消息', + icon: 'none' + }) + return false + } + + let messages = that.data.messages + // 获取会话session_id + let sessionID + if (messages[this.data.currentRole].length !== 0) { + sessionID = messages[this.data.currentRole][messages[this.data.currentRole].length - 1].session_id + } + messages[this.data.currentRole].push({ + is_response: false, + message_content: inputMessage + }) + this.setData({ + inputMessage: '' + }) + + messages[this.data.currentRole].push({ + is_response: true, + message_content: '', + isGenerating: true + }) + that.setData({ + messages: messages, + }) + this.scrollToBottom() + let userId = wx.getStorageSync('userId') + let openid = wx.getStorageSync('openid') + let role = this.data.currentRole + + + let reqTask = app.chatApiRequest({ + url: '/chat/send', + method: 'POST', + enableChunked: true, + data: { + openid, + userid: userId, + prompt: inputMessage, + role_id: role, + session_id: sessionID + }, + success: (res) => { + // console.log('res', res) + }, + fail: (err) => { + console.log('err', err) + } + }) + let newMessages = this.data.messages + let currentMessages = newMessages[this.data.currentRole] + let lastMessages = currentMessages[currentMessages.length - 1] + reqTask.onChunkReceived(r => { + let decoder = new TextDecoder('utf-8'); + let str = decoder.decode(r.data); + let lines = str.split('\n\n') + lines.pop() + for (let i of lines) { + let jsonStr = i + if (i.startsWith("data:")) { + jsonStr = jsonStr.substring(5); + } + let messageObject = JSON.parse(jsonStr) + lastMessages.isGenerating = false + lastMessages.message_content += messageObject.output.text + lastMessages.session_id = messageObject.output.session_id + this.setData({ + messages: newMessages + }) + } + + that.scrollToBottom() + }) + }, + + utf8ArrayToStr(array) { + var out, i, len, c; + var char2, char3; + + out = ""; + len = array.length; + i = 0; + while (i < len) { + c = array[i++]; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxxxxxx + out += String.fromCharCode(c); + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + char2 = array[i++]; + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = array[i++]; + char3 = array[i++]; + out += String.fromCharCode(((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + break; + } + } + + return out; + }, + + + toggleRoleDropdown() { + this.setData({ + showRoleDropdown: !this.data.showRoleDropdown, + }); + }, + switchRole(event) { + const roleIndex = event.currentTarget.dataset.role; + this.setData({ + currentRole: this.data.roles[roleIndex].id, + currentRoleText: this.data.roles[roleIndex].name, + showRoleDropdown: false, + }); + this.getChatRecords() + // 在这里你可以根据需要添加更多逻辑,比如切换到不同的AI模型 + }, + + // 判断邀请用户 + sendReward_invitation: function (uuid) { + app.apiRequest({ + url: '/myapp/reward_invitation', // 后端接口URL + method: 'POST', + data: { + openid: wx.getStorageSync('openid'), + uuid: uuid, + }, + success(res) { + console.log(res); + if (res.data.success == true) { + wx.setStorageSync('defaultDailyFreeParseNum', wx.getStorageSync('defaultDailyFreeParseNum') + 10); + } + }, + fail(err) { + console.error(err); + // 错误处理 + } + }); + + }, + + + onShow() { + app.getCurrentTabbar(1, this); + app.checkUpdateVersion() + wx.showLoading() + app.getUserInfo().then(() => { + if (this.data.uuid != '' && wx.getStorageSync('openid') != '' && wx.getStorageSync('uuid') != this.data.uuid) { + this.sendReward_invitation(this.data.uuid); + } + }).catch(error => { + console.error('获取用户信息失败:', error); + }).finally(() => { + console.log('getUserInfo调用完成'); + }); + }, + + // 清空输入框 + inputClear: function () { + this.setData({ + videoUrl: '' + }) + }, + + copyContent(e) { + console.log(e) + const content = e.target.dataset.content; + wx.setClipboardData({ + data: content, + success() { + wx.showToast({ + title: '内容已复制', + icon: 'none', + }); + }, + fail(err) { + wx.showToast({ + title: '复制失败', + icon: 'none', + }); + console.error('复制失败', err); + } + }); + }, + + onShareAppMessage: function () { + return { + title: '推荐一款免费又超好用的AI视频文案创作工具,快来体验吧', + path: '/pages/index/index?uuid=' + wx.getStorageSync('uuid'), + imageUrl: '/images/index.jpg', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, + onShareTimeline: function () { + return { + title: '推荐一款免费又超好用的AI视频文案创作工具,快来体验吧', + path: '/pages/index/index?uuid=' + wx.getStorageSync('uuid'), + imageUrl: '/images/index.jpg', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, +}) \ No newline at end of file diff --git a/pages/aitools/aitools.json b/pages/aitools/aitools.json new file mode 100644 index 0000000..a5035cb --- /dev/null +++ b/pages/aitools/aitools.json @@ -0,0 +1,7 @@ +{ + "usingComponents": {}, + "navigationBarTitleText": "创作助手", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "custom-tab-bar": "/custom-tab-bar/index" +} \ No newline at end of file diff --git a/pages/aitools/aitools.wxml b/pages/aitools/aitools.wxml new file mode 100644 index 0000000..adc6cd6 --- /dev/null +++ b/pages/aitools/aitools.wxml @@ -0,0 +1,73 @@ + + + + + + {{charCount}}/320 + + + 选择风格: + + {{style}} + + + + 选择尺寸: + + {{item.ratio}} + + + + 运动增强: + + + 数值越高,视频画面越丰富 【文生视频消耗 10创意点/次】 + + + + + + + + + 点击上传图片 + + 只能上传jpg/png文件,且不超过10MB + + + + + {{picCharCount}}/320 + + + 运动增强: + + + 数值越高,视频画面越丰富 【图生视频消耗 10创意点/次】 + + + + + + + {{item.name}} + + + + + + + + {{item.message_content}} + + + + + + + + + + + diff --git a/pages/aitools/aitools.wxss b/pages/aitools/aitools.wxss new file mode 100644 index 0000000..1531aaa --- /dev/null +++ b/pages/aitools/aitools.wxss @@ -0,0 +1,414 @@ +.container,page { + background-color: #222238; +} + +.container { + border-top: 1px solid hsla(0,31%,87%,.5); + box-sizing: border-box; + color: #fff; + padding: 10px 10px 61px; +} + +.navbar { + background: linear-gradient(180deg,#8d72d2,#7183f3); + border-radius: 5px; + display: flex; + justify-content: space-between; + width: 300px; +} + +.nav-item { + color: #fff; + flex: 1; + padding: 5px 10px; + text-align: center; +} + +.nav-item.active { + background: linear-gradient(90deg,#6949bb,#4d65fd); + border-bottom: 3px solid #d9d4e4; + border-radius: 5px; +} + +.description-text { + color: #a790e2; + font-size: 12px; +} + +.input-container { + margin: 10px 0; + position: relative; + width: 100%; +} + +.input-box { + background-color: #333; + border: none; + color: #fff; + height: 150px; +} + +.char-count { + bottom: 10px; + color: #ccc; + position: absolute; + right: 10px; +} + +.optimize-button { + background: linear-gradient(90deg,#6949bb,#4d65fd); + border-radius: 5px; + bottom: 3px; + font-size: 13px; + left: 3px; + padding: 5px; + position: absolute; + text-align: center; + z-index: 9999; +} + +.platform-selector { + background-color: #333; + border-radius: 5px; + margin-bottom: 20px; + padding: 10px; +} + +.platform-text { + font-weight: 700; +} + +.platform-dropdown { + margin-top: 10px; +} + +.size-selector,.style-selector { + margin-bottom: 20px; + width: 100%; +} + +.size-text,.style-text { + font-weight: 700; + margin-bottom: 10px; +} + +.size-options,.style-options { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} + +.size-option,.style-option { + background-color: #333; + border-radius: 5px; + box-shadow: 1px 3px 3px 1px rgba(0,0,0,.3); + color: #fff; + flex: 1; + font-size: 13px; + margin-bottom: 10px; + margin-right: 10px; + padding: 10px; + text-align: center; + transition: all .3s; + white-space: nowrap; +} + +.size-option.active,.style-option.active { + background-color: #4a90e2; +} + +.size-option:last-child,.style-option:last-child { + margin-right: 0; +} + +.enhance-container { + align-items: center; + display: flex; + width: 100%; +} + +.enhance-text { + font-weight: 700; + margin-right: 10px; +} + +.enhance-slider { + flex: 1; +} + +.generate-button { + background: linear-gradient(90deg,#6949bb,#4d65fd); + border: none; + border-radius: 5px; + color: #fff; + margin: 10px auto; + padding: 5px; + text-align: center; + width: 150px; +} + +.full-container { + align-items: center; + display: flex; + flex-direction: column; + width: 100%; +} + +.upload-container { + background-color: #333; + border: 1px dashed #666; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0,0,0,.1); + cursor: pointer; + height: 250px; + margin-top: 15px; + max-width: 400px; + width: 100%; +} + +.upload-wrap { + align-items: center; + display: flex; + flex-direction: column; + height: 250px; + justify-content: center; +} + +.upload-pic { + height: 100%; + width: 100%; +} + +.upload-icon { + height: 50px; + margin-bottom: 10px; + width: 50px; +} + +.upload-text { + color: #999; + font-size: 14px; + margin-bottom: 5px; +} + +.upload-link { + color: #4a90e2; + text-decoration: underline; +} + +.upload-info { + color: #666; + font-size: 12px; +} + +.img-input-container { + margin-top: 10px; + max-width: 400px; + min-height: 200px; + position: relative; + width: 100%; +} + +.input-box { + border: 1px solid #ccc; + border-radius: 5px; + box-sizing: border-box; + font-size: 14px; + min-height: 200px; + padding: 10px; + resize: none; + width: 100%; +} + +.char-count { + color: #999; + font-size: 12px; + margin-top: 5px; + text-align: right; +} + +.chat-box { + + display: flex; + flex-direction: column; + height: calc(100vh - 127px); + margin-top: 10px; +} + +.chat-box,.role-switch { + position: relative; + width: 100%; +} + +.role-switch { + margin: 0 auto; + text-align: center; +} + +.role-button { + align-items: center; + background: linear-gradient(180deg,#2b2b49,#26263a); + border: none; + border-radius: 5px; + box-shadow: 0 4px 6px rgba(0,0,0,.3),0 1px 3px rgba(0,0,0,.08); + color: #fff; + cursor: pointer; + font-size: 16px; + width: 100%; +} + +.role-icon { + height: 16px; + margin-left: 5px; + vertical-align: middle; + width: 16px; +} + +.role-dropdown { + background: linear-gradient(180deg,#2b2b49,#26263a); + border-radius: 5px; + box-shadow: 0 4px 8px rgba(0,0,0,.3); + left: 50%; + margin-top: 5px; + position: absolute; + top: 100%; + transform: translateX(-50%); + z-index: 1000; +} + +.role-option { + border-bottom: 1px solid #b39494; + color: #fff; + cursor: pointer; + padding: 10px; +} + +.role-option:hover { + background: #444; +} + +.chat-window { + box-sizing: border-box; + flex: 1; + overflow-y: auto; + padding: 10px; +} + +.message { + display: flex; + margin-bottom: 10px; + margin-top: 10px; +} + +.message.user { + flex-direction: row-reverse; +} + +.message .avatar { + border-radius: 20px; + height: 40px; + margin: 0 3px; + width: 40px; +} + +.bubble { + border-radius: 10px; + box-shadow: 0 0 5px rgba(0,0,0,.5); + color: #d6d3dd; + max-width: 70%; + padding: 10px; +} + +.message.user .bubble { + background: #6949bb; + color: #fff; +} + +.message.ai .bubble { + background: #505579; + color: #fff; +} + +.username { + color: #888; + font-size: 12px; +} + +.content { + font-size: 14px; + margin-top: 5px; +} + +.input-area { + background-color: #222238; + box-sizing: border-box; + display: flex; + padding: 10px; + width: 100%; + height: 40px; +} + +.input-field { + border: 1px solid #ccc; + border-radius: 5px; + box-sizing: border-box; + flex: 1; + min-height: 40px; + padding: 8px; + +} + +.send-button { + background: linear-gradient(90deg,#6949bb,#4d65fd); + border: none; + border-radius: 5px; + box-sizing: border-box; + color: #fff; + font-size: 16px; + font-weight: 700; + height: 40px; + line-height: 40px; + margin-left: 10px; + padding: 0 20px; +} + +.buttom { + background-color: initial; + height: 60px; + width: 100%; +} + +.loading-container { + align-items: center; + display: flex; + height: 100vh; + justify-content: center; +} + +.loading-dot { + animation: pulse .8s infinite alternate; + background-color: #007bff; + border-radius: 50%; + height: 18px; + width: 18px; +} + +@-webkit-keyframes pulse { + 0% { + transform: scale(1); + } + + 100% { + transform: scale(1.4); + } +} + +@keyframes pulse { + 0% { + transform: scale(1); + } + + 100% { + transform: scale(1.4); + } +} \ No newline at end of file diff --git a/pages/bot-list/bot-list.js b/pages/bot-list/bot-list.js new file mode 100644 index 0000000..ef6041f --- /dev/null +++ b/pages/bot-list/bot-list.js @@ -0,0 +1,263 @@ +// pages/bot-list/bot-list.js +const app = getApp(); + +Page({ + data: { + botList: [], + statusText: { + normal: '状态正常', + abnormal: '状态异常', + full: '已满人' + }, + showQrModal: false, + selectedBot: null, + loading: true, + refreshing: false, + error: null, + refreshTimer: null, + lastUpdateTime: 0, + lastUpdateTimeText: '' + }, + + onLoad() { + this.loadBotData(); + this.startAutoRefresh(); + }, + + onUnload() { + this.clearAutoRefresh(); + }, + + startAutoRefresh() { + this.clearAutoRefresh(); + this.data.refreshTimer = setInterval(() => { + if (Date.now() - this.data.lastUpdateTime > 30000) { // 30秒自动刷新 + this.loadBotData(false); + } + this.updateTimeText(); + }, 1000); + }, + + clearAutoRefresh() { + if (this.data.refreshTimer) { + clearInterval(this.data.refreshTimer); + this.data.refreshTimer = null; + } + }, + + updateTimeText() { + const diff = Math.floor((Date.now() - this.data.lastUpdateTime) / 1000); + let text = ''; + if (diff < 60) { + text = `${diff}秒前更新`; + } else if (diff < 3600) { + text = `${Math.floor(diff / 60)}分钟前更新`; + } else { + text = `${Math.floor(diff / 3600)}小时前更新`; + } + this.setData({ lastUpdateTimeText: text }); + }, + + async onPullRefresh() { + this.setData({ refreshing: true }); + await this.loadBotData(false); + this.setData({ refreshing: false }); + }, + + loadBotData(showLoading = true) { + if (showLoading) { + this.setData({ loading: true, error: null }); + } + + return new Promise((resolve) => { + app.apiRequest({ + url: `/myapp/api/bots/`, + method: 'GET', + success: (res) => { + if (res.statusCode === 200 && res.data.success) { + this.handleDataSuccess(res.data); + } else { + this.handleDataError(res.data.error || '数据加载失败'); + } + }, + fail: (err) => { + this.handleDataError('网络请求失败'); + console.error('API请求失败:', err); + }, + complete: () => { + if (showLoading) { + this.setData({ loading: false }); + } + resolve(); + } + }); + }); + }, + + handleDataSuccess(response) { + const formattedData = response.data.map(bot => ({ + ...bot, + last_check: this.formatDateTime(bot.last_check), + selected: false + })); + + this.setData({ + botList: formattedData, + lastUpdateTime: Date.now(), + error: null + }); + this.updateTimeText(); + }, + + handleDataError(message) { + this.setData({ + error: message, + loading: false + }); + wx.showToast({ + title: message, + icon: 'none', + duration: 2000 + }); + }, + + formatDateTime(datetimeStr) { + if (!datetimeStr) return '暂无数据'; + try { + const date = new Date(datetimeStr); + return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; + } catch { + return datetimeStr; + } + }, + + selectBot(e) { + const bot = e.currentTarget.dataset.bot; + const botList = this.data.botList.map(item => ({ + ...item, + selected: item.wxid === bot.wxid + })); + this.setData({ botList }); + }, + + copyAccount(e) { + const account = e.currentTarget.dataset.account; + wx.setClipboardData({ + data: account, + success: () => { + wx.showToast({ + title: '微信号已复制', + icon: 'success' + }); + }, + fail: () => { + wx.showToast({ + title: '复制失败', + icon: 'none' + }); + } + }); + }, + + showQrcode(e) { + const index = e.currentTarget.dataset.index; + const selectedBot = this.data.botList[index]; + this.setData({ + showQrModal: true, + selectedBot + }); + }, + + closeQrcode() { + this.setData({ + showQrModal: false, + selectedBot: null, + botList: this.data.botList.map(bot => ({ + ...bot, + selected: false + })) + }); + }, + + preventBubble() { + // 防止点击内容区域关闭弹窗 + return; + }, + + saveQrcode() { + if (!this.data.selectedBot?.qrcode_url) { + wx.showToast({ + title: '二维码地址无效', + icon: 'none' + }); + return; + } + + wx.getSetting({ + success: (res) => { + if (!res.authSetting['scope.writePhotosAlbum']) { + wx.authorize({ + scope: 'scope.writePhotosAlbum', + success: () => this.doSaveImage(), + fail: () => this.showAuthGuide() + }); + } else { + this.doSaveImage(); + } + } + }); + }, + + doSaveImage() { + wx.showLoading({ title: '保存中...' }); + wx.downloadFile({ + url: this.data.selectedBot.qrcode_url, + success: (res) => { + wx.saveImageToPhotosAlbum({ + filePath: res.tempFilePath, + success: () => { + wx.hideLoading(); + wx.showToast({ + title: '已保存到相册', + icon: 'success' + }); + }, + fail: () => { + wx.hideLoading(); + wx.showToast({ + title: '保存失败', + icon: 'none' + }); + } + }); + }, + fail: () => { + wx.hideLoading(); + wx.showToast({ + title: '图片下载失败', + icon: 'none' + }); + } + }); + }, + + showAuthGuide() { + wx.showModal({ + title: '需要授权', + content: '请允许保存图片到相册,以便保存二维码', + confirmText: '去设置', + success: (res) => { + if (res.confirm) { + wx.openSetting(); + } + } + }); + }, + + handleImageError() { + wx.showToast({ + title: '二维码加载失败', + icon: 'none' + }); + } +}); \ No newline at end of file diff --git a/pages/bot-list/bot-list.json b/pages/bot-list/bot-list.json new file mode 100644 index 0000000..ef5e900 --- /dev/null +++ b/pages/bot-list/bot-list.json @@ -0,0 +1,6 @@ +{ + "navigationBarTitleText": "机器人监控", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white" + +} \ No newline at end of file diff --git a/pages/bot-list/bot-list.wxml b/pages/bot-list/bot-list.wxml new file mode 100644 index 0000000..ffab7df --- /dev/null +++ b/pages/bot-list/bot-list.wxml @@ -0,0 +1,86 @@ + + + + + + 下载蝴蝶号视频教程:\n1. 添加下方机器人\n2. 转发视频给机器人\n3. 自动回复下载链接 + + + + + + 机器人状态持续监控中... + {{lastUpdateTimeText}} + + + + + + 数据加载中... + + + + + {{error}} + + + + + + + + + + + {{statusText[item.status]}} + 最后检测: {{item.last_check}} + + + + + + + + + + + + + + {{selectedBot.account}} + × + + + + + + + + + + + \ No newline at end of file diff --git a/pages/bot-list/bot-list.wxss b/pages/bot-list/bot-list.wxss new file mode 100644 index 0000000..57b9483 --- /dev/null +++ b/pages/bot-list/bot-list.wxss @@ -0,0 +1,317 @@ +/* pages/bot-list/bot-list.wxss */ + +.container { + padding: 24rpx; + min-height: 100vh; + background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ed 100%); +} + +/* 功能介绍区域 */ +.guide-box { + background: white; + border-radius: 16rpx; + padding: 32rpx; + margin-bottom: 24rpx; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); + display: flex; + align-items: center; + animation: slideIn 0.5s ease-out; +} + +.guide-icon { + width: 80rpx; + height: 80rpx; + margin-right: 24rpx; +} + +.guide-text { + font-size: 28rpx; + color: #333; + line-height: 1.6; +} + +/* 状态监控动画 */ +.monitoring-box { + background: rgba(255, 255, 255, 0.9); + border-radius: 12rpx; + padding: 16rpx 24rpx; + display: flex; + align-items: center; + margin-bottom: 24rpx; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); +} + +.radar-icon { + width: 40rpx; + height: 40rpx; + margin-right: 16rpx; + animation: rotate 2s linear infinite; +} + +@keyframes rotate { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +/* 加载状态 */ +.loading-box { + display: flex; + flex-direction: column; + align-items: center; + padding: 48rpx 0; +} + +.loading-icon { + width: 80rpx; + height: 80rpx; + margin-bottom: 16rpx; + animation: pulse 1.5s ease-in-out infinite; +} + +@keyframes pulse { + 0% { transform: scale(0.95); } + 50% { transform: scale(1.05); } + 100% { transform: scale(0.95); } +} + +/* 错误状态 */ +.error-box { + text-align: center; + padding: 48rpx 24rpx; + color: #ff4d4f; +} + +.retry-btn { + margin-top: 24rpx; + background: #1890ff; + color: white; + border-radius: 8rpx; + font-size: 28rpx; + padding: 16rpx 32rpx; +} + +/* 机器人列表 */ +.bot-list { + max-height: calc(100vh - 300rpx); +} + +.bot-item { + background: white; + border-radius: 12rpx; + padding: 24rpx; + margin-bottom: 16rpx; + display: flex; + align-items: center; + transition: transform 0.2s ease; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); +} + +.bot-item:active { + transform: scale(0.98); +} + +.status-indicator { + width: 16rpx; + height: 16rpx; + border-radius: 50%; + margin-right: 16rpx; +} + +.status-indicator.normal { + background: #52c41a; + box-shadow: 0 0 12rpx rgba(82, 196, 26, 0.4); +} + +.status-indicator.abnormal { + background: #ff4d4f; + box-shadow: 0 0 12rpx rgba(255, 77, 79, 0.4); +} + +.status-indicator.full { + background: #faad14; + box-shadow: 0 0 12rpx rgba(250, 173, 20, 0.4); +} + +.bot-info { + flex: 1; +} + +.bot-account { + font-size: 32rpx; + font-weight: 500; + color: #333; + display: block; +} + +.bot-status { + font-size: 24rpx; + color: #666; + margin-top: 8rpx; + display: block; +} + +.bot-update { + font-size: 22rpx; + color: #999; + margin-top: 4rpx; + display: block; +} + +.action-buttons { + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.btn { + font-size: 24rpx; + padding: 12rpx 24rpx; + border-radius: 6rpx; + border: none; +} + +.copy-btn { + background: #e6f7ff; + color: #1890ff; +} + +.qrcode-btn { + background: #f6ffed; + color: #52c41a; +} + +/* 二维码弹窗 */ +/* pages/bot-list/bot-list.wxss */ +/* 添加或更新以下样式 */ + +.qr-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + z-index: 999; +} + +.qr-modal.show { + opacity: 1; + visibility: visible; +} + +.modal-container { + width: 90%; + background: white; + border-radius: 12rpx; + transform: translateY(50rpx); + opacity: 0; + transition: all 0.3s ease; +} + +.qr-modal.show .modal-container { + transform: translateY(0); + opacity: 1; +} + +.modal-header { + padding: 24rpx; + border-bottom: 1px solid #eee; + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-title { + font-size: 32rpx; + font-weight: 500; + color: #333; +} + +.close-btn { + width: 64rpx; + height: 64rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 40rpx; + color: #999; + cursor: pointer; +} + +.modal-content { + padding: 32rpx; + display: flex; + flex-direction: column; + align-items: center; +} + +.qrcode-image { + width: 100%; + height: auto; + max-width: 500rpx; + margin: 0 auto; +} + +.tip-text { + margin-top: 24rpx; + font-size: 26rpx; + color: #666; +} + +.modal-footer { + padding: 24rpx; + border-top: 1px solid #eee; + display: flex; + justify-content: center; +} + +.save-btn { + background: #07C160; + color: white; + font-size: 28rpx; + padding: 16rpx 48rpx; + border-radius: 8rpx; + border: none; + width: 80%; +} + +.save-btn:active { + opacity: 0.9; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(20rpx); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* 添加响应式设计 */ +@media screen and (max-width: 375px) { + .container { + padding: 16rpx; + } + + .bot-item { + padding: 16rpx; + } + + .action-buttons { + gap: 8rpx; + } + + .btn { + padding: 8rpx 16rpx; + font-size: 22rpx; + } +} \ No newline at end of file diff --git a/pages/business_cooperation/business_cooperation.js b/pages/business_cooperation/business_cooperation.js new file mode 100644 index 0000000..71184a3 --- /dev/null +++ b/pages/business_cooperation/business_cooperation.js @@ -0,0 +1,11 @@ +Page({ + data: {}, + onLoad: function(n) {}, + onReady: function() {}, + onShow: function() {}, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() {} +}); \ No newline at end of file diff --git a/pages/business_cooperation/business_cooperation.json b/pages/business_cooperation/business_cooperation.json new file mode 100644 index 0000000..ba98e8f --- /dev/null +++ b/pages/business_cooperation/business_cooperation.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "商业合作", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/business_cooperation/business_cooperation.wxml b/pages/business_cooperation/business_cooperation.wxml new file mode 100644 index 0000000..75dc565 --- /dev/null +++ b/pages/business_cooperation/business_cooperation.wxml @@ -0,0 +1 @@ + diff --git a/pages/business_cooperation/business_cooperation.wxss b/pages/business_cooperation/business_cooperation.wxss new file mode 100644 index 0000000..5dca70e --- /dev/null +++ b/pages/business_cooperation/business_cooperation.wxss @@ -0,0 +1,9 @@ +view { + margin: 0; + padding: 0; +} + +.qrcode { + height: 100vh; + width: 100%; +} \ No newline at end of file diff --git a/pages/details/details.js b/pages/details/details.js new file mode 100644 index 0000000..301d505 --- /dev/null +++ b/pages/details/details.js @@ -0,0 +1,245 @@ +var app = getApp(); + +Page({ + data: { + currentPath: '', // 当前路径 + breadcrumbPath: '', // 上一级路径 + currentItems: [], // 当前目录内容 + hasMore: false, // 是否有更多数据 + showQRPopup: false, // 控制二维码弹窗显示 + popupAnimation: {}, // 弹窗动画 + page: 1, // 当前页码 + pageSize: 20, // 每页大小 + isRoot: true, // 是否是根目录 + qrcodeUrl: 'https://file.guimiaokeji.com/%E5%B9%BF%E5%91%8A/C55BDC06151A606BDAEBCF787283874E.jpg', // 二维码图片链接 + }, + + onLoad() { + + wx.showShareMenu({ + withShareTicket: !0, + menus: [ "shareAppMessage", "shareTimeline" ] + }); + }, + showVip(){ + wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + }) + } + , + // 默认加载第一个目录 + loadDefaultDirectory() { + wx.showLoading({ title: '加载中...' }); + + app.apiRequest({ + url: '/api/courses/', + method: 'GET', + data: { + path: '/', // 根路径 + page_num: 1, + page_size: 1, // 仅获取第一个目录 + }, + success: (res) => { + if (res.data.status === 'success') { + const firstItem = res.data.data.files[0]; + + if (firstItem && firstItem.type === 1) { + // 如果第一个项目是目录,加载该目录 + this.loadDirectory(`/${firstItem.name}`); + } else { + wx.showToast({ title: '没有可用的目录', icon: 'none' }); + } + } else { + wx.showToast({ title: '获取数据失败', icon: 'none' }); + } + }, + fail: (err) => { + wx.showToast({ title: '加载失败,请重试', icon: 'none' }); + console.error(err); + }, + complete: () => wx.hideLoading(), + }); + }, + + // 加载指定目录内容 + loadDirectory(path, append = false) { + wx.showLoading({ title: '加载中...' }); + + // 确保路径不会出现多个斜杠 + const sanitizedPath = path.replace(/\/+/g, '/'); + + app.apiRequest({ + url: '/api/courses/', + method: 'GET', + data: { + path: sanitizedPath, + page_num: this.data.page, + page_size: this.data.pageSize, + }, + success: (res) => { + if (res.data.status === 'success') { + const newItems = res.data.data.files.map((item) => ({ + ...item, + path: `${sanitizedPath}/${item.name}`, + })); + + const paths = sanitizedPath.split('/').filter(Boolean); + const breadcrumbPath = paths.slice(0, -1).join('/') || '/'; + + this.setData({ + currentItems: append ? this.data.currentItems.concat(newItems) : newItems, + currentPath: sanitizedPath, + breadcrumbPath, + hasMore: newItems.length === this.data.pageSize, + isRoot: sanitizedPath === '/', // 根目录判断 + }); + } else { + wx.showToast({ title: '获取数据失败', icon: 'none' }); + } + }, + fail: (err) => { + wx.showToast({ title: '加载失败,请重试', icon: 'none' }); + console.error(err); + }, + complete: () => wx.hideLoading(), + }); + }, + + // 点击目录或文件 + handleItemClick(e) { + const { type, path } = e.currentTarget.dataset; + + if (type === 1) { // 目录 + this.setData({ page: 1 }); + this.loadDirectory(path); + } else if (type === 0) { // 文件 + this.setData({ + qrcodeUrl: this.data.qrcodeUrl, // 假设文件路径作为二维码图片链接 + }); + this.showQRCode(); + } + }, + + // 返回上级目录 + goToParent() { + const paths = this.data.currentPath.split('/').filter(Boolean); + paths.pop(); + const parentPath = '/' + paths.join('/'); + + this.setData({ page: 1 }); + this.loadDirectory(parentPath); + }, + + // 加载更多 + loadMore() { + if (!this.data.hasMore) return; + + this.setData({ page: this.data.page + 1 }); + this.loadDirectory(this.data.currentPath, true); + }, + + // 显示二维码弹窗 + showQRCode() { + this.setData({ showQRPopup: true }); + const animation = wx.createAnimation({ + duration: 300, + timingFunction: 'ease', + }); + animation.scale(1).opacity(1).step(); + this.setData({ popupAnimation: animation.export() }); + }, + + // 关闭二维码弹窗 + closeQRCode() { + const animation = wx.createAnimation({ + duration: 300, + timingFunction: 'ease', + }); + animation.scale(0.8).opacity(0).step(); + this.setData({ popupAnimation: animation.export() }); + + setTimeout(() => { + this.setData({ showQRPopup: false }); + }, 300); + }, + + // 防止点击弹窗内部关闭弹窗 + preventClose() { + // 空函数,阻止事件冒泡 + }, + + // 保存二维码到相册 + saveQRCode() { + const { qrcodeUrl } = this.data; + + wx.showLoading({ title: '正在保存...' }); + + wx.downloadFile({ + url: qrcodeUrl, + success: (res) => { + if (res.statusCode === 200) { + wx.saveImageToPhotosAlbum({ + filePath: res.tempFilePath, + success: () => { + wx.showToast({ title: '二维码已保存', icon: 'success' }); + }, + fail: (err) => { + wx.showToast({ title: '保存失败,请重试', icon: 'none' }); + console.error(err); + }, + }); + } + }, + fail: (err) => { + wx.showToast({ title: '下载失败,请重试', icon: 'none' }); + console.error(err); + }, + complete: () => wx.hideLoading(), + }); + }, + + + onShareAppMessage: function () { + return { + title: '分享给你一份全链路的自媒体课程,赶快来领取吧', + path: '/pages/details/details?uuid=' + wx.getStorageSync('uuid'), + imageUrl: 'https://file.guimiaokeji.com/kecheng.png', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, + onShareTimeline: function () { + return { + title: '分享给你一份全链路的自媒体课程,赶快来领取吧', + path: '/pages/details/details?uuid=' + wx.getStorageSync('uuid'), + imageUrl: 'https://file.guimiaokeji.com/kecheng.png', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, + +}); diff --git a/pages/details/details.json b/pages/details/details.json new file mode 100644 index 0000000..8e88ffa --- /dev/null +++ b/pages/details/details.json @@ -0,0 +1,9 @@ +{ + "usingComponents": { + "popup": "/popup/popup" + }, + "navigationBarTitleText": "创意启航站", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white" + +} \ No newline at end of file diff --git a/pages/details/details.wxml b/pages/details/details.wxml new file mode 100644 index 0000000..6ecd0f1 --- /dev/null +++ b/pages/details/details.wxml @@ -0,0 +1,39 @@ + + + + 📚 精品资源分享 + + - 🎁 价值上万的*学习资源*,让你轻松打造高质量作品 + - 🛠️ 实用*免费视频剪辑工具和AI创作资料*,提高创作效率 + - 💡 专业的*平台算法解析*和实战技巧,让你少走弯路 + - 🔔 现在仅需 ¥29 即可获得一份精品课程 + - 🩸 现在仅需 ¥599 即可获得代理资格,拥有创意站分销权限和所有课程分销和免费看 + + + + + + + + + + + + + + + + + + + + + + + 📱 长按保存二维码 + 扫一扫领取资料 + + + + + \ No newline at end of file diff --git a/pages/details/details.wxss b/pages/details/details.wxss new file mode 100644 index 0000000..af8d500 --- /dev/null +++ b/pages/details/details.wxss @@ -0,0 +1,208 @@ +/* 页面整体样式 */ +page { + background-color: #222238; + border-top: 1px solid hsla(0,31%,87%,.5); + font-size: 32rpx; + line-height: 1.6; +} +/* 页面整体样式 */ +.course-detail-container { + padding: 20rpx; + background-color: #1a1d3b; + color: #fff; +} + +/* 课程介绍 */ +.course-intro { + margin-bottom: 40rpx; +} + +.intro-title { + font-size: 36rpx; + font-weight: bold; + color: #ffcc00; + margin-bottom: 20rpx; + text-align: center; + margin: 0 auto; +} + +.intro-description { + font-size: 28rpx; + line-height: 1.6; + color: #ccc; +} + +/* 两张图片并排展示 */ +/* 整体背景 */ +.file-browser { + padding: 20rpx; + background-color: #1a1d3b; + color: #fff; + height: 100vh; + display: flex; + flex-direction: column; +} + +/* 头部:返回按钮和路径 */ +.header { + display: flex; + align-items: center; + margin-bottom: 20rpx; + background-color: #2a2e50; + padding: 10rpx; + border-radius: 10rpx; + box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2); +} + +.back-icon { + width: 40rpx; + height: 40rpx; + margin-right: 10rpx; +} + +.breadcrumb-path { + font-size: 28rpx; + color: #ccc; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; +} + +/* 文件和目录列表 */ +.file-list { + flex: 1; + display: flex; + flex-direction: column; + gap: 20rpx; + overflow-y: scroll; +} + +.file-list-root { + height: auto; /* 根目录时内容高度自适应 */ +} + +.file-card { + display: flex; + align-items: center; + padding: 20rpx; + background-color: #2a2e50; + border-radius: 10rpx; + border-bottom: 1px solid #fff; + box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2); + +} + +.file-icon { + width: 60rpx; + height: 60rpx; + margin-right: 20rpx; +} + +.file-info { + flex: 1; + display: flex; + flex-direction: column; + gap: 10rpx; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; /* 长文字处理 */ + max-width: 80%; /* 确保图标不被挤掉 */ +} + +.file-name { + font-size: 28rpx; + color: #fff; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; /* 长文字处理 */ + max-width: 80%; /* 确保图标不被挤掉 */ +} + +.file-updated { + font-size: 24rpx; + color: #aaa; +} + +.load-more { + text-align: center; + color: #aaa; + padding: 20rpx 0; + font-size: 13px; +} + + +/* 功能按钮两行布局 */ +.action-buttons { + display: flex; + flex-direction: column; + margin-bottom: 40rpx; +} + +.button-row { + display: flex; + justify-content: space-between; + margin-bottom: 20rpx; +} + +.action-btn { + width: 48%; + font-size: 28rpx; + padding: 20rpx 0; + color: #fff; + text-align: center; + border-radius: 10rpx; +} + +.green-btn { background-color: #28a745; } +.purple-btn { background-color: #6f42c1; } +.orange-btn { background-color: #fd7e14; } +.yellow-btn { background-color: #ffc107; } + +/* 弹窗样式 */ +.qrcode-popup-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.6); + z-index: 999; + display: flex; + justify-content: center; + align-items: center; +} + +.qrcode-popup { + background: rgba(255, 255, 255, 0.9); + padding: 40rpx; + border-radius: 20rpx; + text-align: center; + position: relative; + animation: fadeIn 0.3s ease-in-out; +} + +.close-icon { + position: absolute; + top: 20rpx; + right: 20rpx; + font-size: 36rpx; + color: #666; +} + +.qrcode-text { + font-size: 28rpx; + color: #333; + margin-bottom: 20rpx; +} + +.qrcode-text text { + display: block; +} + +.qrcode-img { + width: 500rpx; + height: 500rpx; + margin: 20rpx auto; + border-radius: 10rpx; +} diff --git a/pages/extract/extract.js b/pages/extract/extract.js new file mode 100644 index 0000000..1d06e81 --- /dev/null +++ b/pages/extract/extract.js @@ -0,0 +1,182 @@ +var util = require('../../utils/util.js'); // 确保你有这样一个文件 + +var e = getApp(); + +Page({ + data: { + text: "", + type: "", + wxid: "", + alias: "", + uuid: "", + openid: "" + }, + onLoad: function(e) { + wx.showShareMenu({ + withShareTicket: !0, + menus: [ "shareAppMessage", "shareTimeline" ] + }), this.setData({ + text: decodeURIComponent(e.text), + type: decodeURIComponent(e.type) || "", + wxid: decodeURIComponent(e.wxid) || "", + alias: decodeURIComponent(e.alias) || "" + }); + }, + copyText: function() { + wx.setClipboardData({ + success: function() { + wx.showToast({ + title: "复制成功", + duration: 1200 + }); + }, + data: this.data.text + }); + }, + onAdClick: function() { + e.广告(); + }, + rewriteText: function() { + if (console.log(wx.getStorageSync("defaultDailyFreeParseNum")), wx.getStorageSync("defaultDailyFreeParseNum") > 0 || wx.getStorageSync("isMember")) { + var t = this; + wx.showLoading({ + title: "ai改写中..." + }), e.apiRequest({ + url: "/myapp/rewrite_text/", + method: "POST", + data: { + text: this.data.text, + uuid: wx.getStorageSync("uuid"), + openid: wx.getStorageSync("openid"), + type: this.data.type || "", + wxid: this.data.wxid || "", + alias: this.data.alias || "" + }, + success: function(e) { + wx.hideLoading(), "success" === e.data.status ? ( + t.setData({ + text: e.data.rewritten_text + }), + wx.showToast({ + title: "改写完成", + icon: "success", + duration: 2e3 + }) + ) : "次数不足或不是会员" == e.data.error ? wx.showModal({ + title: "提示", + content: "已无体验次数,前往个人中心领取或开通会员", + confirmColor: "#00B269", + cancelColor: "#858585", + success: function(e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }) : wx.showToast({ + title: e.data.error, + icon: "none", + duration: 2e3 + }); + }, + fail: function(e) { + console.error("改写请求失败", e), wx.hideLoading(), wx.showToast({ + title: "请求出错", + icon: "none", + duration: 2e3 + }); + } + }); + } else wx.showToast({ + title: "免费次数已用完!", + icon: "none" + }), wx.showModal({ + title: "提示", + content: "已无体验次数,前往个人中心领取或开通会员", + confirmColor: "#00B269", + cancelColor: "#858585", + success: function(e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }); + }, + saveCopywriting: function() { + e.apiRequest({ + url: "/myapp/create_copywriting/", + method: "POST", + data: { + text_content: this.data.text, + uuid: wx.getStorageSync("uuid") || "", + openid: wx.getStorageSync("openid") || "", + source: this.data.type || "", + tag: this.data.wxid || "", + type: this.data.type || "", + wxid: this.data.wxid || "", + alias: this.data.alias || "" + }, + success: function(e) { + console.log(e); + }, + fail: function(e) { + console.error("请求失败:", e); + } + }); + }, + onReady: function() {}, + onShow: function() { + e.checkUpdateVersion(), wx.showLoading(), e.getUserInfo().then(function() { + console.log("获取用户开始"), console.log("获取用户结束"); + }).catch(function(e) { + console.error("获取用户信息失败:", e); + }).finally(function() { + console.log("getUserInfo调用完成"); + }); + }, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + }, + onShareTimeline: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + } +}); \ No newline at end of file diff --git a/pages/extract/extract.json b/pages/extract/extract.json new file mode 100644 index 0000000..ed54ac6 --- /dev/null +++ b/pages/extract/extract.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "文案提取", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/extract/extract.wxml b/pages/extract/extract.wxml new file mode 100644 index 0000000..95d1d38 --- /dev/null +++ b/pages/extract/extract.wxml @@ -0,0 +1,12 @@ + + + + + + + +文字不要超出2000字哦,否则改写失败 +版权归视频原作者和平台所有 + diff --git a/pages/extract/extract.wxss b/pages/extract/extract.wxss new file mode 100644 index 0000000..a66101c --- /dev/null +++ b/pages/extract/extract.wxss @@ -0,0 +1,63 @@ +page { + border-top: 1px solid hsla(0,31%,87%,.5); +} + +.container,page { + background-color: #222238; +} + +.container { + align-items: center; + display: flex; + flex-direction: column; + padding: 20px; +} + +.extracted-text { + background-color: #333; + border: 1px solid #333; + border-radius: 8px; + color: #fff; + font-size: 16px; + height: 300px; + margin-bottom: 20px; + padding: 10px; + width: 90%; +} + +.buttons-container { + display: flex; + justify-content: space-between; + width: 90%; +} + +.action-button { + border-radius: 25px; + flex: 1; + font-size: 18px; + font-weight: 700; + height: 50px; + line-height: 50px; + margin: 0 10px; +} + +.copy,.rewrite { + background: linear-gradient(90deg,#6949bb,#4052ca); + color: #fff; +} + +.center { + color: #f0f0f0; + font-size: 12px; + text-align: center; +} + +.advertisement { + margin: 5px 0; + width: 100%; + z-index: 9999; +} + +.advertisement image { + width: 100%; +} \ No newline at end of file diff --git a/pages/faq/faq.js b/pages/faq/faq.js new file mode 100644 index 0000000..cbc3298 --- /dev/null +++ b/pages/faq/faq.js @@ -0,0 +1,119 @@ +const n = getApp(); +Page({ + data: { + list: null + }, + onLoad: function() { + wx.showShareMenu({ + withShareTicket: true, + menus: ["shareAppMessage", "shareTimeline"] + }); + }, + saveImage: function(e) { + const n = e.currentTarget.dataset.url; + wx.showActionSheet({ + itemList: ["保存图片"], + success: function(e) { + if (e.tapIndex === 0) { + wx.downloadFile({ + url: n, + success: function(res) { + if (res.statusCode === 200) { + wx.saveImageToPhotosAlbum({ + filePath: res.tempFilePath, + success: function() { + wx.showToast({ + title: "保存成功", + icon: "success", + duration: 2000 + }); + }, + fail: function(err) { + console.log(err); + wx.showToast({ + title: "保存失败", + icon: "none", + duration: 2000 + }); + } + }); + } + }, + fail: function(err) { + console.log(err); + wx.showToast({ + title: "下载失败", + icon: "none", + duration: 2000 + }); + } + }); + } + }, + fail: function(err) { + console.log(err); + } + }); + }, + onShow: function() { + const e = this; + n.check_status() + .then(function(res) { + console.log("获取文章信息", res); + e.setData({ + list: res.data.data.list + }); + }) + .catch(function(err) { + console.error("获取文章信息失败:", err); + }) + .finally(function() { + console.log("check_status调用完成"); + }); + }, + onAdClick: function() { + n.广告(); + }, + onShareAppMessage: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function() { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2000 + }); + }, + fail: function() { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2000 + }); + } + }; + }, + onShareTimeline: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function() { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2000 + }); + }, + fail: function() { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2000 + }); + } + }; + } +}); diff --git a/pages/faq/faq.json b/pages/faq/faq.json new file mode 100644 index 0000000..9b3873b --- /dev/null +++ b/pages/faq/faq.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "使用教程", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/faq/faq.wxml b/pages/faq/faq.wxml new file mode 100644 index 0000000..efdba50 --- /dev/null +++ b/pages/faq/faq.wxml @@ -0,0 +1,19 @@ + + 帮助文档 + + 教程列表 + + {{item.title}} + + + + 联系我们 + + 【保存二维码扫码添加下载机器人】 + + + + + diff --git a/pages/faq/faq.wxss b/pages/faq/faq.wxss new file mode 100644 index 0000000..bc1819e --- /dev/null +++ b/pages/faq/faq.wxss @@ -0,0 +1,73 @@ +page { + background-color: #222238; + border-top: 1px solid hsla(0,31%,87%,.5); +} + +.container { + padding: 20rpx; +} + +.title { + color: #a790e2; + font-size: 36rpx; + font-weight: 700; + margin-bottom: 20rpx; + text-align: center; +} + +.section { + border-radius: 10rpx; + box-shadow: 0 4rpx 8rpx rgba(0,0,0,.1); + margin-bottom: 30rpx; + padding: 20rpx; + width: 100%; +} + +.section-title { + border-bottom: 2rpx solid hsla(0,31%,87%,.5); + color: #fff; + font-size: 30rpx; + font-weight: 700; + margin-bottom: 20rpx; + padding-bottom: 10rpx; +} + +.section-content { + padding-left: 20rpx; +} + +.article-link { + background-color: #333; + border-radius: 5rpx; + color: #fff; + display: block; + font-size: 28rpx; + margin-bottom: 20rpx; + padding: 10rpx; + transition: all .3s ease; +} + +.article-link:hover { + background-color: #e6f2ff; + box-shadow: 0 4rpx 8rpx rgba(0,0,0,.1); + color: #a790e2; +} + +.help,.user-qun { + margin-top: 20rpx; +} + +.user-qun { + border-radius: 10rpx; + box-shadow: 0 4rpx 8rpx rgba(0,0,0,.1); + width: 100%; +} +.advertisement { + margin: 5px 0; + width: 100%; + z-index: 9999; +} + +.advertisement image { + width: 100%; +} \ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..3e1ed99 --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,463 @@ +const app = getApp(); + +Page({ + data: { + mode: 'link', // 默认模式为链接提取 + videoUrl: '', // 视频链接 + uploadFilePath: '', // 上传文件路径 + uuid: '', // 页面参数 uuid + showPopup: false, // 弹窗显示状态 + popupType: '', // 弹窗类型 + popupContent: '', // 弹窗内容 + showMask: false, + records: [], + page: 1, + isLoading: false, + hasMore: true, + externalOpenid:'' + }, + + // 切换单选框模式 + switchMode(e) { + const selectedMode = e.currentTarget.dataset.value; // 获取当前点击的值 + console.log("选择的模式:", selectedMode); + this.setData({ + mode: selectedMode + }); + }, + + // 输入视频链接 + bindVideoInput(e) { + this.setData({ + videoUrl: e.detail.value // 更新输入的视频链接 + }); + }, + +//文案提取记录 + // 显示记录蒙版 + showRecordMask() { + this.setData({ showMask: true }); + console.log('显示记录蒙版') + this.loadRecords(); +}, + +// 隐藏蒙版 +hideMask() { + this.setData({ showMask: false }); +}, + +// 阻止冒泡 +preventDefault() { + return; +}, + +// 加载记录 +// 加载记录 +// 加载记录 +loadRecords() { + if (this.data.isLoading || !this.data.hasMore) return; + + this.setData({ isLoading: true }); + + app.apiRequest({ + url: '/myapp/get_transcription_records/', + method: "POST", + data: { + page: this.data.page, + uuid: wx.getStorageSync("uuid"), + openid: wx.getStorageSync("openid") + }, + success: (res) => { + console.log('原始数据:', res.data); + + if (!res.data || !res.data.records) { + console.error('返回数据格式错误'); + return; + } + + // 获取当前records + const currentRecords = this.data.records || []; + + // 处理新数据 + const newRecords = res.data.records.map(record => { + const formattedResult = this.removeTimestampAndMergeLines(record.result || ''); + return { + id: record.id, + video_url: record.video_url, + task_id: record.task_id, + status: record.status, + result: formattedResult, + preview: formattedResult.substring(0, 15) + '...', + created_at: this.formatTime(record.created_at) + }; + }); + + console.log('处理后的新数据:', newRecords); + + // 使用回调确保数据更新完成 + this.setData({ + records: currentRecords.concat(newRecords), + page: this.data.page + 1, + hasMore: res.data.has_more + }, () => { + console.log('更新后的完整数据:', this.data.records); + }); + }, + fail: (error) => { + console.error('请求失败:', error); + }, + complete: () => { + this.setData({ isLoading: false }); + } + }); +}, + +// 格式化时间显示 +formatTime(timestamp) { + const date = new Date(timestamp); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + return `${month}-${day} ${hours}:${minutes}`; +}, + +// 加载更多 +loadMore() { + this.loadRecords(); +}, + +// 跳转到文案页 +goToExtract(e) { + + const text = encodeURIComponent(this.data.records[e.currentTarget.dataset.text].result); + wx.navigateTo({ + url: `../extract/extract?text=${text}` + }); +}, + + + + + // 上传文件 + uploadFile() { + wx.showToast({ + title: "功能开发者,敬请期待", + icon: "none" + }); + }, + // 提取视频功能 + parseVideo() { + if (!this.data.videoUrl) { + wx.showToast({ + title: "请输入有效的视频链接", + icon: "none" + }); + return; + } + + wx.showLoading({ + title: "正在提取..." + }); + + app.apiRequest({ + url: "/myapp/video/", // 替换为实际后端接口 + method: "POST", + data: { + url: this.data.videoUrl, + uuid: wx.getStorageSync("uuid"), + openid: wx.getStorageSync("openid") + }, + success: (res) => { + console.log("视频提取结果:", res); + if (res.data.data.medias[0]) { + const media = res.data.data.medias[0]; + wx.navigateTo({ + url: `../video/video?url=${encodeURIComponent(media.resource_url)}&image=${encodeURIComponent(media.preview_url)}&preview=${encodeURIComponent(res.data.data.text)}&type=index&read_count=0` + }); + } else { + wx.showToast({ + title: "不支持此链接提交。", + icon: "none" + }); + } + }, + fail: (err) => { + console.error("视频解析失败:", err); + wx.showToast({ + title: "请求失败,请检查网络并稍后重试", + icon: "none" + }); + }, + complete: () => { + wx.hideLoading(); + } + }); + }, +// 提取文案功能 +extractText() { + if (this.data.mode === 'link') { + if (!this.data.videoUrl) { + wx.showToast({ + title: "请输入有效链接", + icon: "none" + }); + return; + } + + let openid = wx.getStorageSync('openid') || ''; + let uuid = wx.getStorageSync('uuid') || ''; + + wx.showLoading({ + title: '后台处理中', + }); + + var that = this; + app.apiRequest({ + url: '/myapp/video_to_text/', + method: 'POST', + header: { + 'content-type': 'application/json', + }, + data: { + url: this.data.videoUrl, + openid: openid, + uuid: uuid + }, + success(res) { + if (res.data.success === false) { + wx.showModal({ + title: "提取视频", + content: '哎呀!去开通会员不限次数使用哦', + confirmColor: "#00B269", + cancelColor: "#858585", + success: function(e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }); + wx.hideLoading(); + return; + } + + let data = res.data; + let taskId = (data?.Data?.TaskId) || data.task_id; + + if (data.result) { + wx.hideLoading(); + let text = that.removeTimestampAndMergeLines(data.result); + text = encodeURIComponent(text); + wx.navigateTo({ + url: `../extract/extract?text=${text}` + }); + } else if (taskId) { + that.search_result(taskId, openid, uuid, (result) => { + wx.hideLoading(); + if (result != 0) { + wx.showToast({ + title: '提取成功', + icon: 'success' + }); + + let text = that.removeTimestampAndMergeLines(result); + text = encodeURIComponent(text); + wx.navigateTo({ + url: `../extract/extract?text=${text}` + }); + } else { + wx.showToast({ + title: '异常', + icon: 'error' + }); + } + }); + } else { + wx.showToast({ + title: '发送文件失败', + icon: 'none' + }); + } + }, + fail(err) { + wx.hideLoading(); + wx.showToast({ + title: '网络异常', + icon: 'none' + }); + } + }); + } else if (this.data.mode === 'upload') { + wx.showToast({ + title: "功能开发中,敬请期待", + icon: "none" + }); + } +}, + +// 查询任务状态 +search_result: function(task_id, openid, uuid, handleResult) { + console.log('查询任务'); + const checkResult = (maxRetries) => { + const fetchTaskStatus = () => { + app.apiRequest({ + url: '/myapp/query_task/', + method: 'POST', + header: { + 'content-type': 'application/json', + }, + data: { + task_id: task_id, + openid: openid, + uuid: uuid + }, + success: function(res) { + const data = res.data; + if (data.result) { + handleResult(data.result); + } else if (maxRetries > 0) { + setTimeout(fetchTaskStatus, 3000); + maxRetries--; + } else { + wx.hideLoading(); + wx.showToast({ + title: '请稍后重试', + icon: 'error' + }); + handleResult(0); + console.log('已达到最大重试次数,停止查询。'); + } + }, + }); + }; + fetchTaskStatus(); + }; + + const maxRetries = 100; + checkResult(maxRetries); +}, +extractVideoFromVideoAccount() { + wx.navigateTo({ + url: `../bot-list/bot-list` +}); +}, +openDownloadRobot(){ + wx.navigateTo({ + url: `../bot-list/bot-list` +}); +}, +// 去掉时间戳并合并行 +removeTimestampAndMergeLines: function(textWithTimestamp) { + let txt = textWithTimestamp.replace(/\[.*\]/g, ""); + txt = txt.replace(/\s+/g, ""); + return txt; +}, + + // 页面加载时触发 + onLoad(options) { + console.log("页面参数:", options); + const uuid = options.uuid || ""; + this.setData({ + uuid: uuid + }); + + wx.showShareMenu({ + withShareTicket: true, + menus: ["shareAppMessage", "shareTimeline"] + }); + + const { externalOpenid, token } = options; + + if (!externalOpenid || !token) { + + return; + } + + // 获取新小程序用户的 openid + const newOpenid = wx.getStorageSync("openid"); // 假设登录状态中已存储 openid + if (!newOpenid) { + wx.showToast({ title: "获取新用户信息失败,请重新登录", icon: "none" }); + return; + } + + // 请求后端完成迁移 + app.apiRequest({ + url: "/myapp/migrate_member/", // 替换为后端迁移接口地址 + method: "POST", + data: { + old_openid: externalOpenid, + new_openid: newOpenid, // 新小程序 openid + token: token, // 加密的 token + }, + success: (res) => { + if (res.data.message === "会员迁移成功") { + this.setData({ migrationStatus: "迁移成功" }); + wx.showToast({ title: "迁移成功", icon: "success" }); + wx.switchTab({ url: "/pages/mine/mine" }); // 跳转到用户中心 + } else { + this.setData({ migrationStatus: "迁移失败" }); + wx.showToast({ title: res.data.error || "迁移失败", icon: "none" }); + } + }, + fail: (err) => { + console.error("迁移失败", err); + this.setData({ migrationStatus: "迁移失败" }); + wx.showToast({ title: "迁移失败,请稍后重试", icon: "none" }); + }, + }); + + + }, + + // 页面显示时触发 + onShow() { + app.getPopupConfig() + .then(() => { + const isEnabled = wx.getStorageSync('popupEnabled'); + const popupType = wx.getStorageSync('popupType'); + const popupContent = wx.getStorageSync('popupContent'); + + if (isEnabled) { + this.setData({ + showPopup: true, + popupType: popupType, + popupContent: popupContent + }); + } + }) + .catch((error) => { + console.error('获取弹窗配置失败:', error); + }); + }, + + // 清空输入框 + inputClear() { + this.setData({ + videoUrl: "" + }); + }, + + // 关闭弹窗 + closePopup() { + this.setData({ + showPopup: false + }); + }, + + // 分享逻辑 + onShareAppMessage() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: `/pages/index/index?uuid=${wx.getStorageSync("uuid")}`, + imageUrl: "/images/share.jpg" + }; + }, + + onShareTimeline() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: `/pages/index/index?uuid=${wx.getStorageSync("uuid")}`, + imageUrl: "/images/share.jpg" + }; + } +}); diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..bdc9a71 --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,9 @@ +{ + "usingComponents": { + "popup": "/popup/popup" + }, + "navigationBarTitleText": "快影下载", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white" + +} \ No newline at end of file diff --git a/pages/index/index.wxml b/pages/index/index.wxml new file mode 100644 index 0000000..a0fac64 --- /dev/null +++ b/pages/index/index.wxml @@ -0,0 +1,114 @@ + + + + 提取视频 + + + + + + + + ->视频号提取 + ->下载机器人 + + + + + + 视频转文案 + + + + + + + 粘贴链接提取 + + + + + 上传本地文件 + + + + + + + + + + + + + + + + + + + + + + + + + + + 文案提取记录 + + + + + + + + + 提取记录 + × + + + + + + + + {{index + 1}} + + {{item.preview}} + {{item.created_at}} + + + + {{item.status === 'completed' ? '完成' : '失败'}} + + + + + + + + + + + 加载中... + + + + + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss new file mode 100644 index 0000000..fd18d38 --- /dev/null +++ b/pages/index/index.wxss @@ -0,0 +1,358 @@ +/* 背景渐变和星星样式 */ +page { + background: linear-gradient(135deg, #1A1A1A 0%, #3A3A57 50%, #000C40 100%); + background-size: cover, 3px 3px; + background-repeat: no-repeat, repeat; + font-size: 32rpx; + line-height: 1.6; +} + +/* 容器样式 */ +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 20px; +} + +/* 卡片样式 */ +.video-extract { + width: 90%; + max-width: 400px; + background: linear-gradient(to bottom right, rgba(58, 85, 97, 0.2), rgba(56, 76, 165, 0.2), rgba(142, 98, 96, 0.2)); + backdrop-filter: blur(20px); + border-radius: 1rem; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + border: 1px solid rgba(255, 255, 255, 0.3); + padding: 20px; + margin-bottom: 20px; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} +.text-extract { + width: 90%; + max-width: 400px; + background: linear-gradient(to bottom right, rgba(105, 105, 105, 0.3), rgba(169, 169, 169, 0.3), rgba(192, 192, 192, 0.3)); /* 金属灰渐变 */ + backdrop-filter: blur(20px); + border-radius: 1rem; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + border: 1px solid rgba(255, 255, 255, 0.3); + padding: 20px; + margin-bottom: 20px; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} +.card:hover { + transform: translateY(-5px); + box-shadow: 0 12px 25px rgba(0, 0, 0, 0.3); +} +.bottom-actions { + display: flex; + justify-content: space-around; + margin-top: 20px; +} + +.bottom-button { + border-radius: 20px; + padding: 5px 20px; + font-size: 14px; + border: none; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 添加阴影,增强立体效果 */ + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.bottom-button:hover { + transform: translateY(-3px); /* 悬停时轻微上移 */ + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); /* 悬停时阴影加深 */ +} + +.bottom-button:first-child { + background-color: #4CAF50; /* 视频号提取按钮颜色:绿色 */ + color: white; +} + +.bottom-button:last-child { + background-color: #ecb35e; /* 下载机器人按钮颜色:橙色 */ + color: white; +} +/* 卡片标题 */ +.card-title { + font-size: 18px; + font-weight: bold; + color: rgb(255, 255, 255); + margin-bottom: 10px; + text-align: center; +} + +/* 卡片描述 */ +.card-description { + font-size: 14px; + color: rgb(201, 199, 199); + margin-bottom: 20px; + text-align: center; +} + +/* 输入框部分 */ +.input-section { + display: flex; + align-items: center; + border-radius: 8px; + padding: 10px; + border: solid .2px rgb(155, 150, 150); + margin-bottom: 15px; +} + +.input-icon { + width: 20px; + height: 20px; + margin-right: 10px; +} + +.input-field { + flex: 1; + border: none; + outline: none; + font-size: 14px; + background: none; + color: rgb(201, 199, 199); +} + +/* 上传按钮 */ +.upload-button { + flex: 1; + padding: 10px; + color: white; + font-size: 14px; + text-align: center; + border-radius: 8px; + +} + +/* 操作按钮 */ +.action-button { + width: 100%; + background: linear-gradient(90deg, #8d72d2, #7183f3); + border-radius: 1rem; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + color: white; + font-size: 16px; + font-weight: bold; + text-align: center; + border: none; + transition: background 0.3s ease, transform 0.3s ease; +} + +.action-button:hover { + background: linear-gradient(to bottom right, rgba(58, 85, 97, 0.8), rgba(56, 76, 165, 0.8), rgba(142, 98, 96, 0.8)); + transform: scale(1.02); +} +/* 单选按钮组样式 */ +.radio-buttons { + display: flex; + justify-content: space-around; + margin-bottom: 15px; +} + +/* 单个选项样式 */ +.radio-option { + display: flex; + align-items: center; + font-size: 14px; + color: rgb(201, 199, 199); + cursor: pointer; +} + +/* 圆圈样式 */ +.radio-circle { + width: 16px; + height: 16px; + border: 2px solid #ccc; + border-radius: 50%; + margin-right: 8px; + background-color: transparent; /* 默认空心 */ + transition: background-color 0.3s, border-color 0.3s; +} + +/* 选中状态 */ +.radio-circle.selected { + background-color: #5b8def; /* 圆圈变为实心 */ + border-color: #eeeeee; /* 边框颜色跟随实心颜色 */ +} + +.record-button-container { + width: 100%; + display: flex; + justify-content: center; + padding: 20rpx 0; + margin-top: 30rpx; +} + +.record-button { + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #4CAF50, #45a049); + padding: 20rpx 40rpx; + border-radius: 40rpx; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15); + transition: transform 0.2s ease; +} + +.record-button:active { + transform: scale(0.98); +} + +.record-icon { + width: 40rpx; + height: 40rpx; + margin-right: 10rpx; +} + +.record-text { + color: #ecf5f3; + font-size: 28rpx; + font-weight: 500; +} +/* 蒙版样式 */ +.record-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 999; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} +.record-num{ + color:rgb(192, 186, 180) +} +.record-mask.show { + opacity: 1; + visibility: visible; +} + +.record-content { + position: fixed; + bottom: -100%; + left: 0; + width: 100%; + height: 80vh; + background: #fff; + border-radius: 24rpx 24rpx 0 0; + transition: all 0.3s ease; +} + +.record-mask.show .record-content { + bottom: 0; +} + +/* 标题栏 */ +.record-header { + padding: 30rpx; + border-bottom: 1rpx solid #eee; + display: flex; + justify-content: space-between; + align-items: center; +} + +.close-btn { + font-size: 40rpx; + color: #999; + padding: 10rpx; +} + +/* 记录列表 */ +.record-list { + height: calc(80vh - 100rpx); +} + +.record-item { + padding: 30rpx; + border-bottom: 1rpx solid #f5f5f5; + display: flex; + justify-content: space-between; + align-items: center; + transition: background-color 0.2s ease; +} + +.record-item:active { + background-color: #f9f9f9; +} + +.record-item-left { + display: flex; + align-items: center; + flex: 1; +} + + +.record-info { + margin-left: 20rpx; + flex: 1; +} + + +.record-time { + font-size: 24rpx; + color: #999; + margin-top: 8rpx; + display: block; +} + +.record-status { + font-size: 24rpx; + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +.record-status.completed { + background: #e8f5e9; + color: #4caf50; +} + +.record-status.False { + background: #fcfeff; + color: #e97a92; +} + +/* 加载动画 */ +.loading { + padding: 30rpx; + text-align: center; + color: #999; + font-size: 24rpx; +} + +.loading-dots { + display: flex; + justify-content: center; + margin-bottom: 10rpx; +} + +.dot { + width: 12rpx; + height: 12rpx; + background: #999; + border-radius: 50%; + margin: 0 6rpx; + animation: dot-jump 1.2s infinite; +} + +.dot:nth-child(2) { + animation-delay: 0.2s; +} + +.dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes dot-jump { + 0%, 80%, 100% { + transform: translateY(0); + } + 40% { + transform: translateY(-10rpx); + } +} \ No newline at end of file diff --git a/pages/invite/invite.js b/pages/invite/invite.js new file mode 100644 index 0000000..71184a3 --- /dev/null +++ b/pages/invite/invite.js @@ -0,0 +1,11 @@ +Page({ + data: {}, + onLoad: function(n) {}, + onReady: function() {}, + onShow: function() {}, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() {} +}); \ No newline at end of file diff --git a/pages/invite/invite.json b/pages/invite/invite.json new file mode 100644 index 0000000..3928faa --- /dev/null +++ b/pages/invite/invite.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/invite/invite.wxml b/pages/invite/invite.wxml new file mode 100644 index 0000000..bc925f6 --- /dev/null +++ b/pages/invite/invite.wxml @@ -0,0 +1 @@ +pages/invite/invite.wxml diff --git a/pages/invite/invite.wxss b/pages/invite/invite.wxss new file mode 100644 index 0000000..e69de29 diff --git a/pages/invite_incentive/invite_incentive.js b/pages/invite_incentive/invite_incentive.js new file mode 100644 index 0000000..45234f1 --- /dev/null +++ b/pages/invite_incentive/invite_incentive.js @@ -0,0 +1,81 @@ +var e = getApp(); + +Page({ + data: { + inviteCount: 0, + rewardCount: 0, + countdown: "3天12时30分20秒", + number: 0, + uuid:wx.getStorageSync("uuid"), + }, + onLoad: function(e) { + wx.showShareMenu({ + withShareTicket: !0, + menus: [ "shareAppMessage", "shareTimeline" ] + }), console.log(1), this.startCountdown(); + }, + startCountdown: function() { + var e = this, n = 30422e4; + setTimeout(function t() { + var o = Math.floor(n / 864e5) + "天" + Math.floor(n % 864e5 / 36e5) + "时" + Math.floor(n % 36e5 / 6e4) + "分" + Math.floor(n % 6e4 / 1e3) + "秒"; + e.setData({ + countdown: o + }), (n -= 1e3) >= 0 ? setTimeout(t, 1e3) : e.setData({ + countdown: "活动已结束" + }); + }, 1e3); + }, + onReady: function() {}, + onShow: function() { + var n = this; + e.getUserInfo().then(function() { + console.log(wx.getStorageSync("invitees_count"), "人"), console.log(10 * wx.getStorageSync("invitees_count"), "次"), + n.setData({ + inviteCount: wx.getStorageSync("invitees_count"), + rewardCount: 10 * wx.getStorageSync("invitees_count"), + number: wx.getStorageSync("balance") + }); + }).catch(function(e) { + console.error("An error occurred:", e); + }); + }, + copyPath: function () { + const path = '/pages/index/index?uuid=' + this.data.uuid; + wx.setClipboardData({ + data: path, + success: function (res) { + wx.showToast({ + title: '复制成功', + icon: 'success', + duration: 1500 + }); + } + }); + }, + + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() { + return { + title: "推荐一款免费又超好用的AI视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + } +}); \ No newline at end of file diff --git a/pages/invite_incentive/invite_incentive.json b/pages/invite_incentive/invite_incentive.json new file mode 100644 index 0000000..1307557 --- /dev/null +++ b/pages/invite_incentive/invite_incentive.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "邀请奖励", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/invite_incentive/invite_incentive.wxml b/pages/invite_incentive/invite_incentive.wxml new file mode 100644 index 0000000..7c72701 --- /dev/null +++ b/pages/invite_incentive/invite_incentive.wxml @@ -0,0 +1,33 @@ + + + + 已邀请: + {{inviteCount}} 人 + + + 邀请奖励: + {{number}} 元 + + + + 邀请规则: + + 每邀请一个新用户使用小程序奖励, + 分享给好友使用即可获得奖励。 + 邀请的用户首次开通会员,您将获得80%返利。 + 后续续费,您将获得40%奖励。 + 提现门槛:100元。 + 禁止任何形式的作弊行为, + 如发现使用外挂等违规行为, + 将取消活动资格。 + 活动限时有效 + + + /pages/index/index?uuid={{uuid}} + + + + + + + \ No newline at end of file diff --git a/pages/invite_incentive/invite_incentive.wxss b/pages/invite_incentive/invite_incentive.wxss new file mode 100644 index 0000000..457e409 --- /dev/null +++ b/pages/invite_incentive/invite_incentive.wxss @@ -0,0 +1,126 @@ +.container { + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; + background-color: #f8f8f8; +} + +.section1 { + width: 90%; + max-width: 600px; + background-color: white; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-bottom: 20px; + display: flex; + justify-content: space-around; +} + +.item { + text-align: center; +} + +.title { + font-size: 14px; + color: #333; + margin-bottom: 5px; +} + +.count { + font-size: 18px; + font-weight: bold; + color: #007bff; +} + +.section2 { + width: 90%; + max-width: 600px; + background-color: white; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-bottom: 20px; +} + +.subtitle { + font-size: 16px; + font-weight: bold; + color: #333; + text-align: center; + +} + +.description { + margin-top: 15px; + font-size: 14px; + color: #666; + line-height: 1.6; + margin-bottom: 8px; +} + +.warning { + color: #d9534f; + margin-top: 5px; +} + +.countdown { + font-size: 14px; + color: #999; + text-align: center; + margin-top: 15px; +} + +.button-container { + width: 90%; + max-width: 600px; + display: flex; + justify-content: space-around; +} +.invite-path { + margin-top: 20px; + padding: 10px; + background-color: #f0f0f0; + border-radius: 5px; + display: flex; + align-items: center; +} + +.path-title { + font-size: 14px; + color: #333; + margin-right: 10px; +} + +.path-text { + font-size: 14px; + color: #007bff; + word-break: break-all; /* 长路径自动换行 */ +} +.reward-button { + width: 48%; + + margin: 10px; + border-radius: 25px; + font-size: 16px; + font-weight: 500; + color: white; /* 字体颜色改为白色 */ + border: none; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影更明显 */ + transition: transform 0.2s ease, box-shadow 0.2s ease; + text-align: center; +} + +.reward-button:active { + transform: translateY(2px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.reward-button1 { + background: linear-gradient(135deg, #4CAF50, #2E7D32); /* 深绿色渐变 */ +} + +.reward-button2 { + background: linear-gradient(135deg, #2196F3, #1976D2); /* 深蓝色渐变 */ +} \ No newline at end of file diff --git a/pages/mine/mine.js b/pages/mine/mine.js new file mode 100644 index 0000000..6c6943c --- /dev/null +++ b/pages/mine/mine.js @@ -0,0 +1,164 @@ +var util = require('../../utils/util.js'); // 确保你有这样一个文件 + + +var e = getApp(); + +Component({ + data: { + defaultDailyFreeParseNum: "--", + totalParseNum: "--", + userInfo: null, + hasUserInfo: !1, + uuid: null, + isVip: !1, + startTime: "--", + endTime: "--", + formattedEndTime: "" + }, + methods: { + onLoad: function() { + wx.showShareMenu({ + withShareTicket: !0, + menus: [ "shareAppMessage", "shareTimeline" ] + }); + }, + onShow: function() { + var t = this; + e.getCurrentTabbar(3, this), e.checkUpdateVersion(), console.log("执行用户.jsonShow"), + e.getUserInfo().then(function() { + console.log("获取用户信息开始"), console.log(wx.getStorageSync("defaultDailyFreeParseNum")), + t.setData({ + hasUserInfo: !0, + uuid: wx.getStorageSync("uuid"), + defaultDailyFreeParseNum: wx.getStorageSync("defaultDailyFreeParseNum"), + totalParseNum: wx.getStorageSync("totalParseNum"), + isVip: wx.getStorageSync("isMember"), + startTime: wx.getStorageSync("startTime"), + endTime: wx.getStorageSync("endTime") + }), t.formatEndTime(), console.log("获取用户信息结束"); + }).catch(function(e) { + console.error("获取用户信息失败:", e); + }).finally(function() { + console.log("getUserInfo调用完成"); + }); + }, + formatEndTime: function() { + var e = this.data.endTime; + // 将秒时间戳转换为毫秒时间戳 + var date = new Date(e * 1000); + + // 格式化为“YYYY年MM月DD日” + var year = date.getFullYear(); + var month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从 0 开始,需要 +1 + var day = String(date.getDate()).padStart(2, "0"); + + var formattedDate = `${year}-${month}-${day}`; + + // 更新到 data + this.setData({ + formattedEndTime: formattedDate + }); + + }, + getUserInfo: function(e) {}, + openvip: function(e) { + wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + }); + }, + opennum: function(e) { + wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + }); + }, + getTotalParseNum: function() { + this.setData({ + defaultDailyFreeParseNum: wx.getStorageSync("defaultDailyFreeParseNum") + }); + }, + showExchangeModal: function(t) { + var o = this; + wx.showLoading(), wx.showModal({ + title: "卡密兑换", + content: "", + editable: !0, + placeholderText: "输入卡密", + success: function(t) { + t.confirm ? (console.log("用户点击确定"), e.apiRequest({ + url: "/myapp/redeem_card/", + method: "POST", + data: { + openid: wx.getStorageSync("openid"), + uuid: wx.getStorageSync("uuid"), + card_code: t.content + }, + success: function(t) { + e.getUserInfo().then(function() { + o.getTotalParseNum(), console.log(wx.getStorageSync("defaultDailyFreeParseNum")); + }).catch(function(e) { + console.error("An error occurred:", e); + }), "success" == t.data.status ? wx.showToast({ + title: t.data.message, + icon: "success", + duration: 1e3 + }) : wx.showToast({ + title: t.data.error, + icon: "error", + duration: 1e3 + }), console.log("卡密兑换成功:", t.data); + }, + fail: function(e) { + wx.showToast({ + title: "请求网络失败", + icon: "none", + duration: 1e3 + }), console.error("卡密兑换失败:", e); + } + })) : t.cancel && (console.log("用户点击取消"), wx.hideLoading()); + } + }); + }, + onShareAppMessage: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + } + }, + onShareTimeline: function() { + return { + title: "推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用", + path: "/pages/index/index?uuid=" + wx.getStorageSync("uuid"), + imageUrl: "/images/share.jpg", + success: function(e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function(e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + }; + } +}); \ No newline at end of file diff --git a/pages/mine/mine.json b/pages/mine/mine.json new file mode 100644 index 0000000..ea4bd95 --- /dev/null +++ b/pages/mine/mine.json @@ -0,0 +1,8 @@ +{ + "navigationBarTitleText": "个人中心", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "custom-tab-bar": "/custom-tab-bar/index", + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/mine/mine.wxml b/pages/mine/mine.wxml new file mode 100644 index 0000000..c2bd938 --- /dev/null +++ b/pages/mine/mine.wxml @@ -0,0 +1,70 @@ + + + + + + + + + + + ID:{{uuid}} + + + + + + + {{defaultDailyFreeParseNum}} + + + 创意点 + + + + {{formattedEndTime}} + 开通会员 + + + 尊贵VIP + 您还不是会员 + + + + + + + + + + 开通会员 + + + + + 新人礼包 + + + + 卡密兑换 + + + + 分享奖励 + + + + + + 使用教程 + + + © 2024 创作者服务 + + diff --git a/pages/mine/mine.wxss b/pages/mine/mine.wxss new file mode 100644 index 0000000..d014b60 --- /dev/null +++ b/pages/mine/mine.wxss @@ -0,0 +1,248 @@ +page { + background: #f5f5f5; +} + +.cu-avatar { + align-items: center; + background-color: #ccc; + background-position: 50%; + background-size: cover; + color: var(--white); + display: inline-flex; + font-size: 1.5em; + font-variant: small-caps; + height: 64rpx; + justify-content: center; + text-align: center; + vertical-align: middle; + white-space: nowrap; + width: 64rpx; +} + +.cu-avatar,button { + margin: 0; + padding: 0; + position: relative; +} + +button { + -webkit-tap-highlight-color: transparent; + background-color: inherit; + border-radius: 0; + box-sizing: border-box; + color: inherit; + display: block; + font-size: inherit; + line-height: inherit; + overflow: hidden; + text-align: inherit; + text-decoration: none; +} + +button::after { + border: none; +} + +.center { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + padding-bottom: 61px; +} + +.center .blue-top { + background-color: #0b0c0c; + border-radius: 0 0 350rpx 350rpx/0 0 30rpx 30rpx; + height: 230rpx; + margin-bottom: 160rpx; + width: 750rpx; +} + +.center .blue-top .user-card { + background: linear-gradient(90deg,#8d72d2,#7183f3); + border-radius: 20rpx; + box-sizing: border-box; + height: 330rpx; + left: 50%; + position: absolute; + transform: translate(-50%,28rpx); + width: 686rpx; +} + +.center .blue-top .user-card .card-top { + border-bottom: 1px solid #eee; + box-sizing: border-box; + height: 190rpx; + position: relative; +} + +.center .blue-top .user-card .card-top .user-top { + position: absolute; + top: -26rpx; + width: 100%; +} + +.center .blue-top .user-card .card-top .user-top .user-vip { + height: 130rpx; + margin: 0 auto; + width: 130rpx; +} + +.center .blue-top .user-card .card-top .user-top .user-vip .user-pic { + background: #fff; + border-radius: 50%; + display: block; + height: 130rpx; + margin: 0 auto; + overflow: hidden; + width: 130rpx; +} + +.center .blue-top .user-card .card-top .user-top .user-board { + -webkit-box-pack: center; + -ms-flex-pack: center; + display: -ms-flexbox; + display: flex; + justify-content: center; + margin-top: 20rpx; + width: 100%; +} + +.center .blue-top .user-card .card-top .user-top .user-board .user-name { + color: #ccc; + font-size: 36rpx; + font-weight: 700; +} + +.center .blue-top .user-card .card-top .user-top .user-board .vip-icon { + display: block; + height: 44rpx; + margin-left: 17rpx; + margin-top: 2rpx; + width: 44rpx; +} + +.center .blue-top .user-card .card-bottom { + box-sizing: border-box; + display: -ms-flexbox; + display: flex; + height: 140rpx; + padding: 18rpx 0; + text-align: center; +} + +.center .blue-top .user-card .card-bottom .left { + border-right: 1px solid #eee; +} + +.center .blue-top .user-card .card-bottom .left,.center .blue-top .user-card .card-bottom .right { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-box-pack: center; + -ms-flex-pack: center; + display: -ms-flexbox; + display: flex; + flex-direction: column; + justify-content: center; + width: 50%; +} + +.center .blue-top .user-card .card-bottom .count { + color: #fff; + font-size: 36rpx; + font-weight: 700; + margin-bottom: 10rpx; +} + +.center .blue-top .user-card .card-bottom .count .num { + color: #fff; + display: inline; +} + +.center .blue-top .user-card .card-bottom .txt { + color: #fff; + font-size: 24rpx; +} + +.center-list { + -webkit-box-orient: vertical; + background-color: #fff; + border-radius: 20rpx; + display: -ms-flexbox; + display: flex; + flex-direction: column; + margin: 0 auto; + overflow: hidden; +} + +.center-list,.center-list-item { + -webkit-box-direction: normal; + width: 686rpx; +} + +.center-list-item { + -webkit-box-orient: horizontal; + border-bottom: 1px solid; + border-color: #eee; + box-sizing: border-box; + display: -webkit-box; + display: -ms-flexbox; + flex-direction: row; + height: 114rpx; + padding: 0rpx 32rpx; +} + +.center-list-item:last-child { + border-bottom: 0; +} + +.center-list-item .icon1 { + background-position: 50%; + background-repeat: no-repeat; + background-size: 50rpx 50rpx; + color: #00c8fd; + display: block; + margin-right: 18rpx; + width: 50rpx; +} + +.center-list-item .icon1,.list-text { + height: 114rpx; + line-height: 114rpx; + text-align: left; +} + +.list-text { + -webkit-box-flex: 1; + color: #1f1f1f; + flex: 1; + font-size: 28rpx; +} + +.icon2 { + color: #8a8a8a; + display: block; + height: 114rpx; + line-height: 114rpx; + text-align: right; + width: 40rpx; +} + +.relief { + color: #999; + font-size: 24rpx; + padding-top: 30rpx; + text-align: center; +} + +.center-list-item { + align-items: center; + display: flex; + justify-content: flex-start; +} + +.icon1 { + height: 30px; + margin-right: 10px; + width: 30px; +} \ No newline at end of file diff --git a/pages/payment/payment.js b/pages/payment/payment.js new file mode 100644 index 0000000..71184a3 --- /dev/null +++ b/pages/payment/payment.js @@ -0,0 +1,11 @@ +Page({ + data: {}, + onLoad: function(n) {}, + onReady: function() {}, + onShow: function() {}, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() {} +}); \ No newline at end of file diff --git a/pages/payment/payment.json b/pages/payment/payment.json new file mode 100644 index 0000000..3928faa --- /dev/null +++ b/pages/payment/payment.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/payment/payment.wxml b/pages/payment/payment.wxml new file mode 100644 index 0000000..76fbecc --- /dev/null +++ b/pages/payment/payment.wxml @@ -0,0 +1 @@ +pages/payment/payment.wxml diff --git a/pages/payment/payment.wxss b/pages/payment/payment.wxss new file mode 100644 index 0000000..e69de29 diff --git a/pages/users/users.js b/pages/users/users.js new file mode 100644 index 0000000..71184a3 --- /dev/null +++ b/pages/users/users.js @@ -0,0 +1,11 @@ +Page({ + data: {}, + onLoad: function(n) {}, + onReady: function() {}, + onShow: function() {}, + onHide: function() {}, + onUnload: function() {}, + onPullDownRefresh: function() {}, + onReachBottom: function() {}, + onShareAppMessage: function() {} +}); \ No newline at end of file diff --git a/pages/users/users.json b/pages/users/users.json new file mode 100644 index 0000000..3928faa --- /dev/null +++ b/pages/users/users.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/users/users.wxml b/pages/users/users.wxml new file mode 100644 index 0000000..274c842 --- /dev/null +++ b/pages/users/users.wxml @@ -0,0 +1 @@ +pages/users/users.wxml diff --git a/pages/users/users.wxss b/pages/users/users.wxss new file mode 100644 index 0000000..e69de29 diff --git a/pages/video/video.js b/pages/video/video.js new file mode 100644 index 0000000..3c27a0f --- /dev/null +++ b/pages/video/video.js @@ -0,0 +1,554 @@ +var util = require('../../utils/util.js'); // 确保你有这样一个文件 +var app = getApp(), + n = ''; +Page({ + data: { + dataUrl: '', + dataImage: '', + preview: '', + type: '', + wxid: '', + alias: '', + videoSize: 0, // 初始化视频大小为0 + totalLength: 0, + isExtracting: false, + read_count: 0, + + }, + onLoad: function (options) { + console.log(options) + this.setData({ + dataUrl: decodeURIComponent(options.url), // 视频链接 + dataImage: decodeURIComponent(options.image) || '', // 视频封面 + preview: decodeURIComponent(options.preview), // 视频标题 + type: decodeURIComponent(options.type) || '', // 设置type的值 + wxid: decodeURIComponent(options.wxid) || '', // 设置微信id + alias: decodeURIComponent(options.alias) || '', // 设置微信号 + read_count: decodeURIComponent(options.read_count) || 0, // 设置微信号 + }); + wx.showShareMenu({ + withShareTicket: true, + menus: ['shareAppMessage', 'shareTimeline'] + }) + + }, + onShow: function () { + + app.checkUpdateVersion() + // 页面显示前更新数据 + console.log('执行video.js onShow') + app.getPopupConfig() + .then(() => { + // 从本地缓存读取数据 + const isEnabled = wx.getStorageSync('popupEnabled'); + const popupType = wx.getStorageSync('popupType'); + const popupContent = wx.getStorageSync('popupContent'); + + if (isEnabled) { + this.setData({ + showPopup: true, + popupType: popupType, + popupContent: popupContent + }); + } + }) + .catch((error) => { + console.error('获取弹窗配置失败:', error); + }); + console.log(this.data.type) + app.getUserInfo().then(() => { + console.log('获取用户信息开始'); + console.log(wx.getStorageSync('defaultDailyFreeParseNum'), ) + // 判断type,并发送提取记录到后端 + if (this.data.type === 'weixin' & wx.getStorageSync('defaultDailyFreeParseNum') > 0) { + console.log('来源微信') + this.getVideoSize(decodeURIComponent(this.data.dataUrl)) + //更新次数 + } else { + this.getVideoSize(app.globalData.downloadPrefix + decodeURIComponent(this.data.dataUrl)) + } + console.log('获取用户信息结束'); + }).catch(error => { + console.error('获取用户信息失败:', error); + }).finally(() => { + console.log('getUserInfo调用完成'); + }); + wx.showToast({ + title: '提取成功', + icon: 'success', + duration: 1500, + }); + + }, + + updateExtractingStatus: function (status) { + console.log(status) + this.setData({ + isExtracting: status, + }); + }, + + + + getVideoSize: function (url) { + let that = this; + wx.request({ + url: url, + method: 'HEAD', // HEAD请求不会下载资源的body,只请求header信息 + success: function (res) { + if (res.statusCode === 200 && res.header['CONTENT-LENGTH'] || res.header['X-Content-Length']) { + let size = res.header['CONTENT-LENGTH'] || res.header['X-Content-Length']; + let sizeInMb = (size / (1024 * 1024)).toFixed(2); // 将大小转换为MB + that.setData({ + videoSize: sizeInMb, // 更新页面数据, + totalLength: size + }); + } + }, + fail: function (err) { + console.log('获取视频大小失败', err); + } + }); + }, + //复制 + copyUrl: async function () { + if (this.data.type == 'weixin') { + wx.showLoading({ + title: '正在请求复制...', + }); + if (!await this.CreditLimit()) return + } + wx.setClipboardData({ + data: this.data.dataUrl, + success: () => { + wx.showToast({ + title: '复制成功', + duration: 2200, + }); + }, + }); + }, + + // 扣除额度 + CreditLimit() { + return new Promise((resolve, reject) => { + app.apiRequest({ + url: '/myapp/increment-download-count/', + method: "POST", + data: { + uuid: wx.getStorageSync("uuid"), + openid: wx.getStorageSync("openid") + }, + success: function (e) { + console.log(e, !e.data.success) + if (e.data.success === false) { + wx.hideLoading() + wx.showModal({ + title: "提取视频", + content: '哎呀!去开通会员不限次数使用哦', + confirmColor: "#00B269", + cancelColor: "#858585", + success: function (e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }) + resolve(false) + } + resolve(true) + } + }) + }) + }, + onAdClick: function() { + app.广告(); +}, + //提取视频 + download: async function () { + wx.showLoading({ + title: '正在下载...', + }); + if (this.data.type == 'weixin') { + if (!await this.CreditLimit()) return + } + var t = this, + e = t.data.dataUrl; + if (t.data.type === 'index') { + e = app.globalData.downloadPrefix + t.data.dataUrl; // 通过nginx中转 + } else { + e = t.data.dataUrl; + } + // 开始实际的下载任务 + const downloadTask = wx.downloadFile({ + url: e, + success: function (o) { + wx.hideLoading(); + wx.saveVideoToPhotosAlbum({ + filePath: o.tempFilePath, + success: function (o) { + t.showToast('保存成功', 'success'); + setTimeout(function () { + wx.setClipboardData({ + data: '', + }); + t.goBack(); + }, 1000); + }, + fail: function (o) { + t.showToast('保存失败'); + } + }); + }, + fail: function (o) { + wx.hideLoading(); + t.showToast('下载失败'); + } + }); + + // 监听下载进度并计算百分比 + downloadTask.onProgressUpdate((o) => { + let percent = this.data.totalLength ? (o.totalBytesWritten / this.data.totalLength) * 100 : o.progress; + if (percent < 100) { + wx.showToast({ + title: `保存中 ${Math.round(percent)}%`, + mask: true, // 添加 mask 参数,保证覆盖式显示 + icon: 'loading' + }); + } else { + wx.hideLoading(); // 下载完成后隐藏加载提示 + } + }); + }, + + // showToast: function (title, icon = 'none') { + // wx.showToast({ + // title: title, + // icon: icon, + // duration: 2000 + // }); + // }, + + + + // 保存到相册 + postSave: function () { + + var that = this; + wx.getSetting({ + success(res) { + // 检查用户是否已授权小程序写入相册的权限 + if (res.authSetting['scope.writePhotosAlbum']) { + // 用户已授权,下载视频 + that.download(); + } else { + // 用户未授权,请求相册权限 + wx.authorize({ + scope: 'scope.writePhotosAlbum', + success() { + // 用户授权成功,下载视频 + that.download(); + }, + fail() { + // 用户拒绝授权,显示提示对话框引导用户开启权限 + wx.showModal({ + title: '提示', + content: '保存视频到相册需要您授权', + showCancel: false, + success(modalRes) { + if (modalRes.confirm) { + // 引导用户前往设置页面手动开启权限 + wx.openSetting({ + success(settingData) { + if (settingData.authSetting['scope.writePhotosAlbum']) { + // 用户在设置页面授权成功,下载视频 + that.download(); + } else { + // 用户最终未授权,可能需要展示一些提示信息 + wx.showToast({ + title: '授权失败,无法保存视频', + icon: 'none' + }); + } + } + }); + } + } + }); + } + }); + } + } + }); + + }, + + + performDownload: function () { + // 在这里实现下载视频并保存到相册的逻辑 + this.download(); + }, + + + removeTimestampAndMergeLines: function (textWithTimestamp) { + let txt = textWithTimestamp.replace(/\[.*\]/g, ""); // 去掉时间前缀 + console.log(txt); + txt = txt.replace(/\s+/g, ""); // 去掉换行、空格字符 + console.log(txt); + return txt; // 删除前后的空白字符并返回 + }, + + // 提取文案功能 + extractText: function () { + // if (this.data.videoSize > 300 || !this.data.videoSize) { + // wx.showToast({ + // title: '视频太大,无法提取', + // icon: 'none' + // }) + // return + // } + let openid = wx.getStorageSync('openid') || ''; + let uuid = wx.getStorageSync('uuid') || ''; + let type = this.data.type || ''; + let wxid = this.data.wxid || ''; + let alias = this.data.alias || ''; + let url = this.data.dataUrl; + console.log('文案提取:' + url); + wx.showLoading({ + title: '后台处理中', + }); + var that = this; + app.apiRequest({ + url: '/myapp/video_to_text/', // 后端接口URL,根据实际情况调整 + method: 'POST', + header: { + 'content-type': 'application/json', + }, + data: { + url: url, + openid: openid, + uuid: uuid, + type: type, + wxid: wxid, + alias: alias, + }, + success(res) { + if (res.data.success === false) { + wx.showModal({ + title: "提取视频", + content: '哎呀!去开通会员不限次数使用哦', + confirmColor: "#00B269", + cancelColor: "#858585", + success: function (e) { + e.confirm ? (console.log("确定"), wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + })) : e.cancel && console.log("取消"); + } + }) + wx.hideLoading() + return + } + let data = res.data; + let taskId = (data?.Data?.TaskId) || data.task_id; + if (data.result) { + wx.hideLoading(); + let text = that.removeTimestampAndMergeLines(data.result); + text = encodeURIComponent(text); + wx.navigateTo({ + url: "../extract/extract?text=" + text + "&type=" + type + "&wxid=" + wxid + "&alias=" + alias, + }); + + } else if (taskId) { + that.search_result(taskId, openid, uuid, type, wxid, alias, (result) => { + wx.hideLoading(); + console.log('处理查询结果:', result); + if (result != 0) { + wx.showToast({ + title: '提取成功', + icon: 'success' + }); + + let text = that.removeTimestampAndMergeLines(result); + text = encodeURIComponent(text); + wx.navigateTo({ + url: "../extract/extract?text=" + text + "&type=" + type + "&wxid=" + wxid + "&alias=" + alias, + }); + } else { + wx.showToast({ + title: '异常', + icon: 'error' + }); + } + }); + } else { + wx.showToast({ + title: '发送文件失败', + icon: 'none' + }); + } + }, + fail(err) { + wx.hideLoading(); + wx.showToast({ + title: '网络异常', + icon: 'none' + }); + } + }); + }, + + // 查询任务状态 + search_result: function (task_id, openid, uuid, type, wxid, alias, handleResult) { + console.log('查询任务'); + const checkResult = (maxRetries) => { + const fetchTaskStatus = () => { + app.apiRequest({ + url: '/myapp/query_task/', + method: 'POST', + header: { + 'content-type': 'application/json', + }, + data: { + task_id: task_id, + openid: openid, + uuid: uuid, + type: type, + wxid: wxid, + alias: alias, + }, + success: function (res) { + const data = res.data; + console.log('查询任务:', data) + if (data.result) { + handleResult(data.result); + } else if (maxRetries > 0) { + setTimeout(fetchTaskStatus, 3000); // 每3秒查询一次 + maxRetries--; + } else { + wx.hideLoading(); + wx.showToast({ + title: '请稍重试', + icon: 'error' + }); + handleResult(0); + console.log('已达到最大重试次数,停止查询。'); + } + }, + }); + }; + fetchTaskStatus(); // 启动任务状态查询 + }; + + const maxRetries = 100; + checkResult(maxRetries); + }, + + // 去掉时间戳并合并行 + removeTimestampAndMergeLines: function (textWithTimestamp) { + let txt = textWithTimestamp.replace(/\[.*\]/g, ""); // 去掉时间前缀 + console.log(txt); + txt = txt.replace(/\s+/g, ""); // 去掉换行、空格字符 + console.log(txt); + return txt; // 删除前后的空白字符并返回 + }, + + // 更新提取状态 + updateExtractingStatus: function (status) { + this.setData({ + extracting: status + }); + }, + onUnload: function () { + console.log('页面卸载'); + }, + goBack: function () { + wx.reLaunch({ + url: '/pages/index/index', + }); + }, + + showToast: function (title, icon = 'none', duration = 2000) { + wx.showToast({ + title: title, + icon: icon, + duration: duration + }); + }, + + + onShareAppMessage: function () { + return { + title: '推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用', + path: '/pages/index/index?uuid=' + wx.getStorageSync('uuid'), + imageUrl: '/images/1.png', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, + onShareTimeline: function () { + return { + title: '推荐一款免费又超好用的视频文案创作工具,分享给大家一起使用', + path: '/pages/index/index?uuid=' + wx.getStorageSync('uuid'), + imageUrl: '/images/1.png', + success: function (e) { + wx.showToast({ + title: "分享成功", + icon: "success", + duration: 2e3 + }); + }, + fail: function (e) { + wx.showToast({ + title: "分享失败", + icon: "none", + duration: 2e3 + }); + } + } + }, + + + // 发送提取记录到后端的方法 + sendExtractionRecordToBackend: function (e) { + const { + dataUrl, + dataImage, + preview, + wxid, + alias + } = this.data; + app.apiRequest({ + url: '/myapp/record_extraction/', // 后端接口URL + method: 'POST', + data: { + openid: wx.getStorageSync('openid'), + uuid: wx.getStorageSync('uuid'), + videoUrl: dataUrl, + videoTitle: preview, + wxid: wxid, + wechatAlias: alias, + type: e || 'weixin' + }, + success(res) { + console.log('提取记录发送成功', res); + // 可以在这里处理后端返回的响应 + }, + fail(err) { + console.error('提取记录发送失败', err); + // 错误处理 + } + }); + }, +}); \ No newline at end of file diff --git a/pages/video/video.json b/pages/video/video.json new file mode 100644 index 0000000..811289b --- /dev/null +++ b/pages/video/video.json @@ -0,0 +1,10 @@ +{ + "navigationBarTitleText": "视频提取浏览", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "custom-tab-bar": "/custom-tab-bar/index", + "usingComponents": { + "popup": "/popup/popup" + } +} \ No newline at end of file diff --git a/pages/video/video.wxml b/pages/video/video.wxml new file mode 100644 index 0000000..2ca4915 --- /dev/null +++ b/pages/video/video.wxml @@ -0,0 +1,28 @@ + + + + + 视频太大的建议复制地址到浏览器自行下载 + 保存失败的也复制链接到浏览器下载 + + + + + + + + + + 版权归视频原作者所有 + + + + diff --git a/pages/video/video.wxss b/pages/video/video.wxss new file mode 100644 index 0000000..32e0a2e --- /dev/null +++ b/pages/video/video.wxss @@ -0,0 +1,89 @@ +page { + background-color: #222238; + border-top: 1px solid hsla(0,31%,87%,.5); +} + +.wrap { + align-items: center; + flex-direction: column; +} + +.buttons-row,.wrap { + display: flex; +} + +.buttons-row { + justify-content: space-around; + margin-top: 20rpx; + width: 100%; +} + +.video-box { + display: block; + height: 700rpx; + margin: 40rpx auto; + width: 560rpx; +} + +.video-title { + word-wrap: break-word; + background-color: #333; + color: #a790e2; + height: 50px; + margin-top: 10px; + padding: 8px; + user-select: text; + white-space: pre-wrap; + width: 90%; +} + +.parsing { + background: linear-gradient(90deg,#6949bb,#4052ca); + box-shadow: 0 14rpx 28rpx rgba(51,122,255,.3); + color: #fff; + display: inline-block; + height: 88rpx; + line-height: 88rpx; + overflow: hidden; + text-align: center; + width: 320rpx; +} + +.copy-url,.extract-text { + background: linear-gradient(90deg,#6949bb,#4d65fd); +} + +.go-back { + background-color: #f8f8f8; + color: #fff; +} + +.video-title-textarea { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-radius: 5rpx; + color: #333; + display: block; + font-size: 20rpx; + height: 80rpx; + line-height: 1.5; + margin: 20rpx auto; + padding: 15rpx; + resize: none; + width: 90%; +} + +.read_count { + color: blue; + font-size: 1rem; +} + +.advertisement { + margin: 5px 0; + width: 100%; + z-index: 9999; +} + +.advertisement image { + width: 100%; +} \ No newline at end of file diff --git a/pages/video_list/video_list.js b/pages/video_list/video_list.js new file mode 100644 index 0000000..7047737 --- /dev/null +++ b/pages/video_list/video_list.js @@ -0,0 +1,328 @@ +const app = getApp(); + +Page({ + data: { + inputValue: '', // 输入框的内容 + detectResult: '', // 识别结果 + detectType: 'text', // 默认识别类型为文本 + maxLength: 20000, // 最大允许的字节数 + inputLength: 0, // 当前输入的字节数 + task_id: '', // 任务ID + detectButtonDisabled: false, // 文本检测按钮是否禁用 + modifyButtonDisabled: false // 智能修改按钮是否禁用 + }, + + onLoad: function(e) { + wx.showShareMenu({ + withShareTicket: true, + menus: ["shareAppMessage", "shareTimeline"] + }); + }, + + onShow: function() { + var t = this; + t.resetData() + app.getCurrentTabbar(2, this); + app.checkUpdateVersion(); + app.getUserInfo().then(() => { + console.log('获取用户信息完成'); + console.log(wx.getStorageSync('defaultDailyFreeParseNum')); + const rewrittenText = wx.getStorageSync('rewrittenText'); // 从缓存中获取存储的文案 + if (rewrittenText) { + this.setData({ + inputValue: rewrittenText // 设置到页面的数据中 + }); + wx.removeStorageSync('rewrittenText'); // 清除数据,避免下次重复加载 + wx.showToast({ + title: '点击开始检测按钮检测文本违规词。', + icon: 'none' + }); + } + + }).catch(error => { + console.error('获取用户信息失败:', error); + }).finally(() => { + console.log('getUserInfo调用完成'); + }); + }, + resetData: function() { + // 重置页面数据为默认值 + this.setData({ + inputValue: '', // 输入框的内容 + detectResult: '', // 识别结果 + detectType: 'text', // 默认识别类型为文本 + inputLength: 0, // 当前输入的字节数 + task_id: '', // 任务ID + detectButtonDisabled: false, // 文本检测按钮是否禁用 + modifyButtonDisabled: false // 智能修改按钮是否禁用 + }); + }, + // 切换识别类型 + switchDetectType(e) { + const detectType = e.currentTarget.dataset.type; + this.recordClick(detectType); + this.setData({ + detectType, + detectResult: '' // 切换时清空结果 + }); + + if (detectType === 'audio' || detectType === 'video') { + wx.showToast({ + title: '该功能正在开发中', + icon: 'none' + }); + } else { + wx.showToast({ + title: '切换到文本识别', + icon: 'none' + }); + } + }, + + // 文本识别函数 + detectText() { + const { inputValue, maxLength } = this.data; + const byteSize = this.getByteLength(inputValue); + + // 检查文本是否为空或长度过短 + if (!inputValue.trim() || this.getByteLength(inputValue) < 10) { + wx.showToast({ + title: '请输入有效的文本', + icon: 'none' + }); + return; + } + + // 超出字节长度检测 + if (byteSize > maxLength) { + wx.showToast({ + title: `内容不能超过 ${maxLength} 字节`, + icon: 'none' + }); + return; + } + + // 禁用检测按钮 + this.setData({ detectButtonDisabled: true }); + + wx.showLoading({ + title: '正在检测...', + }); + + // 调用后端审核接口 + app.apiRequest({ + url: '/myapp/text_review/', + method: 'POST', + data: { + text: inputValue, + openid: wx.getStorageSync('openid'), + nickname: wx.getStorageSync('uuid') + }, + success: (res) => { + wx.hideLoading(); + this.setData({ detectButtonDisabled: false }); // 启用检测按钮 + if (res.data.code === 200) { + // 审核成功 + this.setData({ + detectResult: res.data.data.result, + task_id: res.data.task_id + }); + console.log(res.data.data.result); + wx.showToast({ + title: '检测成功', + icon: 'success' + }); + if (res.data.data.result.conclusion === '不合规') { + wx.showModal({ + title: "提示", + content: "检测结果不合规,是否使用智能合规功能一键修改文案?", + confirmText: "一键修改", + cancelText: "取消", + success: (modalRes) => { + if (modalRes.confirm) { + this.modifyContent(); // 调用一键合规函数 + } + } + }); + } + } else if (res.data.code === 400 && res.data.message === '余额不足') { + // 积分不足,提示充值 + wx.showModal({ + title: "检测文本", + content: '创意点不足!', + confirmColor: "#00B269", + cancelColor: "#858585", + success: function(e) { + if (e.confirm) { + console.log("确定"); + wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + }); + } else { + console.log("取消"); + } + } + }); + } else { + // 其他失败情况 + wx.showToast({ + title: res.data.message || '检测失败,请稍后重试', + icon: 'none' + }); + } + }, + fail: (err) => { + wx.hideLoading(); + this.setData({ detectButtonDisabled: false }); // 启用检测按钮 + console.error('请求失败:', err); + wx.showToast({ + title: '网络异常,请稍后重试', + icon: 'none' + }); + } + }); + }, + + // 计算文本的字节长度(区分中英文) + getByteLength(text) { + return text.replace(/[^\x00-\xff]/g, 'aa').length; + }, + + // 处理输入框内容变化 + bindInput(e) { + const inputValue = e.detail.value; + const inputLength = this.getByteLength(inputValue); + + // 更新输入内容和字节长度 + this.setData({ + inputValue, + inputLength + }); + + // 如果字数超出最大限制,提示用户 + if (inputLength > this.data.maxLength) { + wx.showToast({ + title: `已超出 ${this.data.maxLength} 字节`, + icon: 'none' + }); + } + }, + + // 复制内容 + copyContent() { + wx.setClipboardData({ + data: this.data.inputValue, + success() { + wx.showToast({ + title: '内容已复制', + icon: 'none' + }); + } + }); + }, + + // 清空输入框内容 + clearInput() { + wx.showModal({ + title: "提示", + content: "确定要清空所有内容吗?", + success: (res) => { + if (res.confirm) { + this.setData({ + inputValue: '', + inputLength: 0, + detectResult: '' + }); + wx.showToast({ + title: '已清空内容', + icon: 'none' + }); + } + } + }); + }, + + // 调用智能修改(AI合规) + modifyContent() { + // 禁用智能修改按钮 + this.setData({ modifyButtonDisabled: true }); + + wx.showLoading({ + title: '正在修改...', + }); + + app.apiRequest({ + url: '/myapp/ai_modify_text/', + method: 'POST', + data: { + task_id: this.data.task_id, + openid: wx.getStorageSync('openid') + }, + success: (res) => { + wx.hideLoading(); + this.setData({ modifyButtonDisabled: false }); // 启用智能修改按钮 + if (res.data.code === 200) { + // 修改成功 + this.setData({ + inputValue: res.data.data.modified_text, + detectResult: '' // 清空检测结果 + }); + wx.showToast({ + title: '修改成功', + icon: 'success' + }); + }else if (res.data.code === 400 && res.data.message === '积分不足,请充值') { + // 积分不足,提示用户充值并引导 + wx.showModal({ + title: "提示", + content: "您的积分不足,无法进行智能修改,请充值后再尝试。", + confirmText: "去充值", + cancelText: "取消", + success: (modalRes) => { + if (modalRes.confirm) { + wx.navigateTo({ + url: "../vip_recharge/vip_recharge?show=true" + }); + } + } + }); + } else { + // 其他失败情况 + wx.showToast({ + title: res.data.message || '修改失败,请稍后重试', + icon: 'none' + }); + } + }, + fail: (err) => { + wx.hideLoading(); + this.setData({ modifyButtonDisabled: false }); // 启用智能修改按钮 + console.error('请求失败:', err); + wx.showToast({ + title: '网络异常,请稍后重试', + icon: 'none' + }); + } + }); + }, + + // 记录点击的功能类型 + recordClick(functionClicked) { + app.apiRequest({ + url: `/myapp/record_click/`, // 点击统计接口 + method: 'POST', + data: { + openid: wx.getStorageSync('openid'), + nickname: wx.getStorageSync('uuid'), + function_clicked: functionClicked + }, + header: { + 'content-type': 'application/json' + }, + success: (res) => { + + } + }); + } + +}); diff --git a/pages/video_list/video_list.json b/pages/video_list/video_list.json new file mode 100644 index 0000000..45efe44 --- /dev/null +++ b/pages/video_list/video_list.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "违规词识别", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "custom-tab-bar": "/custom-tab-bar/index" +} \ No newline at end of file diff --git a/pages/video_list/video_list.wxml b/pages/video_list/video_list.wxml new file mode 100644 index 0000000..1721310 --- /dev/null +++ b/pages/video_list/video_list.wxml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + {{inputLength}} / {{maxLength}} + 内容不能超过 {{maxLength}} 字节 + + + + + + + + + + + + + + + 单次消耗3创意点。检测中请勿退出本页面,很快完成 + + + + + + 检测报告 + + + + + 检测结果: {{detectResult.conclusion}} + + + + + + + + 疑似命中 + 关键词 + 字符位置 + 置信度 + + + + + + {{item.reason}} + {{item.keyword}} + {{item.position}} + {{item.confidence}} + + + + + + + + 功能介绍:本功能用于检测文本中可能存在的违规内容,帮助用户规避潜在风险。\n + 免责声明:本检测结果仅供参考,具体结果请以实际情况为准,平台不承担由此产生的任何法律责任。 + + + + + diff --git a/pages/video_list/video_list.wxss b/pages/video_list/video_list.wxss new file mode 100644 index 0000000..6723c30 --- /dev/null +++ b/pages/video_list/video_list.wxss @@ -0,0 +1,204 @@ +page { + background-color: #222238; + border-top: 1px solid hsla(0,31%,87%,.5); +} + +.container { + align-items: center; + display: flex; + flex-direction: column; + padding: 20px; +} + +.header { + display: flex; + justify-content: space-around; + margin-bottom: 20px; + width: 100%; +} + +.button-group { + display: flex; + width: 100%; + justify-content: space-around; +} + +.detect-button{ + width: 30%; + height: 35px; + font-size: 12px; + line-height: 35px; + background: linear-gradient(90deg, #8d72d2, #7183f3); + border-radius: 5px; + text-align: center; + color: white; + box-shadow: 0 4px 10px rgba(141, 114, 210, 0.4); + transition: background 0.3s, transform 0.3s; +} + +.detect-button:hover { + background: linear-gradient(90deg, #664da5, #4e66d8); + +} + +.active { + border: 1px solid #fff; +} + +.input-area { + width: 100%; + background-color: #222238; + box-shadow: 0 4px 10px rgba(141, 114, 210, 0.4); + padding: 20px; + box-sizing: border-box; + border-radius: 10px; + margin-bottom: 20px; +} + +.input-field { + background: #33334c; + color: #a790e2; + padding: 15px; + box-sizing: border-box; + border-radius: 5px; + width: 100%; + height: 230px; + border: 1px solid #a790e2; + outline: none; + resize: none; + font-size: 14px; +} + +.input-field:hover { + border-color: #fff; +} + +.button-group { + display: flex; + justify-content: space-between; + margin-top: 10px; +} + +.copy-button, .modify-button ,.detect-button, .clear-button{ + width: 30%; + + box-sizing: border-box; + background: linear-gradient(90deg, #8d72d2, #7183f3); + border-radius: 5px; + text-align: center; + color: white; + font-size: 14px; + + box-shadow: 0 4px 10px rgba(141, 114, 210, 0.4); + transition: background 0.3s, transform 0.3s; +} + +.copy-button:hover, .modify-button:hover { + background: linear-gradient(90deg, #664da5, #4e66d8); + transform: translateY(-2px); +} + +.result-area { + margin-top: 20px; + background: linear-gradient(135deg, #a3a3df, #eaeaf5); /* 浅色渐变背景 */ + width: 90%; + padding: 15px; + border-radius: 10px; + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); /* 添加轻微阴影效果 */ + margin-bottom: 20px; + border: 1px solid #ddd; /* 增加边框 */ +} +.text-counter{ + font-size: 12px; + color: white; + text-align: left; + margin:2px; +} +.error-text { + color: red; + margin-left: 60px; +} + +/* 报告容器样式 */ +.report-container { + width: 95%; + background-color: #f5f8ff; + padding: 20rpx; + border-radius: 15rpx; + box-shadow: 0rpx 5rpx 15rpx rgba(0, 0, 0, 0.1); + margin-top: 20rpx; + margin-bottom: 45px; +} + +/* 标题样式 */ +.report-title { + font-size: 36rpx; + color: #333; + font-weight: bold; + text-align: center; + margin-bottom: 2rpx; +} + +/* 检测结果样式 */ +.result-summary { + font-size: 28rpx; + color: #666; + margin-bottom: 20rpx; + text-align: center; +} + +/* 合规与不合规文本样式 */ +.compliant { + color: #00b269; /* 绿色 */ +} + +.non-compliant { + color: #ff4d4f; /* 红色 */ +} + +/* 表格样式 */ +.result-table { + width: 100%; + border-collapse: collapse; +} + +/* 表格行样式 */ +.table-row { + display: flex; + justify-content: space-between; + padding: 10rpx 0; + border-bottom: 1rpx solid #eaeaea; +} + +/* 表格头部样式 */ +.table-header { + font-weight: bold; + background-color: #eef1f8; + padding: 10rpx 0; + text-align: center; +} + +/* 表格单元格样式 */ +.table-cell { + flex: 1; + text-align: center; + font-size: 26rpx; + color: #333; + padding: 10rpx 0; +} + +/* 底部空白区 */ +.bottom-space { + height: 50rpx; +} + +/* Disclaimer styling */ +.disclaimer { + margin-top: 20rpx; + padding: 10rpx; + color: #999; + font-size: 22rpx; /* 小号字体 */ + text-align: center; +} + + diff --git a/pages/vip_recharge/vip_recharge.js b/pages/vip_recharge/vip_recharge.js new file mode 100644 index 0000000..57ce500 --- /dev/null +++ b/pages/vip_recharge/vip_recharge.js @@ -0,0 +1,187 @@ +var e = getApp(); + +Page({ + data: { + isVip: false, + startTime: "--", + endTime: "--", + selectedType: null, + cards: [], + isQuota: false, + show: false, + isIOS: false, // 是否为 iOS 系统 + }, + onLoad: function (e) { + const that = this; + getApp().check_status() + .then(function(res) { + that.setData({ + show: res.data.data.show + }); + if (!that.data.show) { + wx.showModal({ + title: "提示", + content: "iOS 暂时无法使用此功能,请稍后再试。", + showCancel: false, + confirmText: "知道了", + success: () => { + // 可选:用户确认后返回上一级页面 + wx.reLaunch({ + url: "/pages/index/index", + }) + } + }); + return; // 停止执行后续逻辑 + } + }) + .catch(function(err) { + console.error("获取文章信息失败:", err); + }) + .finally(function() { + console.log("check_status调用完成"); + }); + // 使用 wx.getDeviceInfo() 检测系统是否为 iOS + + + + // 非 iOS 系统,继续加载页面逻辑 + var t = wx.getStorageSync("cards").filter(function (t) { + return t.is_quota === JSON.parse(e.isQuota || "false"); + }); + + console.log("renderCards", t); + this.setData({ + cards: t, + isQuota: JSON.parse(e.isQuota || "false"), + }); + }, + + + onRecharge: function (e) { + this.setData({ + selectedType: e.currentTarget.dataset.type, + }); + }, + // open_button: function (e) { + // // 如果是 iOS,弹出提示框(备用逻辑) + // if (this.data.isIOS) { + // wx.showModal({ + // title: "提示", + // content: "iOS 暂时无法使用此功能,请稍后再试。", + // showCancel: false, + // confirmText: "知道了", + // }); + // return; + // } + + // // 非 iOS 正常跳转到支付小程序 + // var t = e.currentTarget.dataset.type, + // n = e.currentTarget.dataset.price; + // this.setData({ + // selectedType: t, + // }), + // console.log(t, n), + // wx.navigateToMiniProgram({ + // appId: "wxbe54dfa3311e0443", + // path: "pages/payment/payment?type=" + // .concat(t, "&externalOpenid=") + // .concat(wx.getStorageSync("openid"), "&total_fee=") + // .concat(n, "&transaction_type=member&isDebug=false"), + // envVersion: "release", + // success: function (e) { + // console.log("跳转到支付小程序成功", e); + // }, + // fail: function (e) { + // console.error("跳转到支付小程序失败", e); + // }, + // }); + // }, + open_button: function(t) { + var n = t.currentTarget.dataset.type, o = t.currentTarget.dataset.price; + this.setData({ + selectedType: n + }), console.log(t), e.apiRequest({ + url: "/myapp/wx_pay/", + method: "POST", + data: { + type: n, + openid: wx.getStorageSync("openid"), + total_fee: o, + transaction_type: "member" + }, + success: function(t) { + console.log(t), t.data && t.data.paySign ? wx.requestPayment({ + timeStamp: t.data.timeStamp, + nonceStr: t.data.nonceStr, + package: t.data.package, + signType: "RSA", + paySign: t.data.paySign, + success: function(t) { + e.getinfo().then(function() { + console.log(wx.getStorageSync("cards")), wx.navigateBack({ + delta: 1, + success: function(e) { + console.log("返回上一页成功"); + } + }); + }).catch(function(e) { + console.error("An error occurred:", e); + }), console.log(t), wx.showToast({ + title: "支付成功", + icon: "success" + }); + }, + fail: function(e) { + wx.showToast({ + title: "支付失败", + icon: "error" + }); + } + }) : wx.showToast({ + title: "创建订单失败", + icon: "error" + }); + } + }); + }, + onReady: function () {}, + onShow: function () { + var t = this; + e.getUserInfo() + .then(function () { + t.setData({ + isVip: wx.getStorageSync("isMember"), + startTime: t.formatEndTime(wx.getStorageSync("startTime")), + endTime: t.formatEndTime(wx.getStorageSync("endTime")), + }); + }) + .catch(function (e) { + console.error("获取用户信息失败:", e); + }) + .finally(function () { + console.log("getUserInfo调用完成"); + }); + + // + + }, + formatEndTime: function(e) { + // 将秒时间戳转换为毫秒时间戳 + var date = new Date(e * 1000); + + // 格式化为“YYYY年MM月DD日” + var year = date.getFullYear(); + var month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从 0 开始,需要 +1 + var day = String(date.getDate()).padStart(2, "0"); + + var formattedDate = `${year}-${month}-${day}`; + + return formattedDate + + }, + onHide: function () {}, + onUnload: function () {}, + onPullDownRefresh: function () {}, + onReachBottom: function () {}, + onShareAppMessage: function () {}, +}); diff --git a/pages/vip_recharge/vip_recharge.json b/pages/vip_recharge/vip_recharge.json new file mode 100644 index 0000000..bdf87a5 --- /dev/null +++ b/pages/vip_recharge/vip_recharge.json @@ -0,0 +1,7 @@ +{ + "navigationBarTitleText": "会员中心", + "navigationBarBackgroundColor": "#222238", + "navigationBarTextStyle": "white", + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/vip_recharge/vip_recharge.wxml b/pages/vip_recharge/vip_recharge.wxml new file mode 100644 index 0000000..07cadec --- /dev/null +++ b/pages/vip_recharge/vip_recharge.wxml @@ -0,0 +1,32 @@ + + + + + 尊贵VIP + + + 开通时间:{{startTime}} + 到期时间:{{endTime}} + + + + + 选择订阅套餐: + + + + + {{item.title}} + + 原价¥{{item.price*2}} + 限时¥{{item.price}} + + {{item.description}} + + + + + + 成为会员,享受无限使用功能特权,体验更多专属内容! + + diff --git a/pages/vip_recharge/vip_recharge.wxss b/pages/vip_recharge/vip_recharge.wxss new file mode 100644 index 0000000..ed7167f --- /dev/null +++ b/pages/vip_recharge/vip_recharge.wxss @@ -0,0 +1,133 @@ +page { + background-color: #222238; + border-top: 1px solid hsla(0,31%,87%,.5); +} + +.container { + font-family: Arial; + padding: 20px; +} +.desc{ + white-space: pre-wrap; /* 支持换行 */ + color: #fff; + font-size: 22rpx; + font-weight: 300; +} +.status-section { + background: linear-gradient(90deg,#8d72d2,#7183f3); + display: flex; + justify-content: space-between; + margin-bottom: 20px; + text-align: center; +} + +.footer,.recharge-options,.status-section { + border-radius: 10px; + box-shadow: 0 2px 10px rgba(0,0,0,.1); + color: #a790e2; + padding: 20px 10px; + width: 100%; +} + +.card { + align-items: center; + background-color: #2f2f50; + border-radius: 20rpx; + box-shadow: 0 4px 6px rgba(0,0,0,.3),0 1px 3px rgba(0,0,0,.08); + display: flex; + margin-top: 10px; + padding: 10px; + transition: all .2s; +} + +.card-icon { + height: 50px; + margin-right: 10px; + width: 50px; +} + +.card-content { + flex-grow: 1; + width: 60%; + +} + +.card-title { + color: #a790e2; + font-size: 16px; + font-weight: 700; +} + +.price-wrapper { + align-items: center; + display: flex; + +} + +.original-price { + color: #97a09a; + margin-right: 10rpx; + text-decoration: line-through; +} + +.current-price { + color: #f861f8; +} + +.renew-button { + line-height: 2.4rem; + +} + +.open-button,.renew-button { + + background: linear-gradient(90deg,#592bcc,#d231d8); + border: none; + border-radius: 5px; + box-shadow: 0 4px 8px rgba(0,0,0,.2); + color: #fff; + cursor: pointer; + font-size: 1rem; + height: 2.5rem; + margin-top: 10px; + padding: .5rem 1rem; + text-align: center; + transition: background-color .3s,box-shadow .3s; + width: 6rem; +} + +.open-button { + line-height: 1.9rem; +} + +.open-button:hover,.renew-button:hover { + background-color: #e43333; + box-shadow: 0 6px 12px rgba(0,0,0,.3); +} + +.small-button { + padding: 5px; +} + +.footer { + color: #777; + font-size: 14px; + text-align: center; +} + +.user-vip,.user-vip .user-pic { + height: 130rpx; + margin: 0 auto; + width: 130rpx; +} + +.user-vip .user-pic { + background: #fff; + border-radius: 50%; + display: block; + overflow: hidden; +} + +.right { + color: #fff; +} \ No newline at end of file diff --git a/popup/popup.js b/popup/popup.js new file mode 100644 index 0000000..0d34acc --- /dev/null +++ b/popup/popup.js @@ -0,0 +1,56 @@ +Component({ + properties: { + popupType: { type: String, value: 'announcement' }, // 弹窗类型 + popupContent: { type: String, value: '' }, // 弹窗内容 + buttonText: { type: String, value: '立即前往' }, // 按钮文字 + targetUrl: { type: String, value: '' }, // 按钮跳转链接 + debugMode: { type: Boolean, value: false } // 开关:调试模式 + }, + data: { + isVisible: false // 默认不显示弹窗 + }, + lifetimes: { + attached() { + this.checkPopupStatus(); + } + }, + methods: { + // 检查是否需要显示弹窗 + checkPopupStatus() { + const debugMode = this.properties.debugMode; // 获取调试模式开关 + const lastShownDate = wx.getStorageSync('popup_last_date'); // 读取本地存储的日期 + const today = new Date().toDateString(); // 获取当前日期字符串 + + if (debugMode || lastShownDate !== today) { + // 调试模式或未弹出过,则显示弹窗 + this.setData({ isVisible: true }); + wx.setStorageSync('popup_last_date', today); // 更新本地存储的日期 + } else { + console.log('弹窗今日已显示,不再重复弹出'); + } + }, + + // 关闭弹窗 + closePopup() { + this.setData({ isVisible: false }); + }, + + onMaskTap() { + this.closePopup(); + }, + + preventClose() { + // 防止点击弹窗内部关闭 + }, + + onNavigate() { + if (this.properties.targetUrl) { + wx.navigateTo({ + url: this.properties.targetUrl + }); + } else { + console.warn('未设置跳转链接'); + } + } + } +}); diff --git a/popup/popup.json b/popup/popup.json new file mode 100644 index 0000000..32640e0 --- /dev/null +++ b/popup/popup.json @@ -0,0 +1,3 @@ +{ + "component": true +} \ No newline at end of file diff --git a/popup/popup.wxml b/popup/popup.wxml new file mode 100644 index 0000000..d42161c --- /dev/null +++ b/popup/popup.wxml @@ -0,0 +1,23 @@ + + + + + X + + + + 🎉 活动通知 🎉 + {{popupContent}} + + + + 📢 公告通知 📢 + {{popupContent}} + + + + + + + + diff --git a/popup/popup.wxss b/popup/popup.wxss new file mode 100644 index 0000000..0b2a44e --- /dev/null +++ b/popup/popup.wxss @@ -0,0 +1,82 @@ +/* 背景蒙版模糊 */ +.popup-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(10px); /* 背景模糊 */ + z-index: 1000; +} + +/* 弹窗容器 */ +.popup-container { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0); + background: linear-gradient(135deg, #fff, #f7f7f7); + box-shadow: 0 12rpx 28rpx rgba(0, 0, 0, 0.2); + border-radius: 20rpx; + animation: popup-fade-in 0.3s ease-out forwards; + z-index: 1001; + padding: 30rpx; + width: 80%; + text-align: center; +} + +/* 弹窗显示动画 */ +@keyframes popup-fade-in { + 0% { + transform: translate(-50%, -50%) scale(0.5); + opacity: 0; + } + 100% { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + } +} +.popup-text { + white-space: pre-wrap; /* 支持换行 */ + font-size: 28rpx; + color: #333; + line-height: 1.6; +} + +/* 关闭按钮 */ +.popup-close { + position: absolute; + top: 10rpx; + right: 20rpx; + font-size: 40rpx; + color: #aaa; + cursor: pointer; +} + +/* 标题和内容 */ +.popup-title { + font-size: 40rpx; + font-weight: bold; + margin-bottom: 20rpx; +} + +.popup-body { + font-size: 30rpx; + color: #666; +} + +.popup-btn { + width: 260rpx; /* 按钮宽度 */ + height: 80rpx; /* 按钮高度 */ + background: linear-gradient(135deg, #6DD5FA, #2980B9); /* 按钮渐变背景 */ + color: #fff; /* 文字颜色 */ + text-align: center; /* 文字居中 */ + line-height: 80rpx; /* 文字垂直居中 */ + border-radius: 50rpx; /* 圆角 */ + font-size: 32rpx; /* 字体大小 */ + font-weight: bold; /* 字体加粗 */ + box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.2); /* 添加阴影 */ + transition: all 0.3s ease-in-out; /* 添加过渡动画 */ + cursor: pointer; /* 鼠标指针样式 */ +} \ No newline at end of file diff --git a/project.config.json b/project.config.json new file mode 100644 index 0000000..6641e6b --- /dev/null +++ b/project.config.json @@ -0,0 +1,45 @@ +{ + "compileType": "miniprogram", + "setting": { + "coverView": true, + "es6": true, + "postcss": true, + "minified": true, + "enhance": true, + "showShadowRootInWxmlPanel": true, + "packNpmRelationList": [], + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "lazyloadPlaceholderEnable": false, + "preloadBackgroundData": false, + "autoAudits": false, + "uglifyFileName": true, + "uploadWithSourceMap": true, + "useMultiFrameRuntime": true, + "packNpmManually": false, + "minifyWXSS": true, + "useStaticServer": true, + "showES6CompileOption": false, + "checkInvalidKey": true, + "disableUseStrict": false, + "useCompilerPlugins": false, + "minifyWXML": true, + "ignoreUploadUnusedFiles": false, + "condition": false, + "ignoreDevUnusedFiles": false + }, + "condition": {}, + "editorSetting": { + "tabIndent": "auto", + "tabSize": 2 + }, + "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "packOptions": { + "ignore": [], + "include": [] + }, + "appid": "wx80e72720be2de560" +} \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json new file mode 100644 index 0000000..260c5b6 --- /dev/null +++ b/project.private.config.json @@ -0,0 +1,170 @@ +{ + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "projectname": "wxb5a1857369e5809e", + "setting": { + "compileHotReLoad": true, + "urlCheck": false, + "preloadBackgroundData": false + }, + "libVersion": "development", + "condition": { + "miniprogram": { + "list": [ + { + "name": "pages/bot-list/bot-list", + "pathName": "pages/bot-list/bot-list", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "迁移测试", + "pathName": "pages/index/index", + "query": "externalOpenid=o3aFE4_2uU3lEW0DbL0fNWaJT0Xc&transaction_type=member&token=gAAAAABnh-DsZ1Fxya1ikI-5LpsRM94SzWjds_D2B6nWiui-79tMjxnrHDKk58qGBPvEsHT4wTLoh3nWXfnY4ClMMW1-NCbkjOaWAoD8NwjbFktai2ok3rCMm8ENXwvuvgnCyOyI08jCkmuvo5yhnLJgwQKGbvMgbdh6echVZNaQdLyCtbiXzZHpIoKISB8ogKijL-xYFbAu4iDvPb6ODfztLi3fHEA0_Y8DdyV4G-BPf-Ujoj6z5p7jov8tCDBnbAJCuRYUMX1Vvuplab765qTeAg_5Sr2L9Q%3D%3D", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/details/details", + "pathName": "pages/details/details", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/video/video", + "pathName": "pages/video/video", + "query": "url=https%3A%2F%2Ffinder.video.qq.com%2F251%2F20302%2Fstodownload%3Fencfilekey%3DCvvj5Ix3eewK0tHtibORqcsqchXNh0Gf3sJcaYqC2rQCfmornp3whTPnj2l7Vq3ticgwramgKkTz36fGR1JqvG9bE4VgIVBhfxSPwRBWGvmCMtzCFbP5T3d1APsibaubkFK%26token%3DcztXnd9GyrHyDUNS08mucTAAeWm30HgicdEw44AV0iaVpjUkL6HGh3njcLvWYTesTwadriaTA7jBfBolPVfibmcHJEAa6D44kZjUEBqsPcZu9RV1c1lMn1M8mW5yYCZtKoLdaOTyRx9Yh8P0YuegDvdGDBTUskWaibB2O8LYfWD79vkc%26idx%3D1%26bizid%3D1023%26dotrans%3D0%26hy%3DSH%26m%3D%26uzid%3D1&type=weixin", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/index/index", + "pathName": "pages/index/index", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/extract/extract", + "pathName": "pages/extract/extract", + "query": "text=%25E5%258E%259F%25E6%259D%25A5%25EF%25BC%258C%25E6%25B1%259F%25E6%25B5%2599%25E6%25B2%25AA%25E7%258B%25AC%25E7%2594%259F%25E5%25AD%2590%25E5%25A5%25B3%25E6%2589%258D%25E6%2598%25AF%25E8%25AE%25A1%25E5%2588%2592%25E7%2594%259F%25E8%2582%25B2%25E7%259A%2584%25E6%259C%2580%25E5%25A4%25A7%25E5%258F%2597%25E7%259B%258A%25E8%2580%2585%25E3%2580%2582%25E8%2587%25B3%25E4%25BB%258A%25E9%2583%25BD%25E4%25B8%258D%25E7%259F%25A5%25E9%2581%2593%25E4%25B8%25BA%25E4%25BB%2580%25E4%25B9%2588%25E6%259C%2589%25E4%25BA%25BA%25E4%25BC%259A%25E8%25A7%2589%25E5%25BE%2597%25E7%258B%25AC%25E7%2594%259F%25E5%25AD%2590%25E5%25A5%25B3%25E9%259D%259E%25E5%25B8%25B8%25E5%25AD%25A4%25E7%258B%25AC%25EF%25BC%258C%25E6%25AE%258A%25E4%25B8%258D%25E7%259F%25A5%25EF%25BC%258C%25E4%25BB%2596%25E4%25BB%25AC%25E4%25BA%25AB%25E5%258F%2597%25E7%259D%2580%25E5%2591%25A8%25E5%259B%25B4%25E4%25BA%25BA%25E7%2599%25BE%25E5%2588%2586%25E7%2599%25BE%25E7%259A%2584%25E7%2588%25B1%25EF%25BC%258C%25E6%258B%25BF%25E7%259D%2580%25E7%259A%2584%25E6%2598%25AF%25E4%25BA%25BA%25E7%2594%259F%25E7%259A%2584%25E9%25A1%25B6%25E7%25BA%25A7%25E4%25BD%2593%25E9%25AA%258C%25E5%258D%25A1%25E3%2580%2582%25E4%25B8%2580%25E4%25BD%258D%25E6%25B1%259F%25E6%25B5%2599%25E6%25B2%25AA%25E5%25B0%258F%25E5%25A7%2590%25E5%25A7%2590%25E5%2588%2586%25E4%25BA%25AB%25E5%2588%25B0%25EF%25BC%258C%25E5%259C%25A8%25E8%2587%25AA%25E5%25B7%25B103%25E5%25B9%25B4%25E6%258A%2593%25E5%2591%25A8%25E7%259A%2584%25E6%2597%25B6%25E5%2580%2599%25EF%25BC%258C%25E5%259C%25A8%25E7%25AC%25AC%25E4%25B8%2580%25E5%2590%25AC%25E8%25AF%258A%25E5%2599%25A8%25E3%2580%2581%25E9%2592%259E%25E7%25A5%25A8%25E7%25AD%2589%25E7%2589%25A9%25E5%2593%2581%25E9%2587%258C%25EF%25BC%258C%25E4%25BB%2596%25E6%258B%25BF%25E4%25B8%2580%25E6%2594%25AF%25E8%25BF%25AA%25E5%25A5%25A5%25E7%259A%2584%25E5%258F%25A3%25E7%25BA%25A2%25EF%25BC%258C%25E8%25BF%2599%25E4%25B8%2580%25E4%25B8%25BE%25E5%258A%25A8%25E5%2587%25BA%25E4%25B9%258E%25E4%25BA%2586%25E6%2589%2580%25E6%259C%2589%25E4%25BA%25BA%25E7%259A%2584%25E6%2584%258F%25E6%2596%2599%25EF%25BC%258C%25E5%25AE%25B6%25E9%2587%258C%25E4%25BA%25BA%25E5%25B9%25B6%25E4%25B8%258D%25E6%2598%25AF%25E6%2584%259F%25E5%2588%25B0%25E9%259A%25BE%25E8%25BF%2587%25EF%25BC%258C%25E8%2580%258C%25E6%2598%25AF%25E9%2583%25BD%25E4%25B8%25BA%25E4%25BB%2596%25E9%25AB%2598%25E5%2585%25B4%25EF%25BC%258C%25E4%25B8%258D%25E5%259C%25A8%25E6%2584%258F%25E4%25BB%2596%25E6%259C%25AA%25E6%259D%25A5%25E4%25BC%259A%25E4%25B8%258D%25E4%25BC%259A%25E8%2585%25B0%25E7%25BC%25A0%25E4%25B8%2587%25E8%25B4%25AF%25EF%25BC%258C%25E5%258F%25AA%25E5%25B8%258C%25E6%259C%259B%25E5%25A5%25B9%25E6%2598%25AF%25E4%25B8%2580%25E4%25B8%25AA%25E6%258B%25BF%25E7%259D%2580%25E5%258F%25A3%25E7%25BA%25A2%25E7%259A%2584%25E5%25BF%25AB%25E4%25B9%2590%25E5%25B0%258F%25E5%25A5%25B3%25E5%25AD%25A9%25E3%2580%2582%25E5%25BD%2593%25E5%2590%258C%25E9%25BE%2584%25E4%25BA%25BA%25E7%259A%2584%25E6%2588%2591%25E4%25BB%25AC%25E8%25BF%2598%25E5%259C%25A8%25E6%258B%25BC%25E5%2591%25BD%25E8%2580%2583%25E7%25A0%2594%25E8%2580%2583%25E5%25B7%25A5%25E7%259A%2584%25E6%2597%25B6%25E5%2580%2599%25EF%25BC%258C%25E4%25BB%2596%25E4%25BB%25AC%25E5%258F%25AF%25E8%2583%25BD%25E6%2597%25A9%25E5%25B7%25B2%25E9%25A1%25BA%25E5%2588%25A9%25E4%25BB%258E%25E5%259B%25BD%25E5%25A4%2596%25E5%25B8%25B8%25E9%259D%2592%25E8%2597%25A4%25E5%25A4%25A7%25E5%25AD%25A6%25E6%25AF%2595%25E4%25B8%259A%25E5%259B%259E%25E6%259D%25A5%25EF%25BC%258C%25E6%2589%258B%25E6%258F%25A1%25E5%25A5%25BD%25E5%2587%25A0%25E5%25A5%2597%25E6%2588%25BF%25E4%25BA%25A7%25EF%25BC%258C%25E4%25B8%2580%25E6%258B%25BF%25E9%25A9%25BE%25E9%25A9%25B6%25E8%25AF%2581%25EF%25BC%258C%25E5%25A5%2594%25E9%25A9%25B0%25E5%25AE%259D%25E9%25A9%25AC%25E5%25B0%25B1%25E4%25BC%259A%25E5%25AE%2589%25E6%258E%2592%25E5%2588%25B0%25E4%25BD%258D%25E3%2580%2582%25E4%25B8%25BA%25E4%25BB%2580%25E4%25B9%2588%25E6%25B1%259F%25E6%25B5%2599%25E6%25B2%25AA%25E4%25B8%2580%25E5%25B8%25A6%25E7%258B%25AC%25E7%2594%259F%25E5%25AD%2590%25E5%25A5%25B3%25E9%2595%25BF%25E5%25BE%2597%25E6%2599%25AE%25E9%2581%258D%25E5%25A5%25BD%25E7%259C%258B%25EF%25BC%258C%25E5%25B9%25BC%25E5%2584%25BF%25E5%259B%25AD%25E8%2580%2581%25E5%25B8%2588%25E5%258F%2591%25E7%258E%25B0%25E7%259D%25A1%25E8%25A7%2589%25E5%25BC%25A0%25E5%2598%25B4%25E5%2591%25BC%25E5%2590%25B8%25E4%25B9%258B%25E5%2590%258E%25EF%25BC%258C%25E6%25B2%25A1%25E8%25BF%2587%25E5%2587%25A0%25E5%25A4%25A9%25E5%25B0%25B1%25E5%258E%25BB%25E5%2581%259A%25E4%25BA%2586%25E6%2589%258B%25E6%259C%25AF%25EF%25BC%258C%25E5%259B%25A0%25E4%25B8%25BA%25E5%25AE%25B3%25E6%2580%2595%25E5%25AD%25A9%25E5%25AD%2590%25E5%258F%2591%25E8%2582%25B2%25E6%2588%2590%25E5%25BD%25A2%25E6%25A0%25B7%25E4%25BD%2593%25E9%259D%25A2%25E4%25B9%25B3%25E3%2580%2582%25E5%259C%25A8%25E4%25BB%2596%25E4%25BB%25AC%25E5%25AE%25B6%25E9%2595%25BF%25E5%25AD%259C%25E5%25AD%259C%25E4%25B8%258D%25E5%2580%25A6%25E7%259A%2584%25E4%25BB%258E%25E7%259C%25BC%25E7%259D%259B%25E3%2580%2581%25E9%25BC%25BB%25E5%25AD%2590%25E3%2580%2581%25E7%2589%2599%25E9%25BD%25BF%25E3%2580%2581%25E7%259A%25AE%25E8%2582%25A4%25E3%2580%2581%25E8%25BA%25AB%25E9%25AB%2598%25E7%25AD%2589%25E5%2590%2584%25E4%25B8%25AA%25E6%2596%25B9%25E9%259D%25A2%25E7%259A%2584%25E7%25B2%25BE%25E5%25BF%2583%25E5%2591%25B5%25E6%258A%25A4%25E4%25B8%258B%25EF%25BC%258C%25E6%25AF%258F%25E4%25B8%25AA%25E5%25AD%25A9%25E5%25AD%2590%25E9%2583%25BD%25E9%2595%25BF%25E5%25BE%2597%25E5%25A5%25BD%25E7%259C%258B%25E5%2592%258C%25E8%2587%25AA%25E4%25BF%25A1%25E3%2580%2582&type=index&wxid=undefined&alias=undefined", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/video_list/video_list", + "pathName": "pages/video_list/video_list", + "query": "rewrittenText=123", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/extract/extract", + "pathName": "pages/extract/extract", + "query": "text=123", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/invite_incentive/invite_incentive", + "pathName": "pages/invite_incentive/invite_incentive", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/video_dow/video_dow", + "pathName": "pages/video_dow/video_dow", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/video_task/video_task", + "pathName": "pages/video_task/video_task", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/video_list/video_list", + "pathName": "pages/video_list/video_list", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/mine/mine", + "pathName": "pages/mine/mine", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/index/index", + "pathName": "pages/index/index", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/index/index", + "pathName": "pages/index/index", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/vip_recharge/vip_recharge", + "pathName": "pages/vip_recharge/vip_recharge", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/business_cooperation/business_cooperation", + "pathName": "pages/business_cooperation/business_cooperation", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/invite_incentive/invite_incentive", + "pathName": "pages/invite_incentive/invite_incentive", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/mine/mine", + "pathName": "pages/business_cooperation/business_cooperation", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/vip_recharge/vip_recharge", + "pathName": "pages/vip_recharge/vip_recharge", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/faq/faq", + "pathName": "pages/faq/faq", + "query": "", + "launchMode": "default", + "scene": null + }, + { + "name": "pages/index/index", + "pathName": "pages/index/index", + "query": "", + "launchMode": "default", + "scene": 1007 + } + ] + } + } +} \ No newline at end of file diff --git a/sitemap.json b/sitemap.json new file mode 100644 index 0000000..ca02add --- /dev/null +++ b/sitemap.json @@ -0,0 +1,7 @@ +{ + "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", + "rules": [{ + "action": "allow", + "page": "*" + }] +} \ No newline at end of file diff --git a/utils/aes.js b/utils/aes.js new file mode 100644 index 0000000..dd76dba --- /dev/null +++ b/utils/aes.js @@ -0,0 +1,34 @@ +// 引入加密包(注意存放的路径) +const Crypto = require('./crypto'); + +// 秘钥,转换成utf8格式字符串,用于加密解密,一般长度是16位(由后端提供) +const key = Crypto.enc.Utf8.parse('qw5w6SFE2D1jmxyd') +// 偏移量,转换成utf8格式字符串,一般长度是16位(由后端提供) +const iv = Crypto.enc.Utf8.parse('345GDFED433223DF') + +// 解密(使用CBC模式) +export function Decrtpt(value) { + // 使用外部包中的AES的解密方法 + // value(解密内容)、key(密钥) + let decrypt = Crypto.AES.decrypt(value, key, { + iv, // 偏移量 + mode: Crypto.mode.CBC, // 模式(五种加密模式,各有优缺) + padding: Crypto.pad.Pkcs7 // 填充 + }) + // 转成utf8格式字符串,并返回出去 + let decryptedStr = decrypt.toString(Crypto.enc.Utf8) + return decryptedStr +} + +//加密(使用CBC模式) +export function Encrypt(value) { + // 使用外部包中的AES的加密方法 + // value(加密内容)、key(密钥) + let encrypt = Crypto.AES.encrypt(value, key, { + iv, // 偏移量 + mode: Crypto.mode.CBC, // 模式(五种加密模式) + padding: Crypto.pad.Pkcs7 // 填充 + }) + // 将加密的内容转成字符串返回出去 + return encrypt.toString() +} diff --git a/utils/crypto.js b/utils/crypto.js new file mode 100644 index 0000000..4effb85 --- /dev/null +++ b/utils/crypto.js @@ -0,0 +1,174 @@ +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS = CryptoJS || function (u, p) { + var d = {}, l = d.lib = {}, s = function () { }, t = l.Base = { extend: function (a) { s.prototype = this; var c = new s; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () { c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } }, + r = l.WordArray = t.extend({ + init: function (a, c) { a = this.words = a || []; this.sigBytes = c != p ? c : 4 * a.length }, toString: function (a) { return (a || v).stringify(this) }, concat: function (a) { var c = this.words, e = a.words, j = this.sigBytes; a = a.sigBytes; this.clamp(); if (j % 4) for (var k = 0; k < a; k++)c[j + k >>> 2] |= (e[k >>> 2] >>> 24 - 8 * (k % 4) & 255) << 24 - 8 * ((j + k) % 4); else if (65535 < e.length) for (k = 0; k < a; k += 4)c[j + k >>> 2] = e[k >>> 2]; else c.push.apply(c, e); this.sigBytes += a; return this }, clamp: function () { + var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 << + 32 - 8 * (c % 4); a.length = u.ceil(c / 4) + }, clone: function () { var a = t.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], e = 0; e < a; e += 4)c.push(4294967296 * u.random() | 0); return new r.init(c, a) } + }), w = d.enc = {}, v = w.Hex = { + stringify: function (a) { var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++) { var k = c[j >>> 2] >>> 24 - 8 * (j % 4) & 255; e.push((k >>> 4).toString(16)); e.push((k & 15).toString(16)) } return e.join("") }, parse: function (a) { + for (var c = a.length, e = [], j = 0; j < c; j += 2)e[j >>> 3] |= parseInt(a.substr(j, + 2), 16) << 24 - 4 * (j % 8); return new r.init(e, c / 2) + } + }, b = w.Latin1 = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++)e.push(String.fromCharCode(c[j >>> 2] >>> 24 - 8 * (j % 4) & 255)); return e.join("") }, parse: function (a) { for (var c = a.length, e = [], j = 0; j < c; j++)e[j >>> 2] |= (a.charCodeAt(j) & 255) << 24 - 8 * (j % 4); return new r.init(e, c) } }, x = w.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(b.stringify(a))) } catch (c) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return b.parse(unescape(encodeURIComponent(a))) } }, + q = l.BufferedBlockAlgorithm = t.extend({ + reset: function () { this._data = new r.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = x.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var c = this._data, e = c.words, j = c.sigBytes, k = this.blockSize, b = j / (4 * k), b = a ? u.ceil(b) : u.max((b | 0) - this._minBufferSize, 0); a = b * k; j = u.min(4 * a, j); if (a) { for (var q = 0; q < a; q += k)this._doProcessBlock(e, q); q = e.splice(0, a); c.sigBytes -= j } return new r.init(q, j) }, clone: function () { + var a = t.clone.call(this); + a._data = this._data.clone(); return a + }, _minBufferSize: 0 + }); l.Hasher = q.extend({ + cfg: t.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { q.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (b, e) { return (new a.init(e)).finalize(b) } }, _createHmacHelper: function (a) { + return function (b, e) { + return (new n.HMAC.init(a, + e)).finalize(b) + } + } + }); var n = d.algo = {}; return d +}(Math); +(function () { + var u = CryptoJS, p = u.lib.WordArray; u.enc.Base64 = { + stringify: function (d) { var l = d.words, p = d.sigBytes, t = this._map; d.clamp(); d = []; for (var r = 0; r < p; r += 3)for (var w = (l[r >>> 2] >>> 24 - 8 * (r % 4) & 255) << 16 | (l[r + 1 >>> 2] >>> 24 - 8 * ((r + 1) % 4) & 255) << 8 | l[r + 2 >>> 2] >>> 24 - 8 * ((r + 2) % 4) & 255, v = 0; 4 > v && r + 0.75 * v < p; v++)d.push(t.charAt(w >>> 6 * (3 - v) & 63)); if (l = t.charAt(64)) for (; d.length % 4;)d.push(l); return d.join("") }, parse: function (d) { + var l = d.length, s = this._map, t = s.charAt(64); t && (t = d.indexOf(t), -1 != t && (l = t)); for (var t = [], r = 0, w = 0; w < + l; w++)if (w % 4) { var v = s.indexOf(d.charAt(w - 1)) << 2 * (w % 4), b = s.indexOf(d.charAt(w)) >>> 6 - 2 * (w % 4); t[r >>> 2] |= (v | b) << 24 - 8 * (r % 4); r++ } return p.create(t, r) + }, _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + } +})(); +(function (u) { + function p (b, n, a, c, e, j, k) { b = b + (n & a | ~n & c) + e + k; return (b << j | b >>> 32 - j) + n } function d (b, n, a, c, e, j, k) { b = b + (n & c | a & ~c) + e + k; return (b << j | b >>> 32 - j) + n } function l (b, n, a, c, e, j, k) { b = b + (n ^ a ^ c) + e + k; return (b << j | b >>> 32 - j) + n } function s (b, n, a, c, e, j, k) { b = b + (a ^ (n | ~c)) + e + k; return (b << j | b >>> 32 - j) + n } for (var t = CryptoJS, r = t.lib, w = r.WordArray, v = r.Hasher, r = t.algo, b = [], x = 0; 64 > x; x++)b[x] = 4294967296 * u.abs(u.sin(x + 1)) | 0; r = r.MD5 = v.extend({ + _doReset: function () { this._hash = new w.init([1732584193, 4023233417, 2562383102, 271733878]) }, + _doProcessBlock: function (q, n) { + for (var a = 0; 16 > a; a++) { var c = n + a, e = q[c]; q[c] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360 } var a = this._hash.words, c = q[n + 0], e = q[n + 1], j = q[n + 2], k = q[n + 3], z = q[n + 4], r = q[n + 5], t = q[n + 6], w = q[n + 7], v = q[n + 8], A = q[n + 9], B = q[n + 10], C = q[n + 11], u = q[n + 12], D = q[n + 13], E = q[n + 14], x = q[n + 15], f = a[0], m = a[1], g = a[2], h = a[3], f = p(f, m, g, h, c, 7, b[0]), h = p(h, f, m, g, e, 12, b[1]), g = p(g, h, f, m, j, 17, b[2]), m = p(m, g, h, f, k, 22, b[3]), f = p(f, m, g, h, z, 7, b[4]), h = p(h, f, m, g, r, 12, b[5]), g = p(g, h, f, m, t, 17, b[6]), m = p(m, g, h, f, w, 22, b[7]), + f = p(f, m, g, h, v, 7, b[8]), h = p(h, f, m, g, A, 12, b[9]), g = p(g, h, f, m, B, 17, b[10]), m = p(m, g, h, f, C, 22, b[11]), f = p(f, m, g, h, u, 7, b[12]), h = p(h, f, m, g, D, 12, b[13]), g = p(g, h, f, m, E, 17, b[14]), m = p(m, g, h, f, x, 22, b[15]), f = d(f, m, g, h, e, 5, b[16]), h = d(h, f, m, g, t, 9, b[17]), g = d(g, h, f, m, C, 14, b[18]), m = d(m, g, h, f, c, 20, b[19]), f = d(f, m, g, h, r, 5, b[20]), h = d(h, f, m, g, B, 9, b[21]), g = d(g, h, f, m, x, 14, b[22]), m = d(m, g, h, f, z, 20, b[23]), f = d(f, m, g, h, A, 5, b[24]), h = d(h, f, m, g, E, 9, b[25]), g = d(g, h, f, m, k, 14, b[26]), m = d(m, g, h, f, v, 20, b[27]), f = d(f, m, g, h, D, 5, b[28]), h = d(h, f, + m, g, j, 9, b[29]), g = d(g, h, f, m, w, 14, b[30]), m = d(m, g, h, f, u, 20, b[31]), f = l(f, m, g, h, r, 4, b[32]), h = l(h, f, m, g, v, 11, b[33]), g = l(g, h, f, m, C, 16, b[34]), m = l(m, g, h, f, E, 23, b[35]), f = l(f, m, g, h, e, 4, b[36]), h = l(h, f, m, g, z, 11, b[37]), g = l(g, h, f, m, w, 16, b[38]), m = l(m, g, h, f, B, 23, b[39]), f = l(f, m, g, h, D, 4, b[40]), h = l(h, f, m, g, c, 11, b[41]), g = l(g, h, f, m, k, 16, b[42]), m = l(m, g, h, f, t, 23, b[43]), f = l(f, m, g, h, A, 4, b[44]), h = l(h, f, m, g, u, 11, b[45]), g = l(g, h, f, m, x, 16, b[46]), m = l(m, g, h, f, j, 23, b[47]), f = s(f, m, g, h, c, 6, b[48]), h = s(h, f, m, g, w, 10, b[49]), g = s(g, h, f, m, + E, 15, b[50]), m = s(m, g, h, f, r, 21, b[51]), f = s(f, m, g, h, u, 6, b[52]), h = s(h, f, m, g, k, 10, b[53]), g = s(g, h, f, m, B, 15, b[54]), m = s(m, g, h, f, e, 21, b[55]), f = s(f, m, g, h, v, 6, b[56]), h = s(h, f, m, g, x, 10, b[57]), g = s(g, h, f, m, t, 15, b[58]), m = s(m, g, h, f, D, 21, b[59]), f = s(f, m, g, h, z, 6, b[60]), h = s(h, f, m, g, C, 10, b[61]), g = s(g, h, f, m, j, 15, b[62]), m = s(m, g, h, f, A, 21, b[63]); a[0] = a[0] + f | 0; a[1] = a[1] + m | 0; a[2] = a[2] + g | 0; a[3] = a[3] + h | 0 + }, _doFinalize: function () { + var b = this._data, n = b.words, a = 8 * this._nDataBytes, c = 8 * b.sigBytes; n[c >>> 5] |= 128 << 24 - c % 32; var e = u.floor(a / + 4294967296); n[(c + 64 >>> 9 << 4) + 15] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360; n[(c + 64 >>> 9 << 4) + 14] = (a << 8 | a >>> 24) & 16711935 | (a << 24 | a >>> 8) & 4278255360; b.sigBytes = 4 * (n.length + 1); this._process(); b = this._hash; n = b.words; for (a = 0; 4 > a; a++)c = n[a], n[a] = (c << 8 | c >>> 24) & 16711935 | (c << 24 | c >>> 8) & 4278255360; return b + }, clone: function () { var b = v.clone.call(this); b._hash = this._hash.clone(); return b } + }); t.MD5 = v._createHelper(r); t.HmacMD5 = v._createHmacHelper(r) +})(Math); +(function () { + var u = CryptoJS, p = u.lib, d = p.Base, l = p.WordArray, p = u.algo, s = p.EvpKDF = d.extend({ cfg: d.extend({ keySize: 4, hasher: p.MD5, iterations: 1 }), init: function (d) { this.cfg = this.cfg.extend(d) }, compute: function (d, r) { for (var p = this.cfg, s = p.hasher.create(), b = l.create(), u = b.words, q = p.keySize, p = p.iterations; u.length < q;) { n && s.update(n); var n = s.update(d).finalize(r); s.reset(); for (var a = 1; a < p; a++)n = s.finalize(n), s.reset(); b.concat(n) } b.sigBytes = 4 * q; return b } }); u.EvpKDF = function (d, l, p) { + return s.create(p).compute(d, + l) + } +})(); +CryptoJS.lib.Cipher || function (u) { + var p = CryptoJS, d = p.lib, l = d.Base, s = d.WordArray, t = d.BufferedBlockAlgorithm, r = p.enc.Base64, w = p.algo.EvpKDF, v = d.Cipher = t.extend({ + cfg: l.extend(), createEncryptor: function (e, a) { return this.create(this._ENC_XFORM_MODE, e, a) }, createDecryptor: function (e, a) { return this.create(this._DEC_XFORM_MODE, e, a) }, init: function (e, a, b) { this.cfg = this.cfg.extend(b); this._xformMode = e; this._key = a; this.reset() }, reset: function () { t.reset.call(this); this._doReset() }, process: function (e) { this._append(e); return this._process() }, + finalize: function (e) { e && this._append(e); return this._doFinalize() }, keySize: 4, ivSize: 4, _ENC_XFORM_MODE: 1, _DEC_XFORM_MODE: 2, _createHelper: function (e) { return { encrypt: function (b, k, d) { return ("string" == typeof k ? c : a).encrypt(e, b, k, d) }, decrypt: function (b, k, d) { return ("string" == typeof k ? c : a).decrypt(e, b, k, d) } } } + }); d.StreamCipher = v.extend({ _doFinalize: function () { return this._process(!0) }, blockSize: 1 }); var b = p.mode = {}, x = function (e, a, b) { + var c = this._iv; c ? this._iv = u : c = this._prevBlock; for (var d = 0; d < b; d++)e[a + d] ^= + c[d] + }, q = (d.BlockCipherMode = l.extend({ createEncryptor: function (e, a) { return this.Encryptor.create(e, a) }, createDecryptor: function (e, a) { return this.Decryptor.create(e, a) }, init: function (e, a) { this._cipher = e; this._iv = a } })).extend(); q.Encryptor = q.extend({ processBlock: function (e, a) { var b = this._cipher, c = b.blockSize; x.call(this, e, a, c); b.encryptBlock(e, a); this._prevBlock = e.slice(a, a + c) } }); q.Decryptor = q.extend({ + processBlock: function (e, a) { + var b = this._cipher, c = b.blockSize, d = e.slice(a, a + c); b.decryptBlock(e, a); x.call(this, + e, a, c); this._prevBlock = d + } + }); b = b.CBC = q; q = (p.pad = {}).Pkcs7 = { pad: function (a, b) { for (var c = 4 * b, c = c - a.sigBytes % c, d = c << 24 | c << 16 | c << 8 | c, l = [], n = 0; n < c; n += 4)l.push(d); c = s.create(l, c); a.concat(c) }, unpad: function (a) { a.sigBytes -= a.words[a.sigBytes - 1 >>> 2] & 255 } }; d.BlockCipher = v.extend({ + cfg: v.cfg.extend({ mode: b, padding: q }), reset: function () { + v.reset.call(this); var a = this.cfg, b = a.iv, a = a.mode; if (this._xformMode == this._ENC_XFORM_MODE) var c = a.createEncryptor; else c = a.createDecryptor, this._minBufferSize = 1; this._mode = c.call(a, + this, b && b.words) + }, _doProcessBlock: function (a, b) { this._mode.processBlock(a, b) }, _doFinalize: function () { var a = this.cfg.padding; if (this._xformMode == this._ENC_XFORM_MODE) { a.pad(this._data, this.blockSize); var b = this._process(!0) } else b = this._process(!0), a.unpad(b); return b }, blockSize: 4 + }); var n = d.CipherParams = l.extend({ init: function (a) { this.mixIn(a) }, toString: function (a) { return (a || this.formatter).stringify(this) } }), b = (p.format = {}).OpenSSL = { + stringify: function (a) { + var b = a.ciphertext; a = a.salt; return (a ? s.create([1398893684, + 1701076831]).concat(a).concat(b) : b).toString(r) + }, parse: function (a) { a = r.parse(a); var b = a.words; if (1398893684 == b[0] && 1701076831 == b[1]) { var c = s.create(b.slice(2, 4)); b.splice(0, 4); a.sigBytes -= 16 } return n.create({ ciphertext: a, salt: c }) } + }, a = d.SerializableCipher = l.extend({ + cfg: l.extend({ format: b }), encrypt: function (a, b, c, d) { d = this.cfg.extend(d); var l = a.createEncryptor(c, d); b = l.finalize(b); l = l.cfg; return n.create({ ciphertext: b, key: c, iv: l.iv, algorithm: a, mode: l.mode, padding: l.padding, blockSize: a.blockSize, formatter: d.format }) }, + decrypt: function (a, b, c, d) { d = this.cfg.extend(d); b = this._parse(b, d.format); return a.createDecryptor(c, d).finalize(b.ciphertext) }, _parse: function (a, b) { return "string" == typeof a ? b.parse(a, this) : a } + }), p = (p.kdf = {}).OpenSSL = { execute: function (a, b, c, d) { d || (d = s.random(8)); a = w.create({ keySize: b + c }).compute(a, d); c = s.create(a.words.slice(b), 4 * c); a.sigBytes = 4 * b; return n.create({ key: a, iv: c, salt: d }) } }, c = d.PasswordBasedCipher = a.extend({ + cfg: a.cfg.extend({ kdf: p }), encrypt: function (b, c, d, l) { + l = this.cfg.extend(l); d = l.kdf.execute(d, + b.keySize, b.ivSize); l.iv = d.iv; b = a.encrypt.call(this, b, c, d.key, l); b.mixIn(d); return b + }, decrypt: function (b, c, d, l) { l = this.cfg.extend(l); c = this._parse(c, l.format); d = l.kdf.execute(d, b.keySize, b.ivSize, c.salt); l.iv = d.iv; return a.decrypt.call(this, b, c, d.key, l) } + }) +}(); +(function () { + for (var u = CryptoJS, p = u.lib.BlockCipher, d = u.algo, l = [], s = [], t = [], r = [], w = [], v = [], b = [], x = [], q = [], n = [], a = [], c = 0; 256 > c; c++)a[c] = 128 > c ? c << 1 : c << 1 ^ 283; for (var e = 0, j = 0, c = 0; 256 > c; c++) { var k = j ^ j << 1 ^ j << 2 ^ j << 3 ^ j << 4, k = k >>> 8 ^ k & 255 ^ 99; l[e] = k; s[k] = e; var z = a[e], F = a[z], G = a[F], y = 257 * a[k] ^ 16843008 * k; t[e] = y << 24 | y >>> 8; r[e] = y << 16 | y >>> 16; w[e] = y << 8 | y >>> 24; v[e] = y; y = 16843009 * G ^ 65537 * F ^ 257 * z ^ 16843008 * e; b[k] = y << 24 | y >>> 8; x[k] = y << 16 | y >>> 16; q[k] = y << 8 | y >>> 24; n[k] = y; e ? (e = z ^ a[a[a[G ^ z]]], j ^= a[a[j]]) : e = j = 1 } var H = [0, 1, 2, 4, 8, + 16, 32, 64, 128, 27, 54], d = d.AES = p.extend({ + _doReset: function () { + for (var a = this._key, c = a.words, d = a.sigBytes / 4, a = 4 * ((this._nRounds = d + 6) + 1), e = this._keySchedule = [], j = 0; j < a; j++)if (j < d) e[j] = c[j]; else { var k = e[j - 1]; j % d ? 6 < d && 4 == j % d && (k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255]) : (k = k << 8 | k >>> 24, k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255], k ^= H[j / d | 0] << 24); e[j] = e[j - d] ^ k } c = this._invKeySchedule = []; for (d = 0; d < a; d++)j = a - d, k = d % 4 ? e[j] : e[j - 4], c[d] = 4 > d || 4 >= j ? k : b[l[k >>> 24]] ^ x[l[k >>> 16 & 255]] ^ q[l[k >>> + 8 & 255]] ^ n[l[k & 255]] + }, encryptBlock: function (a, b) { this._doCryptBlock(a, b, this._keySchedule, t, r, w, v, l) }, decryptBlock: function (a, c) { var d = a[c + 1]; a[c + 1] = a[c + 3]; a[c + 3] = d; this._doCryptBlock(a, c, this._invKeySchedule, b, x, q, n, s); d = a[c + 1]; a[c + 1] = a[c + 3]; a[c + 3] = d }, _doCryptBlock: function (a, b, c, d, e, j, l, f) { + for (var m = this._nRounds, g = a[b] ^ c[0], h = a[b + 1] ^ c[1], k = a[b + 2] ^ c[2], n = a[b + 3] ^ c[3], p = 4, r = 1; r < m; r++)var q = d[g >>> 24] ^ e[h >>> 16 & 255] ^ j[k >>> 8 & 255] ^ l[n & 255] ^ c[p++], s = d[h >>> 24] ^ e[k >>> 16 & 255] ^ j[n >>> 8 & 255] ^ l[g & 255] ^ c[p++], t = + d[k >>> 24] ^ e[n >>> 16 & 255] ^ j[g >>> 8 & 255] ^ l[h & 255] ^ c[p++], n = d[n >>> 24] ^ e[g >>> 16 & 255] ^ j[h >>> 8 & 255] ^ l[k & 255] ^ c[p++], g = q, h = s, k = t; q = (f[g >>> 24] << 24 | f[h >>> 16 & 255] << 16 | f[k >>> 8 & 255] << 8 | f[n & 255]) ^ c[p++]; s = (f[h >>> 24] << 24 | f[k >>> 16 & 255] << 16 | f[n >>> 8 & 255] << 8 | f[g & 255]) ^ c[p++]; t = (f[k >>> 24] << 24 | f[n >>> 16 & 255] << 16 | f[g >>> 8 & 255] << 8 | f[h & 255]) ^ c[p++]; n = (f[n >>> 24] << 24 | f[g >>> 16 & 255] << 16 | f[h >>> 8 & 255] << 8 | f[k & 255]) ^ c[p++]; a[b] = q; a[b + 1] = s; a[b + 2] = t; a[b + 3] = n + }, keySize: 8 + }); u.AES = p._createHelper(d) +})(); + +CryptoJS.encrypt = function (word, key, iv) { + return encrypt(word, key, iv) +} + +CryptoJS.decrypt = function (word, key, iv) { + return decrypt(word, key, iv) +} + +/** + * 加密 + * word:原密码 + * key :key + * iv : iv + */ +function encrypt (word, key, iv) { + key = CryptoJS.enc.Utf8.parse(key); + iv = CryptoJS.enc.Utf8.parse(iv); + var encrypted = CryptoJS.AES.encrypt(word, key, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + return encrypted.toString(); +} + +/** + * 解密 + * word:加密后的密码 + * key :key + * iv : iv + */ +function decrypt (word, key, iv) { + key = CryptoJS.enc.Utf8.parse(key); + iv = CryptoJS.enc.Utf8.parse(iv); + var decrypted = CryptoJS.AES.decrypt(word, key, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + decrypted = CryptoJS.enc.Utf8.stringify(decrypted); + return decrypted; +} +/** + * Electronic Codebook block mode. + */ +CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + return ECB; +}()); +/** + * @example + * var CryptoJS = require('./util/aes.js') + * var key = CryptoJS.enc.Utf8.parse("key"); + * var iv = CryptoJS.enc.Utf8.parse("iv"); + * var pwd = CryptoJS.encrypt(this.data.pwdVal, key, iv) + * var original = CryptoJS.encrypt(pwd, key, iv) + */ +module.exports = CryptoJS; \ No newline at end of file diff --git a/utils/miniprogram-text-decoder.js b/utils/miniprogram-text-decoder.js new file mode 100644 index 0000000..0cf09ce --- /dev/null +++ b/utils/miniprogram-text-decoder.js @@ -0,0 +1 @@ +"use strict";let TextDecoderPolyfill;if(Object.defineProperty(exports,"__esModule",{value:!0}),"undefined"==typeof TextDecoder){const e=String.fromCharCode,t=Object.prototype.toString,r=t.call(ArrayBuffer.prototype),o="undefined"!=typeof SharedArrayBuffer?t.call(SharedArrayBuffer):"",d=function(t){const r=t.charCodeAt(0),o=0|t.length;let d=1114112,c=0,a="";switch(r>>>4){case 12:case 13:d=(31&r)<<6|63&t.charCodeAt(1),c=d<128?0:2;break;case 14:d=(15&r)<<12|(63&t.charCodeAt(1))<<6|63&t.charCodeAt(2),c=d<2048?0:3;break;case 15:r>>>3==30&&(d=(7&r)<<18|(63&t.charCodeAt(1))<<12|(63&t.charCodeAt(2))<<6|t.charCodeAt(3),c=d<65536?0:4)}for(c&&(o>>10)|0,56320+(1023&d)|0)):c=0);c { + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + const hour = date.getHours() + const minute = date.getMinutes() + const second = date.getSeconds() + + return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') +} + +const formatDate = (date, separator = '/') => { + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + return [year, month, day].map(formatNumber).join(separator); +} + +const formatNumber = n => { + n = n.toString() + return n[1] ? n : '0' + n +} + + + +module.exports = { + formatTime: formatTime, + formatDate: formatDate, +} \ No newline at end of file