Shandong University of Science and Technology Station

Shandong University of Science and Technology campus mini program. If you think it's good, give it a star :-)
Github: https://github.com/WindrunnerMax/SHST

1. WeChat Mini Program to UNIAPP Conversion

Issues and pitfalls encountered when migrating a WeChat Mini Program to a UNIAPP project recently
Overall, migrating the project is not very complicated, but rather involves a lot of repetitive work

1. File Correspondence

<template></template> corresponds to .wxml file <script></script> corresponds to .js file <style></style> corresponds to .wxss file When creating a .vue file using HBuildX, the template will be automatically generated

2. App.vue File

globalData, onPageNotFound(), onLaunch() are defined here Operations that directly bind to the app's methods need to be handled using this.$scope in onLaunch()

3. Custom Components

The created() method is defined to execute when the component is created <slot></slot> serves as the insertion point for the component's XML and can accept multiple insertion points when the name attribute is set To mount a component separately, import the .vue file and declare the imported component name in export default { components: {} } To globally mount the component, import and mount it in main.js, for example: import example from "example.vue"; Vue.component('example', example);

4. Custom Folder

Custom folders will be automatically compiled to /common/ during packaging Place static resources in the static folder; the directory will not change during packaging, and the wxml import directory will remain unchanged

5. Data Binding

In WeChat Mini Program, use the setData({}) method to send data to the view layer In Vue, data is bound bidirectionally; use this.param = value to re-render the data, You can also rewrite the setData({}) method, as demonstrated in the official website

6. Template Data Rendering

The data to be used must first be declared in export default { data() { return { param: value } } } Use :attr to reference variable values in XML node attributes, and use {{param}} for XML node values Change wx:for="{{list}}" wx:key="{{index}}" to v-for="(item, index) in list" :key="index"

7. Dynamic Binding of Class and Style

In ES6, use the new feature `string${param}string` directly in :attr to concatenate strings, but WeChat Mini Program does not support this Manually concatenate strings using :attr="'string' + param" Vue provides a way to dynamically bind <view class="static" :class="{value:active}" :style="{'attr': param}"></view>

8. page.json

In WeChat Mini Program, the app.json routes are managed by the page.json file in UNAIPP When creating a route in app.json in WeChat Mini Program, a file is created; in HbuildX, when creating a page, there is an option to automatically create the route in page.json In page.json, style corresponds to the JSON file of a specific page in WeChat Mini Program

9. Conditional Compilation Functionality

// #ifdef %PLATFORM% Platform-specific API implementation, UNIAPP provides conditional compilation functionality, which is very suitable for cross-platform development // #endif

10. Alibaba Vector Icon Library - Iconfont

Add icons to the project and download them locally using code Copy iconfont.css to the project, removing all parts similar to url('iconfont.eot?t=1577846073653#iefix') format('embedded-opentype') Use <view class='iconfont icon-shuaxin'></view> to reference the icon

2. Example of Shandong University of Science and Technology Station

1. Directory Structure

SHST-UNI // Shanke Small Station Directory ├── components // Component Packaging │ ├── headslot.vue // Title layout with slot │ ├── layout.vue // Card-style layout │ ├── list.vue // List layout for display │ ├── sentence.vue // Daily sentence packaging │ └── weather.vue // Weather packaging ├── modules // Modular packaging │ ├── cookies.js // Cookies operation │ ├── copy.js // Shallow and deep copy │ ├── datetime.js // Date and time operation │ ├── event-bus.js // Event bus │ ├── global-data.js // Global variables │ ├── loading.js // Loading prompt │ ├── operate-limit.js // Debouncing and throttling │ ├── regex.js // Regular expression matching │ ├── request.js // Network request │ ├── toast.js // Message prompt │ └── update.js // Automatic update ├── pages // Pages │ ├── Ext // Extension group │ ├── Home // Tabbar, auxiliary group │ ├── Lib // Library function group │ ├── Sdust // SDUST group │ ├── Study // Study group │ └── User // User group ├── static // Static resources │ ├── camptour // Campus tour static resources │ └── img // Icon and other static resources ├── unpackage // Packaged files ├── utils // Auxiliary functions │ ├── amap-wx.js // Amap SDK │ └── md5.js // MD5 introduction ├── vector // Deployment packaging │ ├── resources // Resource files │ │ ├── camptour // Campus tour configuration file │ │ ├── asse.mini.wxss // Public style library │ │ └── iconfont.wxss // Icon font │ ├── dispose.js // Mini program deployment │ └── pubFct.js // Public methods ├── App.vue // App global style and listening ├── main.js // Mount App, Vue initialization entry file ├── manifest.json // Configuration for Uniapp packaging, etc. ├── pages.json // Routes └── uni.scss // Built-in common style variables

III. Modularization

1. Cookies Operation

/**
 * GetCookie
 */
function getCookies(res) {
    var cookies = "";
    if (res && res.header && res.header['Set-Cookie']) {
        // #ifdef MP-ALIPAY
        var cookies = res.header['Set-Cookie'][0].split(";")[0] + ";";
        // #endif
        // #ifndef MP-ALIPAY
        var cookies = res.header['Set-Cookie'].split(";")[0] + ";";
        // #endif
        console.log("SetCookie:" + cookies);
        uni.setStorage({
            key: "cookies",
            data: cookies
        });
    } else {
        console.log("Get Cookie From Cache");
        cookies = uni.getStorageSync("cookies") || "";
    }
    return cookies;
}

export { getCookies }
export default { getCookies }

2. Deep and Shallow Copy

function shallowCopy(target, ...origin) {
    return Object.assign(target, ...origin);
}

function extend(target, ...origin) {
    return shallowCopy(target, ...origin);
}

function deepCopy(target, origin) {
    for (let item in origin) {
        if (origin[item] && typeof(origin[item]) === "object") {
            // Object Array Date RegExp Deep Copy
            if (Object.prototype.toString.call(origin[item]) === "[object Object]") {
                target[item] = deepCopy({}, origin[item]);
            } else if (origin[item] instanceof Array) {
                target[item] = deepCopy([], origin[item]);
            } else if (origin[item] instanceof Date) {
                target[item] = new Date(origin[item]);
            } else if (origin[item] instanceof RegExp) {
                target[item] = new RegExp(origin[item].source, origin[item].flags);
            } else {
                target[item] = origin[item];
            }
        } else {
            target[item] = origin[item];
        }
    }
    return target;
}

export { extend, shallowCopy, deepCopy }

export default { extend, shallowCopy, deepCopy }

3. Date and Time Manipulation

/**
 * yyyy year MM month dd day hh 1-12 hour (1-12) HH 24-hour system (0-23) mm minute ss second S millisecond K week
 */
const formatDate = (fmt = "yyyy-MM-dd", date = new Date()) => {
    var week = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var o = {
        "M+": date.getMonth() + 1, //month
        "d+": date.getDate(), //day
        "h+": date.getHours() % 12 || 12, //hour
        "H+": date.getHours(), //hour
        "m+": date.getMinutes(), //minute
        "s+": date.getSeconds(), //second
        "q+": Math.floor((date.getMonth() + 3) / 3), //quarter
        "S": date.getMilliseconds(), //millisecond
        "K": week[date.getDay()]
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(fmt)
            ) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    }
    return fmt;
}

const extDate = () => {
    // console.log("Extend Date prototype");
    Date.prototype.addDate = function(years = 0, months = 0, days = 0) {
        if (days !== 0) this.setDate(this.getDate() + days);
        if (months !== 0) this.setMonth(this.getMonth() + months);
        if (years !== 0) this.setFullYear(this.getFullYear() + years);
    }
}

/**
 * Date difference in days
 */
const dateDiff = (startDateString, endDateString) => {
    var separator = "-"; //date separator
    var startDates = startDateString.split(separator);
    var endDates = endDateString.split(separator);
    var startDate = new Date(startDates[0], startDates[1] - 1, startDates[2]);
    var endDate = new Date(endDates[0], endDates[1] - 1, endDates[2]);
    var diff = parseInt((endDate - startDate) / 1000 / 60 / 60 / 24); //convert the difference in milliseconds into days
    return diff;
}

export { formatDate, extDate, dateDiff }
export default { formatDate, extDate, dateDiff }

4. Event Bus

var PubSub = function() {
    this.handlers = {};
}

PubSub.prototype = {

    on: function(key, handler) { // subscribe
        if (!(key in this.handlers)) this.handlers[key] = [];
        this.handlers[key].push(handler);
    },
off: function(key, handler) { // Unsubscribe
        const index = this.handlers[key].findIndex(item => item === handler);
        if (index < 0) return false;
        if (this.handlers[key].length === 1) delete this.handlers[key];
        else this.handlers[key].splice(index, 1);
        return true;
    },

    commit: function(key, ...args) { // Trigger
        if (!this.handlers[key]) return false;
        this.handlers[key].forEach(handler => handler.apply(this, args));
        return true;
    },

}

export { PubSub }
export default { PubSub }

5. Global Variables

/**
 * Color Scheme
 */

// var colorList = ["#EAA78C", "#F9CD82", "#9ADEAD", "#9CB6E9", "#E49D9B", "#97D7D7", "#ABA0CA", "#9F8BEC",
//     "#ACA4D5", "#6495ED", "#7BCDA5", "#76B4EF","#E1C38F","#F6C46A","#B19ED1","#F09B98","#87CECB","#D1A495","#89D196"
// ];
var colorList = ["#FE9E9F", "#93BAFF", "#D999F9", "#81C784", "#FFCA62", "#FFA477"];

export { colorList }
export default { colorList }

6. Loading Prompt

/**
 * startLoading
 */
function startLoading(option) {
    switch (option.load) {
        case 1:
            uni.showNavigationBarLoading();
            break;
        case 2:
            uni.showNavigationBarLoading();
            uni.setNavigationBarTitle({
                title: option.title || "Loading..."
            })
            break;
        case 3:
            uni.showLoading({
                title: option.title || "Requesting",
                mask: true
            })
            break;
    }
}

/**
 * endLoading
 */
function endLoading(option) {
    switch (option.load) {
        case 1:
            uni.hideNavigationBarLoading();
            break;
        case 2:
            uni.hideNavigationBarLoading();
            uni.setNavigationBarTitle({
                title: option.title || "Mountain Station"
            })
            break;
        case 3:
            uni.hideLoading();
            break;
    }
}

export { startLoading, endLoading }
export default { startLoading, endLoading }

7. Debounce and Throttle

/**
 * Debounce
 * Timer implementation
 */
function debounceGenerater(){
    var timer = null;
    return (wait, funct, ...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => funct(...args), wait);
    }
}
/**
 * Throttle
 * Timestamp implementation
 */
function throttleGenerater(){
    var previous = 0;
    return (wait, funct, ...args) => {
        var now = +new Date();
        if(now - previous > wait){
            funct(...args);
            previous = now;
        }
    }
}

/*
// Throttle
// Timer implementation
function throttleGenerater(){
    var timer = null;
    return (wait, funct, ...args) => {
        if(!timer){
            funct(...args);
            timer = setTimeout(() => timer = null, wait);
        }  
    }
}
 */

export { debounceGenerater, throttleGenerater }
export default { debounceGenerater, throttleGenerater }

8. Regular Expression Matching

/**
 * Regular Expression Matching
 */
const regMatch = (regex, s) => {
    var result = [];
    var temp = null;
    var flags = `${regex.flags}${regex.flags.includes("g") ? "" : "g"}`;
    regex = new RegExp(regex, flags);
    while (temp = regex.exec(s)) result.push(temp[1] ? temp[1] : temp[0]);
    return result;
}

export { regMatch }
export default { regMatch }

9. Network Request

import {startLoading, endLoading} from "./loading";
import {getCookies} from "./cookies";
import {extend} from "./copy";
import {toast} from "./toast";
    
var headers = {'content-type': 'application/x-www-form-urlencoded'};
/**
 * HTTP request
 */
function ajax(requestInfo) {
    var option = {
        load: 1,
        url: "",
        method: "GET",
        data: {},
        headers: headers,
        success: () => {},
        resolve: () => {},
        fail: function() { this.completeLoad = () => { toast("External Error");}},
        reject: () => {},
        complete: () => {},
        completeLoad: () => {}
    };
    extend(option, requestInfo);
    startLoading(option);
    uni.request({
        url: option.url,
        data: option.data,
        method: option.method,
        header: headers,
        success: function(res) {
            if (!headers.cookie) headers.cookie = getCookies(res);
            if(res.statusCode === 200){
                try {
                    option.success(res);
                    option.resolve(res);
                } catch (e) {
                    option.completeLoad = () => { toast("External Error");}
                    console.log(e);
                }
            }else{
                option.fail(res);
                option.reject(res);
            }
            
        },
        fail: function(res) {
            option.fail(res);
        },
        complete: function(res) {
            endLoading(option);
            try {
                option.complete(res);
            } catch (e) {
                console.log(e);
            }
            option.completeLoad(res);
        }
    })
}

/**
 * request promise encapsulation
 */
function request(option) {
    return new Promise((resolve,reject) => {
        option.resolve = resolve;
        option.reject = reject;
        ajax(option);
    })
}


export { ajax, request }
export default { ajax, request }

10. Message Prompt

/**
 * Pop-up prompt
 */
function toast(e, time = 2000, icon = 'none') {
    uni.showToast({
        title: e,
        icon: icon,
        duration: time
    })
}

export { toast }
export default { toast }

11. Automatic Update

/**
 * Mini Program Update
 */
function checkUpdate() {
    if (!uni.getUpdateManager) return false;
    uni.getUpdateManager().onCheckForUpdate((res) => {
        console.log("Update:" + res.hasUpdate);
        if (res.hasUpdate) { // If there's a new version
            uni.getUpdateManager().onUpdateReady(() => { // When the new version is downloaded
                uni.showModal({
                    title: 'Update Prompt',
                    content: 'The new version is ready, click OK to restart the application',
                    success: (res) => {
                        if (res.confirm) uni.getUpdateManager().applyUpdate(); //applyUpdate applies the new version and restarts
                    }
                })
            })
            uni.getUpdateManager().onUpdateFailed(() => { // When the new version download fails
                uni.showModal({
                    title: 'Prompt',
                    content: 'A new version is detected, but the download failed, please check the network settings',
                    showCancel: false
                })
            })
        }
    })
}

export { checkUpdate }
export default { checkUpdate }

12. Startup Event

"use strict";
import globalData from "@/modules/global-data";
import request from "@/modules/request";
import {toast} from "@/modules/toast";
import {extend} from  "@/modules/copy";
import {PubSub} from "@/modules/event-bus";
import {extDate} from "@/modules/datetime";
import {checkUpdate} from  "@/modules/update";
import {getCurWeek} from  "@/vector/pubFct";

function disposeApp(app){
    extDate(); // Extend Date prototype
    checkUpdate(); // Check for updates
    app.$scope.toast = toast;
    app.$scope.extend = extend;
    app.$scope.eventBus = new PubSub();
    app.$scope.extend(app.$scope, request);
    app.$scope.extend(app.globalData, globalData);
    app.globalData.colorN = app.globalData.colorList.length;
    app.globalData.curWeek = getCurWeek(app.globalData.curTermStart);
}
/**
 * APP launch event
 */
function onLaunch() {
    var app = this;
    disposeApp(this);
    var userInfo = uni.getStorageSync("user") || {};
    uni.login({
        scopes: 'auth_base'
    }).then((data) => {
        var [err,res] = data;
        if(err) return Promise.reject(err);
        return app.$scope.request({
            load: 3,
            // #ifdef MP-WEIXIN
            url: app.globalData.url + 'auth/wx',
            // #endif
            // #ifdef MP-QQ
            url: app.globalData.url + 'auth/QQ',
            // #endif
            method: 'POST',
            data: {
                "code": res.code,
                user: JSON.stringify(userInfo)
            }
        })
    }).then((res) => {
        app.globalData.curTerm = res.data.initData.curTerm;
        app.globalData.curTermStart = res.data.initData.termStart;
        app.globalData.curWeek = res.data.initData.curWeek;
        app.globalData.loginStatus = res.data.Message;
        app.globalData.initData = res.data.initData;
        if(app.globalData.initData.custom){
            let custom = app.globalData.initData.custom;
            if(custom.color_list) {
                app.globalData.colorList = JSON.parse(custom.color_list);
                app.globalData.colorN = app.globalData.colorList.length;
            }
        }
        if (res.data.Message === "Ex") app.globalData.userFlag = 1;
        else app.globalData.userFlag = 0;
        console.log("Status:" + (app.globalData.userFlag === 1 ? "User Login" : "New User"));
        if (res.data.openid) {
            var notify = res.data.initData.tips;
            app.globalData.tips = notify;
            var point = uni.getStorageSync("point") || "";
            if (point !== notify) uni.showTabBarRedDot({ index: 2 });
            console.log("SetOpenid:" + res.data.openid);
            app.globalData.openid = res.data.openid;
            uni.setStorageSync('openid', res.data.openid);
        } else {
            console.log("Get Openid From Cache");
            app.globalData.openid = uni.getStorageSync("openid") || "";
        }
        return Promise.resolve(res);
    }).then((res) => {
        if (res.statusCode !== 200 || !res.data.initData || !res.data.initData.curTerm)  return Promise.reject("DATA INIT FAIL");
        else app.$scope.eventBus.commit('LoginEvent', res);
    }).catch((err) => {
        console.log(err);
        uni.showModal({
            title: 'Warning',
            content: 'Data initialization failed, click OK to reinitialize the data',
            showCancel: false,
            success: (res) => {
                if (res.confirm) onLaunch.apply(app);
            }
        })
    })
}
export default {onLaunch, toast}

Four, Componentization

1. Title Component

<template name="headslot">
    <view>

        <view class="head-line">
            <view class="head-left">
                <view class="head-row" v-bind:style="{'background-color': color}"></view>
                <view class="head-title">{{title}}</view>
            </view>
            <view style="margin-top: 3px;">
                <slot></slot>
            </view>
        </view>

    </view>
</template>
<script>
    export default {
        name: "headslot",
        props: {
            title: {
                type: String
            },
            color: {
                type: String,
                default: "#79B2F9"
            },
        },
        methods: {}
    }
</script>
<style>
    .head-line {
        background-color: #FFFFFF;
        padding: 10px 5px;
        box-sizing: border-box;
        display: flex;
        border-bottom: 1px solid #EEEEEE;
        justify-content: space-between;
    }
    .head-row {
        width: 2px;
        margin: 2px 5px;
    }
    .head-left{
        display: flex;
        justify-content: center;
    }
    .head-title{
        display: flex;
        justify-content: center;
        align-items: center;
        white-space: nowrap;
    }
</style>

2. Card Component

<template>
    <view>

        <view class="lay-line" v-show="title">
            <view class="lay-left-con">
                <view class="lay-verline" :style="{background: color}"></view>
                <view>{{title}}</view>
            </view>
            <view>
                <slot name="headslot"></slot>
            </view>
        </view>
        <view class="lay-card" :style="{color: computedColor}" :class="{'lay-min-top':!topSpace}">
            <slot></slot>
        </view>
</view>
</template>
<script>
    export default {
        name: "layout",
        props: {
            title: {
                type: String,
                required: true
            },
            color: {
                type: String,
                default: "#79B2F9"
            },
            topSpace: {
                type: Boolean,
                default: true
            },
            inheritColor: {
                type: Boolean,
                default: false
            }
        },
        computed:{
            computedColor: function(){
                return this.inheritColor ? this.color : "unset";
            }
        },
        methods: {}
    }
</script>
<style>
    .lay-line {
        background-color: #FFFFFF;
        padding: 12px 5px 10px 5px;
        box-sizing: border-box;
        display: flex;
        border-bottom: 1px solid #EEEEEE;
        justify-content: space-between;
        align-items: center;
    }

    .lay-verline {
        width: 2px;
        margin: 2px 5px;
    }

    .lay-verline + view{
        color: #000000;
    }

    .lay-card {
        font-size: 13px;
        background-color: #FFFFFF;
        padding: 11px;
        box-sizing: border-box;
        margin-bottom: 10px;
    }

    .lay-min-top {
        padding-top: 3px;
    }

    .lay-left-con {
        display: flex;
    }
</style>

3. List Component

<template name="list">
    <view>
        
        <view class="list-line">
            <view class="list-left" v-bind:style="{'background-color': color}"></view>
            <view class="list-right">{{title}}</view>
        </view>
        <view v-for="(item,index) in info" :key='index'>
            <view class='list-card'>
                <text>{{item}}</text>
            </view>
        </view>
        
    </view>
</template>S
<script>
    export default {
        name: "list",
        props: {
            title: {
                type: String, 
                default: "Default"
            },
            color: {
                type: String,
                default: "#79B2F9"
            },
            info: {
                type: Array
            }
        },
        methods: {}
    }
</script>
<style>
    .list-line{
        background-color: #FFFFFF;
        padding:10px 5px;
        box-sizing: border-box;
        display: flex;
        margin-bottom: 10px;
    }
    .list-line .list-left{
        width: 2px;
        margin: 2px 5px;
    }
    .list-card{
        font-size: 13px;
        background-color: #FFFFFF;
        padding: 15px;
        box-sizing: border-box;
        margin-bottom: 10px;
    }

</style>

4. Daily Sentence Component

<template name="sentence">
    <view>
        
        <view style="margin: 6px 0 8px 3px;">{{sentence}}</view>
        <view style="margin: 3px 0 8px 3px;">{{content}}</view>
        <image class="sent-image" :src="url" mode="aspectFill"></image>

    </view>
</template>
<script>
    export default {
        name: "sentence",
        props: {},
        methods: {},
        data() {
            return {
                url: "",
                sentence: "",
                content: ""
            }
        },
        created: function() {
            var that = this;
            uni.request({
                url: "https://open.iciba.com/dsapi/",
                success: function(res) {
                    that.url = res.data.picture2;
                    that.sentence = res.data.note;
                    that.content = res.data.content;
                }
            })
        }
    }
</script>
<style>
    .sent-image {
        width: 100%;
    }
</style>
<template name="weather">
    <view>

        <view class='weather'>
            <view class='weaLeft'>
                <view style="display: flex;align-items: center;justify-content: center;">
                    <image class='todayImg' mode="aspectFit" :src="host+'/public/static/weather/'+todayWeather[1]+'.png'"></image>
                </view>
                <view style='text-align:center;margin-top:6px;'>{{todayWeather[0]}}</view>
                <view style='text-align:center;margin-top:3px;'>{{todayWeather[2]}}℃ - {{todayWeather[3]}}℃</view>
                <view style='text-align:center;margin-top:3px;'>{{todayWeather[4]}}</view>
            </view>
            <view class='weaRight'>
                <view class='weaRightTop'>
                    <image class='dayImg' mode="aspectFit" :src="host+'/public/static/weather/'+tomorrowWeather[1]+'.png'"></image>
                    <view class='weatherCon'>
                        <view style='text-align:center;margin-top:6px;'>{{tomorrowWeather[0]}}</view>
                        <view style='text-align:center;margin-top:3px;'>{{tomorrowWeather[2]}}℃ - {{tomorrowWeather[3]}}℃</view>
                    </view>
                </view>
                <view class='weaRightBot'>
                    <image class='dayImg' mode="aspectFit" :src="host+'/public/static/weather/'+tdatomoWeather[1]+'.png'"></image>
                    <view class='weatherCon'>
                        <view style='text-align:center;margin-top:3px;'>{{tdatomoWeather[0]}}</view>
                        <view style='text-align:center;'>{{tdatomoWeather[2]}}℃ - {{tdatomoWeather[3]}}℃</view>
                    </view>
                </view>
            </view>
        </view>
</view>
</template>
<script>
    export default {
        name: "weather",
        props: {},
         methods: {},
         data() {
            return {
               todayWeather: ["", "CLEAR_DAY", 0, 0, "Data fetching"],
               tomorrowWeather: ["", "CLEAR_DAY", 0, 0],
               tdatomoWeather: ["", "CLEAR_DAY", 0, 0],
               host: "https://www.touchczy.top"
            }
         },
         created: function() {
            var that = this;
            var ran = parseInt(Math.random() * 100000000000);
            uni.request({
               url: "https://api.caiyunapp.com/v2/Y2FpeXVuIGFuZHJpb2QgYXBp/120.127164,36.000129/weather?lang=zh_CN&device_id=" +
                     ran,
               success: function(res) {
                     if (res.data.status === "ok") {
                        var weatherData = res.data.result.daily;
                        that.todayWeather = [weatherData.skycon[0].date, weatherData.skycon[0].value, weatherData.temperature[0].min,
                                 weatherData.temperature[0].max, res.data.result.hourly.description
                        ];
                        that.tomorrowWeather = [weatherData.skycon[1].date, weatherData.skycon[1].value, weatherData.temperature[1].min,
                                 weatherData.temperature[1].max
                        ];
                        that.tdatomoWeather = [weatherData.skycon[2].date, weatherData.skycon[2].value, weatherData.temperature[2].min,
                                 weatherData.temperature[2].max
                        ];
                     }
                  }
               });
            }
         }
      </script>
      <style>
         .weather {
            display: flex;
            border: 1px solid #eee;
            transition: all 0.8s;
            font-size: 13px;
            border-radius: 3px;
            border-bottom-left-radius: 0;
            border-bottom-right-radius: 0;
         }

         .weaLeft {
            width: 50% ;
            padding: 10px;
            border-right: 1px solid #eee;
         }

         .todayImg {
            width: 40px !important;
            height: 40px !important;
         }

         .dayImg {
            width: 30px !important;
            height: 30px !important;
            margin: 0 0 0 15px;
            align-self: center;
         }

         .weaRight {
            width: 50%;
         }
      </style>
/* Global Styles */
.weaRightBot,
.weaRightTop {
    display: flex;
    height: 50%;
    text-align: center;
}

.weaRightBot {
    border-top: 1px solid #eee;
}

.weatherCon {
    align-self: center;
    margin: 0 auto;
}

Chapter Five: Mini Program Deployment

1. Initialize the Mini Program

import dispose from "@/vector/dispose";
export default {
    globalData: {
        tips: "0",
        openid: "",
        userFlag: 0, // 0 not logged in, 1 logged in
        initData: {},
        version: "3.3.0",
        curTerm: "2019-2020-1",
        curTermStart: "2019-08-26",
        url: 'https://www.touchczy.top/',
        // url: 'http://dev.touchczy.top/',
    },
    onPageNotFound: (res) => { // Handling 404
        uni.reLaunch({
            url: 'pages/Home/auxiliary/notFound'
        })
    },
    onLaunch: function() {
        console.log("APP INIT");
        dispose.onLaunch.apply(this); // Start load event
    },
    onError: (err) => {
        console.log(err);
        dispose.toast("Internal Error");
    }
}

2. Global Styles

@import "@/vector/resources/asse.mini.wxss";
@import "@/vector/resources/iconfont.wxss";
button:after {
  border: none;
}
button {
  background: #fff;
  border: none;
  box-sizing: unset;
  padding: 0;
  margin: 0;
  font-size: 13px;
  line-height: unset;
  height: auto;
}
.adapt{
    box-sizing: border-box;
}
.tipsCon view{
    padding: 5px;
}