赞
踩
随着科技的发展,人工智能将会是以后的主流方向,ai绘图、chatgpt高科技先后出台,都获得了火爆的发展,因此想借着势头开发一款主打ai绘图的app+小程序
因为后面需要多平台发布,而尽可能减少开发成本,因此选定了uniapp框架作为开发框架,前期目标是 android、ios以及 微信小程序三个平台,android平台名称:易绘,IOS端名称:易绘ai作画,微信小程序端:栾青易绘ai绘画。
有两个方向,一个是百度云,一个是腾讯云,各有优劣,价格方面腾讯云更优惠,但百度推出的时间更早。因为前期接入的是百度云的sdk,所以还是选择了百度云sdk。
主打ai绘图(用文字生成图片),次功能头像制作、老照片修复处理,真人动漫化头像,二次元图片,壁纸美图。开放了一部分功能免费使用,以留住用户。
<template> <view> <uni-nav-bar :statusBar="true" :border="true" :fixed="true" :leftWidth="500"> <template v-slot:left class="uni_flex_row_align_left"> <view class="uni_flex_row_align_left uni_14px uni_font_medium ml14" v-if="isLogined" @click="gotoTaskList"> <image src="@/static/icon/icon_task.png" style="width: 40rpx;height: 40rpx;margin-left: 10rpx;"></image> <text class="uni_15px ml6 uni_color_666">任务列表</text> <text class="ml4 mr2">(</text> <text class="uni_15px" style="color: #f43533;">{{taskNum}}</text> <text class="ml2">)</text> </view> <view v-else class="uni_14px uni_font_regular ml14 uni_color_666"> 用文字绘出梦想,用梦想成就未来 </view> </template> </uni-nav-bar> <!-- 主绘制面板视图 --> <view class="page_root"> <view style="width: 690rpx;height: 15rpx;"></view> <!-- 输入框内容 START --> <view class="input_box"> <!-- 文本输入框 --> <textarea class="textarea_style uni_font_light" :maxlength="maxNum" placeholder="输入你的奇思妙想,AI智能为你作画" v-model="inputContent"></textarea> <!-- 信息操作栏 START --> <view class="input_action_bar"> <view class="uni_flex_row_align_left" @click="startVoice"> <uni-icons type="mic-filled" color="#9686FB" size="19"></uni-icons> <text class="uni_14px ml4 uni_font_regular input_func_text" style="color: #9686FB;">语音输入</text> </view> <view class="uni_flex_row_align_right"> <view class="uni_flex_row_align_left" v-if="inputContent"> <text class="num g1">{{inputContent.length || 0}}</text> <text class="num g2 ml4 mr4">/</text> <text class="num g2">{{maxNum}}</text> </view> <view class="uni_flex_row_align_right" v-else @click="gotoSchool"> <uni-icons type="help" size="21" color="#9686FB"></uni-icons> <text class="uni_14px ml4 uni_font_regular input_func_text" style="color: #9686FB;">教程帮助</text> </view> <view class="sp_line" v-if="inputContent"></view> <!-- 清除 --> <uni-icons type="clear" v-if="inputContent" color="#9686FB" size="19" @click="onClear" click="ml10"></uni-icons> <!-- 复制 --> <uni-icons type="paperclip" v-if="inputContent" color="#9686FB" size="19" class="ml20" @click="onCopy"></uni-icons> </view> </view> <!-- 信息操作栏 START --> </view> <!-- 输入框内容 END --> <!-- 示例 START --> <view class="uni_flex_row_between mt6" v-if="exampleObj.id"> <!-- 示例内容 --> <text class="tip_text" @click="onClickExample">示例:{{exampleObj.content}}</text> <!-- 刷新示例数据 --> <uni-icons :animation="animationData" type="loop" color="#9686FB" class="refresh_icon" size="18" @click="queryExample"></uni-icons> </view> <!-- 示例 END --> <!-- 关键字模块 START --> <view class="mt18 uni_flex_row_between_center"> <view class="uni_flex_row_align_left"> <image src="../../static/icon/icon_keyword.png" style="width: 36rpx; height: 36rpx;"></image> <text class="ml4 uni_16px uni_color_666">可以试试</text> </view> <view class="uni_flex_row_align_right"> <uni-icons type="loop" color="#9686FB" size="17" @click="queryStyles"></uni-icons> <text class="ml4 uni_13px change_next" @click="queryStyles">换一批</text> </view> </view> <view class="uni_flex_warp uni_flex_row_between mt8"> <view v-for="(keyword,id) in keywords" v-bind:key="id" class="tag_item" @click="onClickKeyword(keyword)">{{keyword.name}}</view> </view> <view class="uni_flex_row_align_left mt20"> <text class="uni_16px uni_color_666">高级设置</text> <switch style="transform: scale(0.6);" color="#9686FB" :checked="isShowHeightSetting" @change="setSettingOfShowHeight"></switch> </view> <!-- 画作风格 START --> <view class="uni_flex_row_between mt10" v-if="isShowHeightSetting"> <view class="uni_flex_row_align_left"> <image src="../../static/icon/icon_style.png" style="width: 34rpx;height: 34rpx;"></image> <text class="ml4 uni_15px uni_color_666">绘图风格</text> <text class="ml4 uni_11px uni_color_bbb">(可选,默认不限风格)</text> </view> <view class="uni_flex_row_align_center select_button" @click="showPickerDataObj(true, 'style')"> <text class="uni_14px uni_font_regular uni_color_app1">{{imageStyle.tag || '请选择风格'}}</text> <uni-icons type="right" color="#9686FB" class="ml6"></uni-icons> </view> </view> <!-- 画作风格 END --> <!-- 生成张数 START --> <view class="uni_flex_row_between mt12" v-if="isShowHeightSetting"> <view class="uni_flex_row_align_left"> <image src="../../static/icon/icon_number.png" style="width: 34rpx;height: 34rpx;"></image> <text class="ml4 uni_15px uni_color_666">图片生成张数</text> <text class="ml4 uni_11px uni_color_bbb">(可选,默认1张)</text> </view> <view class="uni_flex_row_align_center select_button" @click="showPickerDataObj(true, 'number')"> <text class="uni_14px uni_font_regular uni_color_app1">{{createAiNumber + ' 张' || '请选择张数'}}</text> <uni-icons type="right" color="#9686FB" class="ml6"></uni-icons> </view> </view> <!-- 生成张数 END --> <!-- 画作分辨率 START --> <view class="uni_flex_row_between mt12" v-if="isShowHeightSetting"> <view class="uni_flex_row_align_left"> <image src="../../static/icon/icon_ratio.png" style="width: 34rpx;height: 34rpx;"></image> <text class="ml4 uni_15px uni_color_666">分辨率</text> <text class="ml4 uni_11px uni_color_bbb">(可选,默认1024*1536)</text> </view> <view class="uni_flex_row_align_center select_button" @click="showPickerDataObj(true, 'ratio')"> <text class="uni_14px uni_font_regular uni_color_app1">{{imageRatio.tag || '请选择分辨率'}}</text> <uni-icons type="right" color="#9686FB" class="ml6"></uni-icons> </view> </view> <!-- 画作分辨率 END --> <!-- 开始绘画按钮 --> <view class="uni_flex_row_align_center mt30"> <view class="start_button able" @click="onCheckStatusAndShowDialog"> <text class="uni_font_regular" style="letter-spacing: 2rpx;">{{isLogined ? 'Ai 绘画创作':'登录后使用Ai绘画功能'}}</text> </view> <uni-badge :text="freeNum" absolute="rightTop" size="normal" :offset="[5,5]"> <view v-if="freeNum>0" class="start_test_btn" @click="showTestDialog(true)"> 免费体验 </view> <view v-else class="start_test_btn_unable"> 暂不可用 </view> </uni-badge> </view> <!-- 客服信息 --> <view class="customer uni_12px mt10 uni_color_999"> <text @click="onCopy('729913920')">QQ交流学习群:729913920 (点击复制)</text> </view> </view> <!-- 数据选择弹框 --> <uni-popup type="bottom" ref="pickerDataObj"> <view class="popup_dialog_style"> <view class="popup_dialog_title"> <text class="uni_color_999 uni_font_regular" @click="showPickerDataObj(false)">取消</text> <text class="uni_color_000 uni_font_medium" v-if="dialogType === 'number'">请选择画作生成张数</text> <text class="uni_color_000 uni_font_medium" v-else-if="dialogType === 'style'">请选择画作风格</text> <text class="uni_color_000 uni_font_medium" v-else-if="dialogType === 'ratio'">请选择画作分辨率</text> <text class="uni_color_222 uni_font_regular" @click="onPickerData('',true)">确定</text> </view> <view class="uni_flex_warp uni_flex_row_between dialog_data_view" v-if="dialogType === 'number'"> <text v-if="dialogType === 'number'" v-for="(dateItem, index) in dialogData" v-bind:key="index" class="style_item_big" :class="tempImageNumber === dateItem ? 'style_checked':''" @click="onPickerData(dateItem)"> {{dateItem}}张 </text> </view> <view class="uni_flex_warp uni_flex_row_align_left" v-if="dialogType === 'style'"> <text v-for="(ratio,index) in styles" v-bind:key="index" class="style_item_big" :class="tempImageStyle.id === ratio.id ? 'style_checked':''" @click="onPickerData(ratio)"> {{ratio.tag}} </text> </view> <view class="uni_flex_warp uni_flex_row_between" v-if="dialogType === 'ratio'"> <text v-for="(ratio,index) in ratios" v-bind:key="index" class="style_item_big" :class="tempImageRatio.id === ratio.id ? 'style_checked':''" @click="onPickerData(ratio)"> {{ratio.tag}} </text> </view> </view> </uni-popup> <!-- 开始AI绘图任务后的状态展示弹窗 --> <uni-popup ref="taskStatusDialog" type="center"> <view class="task_status_dialog"> <image src="../../static/img_ai_status_dialog.gif" style="width: 400rpx;height: 160rpx;"></image> <view class="uni_14px uni_font_regular">{{aiRequestStatusText}}</view> <view class="uni_flex_row_align_center uni_flex_warp mt10 ml10 mr10"> <view v-for="(wait,wid) in waitTime" v-bind:key="wid" class="white_point"></view> </view> <view class="mt4 uni_16px uni_font_medium">{{waitTime.length}}s</view> </view> </uni-popup> <uni-popup ref="dialogTest" type="bottom"> <view class="test_dialog uni_flex_col_align_center"> <view class="uni_font_medium uni_17px uni_color_333 mt10 mb15">免费体验说明</view> <text class="uni_15px uni_color_999 ml5 mr5" style="letter-spacing: 2rpx;"> 全系统今日总共还 <text class="uni_font_regular uni_color_666">剩余{{freeNum}}次免费体验机会,</text> 系统每天晚上20点下放随机数量的免费体验次数,当天用完即止,每个账号可先到先得免费使用一次ai绘图功能(注:为避免占用,每个账号每天有且只有一次免费体验机会) </text> <text class="dialog_btn bg1 mt30" @click="onConfirmTest">立即免费创作</text> <text class="dialog_btn bg3 mt20 mb15" @click="showTestDialog(false)">取消</text> </view> </uni-popup> <!-- 提示信息弹窗 --> <uni-popup ref="message" type="message"> <uni-popup-message type="error" :message="messageText" :duration="3200"></uni-popup-message> </uni-popup> <uni-popup ref="confirmDialog" type="center"> <view class="uni_flex_col_align_center"> <view class="confirm_dialog_bg mb10"> <view class="uni_18px uni_color_000 uni_font_medium mt10 mb15">温馨提示</view> <view class="uni_16px uni_color_666 ml10 mr10" style="letter-spacing: 2rpx;"> <text>您正在使用易绘的Ai绘画功能,此功能按次收费,本次操作将从您的易绘账号上</text> <text class="uni_16px uni_font_regular ml2 uni_color_red">扣除 {{price * createAiNumber}} 钻石</text> <text class="ml2">({{createAiNumber}}张图) 是否已知悉并确认?</text> </view> <!-- <view class="uni_16px uni_color_666" v-if="createAiNumber <= 1">您正在使用Ai绘画功能,AI绘图功能单次需扣除 {{price}} 钻石,是否确定?</view> --> <!-- <view class="uni_16px uni_color_666" v-else>您正在使用Ai绘画功能,当前您设置了同时生成{{createAiNumber}}张图片,本次需扣除 {{price * createAiNumber}} 钻石,是否确定并开始绘画?</view> --> <text class="dialog_btn bg1 mt30 mb20" @click="onClickStartButton('pay')">确认并开始绘画</text> <text v-if="couponNum>0" class="dialog_btn bg2 mb25" @click="onClickStartButton('coupon')"> 使用免费券抵扣<text class="uni_12px uni_color_fff uni_font_light">({{couponNum}}张)</text> </text> <!-- <text class="dialog_btn bg3 mt20 mb15" @click="showTestDialog(false)">取消绘画</text> --> </view> <uni-icons type="close" size="45" color="#ffffff" @click="showAiConfirmDialog(false)"></uni-icons> </view> </uni-popup> </view> </template> <script> import api from '../../common/network/api/api.js'; import dataBase from '../../common/database.js'; import UI from '../../common/UI.js'; import handle from '../../common/handle.js'; export default { data() { return { maxNum: 100, inputContent: '', // 输入的描述内容 errorTip: '', // 错误提示 exampleObj: {}, // 示例 tempImageRatio: {}, tempImageStyle: {}, tempImageNumber: 1, imageStyle: {}, imageRatio: {}, keywords: [], // 关键字列表 // simpleKeyWords:[], // 简单列表的关键字 styles: [], // 风格列表 ratios: [] ,// 分辨率列表 countAiTask: undefined, // ai绘图状态弹窗的计时器 waitTime: [], // ai绘图状态弹窗的 等待时间计时 waiting: '', // 预估等待时间 ableReload: true, // 是否可以重新加载 aiRequestStatusText: '', // AI请求 messageTimeoutTask: undefined, // 临时消息的计时器对象 aiStatus: 0, // AI绘图状态 0|队列中 1|已完成 aiId: '', // 唯一ID taskNum: 0, createAiNumber: 1, // 申请AI绘画的图片数量 isLogined: false, price: 0, dialogType: '', dialogData: [], animationData:{}, freeNum: 0, // 系统免费ai体验次数 isShowHeightSetting: false, } }, onShow() { this.init(); this.getSettingOfShowHeight(); console.error("环境:",process.env.NODE_ENV) }, onLoad() { uni.$on('networkResume',()=>{ this.init(); }); }, onUnload() { uni.$off('networkResume'); this.showTaskStatusDialog(false); }, methods: { getSettingOfShowHeight(){ let temp = dataBase.queryStorage('heightSetting') || false; this.isShowHeightSetting = temp; return temp; }, setSettingOfShowHeight(e){ this.isShowHeightSetting = e.detail.value; dataBase.insertStorage('heightSetting',e.detail.value); }, showAiConfirmDialog(show){ if(show) this.$refs.confirmDialog.open(); else this.$refs.confirmDialog.close(); }, // 确定体验 onConfirmTest(){ this.showTestDialog(false); }, showTestDialog(show){ if(show){ this.onCheckStatusAndShowDialog('free'); // this.$refs.dialogTest.open(); }else{ this.$refs.dialogTest.close(); } }, init(){ // 允许重新加载 this.ableReload = true; this.isLogined = dataBase.queryLoginStatus(); this.queryStyles(); // 查询风格/分辨率等 this.queryExample(); // 查询示例 if(this.isLogined){ this.queryTaskNum(); // 查询任务数据 api.doPost({action:'queryUnreadMessageNumber'}).then(res=>{ let unread = res.data.unread; unread > 0 ? uni.showTabBarRedDot({index: 4}) : uni.hideTabBarRedDot({index: 4}); }); } }, gotoSchool(){ console.error("前往学院"); uni.navigateTo({ url:'/pages_sub/center/pages/school/school' }); }, // 前往任务列表页面 gotoTaskList(){ uni.navigateTo({ url:'/pages_sub/ai/pages/ai-task-list/ai-task-list' }); }, // 查询任务数量 queryTaskNum(){ api.doPost({action:'queryAITaskNumOrList'}).then(res=>{ this.taskNum = res.data.num; this.couponNum = res.data.freeConpon; }); }, // 点击主类关键字 onClickKeyword(item){ if(this.inputContent && this.inputContent.length > 0){ let lastWord = this.inputContent.substring(this.inputContent.length - 1, this.inputContent.length); if(lastWord === ','){ this.inputContent = this.inputContent.substring(0, this.inputContent.length - 1); } } this.inputContent += (this.inputContent ? ',':'') + item.name; // 限制字数 if(this.inputContent.length > this.maxNum){ this.inputContent = this.inputContent.substring(0, this.maxNum); } }, // 选择风格 onPickerData(style, confirm){ if(confirm){ this.showPickerDataObj(false); switch(this.dialogType){ case 'number': this.createAiNumber = this.tempImageNumber; break; case 'style': this.imageStyle = this.tempImageStyle; break; case 'ratio': this.imageRatio = this.tempImageRatio; break; } }else{ switch(this.dialogType){ case 'number': this.tempImageNumber = style; break; case 'style': this.tempImageStyle = style; break; case 'ratio': this.tempImageRatio = style; break; } } }, // 显示和隐藏任务进度弹窗 showTaskStatusDialog(show){ const $that = this; if(this.countAiTask){ clearInterval(this.countAiTask); } if(show){ this.waitTime = []; $that.countAiTask = setInterval(()=>{ $that.waitTime.push(""); // 是否可以重新加载 if($that.ableReload){ $that.queryAiResult(); } }, 2000); $that.$refs.taskStatusDialog.open(); }else{ $that.inputContent = ''; $that.$refs.taskStatusDialog.close(); } }, // 检查条件以及展示价格确认 onCheckStatusAndShowDialog(mode){ const $that = this; // 未登录 if(!this.isLogined){ uni.showModal({ title: '提示', content: '需要登录才能使用此功能,是否前往登录?', confirmText: '前往登录', cancelText: '暂不登录', complete(res) { if(res.confirm){ uni.navigateTo({ url:'/pages_sub/login/pages/login/login' }); return "NO"; } } }); return "NO"; } if(!this.inputContent){ this.messageText = '请在下方输入画作的文字描述' this.$refs.message.open(); return "NO"; } if(this.price > 0 && mode !== 'free'){ // 开始ai的确认弹窗 this.showAiConfirmDialog(true); return "NO"; } $that.onClickStartButton(mode); return "OK" }, // 开始AI绘画 onClickStartButton(mode){ // 隐藏确认对话框 this.showAiConfirmDialog(false); uni.showLoading({ title:'正在提交云端', }); let data = { action:'queryAiTask', text: this.inputContent, ratio: this.imageRatio.tag, style: this.imageStyle.tag, num:this.createAiNumber, mode: mode // 免费 付费 }; api.doPost(data).then(res=>{ uni.hideLoading(); if(res.code === 208){ handle.gotoRecharge(res.message); return; } this.showTaskStatusDialog(true); this.aiStatus = res.data.status; this.aiId = res.data.aid; this.aiRequestStatusText = '已成功连接云端'; // 队列中 if(this.aiStatus === 0){ this.waiting = res.data.waiting; this.aiRequestStatusText = "正在刻画绘图...,预估时长【"+res.data.waiting+"】"; this.queryTaskNum(); } // 已完成 else{ this.aiRequestStatusText = '已完成AI绘图作画任务'; this.showTaskStatusDialog(false); console.error("AI绘图完成",res.data); uni.navigateTo({ url:'/pages_sub/ai/pages/preview-ai-img/preview-ai-img?data='+JSON.stringify(res.data) }); } },err=>{ uni.hideLoading(); }); }, // 单纯查询ai绘图状态 queryAiResult(){ this.ableReload = false; console.error("AI任务查询开始"); api.doPost({action:'queryAiResult',aid:this.aiId}).then(res=>{ console.error("AI任务查询结果:",res); let code = res.code; if(code === 200){ this.showTaskStatusDialog(false); uni.navigateTo({ url:'/pages_sub/ai/pages/preview-ai-img/preview-ai-img?data='+JSON.stringify(res.data) }); }else{ this.ableReload = true; } }, err=>{ console.error("AI任务查询失败:",err); this.ableReload = false; this.showTaskStatusDialog(false); }).catch(e=>{ console.error("AI任务发生异常:",e); }); }, // 清除内容 onClear(){ this.inputContent = ''; }, // 复制内容 onCopy(text){ uni.setClipboardData({ data: this.inputContent, success() { uni.showToast({ title:'复制成功~', icon:'success' }); } }); }, // 显示/关闭数据选择弹窗 showPickerDataObj(show, type){ if(show){ this.dialogType = type; switch(this.dialogType){ case 'number': this.dialogData = [1,2,3,4,5,6]; break; case 'style': this.dialogData = this.styles; break; case 'ratio': this.dialogData = this.ratios; break; } this.$refs.pickerDataObj.open(); }else{ this.$refs.pickerDataObj.close(); } }, // 点击示例文字时,会把示例内容带入到输入框里 onClickExample(){ const $that = this; // 判断示例是否存在内容 if(this.exampleObj.content){ // 如果输入框内已有内容,就弹出对话框提示用户是否确定要用示例替换 if(this.inputContent){ uni.showModal({ title:'温馨提示', content:"是否确定要用示例的内容「替换」输入框描述内容?", confirmText: '确认替换', cancelText: '取消', complete(res) { if(res.confirm){ $that.inputContent = $that.exampleObj.content; } } }) }else{ this.inputContent = this.exampleObj.content; } } }, // 加载/刷新示例 queryExample(){ let data = { action:'queryExample', } // 判断是否有id if(this.exampleObj && this.exampleObj.id){ data.id = this.exampleObj.id; } api.doPost(data).then(res=>{ this.exampleObj = res.data; }); }, // 查询风格列表 queryStyles(){ api.doPost({action:'queryStyles'}).then(res=>{ this.styles = res.data.styles || []; this.ratios = res.data.ratios || []; this.keywords = res.data.keywords || []; this.price = res.data.price || 0; this.freeNum = res.data.freeNum; if(this.styles && this.styles.length > 0){ this.imageStyle = this.styles[0]; this.tempImageStyle = this.styles[0]; } if(this.ratios && this.ratios.length > 0){ this.imageRatio = this.ratios[0]; this.tempImageRatio = this.ratios[0]; } }); }, startVoice() { if(!this.isLogined){ UI.gotoLoginWithComfirmDialog(); return; } // #ifdef APP-PLUS // 开始语音识别 const $that = this; plus.speech.startRecognize({ engine: 'baidu' }, (e => { if (e) { $that.inputContent += e; // 限制字数 if($that.inputContent.length > $that.maxNum){ $that.inputContent = $that.inputContent.substring(0, $that.maxNum); } } }), (e => { if (e.code === 1310722) { uni.showToast({ title: '抱歉,没有听清,请您提高音量再试一遍吧', icon: 'none' }) } })) // #endif } } } </script> <style> @import url('index.css'); </style>
下载链接: Android apk
苹果链接: AppStore链接
<template> <view class="page pageStyle"> <view class="uni_flex_col_align_center flexX margin-top-100"> <view class="uni_flex_col_align_center margin-bottom-50"> <image src="/static/app_logo200.png" class="iconimg"></image> <view class="app_name uni_font_medium uni_25px">{{appName}}</view> <view class="app_version uni-font-regular">{{version}}</view> </view> <!-- #ifdef MP-WEIXIN --> <button @click="getuserinfo" withCredentials="true" class="btn_func uni_flex_row_align_center uni_font_medium">微信授权登陆</button> <view class="btn_func_un uni_flex_row_align_center uni-font-regular" @click="finishPage">暂不登录</view> <!-- #endif --> <!-- #ifdef APP-PLUS --> <view v-if="isShowWX" class="btn_func_bg uni_flex_row_align_center uni_font_medium" @click="doLoginAction('app-wx')"> <image class="icon_wechat" src="/pages_sub/login/static/icon_share_wx.png"></image> <text style="letter-spacing: 4rpx;">微信授权登录</text> </view> <view v-if="isCanPhoneNumberLogin" class="btn_func_bg uni_flex_row_align_center uni_font_medium" @click="doLoginAction('mobile')"> <uni-icons type="phone-filled" color="#E00300" size="20"></uni-icons> <view style="margin-left: 15rpx;">手机号一键登录</view> </view> <view class="btn_func_bg uni_flex_row_align_center uni_font_medium" @click="doLoginAction('apple')" v-if="isApple"> <image class="icon_apple" src="/pages_sub/login/static/icon_apple.png"></image> <view>通过 Apple 登录</view> </view> <view class="btn_func_un uni_flex_row_align_center uni-font-regular" @click="finishPage">暂不登录</view> <!-- #endif --> <!-- #ifdef H5 --> <!-- 下载按钮 --> <view> <view class="uni_flex_row_align_center download_btn bbg1" @click="download(1)"> <image style="width: 45rpx;height: 45rpx;" class="mr4" src="https://mp-4600ec1f-16af-433c-a045-130f8b08315f.cdn.bspapp.com/cloudstorage/3122fd08-63b0-42cd-91f1-f11421e72389.png"></image> <text class="uni_15px uni_font_regular" style="letter-spacing: 2rpx;">下载App (安卓)</text> </view> <view class="uni_flex_row_align_center download_btn bbg2" @click="download(2)"> <image style="width: 40rpx;height: 40rpx;" class="mr4" src="https://mp-4600ec1f-16af-433c-a045-130f8b08315f.cdn.bspapp.com/cloudstorage/a8074492-ae50-42ad-ba0e-5399354ad9c6.png"></image> <text class="uni_15px uni_font_regular" style="letter-spacing: 2rpx;">下载App (苹果)</text> </view> <view class="uni_flex_col_align_center mt15"> <image style="width: 288rpx;height: 288rpx;" class="mr4" src="https://luanqing.oss-cn-shanghai.aliyuncs.com/icon/yihui/min_code_yihui.jpeg"></image> <text class="uni_15px uni_font_regular mt6" style="letter-spacing: 2rpx;">微信小程序码</text> </view> </view> <!-- #endif --> </view> <!-- #ifdef APP-PLUS --> <view class="right uni_flex_col_align_center flexS"> <view class="uni_flex_row_align_center uni_14px uni-font-regular"> <checkbox style="transform: scale(0.65);" color="#8256f6" :checked="agreeState" @click="doAgree"></checkbox> <view class="uni-font-light">已阅读并同意</view> <view class="privacy uni_font_medium" @click="gotoUserAgreen">《用户服务协议》</view> <view class="privacy uni_font_medium" @click="gotoPrivacy">《隐私政策》</view> </view> <view class="uni_13px mt6">上海栾青网络科技有限公司出品</view> <view class="uni_13px mb15">Copyright © 2023</view> </view> <!-- #endif --> </view> </template> <script> // #ifdef APP-PLUS const univerifyManager = uni.getUniverifyManager() // #endif import api from '../../../../common/network/api/api.js'; import dataBase from '../../../../common/database.js'; export default{ data(){ return{ agreeState: false, version:"v1.0", appName: '易绘', fromSource: 'index', // 来源,如果是index,则登录后返回主页,否则返回上一级 code:undefined, isShowWX:true, isApple:false, isCanPhoneNumberLogin: false, } }, onLoad(opt) { // #ifdef MP-WEIXIN const $that = this; this.fromSource = opt.fromSource || 'index'; uni.login({ success(res) { $that.code = res.code; }, fail(res) { }, }) // #endif }, onShow() { const $that = this; $that.version = 'v'+ uni.getSystemInfoSync().appVersion; // #ifdef APP-PLUS if(plus.runtime.isApplicationExist({pname:'com.tencent.mm',action:'weixin://'})){ console.log("微信应用已安装"); $that.isShowWX = true; }else{ console.log("微信应用未安装"); $that.isShowWX = false; } uni.preLogin({ provider:'univerify', success: (suc) => { this.isCanPhoneNumberLogin = true; if(univerifyManager){ univerifyManager.preLogin(); } }, }); this.isApple = uni.getSystemInfoSync().platform == 'ios'; // #endif }, methods:{ download(type){ if(type === 1){ window.location.href = dataBase.appDownloadUrl; }else if(type === 2){ window.location.href = 'https://apps.apple.com/cn/app/%E6%98%93%E7%BB%98ai%E4%BD%9C%E7%94%BB/id1670258950'; } }, finishPage(){ uni.navigateBack({delta:1}); }, // 登录动作中枢 doLoginAction(type){ if(!this.agreeState){ const $that = this; uni.showModal({ title:'温馨提示', content:'您是否已阅读并同意 《用户服务协议》、 《隐私政策》?', confirmText:'同意并登录', cancelText:'拒绝', complete: (res) => { if(res.confirm){ $that.agreeState = true; $that.doLoginAction(type); } } }); return; } switch(type){ case 'apple': this.login4ApplePhone(); break; case 'app-wx': this.login4AppWx(); break; case 'mobile': this.login4Mobild(); break; } }, gotoUserAgreen(){ uni.navigateTo({ url:'/pages_sub/center/pages/webview/webview?url='+dataBase.appAgreement+'&title=用户协议' }); }, gotoPrivacy(){ uni.navigateTo({ url:'/pages_sub/center/pages/webview/webview?url='+dataBase.appPrivacy+'&title=隐私协议' }); }, doAgree(){ this.agreeState = !this.agreeState; }, // 手机号一键登录 login4Mobild(){ const $that = this; // 一键登录必须是手机使用流量的前提下才能获取到手机号码,用Wi-Fi联网时无法获取到手机号码,同时如果是双卡手机,获取到的手机号码是默认移动数据的那个手机卡的号码。 // #ifdef APP-PLUS // 预登录 START // 1.提高一键登录的加载速度 // 2.判断一键登录环境是否可用 univerifyManager.preLogin(); // 调用一键登录弹框 univerifyManager.login({ univerifyStyle: { fullScreen:false, icon: { path:'/static/app_logo200.png' }, privacyTerms:{ defaultCheckBoxState: false, checkBoxSize: 14, privacyItems:[ { "url": dataBase.appAgreement, "title": "用户服务协议" }, { "url": dataBase.appPrivacy, "title": "隐私协议" } ] }, authButton:{ normalColor:"#9686FB", disabledColor:"#AAAAAA" }, otherLoginButton: { visible: true, // 是否显示其他登录按钮,默认值:true normalColor: "", // 其他登录按钮正常状态背景颜色 默认值:透明 highlightColor: "", // 其他登录按钮按下状态背景颜色 默认值:透明 textColor: "#656565", // 其他登录按钮文字颜色 默认值:#656565 title: "其他登录方式", // 其他登录方式按钮文字 默认值:“其他登录方式” borderColor: "", //边框颜色 默认值:透明(仅iOS支持) borderRadius: "0px" // 其他登录按钮圆角 默认值:"24px" (按钮高度的一半) }, }, success (auth) { uniCloud.callFunction({ name:'getPhoneNumber', data:{ openid: auth.authResult.openid, access_token: auth.authResult.access_token}, success(cloudRes) { let {code, phoneNumber} = cloudRes.result; console.error("手机号:",phoneNumber); if(code === 200){ const data = { name: '手机用户', unionId: phoneNumber }; $that.submitLoginData(data); univerifyManager.close(); }else{ univerifyManager.close(); } }, fail: (err) => { console.error("云函数失败:",err); } }) }, fail(res) { // 点击其他登录方式 if(res.code === 30002){ univerifyManager.close(); } } }) // #endif }, // 苹果登录 login4ApplePhone(){ const $that = this; uni.login({ provider: 'apple', success(loginRes){ // 登录成功 uni.getUserInfo({ provider: 'apple', success(res) { // 苹果登录成功:{"errMsg":"getUserInfo:ok","userInfo":{"openId":"001465.6449e1ad2e46401488d67bae89d79c8a.1706","fullName":{"familyName":"许","giveName":"仕永","givenName":"仕永"},"email":"835588741@qq.com","authorizationCode":"c9acf4dd2a2a9491a93d158a7669b4165.0.mruwv.b0hncISXQbHMGinz5_f3vg","identityToken":"eyJraWQiOiJZdXlYb1kiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLmx1YW5xaW5nLmJhYnkiLCJleHAiOjE2MjA5MjU2MTIsImlhdCI6MTYyMDgzOTIxMiwic3ViIjoiMDAxNDY1LjY0NDllMWFkMmU0NjQwMTQ4OGQ2N2JhZTg5ZDc5YzhhLjE3MDYiLCJjX2hhc2giOiJqVG9MWHFKd3BBemxxSlNmV2xjWFBBIiwiZW1haWwiOiI4MzU1ODg3NDFAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiYXV0aF90aW1lIjoxNjIwODM5MjEyLCJub25jZV9zdXBwb3J0ZWQiOnRydWUsInJlYWxfdXNlcl9zdGF0dXMiOjJ9.nAHGpGDpjALPmz-vReHjIAV3IyrYJTrLxHmLDqTd2AShYH6XZW3Qh-27aAgbWjg8_3w4Ex22Tpv8_NhKNTAIrHjCNMN5jnw6WkXL4-utKTZi4mlX4p_WiPpkZSa7e0cJZYKrN5b3UEiI1Vf6yu8b5TeKz4E7cg1Iq6RfFNmXLYJmt92WRtwSPexinTySjVvZmxGZ-_7nnh-TowHXjedLBsUsdB7oRlp1xSRpRQm78YKnibwmF2__iejPTmKL_WwOTXXBsg4NrF5h7rFS0Z7jGvA8WPziJxoaeHDP_j1Iw2pcmfzMLA7FhSXlkcYd38To2Wv01kOma0fLlfIm8JovIg","realUserStatus":2}} at pages/user/login/login.vue:93 __ERROR console.error("苹果登录成功:",res?.userInfo?.fullName?.giveName || "苹果用户",res?.userInfo?.openId); // 获取用户信息成功 const data = { name: res?.userInfo?.fullName?.giveName || "苹果用户", unionId: res?.userInfo?.openId }; $that.submitLoginData(data); } }) }, }); }, // App端微信 login4AppWx(){ const $that = this; uni.login({ provider: 'weixin', success: function (loginRes) { uni.getUserInfo({ success(res) { const data = { avatar:res.userInfo.avatarUrl, name:res.userInfo.nickName, gender:res.userInfo.gender, unionId: res.userInfo.unionId, }; $that.submitLoginData(data); }, }) }, }); }, // 提交登录信息给后端 submitLoginData(data){ data.action = "submitLoginData"; api.doPost(data).then(res=>{ let temp = res.data; dataBase.insertUUIDAtStorage(temp.uuid); dataBase.insertTokenAtStorage(temp.token); this.finishPage(); }); }, // 小程序专用 2 getuserinfo(){ let $that = this; let code = $that.code; uni.showToast({ title:'正在请求中', icon:'none' }); uni.getUserProfile({ desc:'用于登录获取昵称头像', success(res) { console.error("获取的用户资料:",JSON.stringify(res)); const data = { action:'submitLoginDataMP', code:code, avatar:res.userInfo.avatarUrl, name:res.userInfo.nickName, gender:res.userInfo.gender, }; api.doPost(data).then(response=>{ dataBase.insertTokenAtStorage(response.data.token); dataBase.insertUUIDAtStorage(response.data.uuid); $that.finishPage(); }); } }) }, } } </script> <style> @import url("login.css"); </style>
<template> <view> <uni-nav-bar :statusBar="true" :border="false" :fixed="true" :leftWidth="400" :rightWidth="200"> <template v-slot:left class="uni_flex_row_align_left uni_14px uni_font_medium"> <text class="button_import" @click="importImageBg">导入图片</text> <text class="button_save" @click="onSave2PhoneStorage"> 保存本地 <!-- <text class="uni_12px" style="color: #E00300;">免费</text> --> </text> </template> <!-- #ifndef MP --> <template v-slot:right> <view class="uni_flex_row_align_center" @click="onClickHelp(true)"> <uni-icons type="help-filled" size="22" color="#A2A3A4"></uni-icons> <view class="uni_12px uni_color_999">帮助</view> </view> </template> <!-- #endif --> </uni-nav-bar> <view class="uni_flex_col_align_center" v-if="isShowCanvas" style="background-color: #ffffff;position: sticky;top: 140rpx;z-index: 999;"> <canvas id="canvasId" canvas-id="canvasId" class="avatar_panel" @touchstart="onTouchStart" @touchmove="onTouchMove"></canvas> </view> <!-- 缩放、旋转操作栏 START --> <view v-if="moveElement.url_mp || moveElement.url" class="uni_flex_row_align_center mt10"> <view class="tag_fun_text2" @click="onImgTagRotate(-1)"> <image class="tag_fun_img" src="../../static/icon/icon_left.png"></image> </view> <view class="tag_fun_text ml12 mr8" @click="onImgTagScan(-1)">缩小</view> <!-- #ifdef MP --> <!-- <image class="selected_tag" :src="moveElement.url_mp" mode="widthFix"></image> --> <!-- #endif --> <view class="tag_fun_text ml10 mr10" @click="onImgTagRemove">移除</view> <!-- #ifndef MP --> <!-- <image class="selected_tag" :src="moveElement.url" mode="widthFix"></image> --> <!-- #endif --> <view class="tag_fun_text ml8 mr12" @click="onImgTagScan(1)">放大</view> <view class="tag_fun_text2" @click="onImgTagRotate(1)"> <image class="tag_fun_img" src="../../static/icon/icon_right.png"></image> </view> </view> <!-- 缩放、旋转操作栏 END --> <view class="uni_flex_row_align_left ml15 mt25"> <image src="/static/icon/icon_color_piacker.png" style="width: 30rpx;height: 30rpx;"></image> <text class="uni_14px uni_color_222 ml8 uni_font_medium">背景颜色</text> </view> <view class="uni_flex_warp uni_flex_row_between ml15 mr15 mt12"> <view v-for="(color,id) in colorList" class="bg" v-bind:key="id" :style="'background-color:#'+color" @click="onClickColorItem(color)"></view> </view> <view class="input_view ml15 mr15" v-if="false"> <view class="uni_flex_row_align_left uni_font_regular uni_17px"> <text class="mr2">#</text> <input class="input_style" maxlength="6" v-model="customColor" placeholder="请输入6位十六进制码" /> </view> <view class="uni_flex_row_align_right" @click="onClickColorItem()"> <text class="uni_green_209B5C uni_14px uni_font_medium">使用自定义</text> <view class="color_tag ml10" :style="'background-color:#'+customColor"></view> </view> </view> <view class="uni_flex_row_align_left ml15 mt25"> <image src="/static/icon/icon_img_tag.png" style="width: 30rpx;height: 30rpx;"></image> <text class="uni_14px uni_color_222 ml8 uni_font_medium">装饰点缀图案</text> </view> <!-- 点缀的图案 --> <swiper class="uni_flex_col_align_center ml14 mr14 mt12" style="height: 365rpx;" :indicator-dots="true" indicator-active-color="#8256f6"> <swiper-item v-for="(page,pid) in imgTag" v-bind:key="pid" style="width: 690rpx;"> <view class="uni_flex_warp"> <view class="tag_item" v-for="(tag, tid) in page" v-bind:key="tid" @click="onPickerImgTag(tag,tid)"> <image class="tag_size" :src="tag.url"></image> </view> </view> </swiper-item> </swiper> <!-- <view class="page_tip_view mt20" v-if="false"> <text class="uni_13px">三步自定义头像制作</text> <text class="mt4 uni_12px">1.选择背景,添加头像的背景主图</text> <text class="mt2 uni_12px">2.点击添加装饰点缀的图案</text> <text class="mt2 uni_12px">3.点击保存,即可保存到手机(相册查看)</text> </view> --> <uni-popup ref="showHelpDialog" type="top" :isMaskClick="false"> <view class="popup_help_view"> <view class="page_tip_view mt40"> <text class="uni_13px">三步自定义头像制作</text> <text class="mt4 uni_12px">1.选择背景,添加头像的背景主图</text> <text class="mt2 uni_12px">2.点击添加装饰点缀的图案</text> <text class="mt2 uni_12px">3.点击保存,即可保存到手机(相册查看)</text> </view> <view style="height: 40rpx;"></view> <view class="mt18 uni_15px button_round_style" @click="onClickHelp(false)">好的</view> </view> </uni-popup> </view> </template> <script> import api from '../../common/network/api/api'; import dataBase from '../../common/database.js'; export default { data() { return { isShowCanvas: true, // tagImages:[], drawTag:[], // 绘制在画布上的点缀图案列表 imgTag:[], // 可选的点缀图案 canvasBG:'', // 画布的背景主图 moveElement:{}, // 当前选中的元素 canvasBgColor:'#ffffff', // 画布的背景颜色上色 customColor:'FFFFFF', // 自定义颜色吗 canvasSize: 231, colorList:["9686FB","6BADFF","77C38F","FFE16B","FF9F6B","FF6B6B"], } }, onShow() { this.queryTags(); this.isLogin = dataBase.queryLoginStatus(); if(this.isLogin){ api.doPost({action:'queryUnreadMessageNumber'}).then(res=>{ let unread = res.data.unread; unread > 0 ? uni.showTabBarRedDot({index: 4}) : uni.hideTabBarRedDot({index: 4}); }); } }, methods: { onImgTagRemove(){ let id = -1; this.drawTag.forEach((item,itemid)=>{ if(item.id === this.moveElement.id){ id = itemid; } }); if(id != -1){ this.drawTag.splice(id,1); } this.moveElement = {}; this.drawCanvas(); }, // 保存到本地手机存储 onSave2PhoneStorage(item){ uni.canvasToTempFilePath({canvasId:'canvasId',success:(res)=>{ // 保存到手机本地存储 uni.saveImageToPhotosAlbum({filePath: res.tempFilePath,success:(res)=>{ uni.showToast({ title:'已下载到手机(可在相册查看)', icon:'none' }); }}); }}); }, // 导入头像主图 importImageBg(){ // #ifndef H5 uni.chooseImage({ count:1, crop: {width: 1000,height:1000,quality:100}, success: (res) => { this.canvasBG = res.tempFilePaths[0]; this.drawCanvas(); } }) // #endif // #ifdef H5 uni.chooseFile({ count:1, extension:['.png','.jpg'], complete: (res) => { console.error("选择成功:",res); } }); // #endif }, // 显示帮助弹窗 onClickHelp(show){ this.isShowCanvas = !show; if(show){ this.$refs.showHelpDialog.open(); }else{ this.$refs.showHelpDialog.close(); } }, // 查询图案标签列表 queryTags(){ let tagData = dataBase.queryStorage("app_tag_lsit"); if(tagData && tagData.date > (new Date().getTime())){ this.imgTag = tagData.list; }else{ api.doPost({action:'queryImageTag'}).then(res=>{ let temp = res.data || []; let pageSize = 18; let pageNum = temp.length / 18 + (temp.length % 18 > 0 ? 1:0); pageNum = Math.floor(pageNum); this.imgTag = []; for(let i = 0 ; i < pageNum; i++){ let sub; if(i < pageNum - 1){ sub = temp.slice(i * pageSize, pageSize); }else{ sub = temp.slice(i * pageSize, i * pageSize + temp.length % 18); } this.imgTag.push(sub); } let insertData = { list: this.imgTag, date: (new Date().getTime() + 18000000) }; dataBase.insertStorage('app_tag_lsit', insertData); }) } }, // 缩放 onImgTagScan(mode){ if(this.moveElement && this.moveElement.url){ this.moveElement.width += (5 * mode); this.moveElement.height += (5 * mode); } this.drawCanvas(); }, // 旋转 onImgTagRotate(mode){ if(this.moveElement && this.moveElement.url){ if(this.moveElement.degree >= 360){ this.moveElement.degree = mode === -1 ? 350:10; }else if(this.moveElement.degree <= 0){ this.moveElement.degree = mode === -1 ? 360:10; }else{ this.moveElement.degree += (10 * mode); } } this.drawCanvas(); }, // 选择饰品图标 onPickerImgTag(item,id){ item.id = id; item.x = 0; item.y = 0; item.width = 50; item.height = 50; item.degree = 360; this.drawTag.push(item); this.drawCanvas(); }, // 点击颜色卡 onClickColorItem(color){ if(color){ this.customColor = color; this.canvasBgColor = "#"+color; this.drawCanvas(); }else{ if(!this.customColor || this.customColor.length < 6){ this.customColor = "FFFFFF"; uni.showToast({ title:"自定义颜色码不合法,请输入6位的十六进制颜色码", icon:'none' }); return; }else{ this.canvasBgColor = "#"+this.customColor; this.drawCanvas(); } } }, // 绘制的中枢核心方法 drawCanvas(){ const ctx = uni.createCanvasContext('canvasId'); // 填充背景色 ctx.setFillStyle(this.canvasBgColor); ctx.fillRect(0, 0, this.canvasSize, this.canvasSize); // 绘制背景图 if(this.canvasBG){ ctx.drawImage(this.canvasBG, this.bgLeft, this.bgTop, this.canvasSize, this.canvasSize); } // 饰品点缀图以及旋转逻辑处理 this.drawTag.forEach(item=>{ if(item.url){ // 旋转的处理代码 if(item.degree > 0){ ctx.translate(item.x + item.width / 2, item.y + item.height / 2); ctx.rotate(item.degree * Math.PI / 180); ctx.translate((item.x + item.width / 2) * -1, (item.y + item.height / 2) * -1); } if(this.moveElement && item.id === this.moveElement.id){ ctx.setStrokeStyle('red'); ctx.strokeRect(item.x - 2 , item.y - 2 , item.width + 2, item.height + 2) } // 绘制饰品点缀图 //#ifdef MP ctx.drawImage(item.url_mp, item.x, item.y, item.width, item.height); //#endif //#ifndef MP ctx.drawImage(item.url, item.x, item.y, item.width, item.height); //#endif } }); ctx.draw(); }, // 触摸开始,用于定位点击的是哪个tag装饰 onTouchStart(e){ let x = e.touches[0].x; let y = e.touches[0].y; x = x < 0 ? 0 : x; y = y < 0 ? 0 : y; x = x > this.canvasSize ? this.canvasSize : x; y = y > this.canvasSize ? this.canvasSize : y; let cur = this.drawTag.find(item=>{ return ((x >= item.x && y >= item.y) && (x <= (item.x + item.width) && y <= (item.y + item.height))); }); if(cur){ this.moveElement = cur; } this.drawCanvas(); }, // 移动进行中,拖动生效 onTouchMove(e){ let x = e.touches[0].x; let y = e.touches[0].y; x = x < 0 ? 0 : x; y = y < 0 ? 0 : y; x = x - this.moveElement.width; y = y - this.moveElement.height; // let offset = 20; // x = x > this.canvasSize - this.moveElement.width - offset ? this.canvasSize - this.moveElement.width - offset : x; // y = y > this.canvasSize - this.moveElement.height - offset ? this.canvasSize - this.moveElement.height - offset: y; this.moveElement.x = x; this.moveElement.y = y; this.drawCanvas(); }, } } </script> <style> @import url('index.css'); </style>
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。