refactor: 确立独立子工程架构 (backend, admin, mpuniapp) 并同步更新 AGENTS.md 规范
这个提交包含在:
@@ -0,0 +1,334 @@
|
||||
jest.setTimeout(30000)
|
||||
|
||||
const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase()
|
||||
const isIOS = platformInfo.startsWith('ios')
|
||||
const isMP = platformInfo.startsWith('mp')
|
||||
|
||||
describe('ExtApi-StorageInfoTest', () => {
|
||||
if ( isMP) {
|
||||
it('skip', async () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isIOS &&
|
||||
(
|
||||
platformInfo.indexOf('15.5') != -1 ||
|
||||
platformInfo.indexOf('14.5') != -1 ||
|
||||
platformInfo.indexOf('13.7') != -1 ||
|
||||
platformInfo.indexOf('12.4') != -1
|
||||
)
|
||||
) {
|
||||
// TODO: 排查 ios 不兼容版本 测试异常原因
|
||||
it('ios 15.5 14.5 13.7 12.4 测试异常', () => {
|
||||
expect(1).toBe(1)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const StorageKeysBlackList = [
|
||||
'$$STAT__DBDATA:__UNI__HelloUniAppX',
|
||||
'_STAT_LAST_PAGE_ROUTE',
|
||||
'UNI_STAT_DATA:__UNI__HelloUniAppX',
|
||||
'UNI_STAT_LAST_PAGE_ROUTE'
|
||||
]
|
||||
const filterStorageKeys = (keys) => {
|
||||
return keys.filter(key => {
|
||||
return !StorageKeysBlackList.includes(key)
|
||||
})
|
||||
}
|
||||
|
||||
const PAGE_PATH = '/pages/API/storage/storage'
|
||||
let page;
|
||||
|
||||
// 测试辅助函数
|
||||
async function setPageData(newData) {
|
||||
return await page.setData({ data: newData });
|
||||
}
|
||||
|
||||
function getData (key = '') {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const data = await page.data('data')
|
||||
resolve(key ? data[key] : data)
|
||||
})
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
page = await program.reLaunch(PAGE_PATH)
|
||||
await page.waitFor(600);
|
||||
});
|
||||
|
||||
it('Check async properties', async () => {
|
||||
// 异步存储测试
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: "长安大道连狭斜,青牛白马七香车。玉辇纵横过主第,金鞭络绎向侯家。龙衔宝盖承朝日,凤吐流苏带晚霞。百尺游丝争绕树,一群娇鸟共啼花。游蜂戏蝶千门侧,碧树银台万种色。复道交窗作合欢,双阙连甍垂凤翼。"
|
||||
})
|
||||
await page.waitFor(600)
|
||||
const btnSetStorageButtonInfo = await page.$('.btn-setstorageAsync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
const btnGetStorageButtonInfo = await page.$('.btn-getstorageAsync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual("长安大道连狭斜,青牛白马七香车。玉辇纵横过主第,金鞭络绎向侯家。龙衔宝盖承朝日,凤吐流苏带晚霞。百尺游丝争绕树,一群娇鸟共啼花。游蜂戏蝶千门侧,碧树银台万种色。复道交窗作合欢,双阙连甍垂凤翼。")
|
||||
|
||||
// 测试 clear
|
||||
let btnGetStorageInfoASyncButton = await page.$('.btn-getStorageInfoASync')
|
||||
// await btnGetStorageInfoASyncButton.tap()
|
||||
// await page.waitFor(600)
|
||||
// storageInfoRet = await getData('apiGetData')
|
||||
// expect(storageInfoRet.keys[0]).toEqual("autotest_key_mock")
|
||||
|
||||
const btnClearStorageInfoASyncButton = await page.$('.btn-clearStorageInfoASync')
|
||||
await btnClearStorageInfoASyncButton.tap()
|
||||
page.waitFor(600)
|
||||
|
||||
await btnGetStorageInfoASyncButton.tap()
|
||||
await page.waitFor(600)
|
||||
storageInfoRet = await getData('apiGetData')
|
||||
expect(filterStorageKeys(storageInfoRet.keys).length).toEqual(0)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: 1100.8989
|
||||
})
|
||||
await page.waitFor(600)
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual(1100.8989)
|
||||
|
||||
// 测试 remove
|
||||
// await btnGetStorageInfoASyncButton.tap()
|
||||
// await page.waitFor(600)
|
||||
// storageInfoRet = await getData('apiGetData')
|
||||
// expect(storageInfoRet.keys[0]).toEqual("autotest_key_mock")
|
||||
|
||||
const btnRemoveStorageInfoASyncButton = await page.$('.btn-removeStorageInfoASync')
|
||||
await btnRemoveStorageInfoASyncButton.tap()
|
||||
page.waitFor(600)
|
||||
|
||||
await btnGetStorageInfoASyncButton.tap()
|
||||
await page.waitFor(600)
|
||||
storageInfoRet = await getData('apiGetData')
|
||||
expect(filterStorageKeys(storageInfoRet.keys).length).toEqual(0)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: 123456789
|
||||
})
|
||||
await page.waitFor(600)
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual(123456789)
|
||||
|
||||
let userObj = {
|
||||
name: "zhangsan",
|
||||
age: 12
|
||||
}
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: userObj
|
||||
})
|
||||
await page.waitFor(600)
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual(userObj)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: {
|
||||
name: "zhangsan",
|
||||
age: 122
|
||||
}
|
||||
})
|
||||
await page.waitFor(600)
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let objRet = await getData('apiGetData')
|
||||
expect(objRet.age).toEqual(122)
|
||||
});
|
||||
|
||||
it('Check sync properties', async () => {
|
||||
let btnComplexStaticTest = await page.$('.btn-complexStaticTest')
|
||||
await btnComplexStaticTest.tap()
|
||||
await page.waitFor(600)
|
||||
if (!isIOS) {
|
||||
expect(await getData('staticComplexRet')).toEqual(true)
|
||||
}
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: "长安大道连狭斜,青牛白马七香车。玉辇纵横过主第,金鞭络绎向侯家。龙衔宝盖承朝日,凤吐流苏带晚霞。百尺游丝争绕树,一群娇鸟共啼花。游蜂戏蝶千门侧,碧树银台万种色。复道交窗作合欢,双阙连甍垂凤翼。"
|
||||
})
|
||||
await page.waitFor(600)
|
||||
let btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual("长安大道连狭斜,青牛白马七香车。玉辇纵横过主第,金鞭络绎向侯家。龙衔宝盖承朝日,凤吐流苏带晚霞。百尺游丝争绕树,一群娇鸟共啼花。游蜂戏蝶千门侧,碧树银台万种色。复道交窗作合欢,双阙连甍垂凤翼。")
|
||||
|
||||
// 测试clear
|
||||
const btnGetStorageInfoSyncButton = await page.$('.btn-getStorageInfoSync')
|
||||
// await btnGetStorageInfoSyncButton.tap()
|
||||
// await page.waitFor(600)
|
||||
// let storageInfoRet = await getData('apiGetData')
|
||||
// expect(storageInfoRet.keys[0]).toEqual("autotest_key_mock")
|
||||
|
||||
const btnClearStorageInfoSyncButton = await page.$('.btn-clearStorageInfoSync')
|
||||
await btnClearStorageInfoSyncButton.tap()
|
||||
|
||||
await btnGetStorageInfoSyncButton.tap()
|
||||
await page.waitFor(600)
|
||||
storageInfoRet = await getData('apiGetData')
|
||||
expect(filterStorageKeys(storageInfoRet.keys).length).toEqual(0)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: 12345789.235689
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual(12345789.235689)
|
||||
|
||||
// 测试 remove
|
||||
// await btnGetStorageInfoSyncButton.tap()
|
||||
// await page.waitFor(600)
|
||||
// storageInfoRet = await getData('apiGetData')
|
||||
// expect(storageInfoRet.keys[0]).toEqual("autotest_key_mock")
|
||||
|
||||
const btnRemoveStorageInfoSyncButton = await page.$('.btn-removeStorageInfoSync')
|
||||
await btnRemoveStorageInfoSyncButton.tap()
|
||||
page.waitFor(600)
|
||||
|
||||
await btnGetStorageInfoSyncButton.tap()
|
||||
await page.waitFor(600)
|
||||
storageInfoRet = await getData('apiGetData')
|
||||
expect(filterStorageKeys(storageInfoRet.keys).length).toEqual(0)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: 0
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
expect(await getData('apiGetData')).toEqual(0)
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: {
|
||||
name: "tom",
|
||||
age: 10
|
||||
}
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let objRet = await getData('apiGetData')
|
||||
expect(objRet.name).toEqual("tom")
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: JSON.stringify({
|
||||
name: "james",
|
||||
age: 12,
|
||||
from: "american"
|
||||
})
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let jsonStr = await getData('apiGetData')
|
||||
// 顺序不能保证,验证长度和各个属性来区分
|
||||
let parseObj = JSON.parse(jsonStr)
|
||||
expect(jsonStr.length).toEqual(43)
|
||||
expect(parseObj['age']).toEqual(12)
|
||||
expect(parseObj['from']).toEqual('american')
|
||||
expect(parseObj['name']).toEqual('james')
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: "1234567890"
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let strRet = await getData('apiGetData')
|
||||
// 顺序不能保证,验证长度和各个属性来区分
|
||||
expect(typeof strRet).toEqual("string")
|
||||
expect(strRet).toEqual("1234567890")
|
||||
|
||||
await setPageData({
|
||||
key: "autotest_key_mock",
|
||||
data: "1234567.890"
|
||||
})
|
||||
await page.waitFor(600)
|
||||
btnSetStorageButtonInfo = await page.$('.btn-setstorageSync')
|
||||
await btnSetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
btnGetStorageButtonInfo = await page.$('.btn-getstorageSync')
|
||||
await btnGetStorageButtonInfo.tap()
|
||||
await page.waitFor(600)
|
||||
let strRet2 = await getData('apiGetData')
|
||||
// 顺序不能保证,验证长度和各个属性来区分
|
||||
expect(typeof strRet2).toEqual("string")
|
||||
expect(strRet2).toEqual("1234567.890")
|
||||
});
|
||||
|
||||
it('saveUTSJSONObject', async () => {
|
||||
await page.callMethod('jest_saveUTSJSONObject')
|
||||
await page.waitFor(600)
|
||||
const {
|
||||
jest_saveUTSJSONObjectSyncResult,
|
||||
jest_saveUTSJSONObjectAsyncResult
|
||||
} = await page.data('data')
|
||||
expect(jest_saveUTSJSONObjectSyncResult).toBe(1)
|
||||
expect(jest_saveUTSJSONObjectAsyncResult).toBe(1)
|
||||
})
|
||||
|
||||
// ios js 层与原生层通信时,原始数据类型丢失
|
||||
if (!isIOS) {
|
||||
it('saveUTSJSONObjectArray', async () => {
|
||||
await page.callMethod('jest_saveUTSJSONObjectArray')
|
||||
await page.waitFor(600)
|
||||
const {
|
||||
jest_saveUTSJSONObjectArraySyncResult
|
||||
} = await page.data('data')
|
||||
expect(jest_saveUTSJSONObjectArraySyncResult).toBe(1)
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,525 @@
|
||||
<template>
|
||||
<!-- #ifdef APP && !VUE3-VAPOR -->
|
||||
<scroll-view class="page-scroll-view">
|
||||
<!-- #endif -->
|
||||
<view>
|
||||
<page-head :title="data.title"></page-head>
|
||||
<view class="uni-common-mt">
|
||||
<view class="uni-list">
|
||||
<view class="uni-list-cell uni-list-cell-line">
|
||||
<view class="uni-list-cell-left">
|
||||
<view class="uni-label">key</view>
|
||||
</view>
|
||||
<view class="uni-list-cell-db">
|
||||
<input class="uni-input" type="text" placeholder="请输入key" name="key" :value="data.key" :maxlength="-1"
|
||||
@input="keyChange" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-list-cell">
|
||||
<view class="uni-list-cell-left">
|
||||
<view class="uni-label">value</view>
|
||||
</view>
|
||||
<view class="uni-list-cell-db">
|
||||
<input class="uni-input" type="text" placeholder="请输入value" name="data"
|
||||
:value="typeof data.data === 'string' ? data.data : JSON.stringify(data.data)" :maxlength="-1" @input="dataChange" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-padding-wrap">
|
||||
<view class="uni-btn-v">
|
||||
<button class="uni-btn btn-getStorageInfoASync" type="primary" @tap="getStorageInfo">
|
||||
获取存储概述信息-异步
|
||||
</button>
|
||||
<button class="uni-btn btn-getStorageInfoSync" @tap="getStorageInfoSync">
|
||||
获取存储概述信息-同步
|
||||
</button>
|
||||
</view>
|
||||
<text class="uni-list-cell-db-text">{{ data.storageInfo }}</text>
|
||||
<view class="uni-row">
|
||||
<button type="default" style="width:50%" @tap="strMock">
|
||||
填充字符串
|
||||
</button>
|
||||
<button type="default" style="width:50%" @tap="complexMock">
|
||||
填充复杂对象
|
||||
</button>
|
||||
</view>
|
||||
<view class="uni-row">
|
||||
<button type="default" style="width:50%" @tap="numberMock">
|
||||
填充整型
|
||||
</button>
|
||||
<button type="default" style="width:50%" @tap="floatMock">
|
||||
填充浮点型
|
||||
</button>
|
||||
</view>
|
||||
<view class="uni-row">
|
||||
<button type="default" style="width:50%" @tap="jsonLikeMock">
|
||||
填充json字符串
|
||||
</button>
|
||||
<button type="default" style="width:50%" @tap="longLikeMock">
|
||||
填充整数字符串
|
||||
</button>
|
||||
</view>
|
||||
<view class="uni-row">
|
||||
<button type="default" style="width:50%" @tap="floatLikeMock">
|
||||
填充浮点字符串
|
||||
</button>
|
||||
<button type="default" style="width:50%" @tap="negativeLikeMock">
|
||||
填充负数字符串
|
||||
</button>
|
||||
</view>
|
||||
<view class="uni-row">
|
||||
<button type="default" class="uni-btn btn-complexStaticTest" style="width:100%" @tap="complexStaticTest">
|
||||
字面量读写测试
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-padding-wrap">
|
||||
<view class="uni-btn-v">
|
||||
<button type="primary" class="uni-btn btn-setstorageAsync" @tap="setStorage">
|
||||
存储数据-异步
|
||||
</button>
|
||||
<button class="uni-btn btn-getstorageAsync" @tap="getStorage">读取数据-异步</button>
|
||||
<button class="uni-btn btn-removeStorageInfoASync" @tap="removeStorage">移除数据-异步</button>
|
||||
<button class="uni-btn btn-clearStorageInfoASync" @tap="clearStorage">清理数据-异步</button>
|
||||
</view>
|
||||
|
||||
<view class="uni-btn-v">
|
||||
<button type="primary" class="uni-btn btn-setstorageSync" @tap="setStorageSync">
|
||||
存储数据-同步
|
||||
</button>
|
||||
<button class="uni-btn btn-getstorageSync" @tap="getStorageSync">读取数据-同步</button>
|
||||
<button class="uni-btn btn-removeStorageInfoSync" @tap="removeStorageSync">
|
||||
移除数据-同步
|
||||
</button>
|
||||
<button class="uni-btn btn-clearStorageInfoSync" @tap="clearStorageSync">
|
||||
清理数据-同步
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button type="primary" @click="goto">前往storage管理器</button>
|
||||
</view>
|
||||
<!-- #ifdef APP && !VUE3-VAPOR -->
|
||||
</scroll-view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
type DataType = {
|
||||
title: string
|
||||
key: string
|
||||
data: any
|
||||
apiGetData: any | null
|
||||
storageInfo: string
|
||||
staticComplexRet: boolean
|
||||
jest_saveUTSJSONObjectSyncResult: number
|
||||
jest_saveUTSJSONObjectAsyncResult: number
|
||||
jest_saveUTSJSONObjectArraySyncResult: number
|
||||
}
|
||||
// 使用reactive避免ref数据在自动化测试中无法访问
|
||||
const data = reactive({
|
||||
title: 'get/set/clearStorage',
|
||||
key: '',
|
||||
data: '',
|
||||
apiGetData: '',
|
||||
storageInfo: '',
|
||||
staticComplexRet: false,
|
||||
jest_saveUTSJSONObjectSyncResult: 0,
|
||||
jest_saveUTSJSONObjectAsyncResult: 0,
|
||||
jest_saveUTSJSONObjectArraySyncResult: 0
|
||||
} as DataType)
|
||||
|
||||
const getStorageInfo = () => {
|
||||
uni.getStorageInfo({
|
||||
success: (res) => {
|
||||
data.apiGetData = res
|
||||
data.storageInfo = JSON.stringify(res)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const getStorageInfoSync = () => {
|
||||
try {
|
||||
const res = uni.getStorageInfoSync()
|
||||
data.apiGetData = res
|
||||
data.storageInfo = JSON.stringify(res)
|
||||
} catch (e) {
|
||||
// error
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
const jsonLikeMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = JSON.stringify({
|
||||
name: "james",
|
||||
age: 12,
|
||||
from: "american"
|
||||
});
|
||||
}
|
||||
|
||||
const longLikeMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = "1234567890"
|
||||
}
|
||||
|
||||
const floatLikeMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = "321456.1234567890"
|
||||
}
|
||||
|
||||
const negativeLikeMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = "-321456"
|
||||
}
|
||||
|
||||
const strMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = '测试字符串数据,长度为16个字符'
|
||||
}
|
||||
|
||||
const complexStaticTest = () => {
|
||||
uni.setStorageSync("key_complexStaticMock", {
|
||||
name: "张三",
|
||||
age: 12
|
||||
})
|
||||
let savedData = uni.getStorageSync("key_complexStaticMock")
|
||||
data.staticComplexRet = false
|
||||
if (savedData instanceof UTSJSONObject) {
|
||||
if ((savedData as UTSJSONObject).getNumber('age') == 12) {
|
||||
data.staticComplexRet = true
|
||||
uni.showToast({
|
||||
icon: 'success',
|
||||
title: '测试通过'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const complexMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
let jsonObj = {
|
||||
name: '张三',
|
||||
age: 12,
|
||||
classMate: [
|
||||
{
|
||||
id: 1001,
|
||||
name: '李四',
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
name: 'jack ma',
|
||||
},
|
||||
],
|
||||
}
|
||||
data.data = jsonObj
|
||||
}
|
||||
|
||||
const numberMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = 10011
|
||||
}
|
||||
|
||||
const floatMock = () => {
|
||||
data.key = 'key_' + Math.random()
|
||||
data.data = 3.1415926535893384626
|
||||
}
|
||||
|
||||
const keyChange = (e : InputEvent) => {
|
||||
data.key = e.detail.value
|
||||
}
|
||||
|
||||
const dataChange = (e : InputEvent) => {
|
||||
data.data = e.detail.value
|
||||
}
|
||||
|
||||
const getStorage = () => {
|
||||
var key = data.key
|
||||
if (key.length == 0) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '读取数据失败',
|
||||
content: 'key 不能为空',
|
||||
showCancel: false,
|
||||
})
|
||||
} else {
|
||||
uni.getStorage({
|
||||
key: key,
|
||||
success: (res) => {
|
||||
data.apiGetData = res.data
|
||||
let desc : string = typeof data.apiGetData
|
||||
if ("object" == desc) {
|
||||
desc = desc + ": " + JSON.stringify(data.apiGetData)
|
||||
} else {
|
||||
desc = desc + ": " + data.apiGetData
|
||||
}
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '读取数据成功',
|
||||
content: desc,
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '读取数据失败',
|
||||
content: '找不到 key 对应的数据',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const getStorageSync = () => {
|
||||
var key = data.key
|
||||
if (key.length == 0) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '读取数据失败',
|
||||
content: 'key 不能为空',
|
||||
showCancel: false,
|
||||
})
|
||||
} else {
|
||||
data.apiGetData = uni.getStorageSync(key)
|
||||
|
||||
let desc : string = typeof data.apiGetData
|
||||
if ("object" == desc) {
|
||||
desc = desc + ": " + JSON.stringify(data.apiGetData)
|
||||
} else {
|
||||
desc = desc + ": " + data.apiGetData
|
||||
}
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '读取数据成功',
|
||||
content: desc,
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const setStorage = () => {
|
||||
var key = data.key
|
||||
var storageData = data.data
|
||||
if (key.length == 0) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '保存数据失败',
|
||||
content: 'key 不能为空',
|
||||
showCancel: false,
|
||||
})
|
||||
} else {
|
||||
uni.setStorage({
|
||||
key: key,
|
||||
data: storageData,
|
||||
success: () => {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '存储数据成功',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '储存数据失败!',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const setStorageSync = () => {
|
||||
var key = data.key
|
||||
var storageData = data.data
|
||||
if (key.length == 0) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '保存数据失败',
|
||||
content: 'key 不能为空',
|
||||
showCancel: false,
|
||||
})
|
||||
} else {
|
||||
uni.setStorageSync(key, storageData)
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '存储数据成功',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeStorage = () => {
|
||||
uni.removeStorage({
|
||||
key: data.key,
|
||||
success: () => {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '移除数据成功',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '移除数据失败',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const removeStorageSync = () => {
|
||||
uni.removeStorageSync(data.key)
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '移除数据成功',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
|
||||
const clearStorage = () => {
|
||||
data.key = ''
|
||||
data.data = ''
|
||||
uni.clearStorage({
|
||||
success: function (_) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '清除数据成功',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
fail: function (_) {
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '清除数据失败',
|
||||
showCancel: false,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const clearStorageSync = () => {
|
||||
data.key = ''
|
||||
data.data = ''
|
||||
uni.clearStorageSync()
|
||||
// #ifndef MP
|
||||
uni.hideModal({
|
||||
modalPage:null
|
||||
})
|
||||
// #endif
|
||||
uni.showModal({
|
||||
title: '清除数据成功',
|
||||
content: ' ',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
|
||||
const jest_saveUTSJSONObject = () => {
|
||||
const key = 'test_key_saveUTSJSONObject'
|
||||
uni.setStorageSync(key, {
|
||||
a: {
|
||||
b: 1
|
||||
}
|
||||
})
|
||||
const dataSync = uni.getStorageSync(key) as UTSJSONObject
|
||||
const dataSyncA = dataSync['a'] as UTSJSONObject
|
||||
data.jest_saveUTSJSONObjectSyncResult = dataSyncA.get('b') as number
|
||||
uni.getStorage({
|
||||
key,
|
||||
success: (res) => {
|
||||
const dataAsync = res.data as UTSJSONObject
|
||||
const dataAsyncA = dataAsync['a'] as UTSJSONObject
|
||||
data.jest_saveUTSJSONObjectAsyncResult = dataAsyncA.get('b') as number
|
||||
console.log('data.jest_saveUTSJSONObjectSyncResult: ' + data.jest_saveUTSJSONObjectSyncResult)
|
||||
console.log('data.jest_saveUTSJSONObjectAsyncResult: ' + data.jest_saveUTSJSONObjectAsyncResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const jest_saveUTSJSONObjectArray = () => {
|
||||
const key = 'test_key_saveUTSJSONObjectArray'
|
||||
uni.setStorageSync(key, [{
|
||||
a: 1
|
||||
}] as UTSJSONObject[])
|
||||
const dataSync = uni.getStorageSync(key) as UTSJSONObject[]
|
||||
data.jest_saveUTSJSONObjectArraySyncResult = dataSync[0].get('a') as number
|
||||
}
|
||||
|
||||
const goto = () => {
|
||||
uni.navigateTo({
|
||||
url:"/pages/API/storage/storagemanage"
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
data,
|
||||
jest_saveUTSJSONObject,
|
||||
jest_saveUTSJSONObjectArray
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,176 @@
|
||||
const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase()
|
||||
const isMP = platformInfo.startsWith('mp')
|
||||
const isWeb = platformInfo.startsWith('web')
|
||||
const isIos = platformInfo.startsWith('ios')
|
||||
const isDom2 = process.env.UNI_APP_X_DOM2 === "true"
|
||||
|
||||
describe('Storage管理器页面-多类型新增', () => {
|
||||
if (isIos || isMP) {
|
||||
it('skip', () => {
|
||||
expect(1).toBe(1)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (isDom2) {
|
||||
it('dom2 暂不支持 .input api', () => {
|
||||
expect(1).toBe(1)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 定义类型默认值映射,与页面保持一致
|
||||
const valueTypeDefaultMap = new Map([
|
||||
['String', 'hello'],
|
||||
['Number', '1'],
|
||||
['Boolean', 'true'],
|
||||
['Object', '{"name": "张三","age": 12}'],
|
||||
['Array', '[1, "hello", true, { "key": "value" }]']
|
||||
])
|
||||
let page
|
||||
beforeAll(async () => {
|
||||
page = await program.navigateTo('/pages/API/storage/storagemanage')
|
||||
// 开启测试模式,跳过确认弹窗
|
||||
await page.callMethod('setTestMode', true)
|
||||
await page.waitFor(500)
|
||||
const list = await page.callMethod('getStorageList')
|
||||
// 点击清空按钮
|
||||
if (list.length) {
|
||||
const clearBtn = await page.$('.btn-clear')
|
||||
await clearBtn.tap()
|
||||
await page.waitFor(300)
|
||||
}
|
||||
})
|
||||
afterAll(async () => {
|
||||
// 关闭测试模式
|
||||
await page.callMethod('setTestMode', false)
|
||||
})
|
||||
|
||||
it('1. 新增String类型', async () => {
|
||||
// 点击新建按钮
|
||||
const createBtn = await page.$('.btn-create')
|
||||
await createBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 获取弹窗元素
|
||||
const mask = await page.$('.dialog-mask')
|
||||
const keyInput = await mask.$('.edit-input')
|
||||
const valueTextarea = await mask.$('.edit-textarea')
|
||||
const saveBtn = await mask.$('.btn-save')
|
||||
// 输入内容
|
||||
await keyInput.input('test_string')
|
||||
await valueTextarea.input('hello world')
|
||||
await saveBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 验证新增成功
|
||||
const list = await page.callMethod('getStorageList')
|
||||
expect(list.length).toBe(1)
|
||||
if (!isMP) {
|
||||
expect(list[0].key).toBe('test_string')
|
||||
expect(list[0].value).toBe('hello world')
|
||||
}
|
||||
})
|
||||
|
||||
it('2. 编辑String类型', async () => {
|
||||
// 点击编辑按钮
|
||||
const editBtn = await page.$('.btn-edit')
|
||||
await editBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 获取弹窗元素
|
||||
const mask = await page.$('.dialog-mask')
|
||||
const keyInput = await mask.$('.edit-input')
|
||||
const valueTextarea = await mask.$('.edit-textarea')
|
||||
const saveBtn = await mask.$('.btn-save')
|
||||
// 修改内容
|
||||
await keyInput.input('test_string_edited')
|
||||
await valueTextarea.input('hello world edited')
|
||||
await saveBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 验证修改成功
|
||||
const list = await page.callMethod('getStorageList')
|
||||
// 微信小程序端,基础库3.5.8以上版本,获取 value是[object HTMLElement] 暂时跳过
|
||||
if (!isMP) {
|
||||
expect(list[0].key).toBe('test_string_edited')
|
||||
expect(list[0].value).toBe('hello world edited')
|
||||
}
|
||||
})
|
||||
|
||||
it('3. 删除String类型', async () => {
|
||||
// 获取list-view的所有项,并选择第一个
|
||||
const listView = await page.$('.list-view')
|
||||
const listItems = await listView.$$('list-item')
|
||||
await listItems[0].tap()
|
||||
await page.waitFor(300)
|
||||
// 点击删除按钮
|
||||
const deleteBtn = await page.$('.btn-delete')
|
||||
await deleteBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 验证删除成功
|
||||
const list = await page.callMethod('getStorageList')
|
||||
expect(list.length).toBe(0)
|
||||
})
|
||||
|
||||
it('4. 测试切换类型自动填充默认值', async () => {
|
||||
// 点击新建按钮
|
||||
const createBtn = await page.$('.btn-create')
|
||||
await createBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 获取弹窗元素
|
||||
const mask = await page.$('.dialog-mask')
|
||||
const typeItems = await mask.$$('.edit-type-radio')
|
||||
// 测试每种类型
|
||||
for (let i = 0; i < typeItems.length; i++) {
|
||||
await typeItems[i].tap()
|
||||
await page.waitFor(200)
|
||||
// 验证默认值是否正确
|
||||
const editValue = await page.data('editValue')
|
||||
const editValueType = await page.data('editValueType')
|
||||
if (isWeb && editValueType._value != 'String') {
|
||||
// 获取 ref 的 value 属性
|
||||
expect(editValue._value).toBe(valueTypeDefaultMap.get(editValueType._value))
|
||||
}
|
||||
}
|
||||
// 关闭弹窗
|
||||
const cancelBtn = await mask.$('.btn-cancel')
|
||||
await cancelBtn.tap()
|
||||
await page.waitFor(300)
|
||||
})
|
||||
|
||||
it('5. 新增所有类型', async () => {
|
||||
const types = ['String', 'Number', 'Boolean', 'Object', 'Array']
|
||||
for (const type of types) {
|
||||
// 点击新建按钮
|
||||
const createBtn = await page.$('.btn-create')
|
||||
await createBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 获取弹窗元素
|
||||
const mask = await page.$('.dialog-mask')
|
||||
const keyInput = await mask.$('.edit-input')
|
||||
const valueTextarea = await mask.$('.edit-textarea')
|
||||
const saveBtn = await mask.$('.btn-save')
|
||||
const typeRadios = await mask.$$('.edit-type-radio')
|
||||
// 选择类型
|
||||
const typeIndex = types.indexOf(type)
|
||||
await typeRadios[typeIndex].tap()
|
||||
await page.waitFor(100)
|
||||
// 输入内容
|
||||
await keyInput.input(`test_${type.toLowerCase()}`)
|
||||
await valueTextarea.input(valueTypeDefaultMap.get(type))
|
||||
await saveBtn.tap()
|
||||
await page.waitFor(300)
|
||||
}
|
||||
// 验证所有类型都添加成功
|
||||
const list = await page.callMethod('getStorageList')
|
||||
if (!isMP) {
|
||||
expect(list.length).toBe(types.length)
|
||||
}
|
||||
})
|
||||
|
||||
it('6. 清空所有存储项', async () => {
|
||||
// 点击清空按钮
|
||||
const clearBtn = await page.$('.btn-clear')
|
||||
await clearBtn.tap()
|
||||
await page.waitFor(300)
|
||||
// 验证清空成功
|
||||
const list = await page.callMethod('getStorageList')
|
||||
expect(list.length).toBe(0)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,548 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="uni-title-text">Storage管理器</text>
|
||||
<button class="btn btn-create" type="primary" @click="openEditDialogNew">新建</button>
|
||||
<button class="btn btn-clear" type="default" @click="confirmClear" v-if="storageList.length>0">清空所有</button>
|
||||
</view>
|
||||
<list-view class="list-view" v-if="storageList.length>0">
|
||||
<list-item v-for="(item, index) in storageList" :key="item.key" @click="showDetail(item)">
|
||||
<view class="item-block">
|
||||
<view class="item-row">
|
||||
<text class="item-label">Key:</text>
|
||||
<text class="item-key">{{ item.key }}</text>
|
||||
</view>
|
||||
<view class="item-row">
|
||||
<text class="item-label">Data:</text>
|
||||
<text class="item-key">{{ truncate(item.value) }}</text>
|
||||
</view>
|
||||
<view class="item-row">
|
||||
<text class="item-label">Type:</text>
|
||||
<text class="item-key">{{ item.type }}</text>
|
||||
</view>
|
||||
<view class="item-row item-actions-row">
|
||||
<button class="btn btn-delete" type="default" @click.stop="confirmDelete(index)">删除</button>
|
||||
<button class="btn btn-edit" type="primary" @click.stop="openEditDialogEdit(item, index)">编辑</button>
|
||||
</view>
|
||||
</view>
|
||||
</list-item>
|
||||
</list-view>
|
||||
|
||||
<view v-else class="uni-center">
|
||||
<text class="uni-hello-text">暂无数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<view v-if="showDetailDialog" class="dialog-mask" @click="closeDetail">
|
||||
<view class="dialog-content" @click.stop>
|
||||
<text class="dialog-title">详情</text>
|
||||
<view class="detail-row">
|
||||
<text class="item-label">Key:</text>
|
||||
<text class="item-key">{{ detailItem.key }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="item-label">Data:</text>
|
||||
<text class="item-key uni-list-cell-db-text">{{ detailItem.value }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="item-label">Type:</text>
|
||||
<text class="item-key">{{ detailItem.type }}</text>
|
||||
</view>
|
||||
<view class="uni-common-mt popup-actions">
|
||||
<button class="btn mr-20" type="primary" @click="openEditDialogEdit(detailItem, getDetailIndex())">编辑</button>
|
||||
<button class="btn mr-20" type="warn" @click="confirmDelete(getDetailIndex())">删除</button>
|
||||
<button class="btn" @click="closeDetail">关闭</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 新建/编辑弹窗 -->
|
||||
<view v-show="showEditDialog" class="dialog-mask" @click="closeEdit">
|
||||
<view class="dialog-content" @click.stop>
|
||||
<text class="dialog-title">{{ isEditing ? '编辑' : '新建' }}</text>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">Key</text>
|
||||
<input v-model="editKey" placeholder="请输入key" class="edit-input" />
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">Value</text>
|
||||
<textarea v-model="editValue" placeholder="请输入value" class="edit-textarea" />
|
||||
</view>
|
||||
<view class="edit-row" v-if="!isEditing">
|
||||
<text class="edit-label">类型</text>
|
||||
<radio-group class="edit-type-group" @change="onValueTypeChange">
|
||||
<radio v-for="vt in valueTypeOptions" :key="vt" :value="vt" :checked="editValueType===vt"
|
||||
class="edit-type-radio">
|
||||
<text>{{ vt }}</text>
|
||||
</radio>
|
||||
</radio-group>
|
||||
</view>
|
||||
<view class="popup-actions">
|
||||
<button class="btn mr-20 btn-cancel" type="default" @click="closeEdit">取消</button>
|
||||
<button class="btn btn-save" type="primary" @click="saveEdit">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
type StorageItem = {
|
||||
key : string
|
||||
value : string
|
||||
type : string
|
||||
}
|
||||
type StorageList = Array<StorageItem>
|
||||
const storageList = ref([] as StorageItem[])
|
||||
const newKey = ref('')
|
||||
const newValue = ref('')
|
||||
const isEditing = ref(false)
|
||||
const editIndex = ref(-1)
|
||||
const detailItem = ref({ key: '', value: '', type: '' } as StorageItem)
|
||||
const editKey = ref('')
|
||||
const editValue = ref('')
|
||||
const editValueType = ref('Number')
|
||||
const showDetailDialog = ref(false)
|
||||
const showEditDialog = ref(false)
|
||||
const valueTypeOptions = ['String', 'Number', 'Boolean', 'Object', 'Array']
|
||||
const valueTypeDefaultMap = new Map<string, string>()
|
||||
valueTypeDefaultMap.set('String', '')
|
||||
valueTypeDefaultMap.set('Number', '1')
|
||||
valueTypeDefaultMap.set('Boolean', 'true')
|
||||
valueTypeDefaultMap.set('Object', `{"name": "张三","age": 12}`)
|
||||
valueTypeDefaultMap.set('Array', `[1, "hello", true, { "key": "value" }]`)
|
||||
// 自动化测试使用
|
||||
const isTestMode = ref(false)
|
||||
|
||||
function getStorageList() : StorageList {
|
||||
const list : StorageList = []
|
||||
const storageInfo = uni.getStorageInfoSync()
|
||||
storageInfo.keys.forEach((key : string) => {
|
||||
const value = uni.getStorageSync(key)
|
||||
let strValue : string | null = null
|
||||
let typeStr : string = typeof value
|
||||
if (value != null) {
|
||||
if (typeStr == 'object') {
|
||||
const jsonStr = JSON.stringify(value)
|
||||
strValue = jsonStr
|
||||
if (Array.isArray(JSON.parse(jsonStr))) {
|
||||
typeStr = 'Array'
|
||||
} else {
|
||||
typeStr = 'Object'
|
||||
}
|
||||
} else if (typeStr == 'boolean') {
|
||||
strValue = value == true ? 'true' : 'false'
|
||||
typeStr = 'Boolean'
|
||||
} else if (typeStr == 'number') {
|
||||
strValue = value.toString()
|
||||
typeStr = 'Number'
|
||||
} else {
|
||||
strValue = value.toString()
|
||||
typeStr = 'String'
|
||||
}
|
||||
}
|
||||
if (strValue != null) {
|
||||
list.push({
|
||||
key: key,
|
||||
value: strValue,
|
||||
type: typeStr
|
||||
})
|
||||
}
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
function setStorage(key : string, value : any) {
|
||||
try {
|
||||
uni.setStorageSync(key, value)
|
||||
} catch (e) {
|
||||
console.error('Storage set error:', e)
|
||||
}
|
||||
}
|
||||
function removeStorage(key : string) {
|
||||
try {
|
||||
uni.removeStorageSync(key)
|
||||
} catch (e) {
|
||||
console.error('Storage remove error:', e)
|
||||
}
|
||||
}
|
||||
function clearStorage() {
|
||||
try {
|
||||
uni.clearStorageSync()
|
||||
} catch (e) {
|
||||
console.error('Storage clear error:', e)
|
||||
}
|
||||
}
|
||||
function getStorage(key : string) : string | null {
|
||||
try {
|
||||
const value = uni.getStorageSync(key)
|
||||
return value != null ? value.toString() : null
|
||||
} catch (e) {
|
||||
console.error('Storage get error:', e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function refreshList() {
|
||||
const list = getStorageList()
|
||||
console.log('list: ',list);
|
||||
if (!isEditing.value && editKey.value != '') {
|
||||
const idx = list.findIndex(item => item.key === editKey.value)
|
||||
if (idx > 0) {
|
||||
const spliced = list.splice(idx, 1)
|
||||
if (spliced.length > 0) {
|
||||
list.unshift(spliced[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
storageList.value = list
|
||||
}
|
||||
|
||||
function truncate(value : string) : string {
|
||||
if (value.length > 100) {
|
||||
return value.slice(0, 100) + '...'
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function showDetail(item : StorageItem) {
|
||||
detailItem.value = item
|
||||
showDetailDialog.value = true
|
||||
}
|
||||
function closeDetail() {
|
||||
showDetailDialog.value = false
|
||||
}
|
||||
function openEditDialogNew() {
|
||||
editKey.value = ''
|
||||
editValueType.value = 'String'
|
||||
editValue.value = valueTypeDefaultMap.get('String') ?? ''
|
||||
isEditing.value = false
|
||||
editIndex.value = -1
|
||||
showEditDialog.value = true
|
||||
}
|
||||
function openEditDialogEdit(item : StorageItem, index : number) {
|
||||
editKey.value = item.key
|
||||
editValue.value = item.value
|
||||
isEditing.value = true
|
||||
editIndex.value = index
|
||||
editValueType.value = valueTypeOptions.indexOf(item.type) >= 0 ? item.type : 'String'
|
||||
showEditDialog.value = true
|
||||
closeDetail()
|
||||
}
|
||||
function saveEdit() {
|
||||
if (!isTestMode.value && (editKey.value.trim() === '' || editValue.value.trim() === '')) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: 'Key 和 Value 都不能为空',
|
||||
showCancel: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
let storeValue : any
|
||||
switch (editValueType.value) {
|
||||
case 'Number':
|
||||
storeValue = parseFloat(editValue.value)
|
||||
break
|
||||
case 'Boolean':
|
||||
storeValue = (editValue.value === 'true' || editValue.value === '1')
|
||||
break
|
||||
case 'Object':
|
||||
try {
|
||||
const obj = JSON.parse(editValue.value)
|
||||
storeValue = obj as UTSJSONObject
|
||||
} catch {
|
||||
storeValue = {} as UTSJSONObject
|
||||
}
|
||||
break
|
||||
case 'Array':
|
||||
try {
|
||||
const arr = JSON.parse(editValue.value) as Array<any>
|
||||
storeValue = arr // 直接存储数组
|
||||
} catch {
|
||||
storeValue = [] as Array<any>
|
||||
}
|
||||
break
|
||||
default:
|
||||
storeValue = editValue.value
|
||||
}
|
||||
if (editIndex.value >= 0) {
|
||||
const oldItem = storageList.value[editIndex.value]
|
||||
if (oldItem.key != editKey.value) {
|
||||
removeStorage(oldItem.key)
|
||||
}
|
||||
setStorage(editKey.value, storeValue)
|
||||
} else {
|
||||
setStorage(editKey.value, storeValue)
|
||||
}
|
||||
refreshList()
|
||||
isEditing.value = false
|
||||
editIndex.value = -1
|
||||
editKey.value = ''
|
||||
editValue.value = ''
|
||||
editValueType.value = 'String'
|
||||
showEditDialog.value = false
|
||||
}
|
||||
function closeEdit() {
|
||||
showEditDialog.value = false
|
||||
}
|
||||
function handleDelete(index : number) {
|
||||
if (index >= 0 && index < storageList.value.length) {
|
||||
const item = storageList.value[index]
|
||||
removeStorage(item.key)
|
||||
refreshList()
|
||||
if (isEditing.value && editIndex.value == index) {
|
||||
isEditing.value = false
|
||||
editIndex.value = -1
|
||||
editKey.value = ''
|
||||
editValue.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
function confirmDelete(index : number) {
|
||||
// 自动化测试时不显示模态弹窗
|
||||
if (!isTestMode.value) {
|
||||
uni.showModal({
|
||||
title: '确认操作',
|
||||
content: '确定要删除该项吗?',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
showDetailDialog.value = false
|
||||
handleDelete(index)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
showDetailDialog.value = false
|
||||
handleDelete(index)
|
||||
}
|
||||
}
|
||||
function handleClear() {
|
||||
clearStorage()
|
||||
refreshList()
|
||||
isEditing.value = false
|
||||
editIndex.value = -1
|
||||
editKey.value = ''
|
||||
editValue.value = ''
|
||||
}
|
||||
function confirmClear() {
|
||||
// 自动化测试时不显示模态弹窗
|
||||
if (!isTestMode.value) {
|
||||
uni.showModal({
|
||||
title: '确认操作',
|
||||
content: '确定要清空所有数据吗?',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
showDetailDialog.value = false
|
||||
handleClear()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
showDetailDialog.value = false
|
||||
handleClear()
|
||||
}
|
||||
}
|
||||
function getDetailIndex() : number {
|
||||
return storageList.value.findIndex(item => item.key === detailItem.value.key)
|
||||
}
|
||||
function onValueTypeChange(e : UniRadioGroupChangeEvent) {
|
||||
const type = e.detail.value
|
||||
editValueType.value = type
|
||||
if (valueTypeDefaultMap.has(type)) {
|
||||
editValue.value = valueTypeDefaultMap.get(type) ?? ''
|
||||
} else {
|
||||
editValue.value = ''
|
||||
}
|
||||
}
|
||||
onLoad(() => {
|
||||
refreshList()
|
||||
})
|
||||
|
||||
/**
|
||||
* 仅供自动化测试用例调用,设置测试模式
|
||||
*/
|
||||
function setTestMode(val: boolean) {
|
||||
isTestMode.value = val
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
editValue,
|
||||
editValueType,
|
||||
getStorageList,
|
||||
setTestMode, // 仅供自动化测试用例调用
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
flex-direction: column;
|
||||
background: #f7f8fa;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mr-20 {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.list-view {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.item-block {
|
||||
padding: 13px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
margin-right: 4px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.item-key {
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
flex: 1;
|
||||
/* #ifdef WEB */
|
||||
word-break: break-all;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.item-actions-row {
|
||||
justify-content: space-between;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px 16px 16px 16px;
|
||||
min-width: 270px;
|
||||
max-width: 345px;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
position: relative;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 14px;
|
||||
text-align: center;
|
||||
color: #222;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.error-tip {
|
||||
color: #FF3B30;
|
||||
font-size: 15px;
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.edit-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
.edit-label {
|
||||
min-width: 35px;
|
||||
color: #888;
|
||||
font-size: 15px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.edit-input {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 0 6px;
|
||||
font-size: 15px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-textarea {
|
||||
flex: 1;
|
||||
min-height: 80px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 10px 6px;
|
||||
font-size: 15px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-type-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.edit-type-radio {
|
||||
margin-right: 12px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
</style>
|
||||
在新工单中引用
屏蔽一个用户