快应用:基本完成API对接

This commit is contained in:
7YHong 2022-02-09 00:23:04 +08:00
parent 4232570aba
commit 03f0e531ad
21 changed files with 994 additions and 498 deletions

View File

@ -12,15 +12,21 @@
"gen": "node ./scripts/gen/index.js",
"precommit-msg": "echo '🚧 start pre-commit checks ...' && exit 0",
"prettier": "node ./scripts/selfCloseInputTag.js && prettier --write \"src/**/*.{ux,js,json,less,scss,css,pcss,md,vue}\"",
"prettier-watcher": "onchange '**/*.md' \"src/**/**/*.{ux,js,json,less,scss,css,pcss,md,vue}\" -- prettier --write {{changed}}"
"prettier-watcher": "onchange '**/*.md' \"src/**/**/*.{ux,js,json,less,scss,css,pcss,md,vue}\" -- prettier --write {{changed}}",
"fa-build": "node node_modules/webpack/bin/webpack.js --config ./node_modules/fa-toolkit/webpack.config.js",
"fa-watch": "node node_modules/webpack/bin/webpack.js --watch --config ./node_modules/fa-toolkit/webpack.config.js",
"fa-release": "node ./node_modules/cross-env/src/bin/cross-env.js uglifyjs=true sign=release node_modules/webpack/bin/webpack.js --config ./node_modules/fa-toolkit/webpack.config.js"
},
"dependencies": {
"apex-ui": "^1.9.2"
"apex-ui": "^1.9.2",
"dayjs": "^1.10.7"
},
"devDependencies": {
"@babel/runtime": "^7.12.5",
"@types/quickapp": "npm:quickapp-interface@^1.0.0",
"colors": "^1.4.0",
"cross-env": "^7.0.2",
"fa-toolkit": "file:fa-toolkit-11.6.1-Stable.300.tgz",
"husky": "^7.0.1",
"less": "^4.1.1",
"less-loader": "^10.0.1",
@ -55,4 +61,4 @@
"browserslist": [
"chrome 65"
]
}
}

View File

@ -1,17 +1,62 @@
<script>
/**
* 应用级别的配置,供所有页面公用
*/
/**
* 应用级别的配置,供所有页面公用
*/
const $utils = require('./helper/utils').default
const $apis = require('./helper/apis').default
const $utils = require('./helper/utils').default
const $apis = require('./helper/apis').default
const $storage = require('@system.storage')
/* @desc: 注入方法至全局 global,以便页面调用 */
const hook2global = global.__proto__ || global
hook2global.$utils = $utils
hook2global.$apis = $apis
console.log('app: create channel');
const appInitC = new BroadcastChannel('init');
export default {
onCreate() {}
}
/* @desc: 注入方法至全局 global,以便页面调用 */
const hook2global = Object.getPrototypeOf(global) || global;
hook2global.$utils = $utils
hook2global.API = $apis
const _promiseFactory = (pointer, params = {}) => {
return new Promise((resolve, reject) => {
params = Object.assign({
success: (data) => { resolve(data); },
fail: (err, code) => { reject(err, code) }
}, params);
pointer(params);
});
}
hook2global.promiseFactory = _promiseFactory;
const userinfoFromToken = async (token) => {
$apis.setToken(token)
let userinfo = await $apis.userInfo()
userinfo.token = token
hook2global.$userinfo = userinfo
_promiseFactory($storage.set, { key: 'token', value: token })
appInitC.postMessage(1)
appInitC.close()
}
export default {
onCreate() {
console.log('app: init oncreate');
appInitC.onmessage = ({ data: token }) => {
console.log('app: login success, data=', JSON.stringify(token));
userinfoFromToken(token)
}
(async () => {
let token = await _promiseFactory($storage.get, { key: 'token' })
.catch((data, code) => {
console.warn(`get token from storage fail, code = ${code}`)
})
console.log(`app: get token = ${token} from storage success`)
if (token.length === 0) {
console.log('app: init token.length==0, send init message');
appInitC.postMessage(0)
return
}
userinfoFromToken(token)
})()
}
}
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -6,7 +6,7 @@ import $utils from './utils'
const TIMEOUT = 20000
Promise.prototype.finally = function(callback) {
Promise.prototype.finally = function (callback) {
const P = this.constructor
return this.then(
value => P.resolve(callback()).then(() => value),
@ -25,24 +25,21 @@ function fetchPromise(params) {
return new Promise((resolve, reject) => {
$fetch
.fetch({
url: params.url,
method: params.method,
data: params.data
...params,
responseType: 'json',
})
.then(response => {
const result = response.data
const content = JSON.parse(result.data)
/* @desc: 可跟具体不同业务接口数据,返回你所需要的部分,使得使用尽可能便捷 */
content.success ? resolve(content.value) : resolve(content.message)
.then(res => {
// console.log('ajax then', res)
const data = res.data.data
data.code === 0 ?
resolve(data.content)
: reject({ code: data.code, msg: data.error })
})
.catch((error, code) => {
console.log(`🐛 request fail, code = ${code}`)
reject(error)
})
.finally(() => {
console.log(`✔️ request @${params.url} has been completed.`)
resolve()
.catch(err => {
console.warn('ajax catch', err.data, err.code);
reject({ msg: err.data, code: err.code })
})
})
}
@ -66,20 +63,20 @@ function requestHandle(params, timeout = TIMEOUT) {
}
export default {
post: function(url, params) {
post: function (url, params) {
return requestHandle({
method: 'post',
url: url,
data: params
})
},
get: function(url, params) {
get: function (url, params) {
return requestHandle({
method: 'get',
url: $utils.queryString(url, params)
})
},
put: function(url, params) {
put: function (url, params) {
return requestHandle({
method: 'put',
url: url,

View File

@ -0,0 +1,75 @@
import $ajax from './ajax'
/**
* @desc 在实际开发中您可以将 baseUrl 替换为您的请求地址前缀
*
* 已将 $apis 挂载在 global您可以通过如下方式进行调用
* $apis.example.getApi().then().catch().finally()
*
* 备注如果您不需要发起请求删除 apis 目录以及 app.ux 中引用即可
*/
const baseUrl = 'https://pushdeer.qiyanghong.cn:5443/'
let token = ""
function to(promise) {
return promise
.catch(err => { $utils.showToast(err) });
}
export default {
setToken(t) {
token = t
},
login() {
return to($ajax.get(`${baseUrl}login/fake`).then(res => res.token))
},
userInfo() {
return to($ajax.post(`${baseUrl}user/info`, { token }))
},
// device
deviceReg(name, device_id) {
return to($ajax.post(`${baseUrl}device/reg`, { token, is_clip: 1, name, device_id }))
.then(res => res.devices)
},
deviceList() {
return to($ajax.post(`${baseUrl}device/list`, { token }))
.then(res => res.devices)
},
deviceRename(id, name) {
return to($ajax.post(`${baseUrl}device/rename`, { token, id, name }))
},
deviceRemove(id) {
return to($ajax.post(`${baseUrl}device/remove`, { token, id }))
},
// key
keyGen() {
return to($ajax.post(`${baseUrl}key/gen`, { token }))
.then(res => res.keys)
},
keyList() {
return to($ajax.post(`${baseUrl}key/list`, { token }))
.then(res => res.keys)
},
keyRename(id, name) {
return to($ajax.post(`${baseUrl}key/rename`, { token, id, name }))
},
keyRegen(id) {
return to($ajax.post(`${baseUrl}key/regen`, { token, id }))
},
keyRemove(id) {
return to($ajax.post(`${baseUrl}key/remove`, { token, id }))
},
// message
messageList() {
return to($ajax.post(`${baseUrl}message/list`, { token }))
.then(res => res.messages)
// [{"id":3,"uid":"1","text":"\u8fd9\u662f\u4ec0\u4e48\u54401111","desp":"","type":"markdown","created_at":"2021-12-22T12:09:46.000000Z"},{"id":2,"uid":"1","text":"\u8fd9\u662f\u4ec0\u4e48\u5440234","desp":"","type":"markdown","created_at":"2021-12-22T12:08:32.000000Z"}]
},
messagePush(text, desp, type) {
return to($ajax.post(`${baseUrl}message/push`, { token, text, desp, type }))
},
messageRemove(id) {
return to($ajax.post(`${baseUrl}message/remove`, { token, id }))
}
}

View File

@ -1,20 +0,0 @@
import $ajax from '../ajax'
/**
* @desc 在实际开发中您可以将 baseUrl 替换为您的请求地址前缀
*
* 已将 $apis 挂载在 global您可以通过如下方式进行调用
* $apis.example.getApi().then().catch().finally()
*
* 备注如果您不需要发起请求删除 apis 目录以及 app.ux 中引用即可
*/
const baseUrl = 'https://api.exampel.com/'
export default {
getApi(data) {
return $ajax.get(`${baseUrl}your-project-api`, data)
},
postOtherApi(data) {
return $ajax.post(`${baseUrl}your-project-api`, data)
}
}

View File

@ -1,14 +0,0 @@
/**
* 导出 apis 下目录的所有接口
*/
const files = require.context('.', true, /\.js/)
const modules = {}
files.keys().forEach(key => {
if (key === './index.js') {
return
}
modules[key.replace(/(^\.\/|\.js$)/g, '')] = files(key).default
})
export default modules

View File

@ -1,5 +1,5 @@
{
"package": "com.pushdeer.app",
"package": "dev.pushdeer.app",
"name": "pushdeer",
"versionName": "1.0.0",
"versionCode": 1,
@ -17,6 +17,12 @@
},
{
"name": "system.fetch"
},
{
"name": "system.storage"
},
{
"name": "system.device"
}
],
"permissions": [
@ -24,7 +30,6 @@
"origin": "*"
}
],
"template/official": "demo-template",
"config": {
"logLevel": "debug"
},
@ -37,6 +42,12 @@
"pages/Home": {
"component": "index",
"launchMode": "singleTask"
},
"pages/component": {
"component": "devpage"
},
"pages/swipe":{
"component": "index"
}
}
},

View File

@ -1,31 +0,0 @@
<template>
<div class="wrapper">
<text class="title">{{ title }}</text>
</div>
</template>
<script>
export default {
data: {
title: "Hello World. Quickapp Component."
},
props: [],
onInit() {}
}
</script>
<style lang="less">
@import './../../assets/styles/style.less';
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
}
.title {
text-align: center;
color: #212121;
}
</style>

View File

@ -1,4 +1,5 @@
<import name="dev-card" src="./card"></import>
<import name="swipe-item" src="../swipeItem"></import>
<template>
<div class="wrapper">
<!-- <text class="title">device</text>
@ -9,50 +10,99 @@
</div>
<list style="width: 80%">
<list-item type="devitem" for="{{ dev in devs}}">
<dev-card dev-obj="{{ dev }}" idx="{{ $idx }}"></dev-card>
<swipe-item>
<dev-card
slot="content"
dev-obj="{{ dev }}"
idx="{{ $idx }}"
></dev-card>
<div
slot="right"
style="height: 60px;width: 100px;padding: 0 20px;justify-content: center;"
@click="handleDeleteClick($idx)"
>
<image src="/assets/images/trash.png"></image>
</div>
</swipe-item>
</list-item>
</list>
</div>
</template>
<script>
export default {
data: {
devs: [
{ icon: "/assets/images/device-ipad.svg", name: "Easys iPad(当前设备)" },
{ icon: "/assets/images/device-ipad.svg", name: "备用机iPhone2" },
],
},
import device from '@system.device'
onPlusBtnClick() {
// $utils.showToast('aaaaa')
this.devs.push({ icon: "/assets/images/device-iphone.svg", name: "备用机iPhone" + (this.devs.length + 1) })
},
onInit() {
console.log('device', 'init')
const devIcon = {
"ios": "/assets/images/device-iphone.png",
"default": "/assets/images/device-iphone.png",
}
const handleDevResult = (data) => data.map((item) => {
return {
id: item.id,
name: item.name,
icon: item.type in devIcon ? devIcon[item.type] : devIcon["default"],
}
})
export default {
data: {
devs: [],
},
async onPlusBtnClick() {
try {
let devId = await promiseFactory(device.getDeviceId, {})
.then(res => res.deviceId)
let devList = await API.deviceReg($userinfo.name + '的手机', devId)
// console.log('devList: ', JSON.stringify(devList));
this.devs = handleDevResult(devList)
} catch (e) {
$utils.showToast(e.name + ':' + e.message)
}
},
async handleDeleteClick(idx) {
const id = this.devs[idx].id
console.log(`device: del item: idx=${idx}, id=${id}`);
this.devs.splice(idx)
API.deviceRemove(id)
},
onInit() {
console.log('device', 'init');
(async () => {
let devList = await API.deviceList()
// console.log('devList: ', JSON.stringify(devList));
this.devs = handleDevResult(devList)
// console.log('devs: ', JSON.stringify(this.devs));
// [{"uid":"1","is_clip":0,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"新设备","id":1,"type":"ios"},{"uid":"1","is_clip":1,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"easychen+new","id":2,"type":"ios"}]
})()
},
onReady() {
console.log('device', 'onready')
},
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
@import '../../../assets/styles/style.less';
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
text {
font-size: 48px;
color: #000000;
text {
font-size: 48px;
color: #000000;
}
}
}
}
</style>

View File

@ -2,116 +2,133 @@
<div class="card">
<div class="header">
<image style="height: 80px" src="/assets/images/avatar.svg" />
<text class="name" @click="onKeyNameClick">{{ key.name }}</text>
<input
id="keyname"
class="name"
enterkeytype="go"
@enterkeyclick="onKeynameEdited"
value="{{ key.name }}"
></input>
<image style="height: 36px" src="/assets/images/calander.svg" />
<text class="date">{{ key.date }}</text>
</div>
<text class="value">{{ key.value }} </text>
<text class="value">{{ key.value }}</text>
<!-- <div class="divider"></div> -->
<image class="divider" src="/assets/images/divider.png"></image>
<div class="footer">
<text style="color: #3b4789; border-color: #3b4789">重置</text>
<text
style="color: #3b4789; border-color: #3b4789"
@click="onResetBtnClick"
>
重置
</text>
<text
style="color: #ffffff; background-color: #3b4789"
@click="onCopyBtnClick"
>复制</text
>
复制
</text>
</div>
</div>
</template>
<script>
import clipboard from '@system.clipboard'
export default {
import clipboard from '@system.clipboard'
export default {
props: ['key', 'idx'],
props: ['key', 'idx'],
onKeyNameClick() {
$utils.showToast('改名功能待实现')
},
onKeynameEdited({ value: newname }) {
this.$element('keyname').focus({ focus: false })
this.$emit('keyRename', { idx: this.idx, newname })
},
onCopyBtnClick() {
clipboard.set({
text: this.key.value,
success: () => {
$utils.showToast('key已经复制到剪贴板')
}
})
},
onResetBtnClick() {
this.$emit('keyReset', { idx: this.idx });
},
onInit() {
// console.log('key', this.key, this.idx)
// console.log('card', 'name', this.devObj.name)
onCopyBtnClick() {
clipboard.set({
text: this.key.value,
success: () => {
$utils.showToast('key已经复制到剪贴板')
}
})
},
onInit() {
// console.log('key', this.key, this.idx)
// console.log('card', 'name', this.devObj.name)
}
}
}
</script>
<style lang="less">
@primary-color: #3b4789;
@secondry-color: #d6d6d6;
@font-color: #a7a7a7;
@primary-color: #3b4789;
@secondry-color: #d6d6d6;
@font-color: #a7a7a7;
.card {
flex-direction: column;
border-color: @primary-color;
border-radius: 16px;
border-width: 3px;
padding: 32px;
margin: 24px 0;
background-color: #ffffff;
width: 100%;
/* justify-content: center;
align-items: center; */
.header {
align-items: flex-end;
.date {
font-size: 24px;
color: @font-color;
}
.name {
color: @primary-color;
font-size: 36px;
flex-grow: 1;
}
}
.value {
margin: 48px 0;
padding: 16px;
font-size: 24px;
border-width: 2px;
border-radius: 8px;
border-color: @secondry-color;
color: @font-color;
lines: 1;
}
.divider {
.card {
flex-direction: column;
border-color: @primary-color;
border-radius: 16px;
border-width: 3px;
padding: 32px;
margin: 24px 0;
background-color: #ffffff;
width: 100%;
margin-bottom: 48px;
}
/* justify-content: center;
align-items: center; */
.footer {
justify-content: space-between;
.header {
align-items: flex-end;
text {
font-size: 30px;
padding: 16px 48px;
.date {
font-size: 24px;
color: @font-color;
}
.name {
color: @primary-color;
font-size: 36px;
flex-grow: 1;
}
}
.value {
margin: 48px 0;
padding: 16px;
font-size: 24px;
border-width: 2px;
border-radius: 16px;
border-radius: 8px;
border-color: @secondry-color;
color: @font-color;
lines: 1;
}
.divider {
width: 100%;
margin-bottom: 48px;
}
.footer {
justify-content: space-between;
text {
font-size: 30px;
padding: 16px 48px;
border-width: 2px;
border-radius: 16px;
}
}
}
}
/* .wrapper {
flex-direction: column;
justify-content: center;
align-items: center;
}
.title {
text-align: center;
color: #212121;
} */
/* .wrapper {
flex-direction: column;
justify-content: center;
align-items: center;
}
.title {
text-align: center;
color: #212121;
} */
</style>

View File

@ -1,4 +1,5 @@
<import name="key-card" src="./card"></import>
<import name="swipe-item" src="../swipeItem"></import>
<template>
<div class="wrapper">
<!-- <text class="title">device</text>
@ -9,52 +10,107 @@
</div>
<list style="width: 80%">
<list-item type="keyitem" for="{{ key in keys}}">
<key-card key="{{ key }}" idx="{{ $idx }}"></key-card>
<swipe-item>
<key-card
slot="content"
key="{{ key }}"
idx="{{ $idx }}"
@key-reset="onKeyReset"
@key-rename="onKeyRename"
></key-card>
<div
slot="right"
style="height: 60px;width: 100px;justify-content: center;"
@click="onDelBtnClick($idx)"
>
<image src="/assets/images/trash.png"></image>
</div>
</swipe-item>
</list-item>
</list>
</div>
</template>
<script>
export default {
data: {
keys: [
{ name: "Default", value: "PDU1DSE543JDZpq8Lx2gsSE543JD…", date: "2021/12/01" },
{ name: "点击改Key名", value: "PDU1DSE543JDZpq8Lx2gsSE543JD…", date: "2021/12/01" },
],
},
import dayjs from 'dayjs'
const handleKeyResult = (data) => data.map((item) => {
return {
id: item.id,
name: item.name,
value: item.key,
date: dayjs(item.created_at).format('YYYY/MM/DD'),
}
})
export default {
data: {
keys: [],
},
onPlusBtnClick() {
// $utils.showToast('aaaaa')
this.keys.push(
{ name: "Default", value: "PDU1DSE543JDZpq8Lx2gsSE543JD…", date: "2021/12/01" },
)
},
async onPlusBtnClick() {
let keyList = await API.keyGen()
this.keys = handleKeyResult(keyList)
},
onInit() {
console.log('key', 'init', this.keys)
async handleRename(e) {
console.log(JSON.stringify(e));
},
async onDelBtnClick(idx) {
const id = this.keys[idx].id
console.log(`key: del item: idx=${idx}, id=${id}`);
this.keys.splice(idx)
API.keyRemove(id)
},
async onKeyReset({ detail: { idx } }) {
console.log(`key: onKeyReset: idx=${idx}`);
const id = this.keys[idx].id
let result = await API.keyRegen(id)
if (!result) { return }
let keyList = await API.keyList()
this.keys = handleKeyResult(keyList)
},
async onKeyRename({ detail: { idx, newname } }) {
const id = this.keys[idx].id
console.log(`key: onKeyRename: idx=${idx}, newname=${newname}`);
let result = await API.keyRename(id, newname)
if (result) {
this.keys[idx].name = newname
}
},
onInit() {
(async () => {
let keyList = await API.keyList()
// console.log('devList: ', JSON.stringify(devList));
this.keys = handleKeyResult(keyList)
console.log('keys: ', JSON.stringify(this.keys));
})().catch(e => {
console.log(e);
})
}
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
@import '../../../assets/styles/style.less';
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
text {
font-size: 48px;
color: #000000;
text {
font-size: 48px;
color: #000000;
}
}
}
}
</style>

View File

@ -1,6 +1,4 @@
<import name="msg-text" src="./msg-text"></import>
<import name="msg-image" src="./msg-image"></import>
<import name="msg-markdown" src="./msg-markdown"></import>
<import name="msg-card" src="./msg-card"></import>
<template>
<div class="wrapper">
<div class="header">
@ -11,9 +9,7 @@
/>
</div>
<div if="{{!collapsed}}" class="pushmsg-region">
<textarea class="textarea" @change="onTextAreaChange">{{
input
}}</textarea>
<textarea class="textarea" @change="onTextAreaChange">{{input}}</textarea>
<text class="pushbtn" @click="onPushBtnClick">推送测试</text>
</div>
<list>
@ -22,108 +18,116 @@
if="{{supportType.includes(msg.type)}}"
for="{{ msg in msgs}}"
>
<component is="{{ 'msg-'+msg.type}}" msg="{{ msg}}"></component>
<msg-card msg="{{ msg}}"></msg-card>
</list-item>
</list>
</div>
</template>
<script>
export default {
data: {
collapsed: false,
supportType: ['text', 'image', 'markdown'],
input: '',
msgs: [
{
name: "Default", created_at: "5分钟前", type: "text",
text: `纯文本的效果。长文字需要自动换行。
长文字需要自动换行。行间距24。
长按可以复制文本内容。左滑显示删除。`
},
{
name: "推送Key的名字", created_at: "5分钟前", type: "markdown",
text: `<p>支持Markdown语法。比如可以插入<a href="https://www.baidu.com/">链接</a>
点击后使用系统浏览器直接打开。</p>`
},
{
name: "Default", created_at: "5分钟前", type: "image",
text: `https://wikipic.ftqq.com/wp-content/uploads/2021/08/jessy-smith-zFOm6KzA-7g-unsplash.jpg`
},
],
},
onArrowBtnClick() {
this.collapsed = !this.collapsed
},
onTextAreaChange(e) {
// 只能在change事件里取值不知道作者怎么想的。。。
this.input = e.text
},
onPushBtnClick() {
if (this.input.length == 0) {
$utils.showToast("消息内容为空")
return
import dayjs from 'dayjs'
var md = require('markdown-it')();
const handleMessageResult = (data) => data.map((item) => {
const created_at = dayjs(item.created_at)
const diffMinute = dayjs().diff(created_at, 'm')
return {
id: item.id,
name: item.pushkey_name,
type: item.type,
text: item.type === 'markdown' ? md.render(item.text) : item.text,
desp: item.desp,
created_at: diffMinute >= 0 && diffMinute <= 10 ? `${diffMinute}分钟前` : created_at.format('YYYY/MM/DD hh:mm:ss'),
}
console.log('message', 'onPushBtnClick', this.input)
this.msgs.unshift({ name: "本设备", created_at: "刚刚", type: "text", text: this.input })
this.input = ""
},
}).reverse()
onInit() {
console.log('message', 'init')
export default {
data: {
collapsed: false,
supportType: ['text', 'image', 'markdown'],
input: '',
msgs: [],
},
onArrowBtnClick() {
this.collapsed = !this.collapsed
},
onTextAreaChange(e) {
// 只能在change事件里取值不知道作者怎么想的。。。
this.input = e.text
},
onPushBtnClick() {
if (this.input.length == 0) {
$utils.showToast("消息内容为空")
return
}
console.log('message', 'onPushBtnClick', this.input)
this.msgs.unshift({ name: "本设备", created_at: "刚刚", type: "text", text: this.input })
this.input = ""
},
onInit() {
console.log('message', 'init');
(async () => {
let messageList = await API.messageList()
console.log('messageList: ', JSON.stringify(messageList));
this.msgs = handleMessageResult(messageList)
console.log('msgs: ', JSON.stringify(this.msgs));
})().catch(e => {
console.log(e);
})
}
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
@import '../../../assets/styles/style.less';
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.wrapper {
.flex-box-mixins(column, flex-start, center);
width: 100%;
height: 100%;
padding-top: 84px;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
flex-shrink: 0;
.header {
margin-bottom: 24px;
width: 80%;
justify-content: space-between;
flex-shrink: 0;
text {
font-size: 48px;
color: #000000;
text {
font-size: 48px;
color: #000000;
}
}
.pushmsg-region {
margin: 24px 0;
width: 80%;
height: 30%;
flex-direction: column;
/* justify-content: space-between; */
align-items: flex-start;
.textarea {
width: 100%;
flex-grow: 1;
padding: 24px;
font-size: 32px;
border-color: @primary-color;
border-width: 3px;
border-radius: 8px;
background-color: #ffffff;
}
.pushbtn {
color: #ffffff;
font-size: 30px;
margin-top: 48px;
padding: 24px;
border-radius: 16px;
background-color: @primary-color;
}
}
}
.pushmsg-region {
margin: 24px 0;
width: 80%;
height: 30%;
flex-direction: column;
/* justify-content: space-between; */
align-items: flex-start;
.textarea {
width: 100%;
flex-grow: 1;
padding: 24px;
font-size: 32px;
border-color: @primary-color;
border-width: 3px;
border-radius: 8px;
background-color: #ffffff;
}
.pushbtn {
color: #ffffff;
font-size: 30px;
margin-top: 48px;
padding: 24px;
border-radius: 16px;
background-color: @primary-color;
}
}
}
</style>

View File

@ -0,0 +1,58 @@
<import name="msg-header" src="./msg-header"></import>
<import name="swipe-item" src="../swipeItem"></import>
<template>
<div class="card">
<msg-header title="{{msg.name +' · '+ msg.created_at}}"></msg-header>
<text if="{{msg.type === 'text'}}" class="text">{{ msg.text }}</text>
<div if="{{msg.type ==='markdown'}}" class="text">
<richtext type="html">{{msg.text}}</richtext>
</div>
<image if="{{msg.type ==='image'}}" class="image" src="{{msg.text}}"></image>
</div>
</template>
<script>
import clipboard from '@system.clipboard'
export default {
props: ['msg'],
onInit() {
// console.log('msg-text',this.msg)
if (this.msg.type !== 'image' && this.msg.desp.length > 0) {
this.msg.text += "\n" + this.msg.desp
}
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
.card {
.flex-box-mixins(column, flex-start, center);
margin: 24px 0;
width: 100%;
.text {
width: 80%;
margin-top: 32px;
color: #535353;
font-size: 24px;
line-height: 48px;
padding: 24px;
border-width: 2px;
border-radius: 8px;
border-color: @primary-color;
background-color: #ffffff;
}
.image {
width: 100%;
margin-top: 32px;
}
}
</style>

View File

@ -1,34 +0,0 @@
<import name="msg-header" src="./msg-header"></import>
<template>
<div class="card">
<msg-header title="{{msg.name +' · '+ msg.created_at}}"></msg-header>
<image class="image" src="{{msg.text}}"></image>
</div>
</template>
<script>
import clipboard from '@system.clipboard'
export default {
props: ['msg'],
onInit() {
// console.log('msg-text',this.msg)
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
.card {
.flex-box-mixins(column, flex-start, center);
margin: 24px 0;
width: 100%;
.image {
width: 100%;
margin-top: 32px;
}
}
</style>

View File

@ -1,44 +0,0 @@
<import name="msg-header" src="./msg-header"></import>
<template>
<div class="card">
<msg-header title="{{msg.name +' · '+ msg.created_at}}"></msg-header>
<div class="markdown">
<richtext type="html" >{{msg.text}}</richtext>
</div>
</div>
</template>
<script>
import clipboard from '@system.clipboard'
export default {
props: ['msg'],
onInit() {
// console.log('msg-text',this.msg)
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
.card {
.flex-box-mixins(column, flex-start, center);
margin: 24px 0;
width: 100%;
.markdown {
width: 80%;
margin-top: 32px;
color: #535353;
font-size: 24px;
line-height: 48px;
padding: 24px;
border-width: 2px;
border-radius: 8px;
border-color: @primary-color;
background-color: #ffffff;
}
}
</style>

View File

@ -1,42 +0,0 @@
<import name="msg-header" src="./msg-header"></import>
<template>
<div class="card">
<msg-header title="{{msg.name +' · '+ msg.created_at}}"></msg-header>
<text class="text">{{ msg.text }}</text>
</div>
</template>
<script>
import clipboard from '@system.clipboard'
export default {
props: ['msg'],
onInit() {
// console.log('msg-text',this.msg)
}
}
</script>
<style lang="less">
@import '../../../assets/styles/style.less';
.card {
.flex-box-mixins(column, flex-start, center);
margin: 24px 0;
width: 100%;
.text {
width: 80%;
margin-top: 32px;
color: #535353;
font-size: 24px;
line-height: 48px;
padding: 24px;
border-width: 2px;
border-radius: 8px;
border-color: @primary-color;
background-color: #ffffff;
}
}
</style>

View File

@ -0,0 +1,163 @@
<!-- <import name="button" src="apex-ui/components/button/index"></import> -->
<template>
<!-- template里只能有一个根节点 -->
<div class="wrapper">
<list style="width: 50%">
<list-item type="devitem" for="{{ s in btns}}">
<text style="width: 100%;" @click="{{handleBtnClick($idx)}}">
{{s.label}}
</text>
</list-item>
</list>
</div>
</template>
<script>
import device from '@system.device'
export default {
// 页面级组件的数据模型影响传入数据的覆盖机制private内定义的属性不允许被覆盖
private: {
btns: [
{
label: '获取userinfo', handle: async () => {
let userinfo = await API.userInfo()
console.log(`userinfo is `, userinfo)
// {"updated_at":"2022-01-30T15:48:56.000000Z","level":1,"name":"easychen+new","created_at":"2022-01-30T15:48:56.000000Z","id":1,"apple_id":"theid999","email":"easychen+new@gmail.com"}
}
},
{
label: '获取deviceID', handle: async () => {
let devId = await promiseFactory(device.getDeviceId, {})
.then(res => res.deviceId)
console.log(`deviceId is `, devId);
}
},
// Device
{
label: '注册设备', handle: async () => {
let devId = await promiseFactory(device.getDeviceId, {})
.then(res => res.deviceId)
let userinfo = await API.userInfo()
console.log(`获取到name=${userinfo.name} ,deviceId=${devId}`);
let result = await API.deviceReg(userinfo.name, devId)
console.log('注册结果:', JSON.stringify(result));
// [{"uid":"1","is_clip":0,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"新设备","id":1,"type":"ios"},{"uid":"1","is_clip":1,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"easychen+new","id":2,"type":"ios"}]
}
},
{
label: '设备列表', handle: async () => {
let devList = await API.deviceList()
console.log('devList: ', JSON.stringify(devList));
// [{"uid":"1","is_clip":0,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"新设备","id":1,"type":"ios"},{"uid":"1","is_clip":1,"device_id":"f787bbf3-fffd-a2d7-fef9-716ff1bf1809","name":"easychen+new","id":2,"type":"ios"}]
}
},
{
label: '重命名设备', handle: async () => {
let result = await API.deviceRename(1, '新设备')
console.log('重命名结果: ', JSON.stringify(result));
// {"message":"done"}
}
},
{
label: '移除设备', handle: async () => {
let result = await API.deviceRemove(2)
console.log('移除结果: ', JSON.stringify(result));
// {"message":"done"}
}
},
// Key
{
label: '生成Key', handle: async () => {
let result = await API.keyGen()
console.log('生成结果:', JSON.stringify(result));
//[{"uid":"1","name":"KeydjzKuP4v","created_at":"2022-02-05T05:05:44.000000Z","id":1,"key":"PDU1TEkEzYvahqzI9BVsPLojC86XQJWX6AcWW"},{"uid":"1","name":"KeyD56XoKTR","created_at":"2022-02-05T05:06:08.000000Z","id":2,"key":"PDU1TYHP2rEnVGUpGjJ4uwm59nBwLAraN3QwV"}]
}
},
{
label: 'Key列表', handle: async () => {
let keyList = await API.keyList()
console.log('keyList: ', JSON.stringify(keyList));
//[{"uid":"1","name":"KeydjzKuP4v","created_at":"2022-02-05T05:05:44.000000Z","id":1,"key":"PDU1TEkEzYvahqzI9BVsPLojC86XQJWX6AcWW"},{"uid":"1","name":"KeyD56XoKTR","created_at":"2022-02-05T05:06:08.000000Z","id":2,"key":"PDU1TYHP2rEnVGUpGjJ4uwm59nBwLAraN3QwV"}]
}
},
{
label: '重命名Key', handle: async () => {
let result = await API.keyRename(1, '新Key')
console.log('重命名结果: ', JSON.stringify(result));
// {"message":"done"}
}
},
{
label: '移除Key', handle: async () => {
let result = await API.keyRemove(4)
console.log('移除结果: ', JSON.stringify(result));
// {"message":"done"}
}
},
{
label: '消息列表', handle: async () => {
let messageList = await API.messageList()
console.log('messageList: ', JSON.stringify(messageList));
}
},
{
label: '发送消息', handle: async () => {
let result = await API.messagePush('text', 'desp', 'text')
console.log('发送结果: ', JSON.stringify(result));
}
},
{
label: '移除message', handle: async () => {
let result = await API.messageRemove(1)
console.log('移除结果: ', JSON.stringify(result));
// {"message":"done"}
}
},
]
},
handleBtnClick(idx) {
this.btns[idx].handle()
},
onInit() {
},
}
</script>
<style lang="less">
.wrapper {
flex-direction: column;
align-items: center;
height: 100%;
.logo {
flex-direction: column;
justify-content: center;
height: 60%;
width: 50%;
}
/* .btn-group {
flex-direction: column;
width: 50%; */
/* margin: 0 auto; */
text {
margin: 16px 0;
padding: 24px;
border-width: 3px;
border-radius: 8px;
text-align: center;
font-size: 32px;
}
.btn-wx {
color: #296c05;
border-color: #296c05;
}
}
/* } */
</style>

View File

@ -0,0 +1,108 @@
<template>
<stack
class="swipe_item"
@touchstart="dealTouchStart"
@touchmove="dealTouchMove"
@touchend="dealTouchEnd"
@touchcancel="dealTouchEnd"
>
<div id="right">
<slot name="right"></slot>
</div>
<div id="content">
<slot name="content"></slot>
</div>
</stack>
</template>
<style lang="less">
.swipe_item {
width: 100%;
justify-content: flex-end;
align-items: center;
}
</style>
<script>
let $animation = null
module.exports = {
data: {
movestartX: 0,
threshold: 30,
isOpened: false,
contentPosX: 0,
btnAreaWidth: 120,
},
computed: {
},
onInit() {
let that=this
setTimeout(() => {
this.$element('right').getBoundingClientRect({
success(res) {
that.btnAreaWidth=res.width
// console.log(`res=${JSON.stringify(res)}`);
}
})
}, 500);
},
dealTouchStart(e) {
this.movestartX = e.touches[0].clientX;
console.info("dealTouchStart movestartX=" + e.touches[0].clientX);
},
dealTouchMove(e) {
let [deltaX, contentX] = this.calX(e.touches[0].clientX)
// console.info(`dealTouchMove deltaX= ${deltaX},contentX= ${contentX}`);
if (Math.abs(deltaX) < this.threshold) {
return;
}
if (contentX > 0) {
return
}
this.animate(contentX, contentX, true)
},
dealTouchEnd(e) {
let [deltaX, contentX] = this.calX(e.changedTouches[0].clientX)
if (contentX > 0) {
contentX = 0
}
this.isOpened = contentX < -this.btnAreaWidth ? true : false
this.contentPosX = this.isOpened ? -this.btnAreaWidth : 0
console.info(`dealTouchEnd dis=${deltaX}, contentX=${contentX}, isOpened=${this.isOpened},contentPosX=${this.contentPosX}`);
this.animate(contentX, this.contentPosX)
},
calX(clientX) {
let deltaX = clientX - this.movestartX
let contentX = this.contentPosX + deltaX
return [deltaX, contentX]
},
animate(value1, value2, immediately = false) {
// console.log(`animate from ${value1} to ${value2}, immediately=${immediately}`)
let options = {
duration: immediately ? 0 : 300,
easing: 'linear',
delay: 0,
fill: 'forwards',
iterations: 1
}
let frames = [
{
transform: {
translateX: `${value1}px`,
}
},
{
transform: {
translateX: `${value2}px`,
}
}];
let $animation = this.$element('content').animate(frames, options);
$animation.play();
},
}
</script>

View File

@ -3,11 +3,11 @@
<!-- template里只能有一个根节点 -->
<div class="wrapper">
<div class="logo">
<img src="/assets/images/index-logo.svg" />
<image src="/assets/images/index-logo.svg" />
</div>
<div class="btn-group">
<text class="btn-wx" @click="onWxSignBtnClick">Sign in with WeChat</text>
<!-- class="btn-wx"
<!-- class="btn-wx"
value="Sign in with WeChat"
onclick="onWxSignBtnClick"
/> -->
@ -16,54 +16,66 @@
</template>
<script>
import router from '@system.router'
import router from '@system.router'
export default {
// 页面级组件的数据模型影响传入数据的覆盖机制private内定义的属性不允许被覆盖
private: {
},
const appInitC = new BroadcastChannel('init')
appInitC.onmessage = ({ data }) => {
console.log(`index: received app init message:${data}`);
if (data === 1) {
appInitC.close()
router.replace({
uri: 'pages/Home'
})
}
}
onWxSignBtnClick() {
router.replace({
uri: '/pages/Home',
})
},
export default {
// 页面级组件的数据模型影响传入数据的覆盖机制private内定义的属性不允许被覆盖
private: {
},
onInit() {
},
}
async onWxSignBtnClick() {
API.login()
.then(token => {
appInitC.postMessage(token)
})
},
onInit() {
},
}
</script>
<style lang="less">
.wrapper {
flex-direction: column;
align-items: center;
height: 100%;
.logo {
.wrapper {
flex-direction: column;
justify-content: center;
height: 60%;
width: 50%;
}
align-items: center;
height: 100%;
.btn-group {
flex-direction: column;
width: 50%;
/* margin: 0 auto; */
text {
margin: 16px 0;
padding: 24px;
border-width: 3px;
border-radius: 8px;
text-align: center;
font-size: 32px;
.logo {
flex-direction: column;
justify-content: center;
height: 60%;
width: 50%;
}
.btn-wx {
color: #296c05;
border-color: #296c05;
.btn-group {
flex-direction: column;
width: 50%;
/* margin: 0 auto; */
text {
margin: 16px 0;
padding: 24px;
border-width: 3px;
border-radius: 8px;
text-align: center;
font-size: 32px;
}
.btn-wx {
color: #296c05;
border-color: #296c05;
}
}
}
}
</style>

View File

@ -0,0 +1,79 @@
<import name="swipe_item" src="../component/swipeItem"></import>
<template>
<div>
<swipe_item>
<text slot="content" class="main">text</text>
<div slot="right" class="right">
<image src="/assets/images/trash.png"></image>
</div>
</swipe_item>
</div>
</template>
<style>
.main {
width: 100%;
text-align: center;
background-color: blue;
height: 100px;
}
.right {
height: 60px;
width: 100px;
justify-content: center;
}
</style>
<script>
import prompt from '@system.prompt'
export default {
private: {
componentName: 'slide-view',
slideButton1: [
{
id: "button1",
buttonWidth: '200px',
text: '删除',
backgroundColor: "#cc0000",
secondaryConfirm: {
text: '二次确认'
}
}
],
slideButton2: [
{
id: "button2",
buttonWidth: '200px',
icon: '../../../common/logo.png',
backgroundColor: "#cc0000",
secondaryConfirm: {
text: '二次确认'
}
}
]
},
onInit() {
this.$page.setTitleBar({ text: 'slide-view' })
},
slideViewOpen() {
console.info(`### slide view is open ###`)
},
slideViewClose() {
console.info(`### slide view is close ###`)
},
slideViewSlide({ offset }) {
console.info(`### slide view is slide, offset is ${offset} ###`)
},
buttonClick(data) {
const { id, isSecondaryConfirm } = data
console.info(`### button:${id} is click, data is ${data} ###`)
if (isSecondaryConfirm) {
prompt.showToast({
message: '第二次点击触发'
})
} else {
prompt.showToast({
message: '第一次点击触发'
})
}
}
}
</script>