用uniapp开发一款商用的ai绘图软件

504 阅读2分钟

随着科技的发展,人工智能将会是以后的主流方向,ai绘图、chatgpt高科技先后出台,都获得了火爆的发展,因此想借着势头开发一款主打ai绘图的app+小程序

一、前期准备

1、选定技术框架

因为后面需要多平台发布,而尽可能减少开发成本,因此选定了uniapp框架作为开发框架,前期目标是 android、ios以及 微信小程序三个平台,android平台名称:易绘,IOS端名称:易绘ai作画,微信小程序端:栾青易绘ai绘画。

2、ai绘图的api选择

有两个方向,一个是百度云,一个是腾讯云,各有优劣,价格方面腾讯云更优惠,但百度推出的时间更早。因为前期接入的是百度云的sdk,所以还是选择了百度云sdk。

3、功能整合

主打ai绘图(用文字生成图片),次功能头像制作、老照片修复处理,真人动漫化头像,二次元图片,壁纸美图。开放了一部分功能免费使用,以留住用户。

二、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>

  


三、成品展示图

ai绘图主页

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

下载链接: 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>