first commit

This commit is contained in:
Jane Doe
2025-03-04 15:25:38 +08:00
commit 4ad00dedd5
188 changed files with 7420 additions and 0 deletions

31
pages/agent/agent.js Normal file
View File

@@ -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
});
}
};
}
});

3
pages/agent/agent.json Normal file
View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

1
pages/agent/agent.wxml Normal file
View File

@@ -0,0 +1 @@
<text>pages/agent/agent.wxml</text>

0
pages/agent/agent.wxss Normal file
View File

641
pages/aitools/aitools.js Normal file
View File

@@ -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
});
}
}
},
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "创作助手",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"custom-tab-bar": "/custom-tab-bar/index"
}

View File

@@ -0,0 +1,73 @@
<view class="container">
<view class="navbar"></view>
<view wx:if="{{currentTab==='textToVideo'}}">
<view class="input-container">
<textarea bindinput="onInput" class="input-box" maxlength="320" placeholder="输入文本或者图片即可生成原创视频,请用一句话描述您的视频主题、场景、风格等,简洁明了!" value="{{inputValue}}"></textarea>
<view class="char-count">{{charCount}}/320</view>
</view>
<view class="style-selector">
<view class="style-text">选择风格:</view>
<view class="style-options">
<view bindtap="selectStyle" class="style-option {{selectedStyle===key?'active':''}}" data-key="{{key}}" wx:for="{{styles}}" wx:for-index="key" wx:for-item="style" wx:key="{{key}}"> {{style}} </view>
</view>
</view>
<view class="size-selector">
<text class="size-text">选择尺寸:</text>
<view class="size-options">
<view bindtap="selectSize" class="size-option {{selectedSize===item.ratio?'active':''}}" data-height="{{item.height}}" data-ratio="{{item.ratio}}" data-width="{{item.width}}" wx:for="{{sizes}}" wx:key="index"> {{item.ratio}} </view>
</view>
</view>
<view class="enhance-container">
<text class="enhance-text">运动增强:</text>
<slider showValue bindchange="onSliderChange" class="enhance-slider" max="10" min="0" value="{{enhanceValue}}"></slider>
</view>
<text class="description-text">数值越高,视频画面越丰富 【文生视频消耗 10创意点/次】</text>
<button bindtap="textGenerateSubmit" class="generate-button">生成视频</button>
</view>
<view class="full-container" wx:if="{{currentTab==='imageToVideo'}}">
<view bindtap="uploadImage" class="upload-container">
<image class="upload-pic" mode="aspectFit" src="{{ShowPicUrl}}" wx:if="{{ShowPicUrl}}"></image>
<view class="upload-wrap" wx:else>
<image class="upload-icon" src="/images/icon-upload.png"></image>
<text class="upload-text">
<text class="upload-link">点击上传图片</text>
</text>
<text class="upload-info">只能上传jpg/png文件且不超过10MB</text>
</view>
</view>
<view class="img-input-container">
<textarea bindinput="onPicInput" class="input-box" maxlength="320" placeholder="输入提示词来描述您想要的视频内容" value="{{picInputValue}}"></textarea>
<view class="char-count">{{picCharCount}}/320</view>
</view>
<view class="enhance-container" style="margin-top: 10px;">
<text class="enhance-text">运动增强:</text>
<slider showValue bindchange="onPicSliderChange" class="enhance-slider" max="10" min="0" value="{{picEnhanceValue}}"></slider>
</view>
<text class="description-text" style="float: left;">数值越高,视频画面越丰富 【图生视频消耗 10创意点/次】</text>
<button bindtap="picGenerateSubmit" class="generate-button">生成视频</button>
</view>
<view class="chat-box" wx:if="{{currentTab==='ToText'}}">
<view class="role-switch">
<button bindtap="toggleRoleDropdown" class="role-button">{{currentRoleText}} <image class="role-icon" src="../../images/切换角色.png"></image>
</button>
<view class="role-dropdown" wx:if="{{showRoleDropdown}}">
<view bindtap="switchRole" class="role-option" data-role="{{index}}" wx:for="{{roles}}" wx:key="index">{{item.name}}</view>
</view>
</view>
<scroll-view class="chat-window" scrollIntoView="{{toView}}" scrollY="true">
<view class="message {{item.is_response?'ai':'user'}}" wx:for="{{messages[currentRole?currentRole:9]}}" wx:key="index">
<image class="avatar" src="{{item.is_response?'../../images/人工智能机器人.png':'../../images/老师教师男人.png'}}"></image>
<view class="bubble">
<view class="loading-dot" wx:if="{{item.isGenerating}}"></view>
<text bindtap="copyContent" class="content" data-content="{{item.message_content}}" wx:else>{{item.message_content}}</text>
</view>
</view>
<view id="toBottom1"></view>
<view id="toBottom2"></view>
</scroll-view>
<view class="input-area">
<input autoHeight adjust-position='true' bindinput="bindInput" class="input-field" placeholder="请输入消息..." value="{{inputMessage}}"></input>
<button bindtap="sendMessage" class="send-button">发送</button>
</view>
</view>
</view>

414
pages/aitools/aitools.wxss Normal file
View File

@@ -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);
}
}

263
pages/bot-list/bot-list.js Normal file
View File

@@ -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'
});
}
});

View File

@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "机器人监控",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white"
}

View File

@@ -0,0 +1,86 @@
<!-- pages/bot-list/bot-list.wxml -->
<view class="container">
<!-- 功能介绍区域 -->
<view class="guide-box">
<image src="/images/butterfly-icon.png" class="guide-icon" mode="aspectFit"></image>
<text class="guide-text">下载蝴蝶号视频教程:\n1. 添加下方机器人\n2. 转发视频给机器人\n3. 自动回复下载链接</text>
</view>
<!-- 状态监控动画 -->
<view class="monitoring-box">
<image src="/images/radar.png" class="radar-icon"></image>
<text>机器人状态持续监控中...</text>
<text class="update-time">{{lastUpdateTimeText}}</text>
</view>
<!-- 加载状态 -->
<view class="loading-box" wx:if="{{loading}}">
<image src="/images/loading.png" class="loading-icon"></image>
<text>数据加载中...</text>
</view>
<!-- 错误状态 -->
<view class="error-box" wx:if="{{error}}">
<text>{{error}}</text>
<button class="retry-btn" bindtap="loadBotData">重新加载</button>
</view>
<!-- 机器人列表 -->
<scroll-view
scroll-y
class="bot-list"
wx:if="{{!loading && !error}}"
refresher-enabled="{{true}}"
refresher-triggered="{{refreshing}}"
bindrefresherrefresh="onPullRefresh">
<view class="bot-list-inner">
<view class="bot-item {{item.selected ? 'selected' : ''}}"
wx:for="{{botList}}"
wx:key="wxid"
bindtap="selectBot"
data-bot="{{item}}">
<view class="status-indicator {{item.status}}"></view>
<view class="bot-info">
<text class="bot-account">{{item.account}}</text>
<text class="bot-status">{{statusText[item.status]}}</text>
<text class="bot-update">最后检测: {{item.last_check}}</text>
</view>
<view class="action-buttons">
<button
class="btn copy-btn"
catchtap="copyAccount"
data-account="{{item.account}}">
复制微信号
</button>
<button
class="btn qrcode-btn"
catchtap="showQrcode"
data-index="{{index}}">
查看二维码
</button>
</view>
</view>
</view>
</scroll-view>
<!-- 二维码弹窗 -->
<view class="qr-modal {{showQrModal ? 'show' : ''}}" bindtap="closeQrcode">
<view class="modal-container" catchtap="preventBubble">
<view class="modal-header">
<text class="modal-title">{{selectedBot.account}}</text>
<view class="close-btn" bindtap="closeQrcode">×</view>
</view>
<view class="modal-content">
<image
src="{{selectedBot.qrcode_url}}"
mode="widthFix"
class="qrcode-image"
binderror="handleImageError">
</image>
</view>
<view class="modal-footer">
<button class="save-btn" bindtap="saveQrcode">保存到相册</button>
</view>
</view>
</view>
</view>

View File

@@ -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;
}
}

View File

@@ -0,0 +1,11 @@
Page({
data: {},
onLoad: function(n) {},
onReady: function() {},
onShow: function() {},
onHide: function() {},
onUnload: function() {},
onPullDownRefresh: function() {},
onReachBottom: function() {},
onShareAppMessage: function() {}
});

View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "商业合作",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<image class="qrcode" src="https://file.guimiaokeji.com/1.png"></image>

View File

@@ -0,0 +1,9 @@
view {
margin: 0;
padding: 0;
}
.qrcode {
height: 100vh;
width: 100%;
}

245
pages/details/details.js Normal file
View File

@@ -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
});
}
}
},
});

View File

@@ -0,0 +1,9 @@
{
"usingComponents": {
"popup": "/popup/popup"
},
"navigationBarTitleText": "创意启航站",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white"
}

View File

@@ -0,0 +1,39 @@
<view class="course-detail-container">
<!-- 课程介绍 -->
<view class="course-intro">
<view class="intro-title">📚 精品资源分享</view>
<text class="intro-description">
- 🎁 价值上万的*学习资源*,让你轻松打造高质量作品
- 🛠️ 实用*免费视频剪辑工具和AI创作资料*,提高创作效率
- 💡 专业的*平台算法解析*和实战技巧,让你少走弯路
- 🔔 现在仅需 ¥29 即可获得一份精品课程
- 🩸 现在仅需 ¥599 即可获得代理资格,拥有创意站分销权限和所有课程分销和免费看
</text>
</view>
<!-- 功能按钮 -->
<view class="action-buttons">
<view class="button-row">
<button class="action-btn green-btn" bindtap="showQRCode">🎁 领取课程资源</button>
<button class="action-btn purple-btn" bindtap="showVip">🛠️ 成为代理会员</button>
</view>
<view class="button-row">
<button class="action-btn orange-btn" bindtap="showQRCode">📦 免费素材资源</button>
<button class="action-btn yellow-btn" bindtap="showQRCode">💡 运营专家解答</button>
</view>
</view>
<!-- 弹出二维码弹窗 -->
<view wx:if="{{showQRPopup}}" class="qrcode-popup-mask" animation="{{popupAnimation}}" catchtap="closeQRCode">
<view class="qrcode-popup" catchtap="preventClose">
<text class="close-icon" bindtap="closeQRCode">✕</text>
<view class="qrcode-text">
<text>📱 长按保存二维码</text>
<text>扫一扫领取资料</text>
</view>
<image class="qrcode-img" src="{{qrcodeUrl}}" mode="aspectFit" bindlongtap="saveQRCode"></image>
</view>
</view>
</view>

208
pages/details/details.wxss Normal file
View File

@@ -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;
}

182
pages/extract/extract.js Normal file
View File

@@ -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
});
}
};
}
});

View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "文案提取",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,12 @@
<view class="container">
<textarea readonly class="extracted-text" maxlength="-1" placeholder="这里将显示提取的文案" value="{{text}}"></textarea>
<view class="buttons-container">
<button bindtap="copyText" class="action-button copy">复制文案</button>
<button bindtap="rewriteText" class="action-button rewrite">AI改写</button>
</view>
</view>
<view class="center" style="color: #fff;font-size: 12px;">文字不要超出2000字哦,否则改写失败</view>
<view class="center">版权归视频原作者和平台所有</view>
<!-- <view bindtap="onAdClick" class="advertisement">
<image src="https://file.guimiaokeji.com/kecheng.png"></image>
</view> -->

View File

@@ -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%;
}

119
pages/faq/faq.js Normal file
View File

@@ -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
});
}
};
}
});

7
pages/faq/faq.json Normal file
View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "使用教程",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"usingComponents": {}
}

19
pages/faq/faq.wxml Normal file
View File

@@ -0,0 +1,19 @@
<view class="container">
<view class="title">帮助文档</view>
<view class="section">
<view class="section-title">教程列表</view>
<view class="section-content">
<navigator class="article-link" url="/pages/webview/webview?url={{item.url}}" wx:for="{{list}}" wx:key="index"> {{item.title}} </navigator>
</view>
</view>
<view class="section">
<view class="section-title">联系我们</view>
<view class="section-content help">
<text style="color: #a790e2;text-align: center;display: block;">【保存二维码扫码添加下载机器人】</text>
<image bindlongtap="saveImage" class="user-qun" data-url="https://file.guimiaokeji.com/%E5%B9%BF%E5%91%8A/1.jpg" mode="aspectFit" src="https://file.guimiaokeji.com/%E5%B9%BF%E5%91%8A/1.jpg"></image>
</view>
</view>
<!-- <view bindtap="onAdClick" class="advertisement">
<image src="https://file.guimiaokeji.com/kecheng.png"></image>
</view> -->
</view>

73
pages/faq/faq.wxss Normal file
View File

@@ -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%;
}

463
pages/index/index.js Normal file
View File

@@ -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"
};
}
});

9
pages/index/index.json Normal file
View File

@@ -0,0 +1,9 @@
{
"usingComponents": {
"popup": "/popup/popup"
},
"navigationBarTitleText": "快影下载",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white"
}

114
pages/index/index.wxml Normal file
View File

@@ -0,0 +1,114 @@
<view class="container">
<!-- 提取视频卡片 -->
<view class="card video-extract">
<view class="card-title">提取视频</view>
<view class="input-section">
<image src="../../images/link_icon.png" class="input-icon"></image>
<input placeholder="请输入视频链接,支持多平台" class="input-field" bindinput="bindVideoInput"></input>
</view>
<button class="action-button" bindtap="parseVideo">提取视频</button>
<view class="bottom-actions">
<view class="bottom-button" bindtap="extractVideoFromVideoAccount">->视频号提取</view>
<view class="bottom-button" bindtap="openDownloadRobot">->下载机器人</view>
</view>
</view>
<!-- 视频转文案卡片 -->
<view class="card text-extract">
<view class="card-title">视频转文案</view>
<!-- 单选切换 -->
<view class="radio-buttons">
<!-- 粘贴链接提取 -->
<view class="radio-option" bindtap="switchMode" data-value="link">
<view class="radio-circle {{mode === 'link' ? 'selected' : ''}}"></view>
<text>粘贴链接提取</text>
</view>
<!-- 上传本地文件 -->
<view class="radio-option" bindtap="switchMode" data-value="upload">
<view class="radio-circle {{mode === 'upload' ? 'selected' : ''}}"></view>
<text>上传本地文件</text>
</view>
</view>
<!-- 链接输入框 -->
<view wx:if="{{mode === 'link'}}" class="input-section">
<image src="../../images/link_icon.png" class="input-icon"></image>
<input placeholder="请输入视频链接,支持多平台" class="input-field" bindinput="bindVideoInput"></input>
</view>
<!-- 文件上传框 -->
<view wx:if="{{mode === 'upload'}}" class="input-section">
<view class="upload-button" bindtap="uploadFile">
<image src="../../images/upload_icon.png" class="input-icon"></image>
</view>
</view>
<button class="action-button" bindtap="extractText">提取文案</button>
</view>
</view>
<!-- 文案提取记录按钮 放在最后的</view>标签前 -->
<!-- 记录按钮 -->
<view class="record-button-container">
<view class="record-button" bindtap="showRecordMask">
<text class="record-text">文案提取记录</text>
</view>
</view>
<!-- 记录蒙版 -->
<view class="record-mask {{showMask ? 'show' : ''}}" bindtap="hideMask">
<view class="record-content" catchtap="preventDefault">
<!-- 标题栏 -->
<view class="record-header">
<text>提取记录</text>
<view class="close-btn" bindtap="hideMask">×</view>
</view>
<!-- 记录列表 -->
<scroll-view
scroll-y="true"
class="record-list"
bindscrolltolower="loadMore"
lower-threshold="50">
<view wx:for="{{records}}"
wx:key="id"
class="record-item"
bindtap="goToExtract"
data-text="{{index}}">
<view class="record-item-left">
<view class="record-num">{{index + 1}}</view>
<view class="record-info">
<text class="record-text" style="color:rgb(61, 61, 61)">{{item.preview}}</text>
<text class="record-time">{{item.created_at}}</text>
</view>
</view>
<view class="record-status {{item.status === 'completed' ? 'completed' : 'False'}}">
{{item.status === 'completed' ? '完成' : '失败'}}
</view>
</view>
<!-- 加载更多 -->
<view class="loading" wx:if="{{isLoading}}">
<view class="loading-dots">
<view class="dot"></view>
<view class="dot"></view>
<view class="dot"></view>
</view>
<text>加载中...</text>
</view>
</scroll-view>
</view>
</view>
<popup
wx:if="{{showPopup}}"
popupType="{{popupType}}"
popupContent="{{popupContent}}"
buttonText="查看详情"
targetUrl="/pages/details/details"
/>

358
pages/index/index.wxss Normal file
View File

@@ -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);
}
}

11
pages/invite/invite.js Normal file
View File

@@ -0,0 +1,11 @@
Page({
data: {},
onLoad: function(n) {},
onReady: function() {},
onShow: function() {},
onHide: function() {},
onUnload: function() {},
onPullDownRefresh: function() {},
onReachBottom: function() {},
onShareAppMessage: function() {}
});

3
pages/invite/invite.json Normal file
View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

1
pages/invite/invite.wxml Normal file
View File

@@ -0,0 +1 @@
<text>pages/invite/invite.wxml</text>

0
pages/invite/invite.wxss Normal file
View File

View File

@@ -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
});
}
};
}
});

View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "邀请奖励",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,33 @@
<view class="container">
<view class="section1">
<view class="item">
<text class="title">已邀请:</text>
<text class="count">{{inviteCount}} 人</text>
</view>
<view class="item">
<text class="title">邀请奖励:</text>
<text class="count">{{number}} 元</text>
</view>
</view>
<view class="section2">
<text class="subtitle">邀请规则:</text>
<view class="description">每邀请一个新用户使用小程序奖励,</view>
<view class="description">分享给好友使用即可获得奖励。</view>
<view class="description">邀请的用户首次开通会员您将获得80%返利。</view>
<view class="description">后续续费您将获得40%奖励。</view>
<view class="description">提现门槛100元。</view>
<view class="description warning">禁止任何形式的作弊行为,</view>
<view class="description warning">如发现使用外挂等违规行为,</view>
<view class="description warning">将取消活动资格。</view>
<view class="countdown">活动限时有效</view>
<view class="invite-path">
<text class="path-text" bindtap="copyPath" selectable="true">/pages/index/index?uuid={{uuid}}</text>
</view>
</view>
<view class="button-container">
<button class="reward-button reward-button1" openType="contact">提现</button>
<button class="reward-button reward-button2" openType="share">邀请好友</button>
</view>
</view>

View File

@@ -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); /* 深蓝色渐变 */
}

164
pages/mine/mine.js Normal file
View File

@@ -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
});
}
};
}
});

8
pages/mine/mine.json Normal file
View File

@@ -0,0 +1,8 @@
{
"navigationBarTitleText": "个人中心",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"custom-tab-bar": "/custom-tab-bar/index",
"usingComponents": {}
}

70
pages/mine/mine.wxml Normal file
View File

@@ -0,0 +1,70 @@
<view class="center">
<view class="blue-top">
<view class="user-card">
<view class="card-top">
<view class="user-top">
<view class="user-vip" style="position:relative;">
<image class="user-pic" src="/images/老师教师男人.png"></image>
</view>
<view class="user-board">
<button bindgetuserinfo="getUserInfo" class="user-name" openType="getUserInfo" wx:if="{{!hasUserInfo}}">点击登陆</button>
<view class="user-name" userSelect="true" wx:if="{{hasUserInfo}}">ID:{{uuid}}</view>
</view>
</view>
</view>
<view class="card-bottom">
<view class="left">
<view class="count">
<text class="num">{{defaultDailyFreeParseNum}} </text>
</view>
<!-- <text bindtap="opennum" class="txt">创意点</text> -->
<text class="txt">创意点</text>
</view>
<view class="right">
<view class="count">
<text class="num" style="color:rgb(253, 217, 10)" wx:if="{{isVip}}">{{formattedEndTime}}</text>
<text class="num" bindtap="openvip" wx:else>开通会员</text>
<!-- <text class="num" wx:else>Null</text> -->
</view>
<text class="txt" style="color:rgb(253, 217, 10)" wx:if="{{isVip}}">尊贵VIP</text>
<text class="txt" wx:else>您还不是会员</text>
</view>
</view>
</view>
</view>
<!-- <navigator class="center-list-item" url="/pages/vip_recharge/vip_recharge"> -->
<view class="center-list">
<navigator class="center-list-item" url="/pages/vip_recharge/vip_recharge">
<image class="icon1" src="../../images/huiyuan.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">开通会员</text>
</navigator>
<navigator class="center-list-item" url="/pages/details/details">
<image class="icon1" src="../../icons/lw.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">新人礼包</text>
</navigator>
<view bindtap="showExchangeModal" class="center-list-item">
<image class="icon1" src="../../images/兑换码.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">卡密兑换</text>
</view>
<navigator class="center-list-item" url="/pages/invite_incentive/invite_incentive">
<image class="icon1" src="../../images/人民币.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">分享奖励</text>
</navigator>
<!-- <navigator class="center-list-item" url="/pages/business_cooperation/business_cooperation">
<image class="icon1" src="../../images/代理商.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">商业合作</text>
</navigator> -->
<button class="center-list-item" openType="contact">
<image class="icon1" src="../../images/客服.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">联系客服</text>
</button>
<navigator class="center-list-item" url="/pages/faq/faq">
<image class="icon1" src="../../images/帮助.png" style="width: 30px; height: 30px;"></image>
<text class="list-text">使用教程</text>
</navigator>
</view>
<view class="relief">© 2024 创作者服务</view>
<view class="buttom" style="height: 65px;"></view>
</view>

248
pages/mine/mine.wxss Normal file
View File

@@ -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;
}

11
pages/payment/payment.js Normal file
View File

@@ -0,0 +1,11 @@
Page({
data: {},
onLoad: function(n) {},
onReady: function() {},
onShow: function() {},
onHide: function() {},
onUnload: function() {},
onPullDownRefresh: function() {},
onReachBottom: function() {},
onShareAppMessage: function() {}
});

View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<text>pages/payment/payment.wxml</text>

View File

11
pages/users/users.js Normal file
View File

@@ -0,0 +1,11 @@
Page({
data: {},
onLoad: function(n) {},
onReady: function() {},
onShow: function() {},
onHide: function() {},
onUnload: function() {},
onPullDownRefresh: function() {},
onReachBottom: function() {},
onShareAppMessage: function() {}
});

3
pages/users/users.json Normal file
View File

@@ -0,0 +1,3 @@
{
"usingComponents": {}
}

1
pages/users/users.wxml Normal file
View File

@@ -0,0 +1 @@
<text>pages/users/users.wxml</text>

0
pages/users/users.wxss Normal file
View File

554
pages/video/video.js Normal file
View File

@@ -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);
// 错误处理
}
});
},
});

10
pages/video/video.json Normal file
View File

@@ -0,0 +1,10 @@
{
"navigationBarTitleText": "视频提取浏览",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"custom-tab-bar": "/custom-tab-bar/index",
"usingComponents": {
"popup": "/popup/popup"
}
}

28
pages/video/video.wxml Normal file
View File

@@ -0,0 +1,28 @@
<view class="wrap">
<textarea autoHeight class="video-title" value="{{preview}}"></textarea>
<video class="video-box" poster="{{dataImage}}" src="{{dataUrl}}" wx:if="{{dataUrl!=''}}"></video>
<image class="video-box" src="{{dataImage}}" wx:else></image>
<view style="font-size: 10px; text-align: center; color: #a790e2;font-size: 15px;">视频太大的建议复制地址到浏览器自行下载</view>
<view style="font-size: 10px; text-align: center;color: #a790e2;font-size: 15px;">保存失败的也复制链接到浏览器下载</view>
<view style="width: 100%;"></view>
<view class="buttons-row">
<button bindgetuserinfo="postSave" class="parsing" openType="getUserInfo">保存到相册</button>
<button bindtap="copyUrl" class="parsing copy-url">复制地址</button>
</view>
<view class="buttons-row">
<button bindtap="extractText" class="parsing extract-text" data-url="{{dataUrl}}" disabled="{{isExtracting}}">视频文案提取</button>
<button bindtap="goBack" class="parsing go-back">返回首页</button>
</view>
<view class="center" style="color: #a790e2; margin-top: 10px;font-size: 13px;">版权归视频原作者所有</view>
<!-- <view bindtap="onAdClick" class="advertisement">
<image src="https://file.guimiaokeji.com/kecheng.png"></image>
</view> -->
</view>
<popup
wx:if="{{showPopup}}"
popupType="{{popupType}}"
popupContent="{{popupContent}}"
buttonText="查看详情"
targetUrl="/pages/details/details"
/>

89
pages/video/video.wxss Normal file
View File

@@ -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%;
}

View File

@@ -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) => {
}
});
}
});

View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "违规词识别",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"custom-tab-bar": "/custom-tab-bar/index"
}

View File

@@ -0,0 +1,85 @@
<view class="container">
<!-- 顶部按钮组 -->
<view class="header">
<view class="button-group">
<button class="detect-button active" data-type="text" bindtap="switchDetectType">文本识别</button>
<button class="detect-button" data-type="audio" bindtap="switchDetectType">音频识别</button>
<button class="detect-button" data-type="video" bindtap="switchDetectType">视频识别</button>
</view>
</view>
<!-- 输入框区域 -->
<view class="input-area">
<textarea class="input-field"
bindinput="bindInput"
value="{{inputValue}}"
placeholder-class="b-palceholder"
placeholder="输入或粘贴文本,自动识别违规内容并智能修改..."
maxlength="20000">
</textarea>
<!-- 字数统计及提示信息 -->
<view class="text-counter">
<text>{{inputLength}} / {{maxLength}}</text>
<text wx:if="{{inputLength > maxLength}}" class="error-text">内容不能超过 {{maxLength}} 字节</text>
</view>
<!-- 操作按钮 第一行:检测和智能修改 -->
<view class="button-group">
<button class="detect-button" disabled="{{detectButtonDisabled}}" bindtap="detectText">开始检测</button>
<button class="modify-button" disabled="{{modifyButtonDisabled}}" bindtap="modifyContent">一键合规</button>
</view>
<!-- 操作按钮 第二行:复制和清空 -->
<view class="button-group">
<button class="copy-button" bindtap="copyContent">复制内容</button>
<button class="clear-button" bindtap="clearInput">清空输入</button>
</view>
<view class="disclaimer">
<text>单次消耗3创意点。检测中请勿退出本页面很快完成</text>
</view>
</view>
<view class="report-container" wx:if="{{detectResult}}">
<!-- 报告标题 -->
<view class="report-title">检测报告</view>
<!-- 检测结果 -->
<view class="result-summary">
<text class="{{detectResult.conclusion === '合规' ? 'compliant' : 'non-compliant'}}">
检测结果: {{detectResult.conclusion}}
</text>
</view>
<!-- 表格 -->
<view class="result-table">
<!-- 表头 -->
<view class="table-row table-header">
<view class="table-cell">疑似命中</view>
<view class="table-cell">关键词</view>
<view class="table-cell">字符位置</view>
<view class="table-cell">置信度</view>
</view>
<!-- 表格内容 -->
<block wx:for="{{detectResult.data}}" wx:key="index">
<view class="table-row">
<view class="table-cell">{{item.reason}}</view>
<view class="table-cell">{{item.keyword}}</view>
<view class="table-cell">{{item.position}}</view>
<view class="table-cell">{{item.confidence}}</view>
</view>
</block>
</view>
<!-- 设置底部间距 -->
<view class="bottom-space"></view>
<view class="disclaimer">
<text>功能介绍:本功能用于检测文本中可能存在的违规内容,帮助用户规避潜在风险。\n</text>
<text>免责声明:本检测结果仅供参考,具体结果请以实际情况为准,平台不承担由此产生的任何法律责任。</text>
</view>
</view>
</view>

View File

@@ -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;
}

View File

@@ -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 () {},
});

View File

@@ -0,0 +1,7 @@
{
"navigationBarTitleText": "会员中心",
"navigationBarBackgroundColor": "#222238",
"navigationBarTextStyle": "white",
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,32 @@
<view class="container" wx:if="{{show}}">
<view class="status-section" wx:if="{{isVip}}">
<view class="user-vip " style="position:relative;">
<image class="user-pic" src="/images/老师教师男人.png"></image>
<view style="width: 200px;text-align: left; color: rgb(253, 217, 10);font-weight: 800;">尊贵VIP</view>
</view>
<view class="right">
<view>开通时间:{{startTime}}</view>
<view>到期时间:{{endTime}}</view>
<button bindtap="open_button" class="renew-button small-button" data-price="{{cards[4].price}}" data-type="{{cards[4].type}}">续费</button>
</view>
</view>
<view class="recharge-options">
<text class="title">选择订阅套餐:</text>
<view bindtap="onRecharge" class="card" data-price="{{item.price}}" data-type="{{item.type}}" wx:for="{{cards}}" wx:key="index">
<image class="card-icon" src="https://file.guimiaokeji.com/VIP.png" wx:if="{{!isQuota}}"></image>
<image class="card-icon" src="../../images/积分.png" wx:if="{{isQuota}}"></image>
<view class="card-content">
<text class="card-title">{{item.title}}</text>
<view class="price-wrapper">
<text class="original-price">原价¥{{item.price*2}}</text>
<text class="current-price">限时¥{{item.price}}</text>
</view>
<view class='desc'>{{item.description}}</view>
</view>
<button bindtap="open_button" class="open-button" data-price="{{item.price}}" data-type="{{item.type}}" wx:if="{{selectedType===item.type}}">开通</button>
</view>
</view>
<view class="footer">
<text>成为会员,享受无限使用功能特权,体验更多专属内容!</text>
</view>
</view>

View File

@@ -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;
}