优化生产css
This commit is contained in:
commit
7bcaf09421
@ -1,4 +1,3 @@
|
||||
# 开发环境
|
||||
# 请求接口地址
|
||||
VITE_REQUEST_BASE_URL = https://36.112.48.190
|
||||
#VITE_REQUEST_BASE_URL = http://10.75.166.6:8080
|
||||
|
@ -13,4 +13,20 @@ export function initDictOption(dictCode) { // 获取部门所有人员信息
|
||||
method: 'get',
|
||||
data: dictCode
|
||||
})
|
||||
}
|
||||
|
||||
export function writeCommonJsonDisplay(dictCode) { // 通用json数据写入API
|
||||
return https({
|
||||
url: ' /sys/dict/getDictItems',
|
||||
method: 'get',
|
||||
data: dictCode
|
||||
})
|
||||
}
|
||||
|
||||
export function readCommonJsonDisplay(params) { // 通用json数据写入API
|
||||
return https({
|
||||
url: '/cxcPersonalTailor/cxcPersonalTailor/getByRules',
|
||||
method: 'get',
|
||||
data: params
|
||||
})
|
||||
}
|
@ -18,8 +18,6 @@ export function queryJinriTrqShengchansj(params) { // 获取当前日期、今
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function queryYearShengchansj(params) { // 获取今年以来天然气的生产数据
|
||||
return https({
|
||||
url: '/scdt.CxcScdtChart/cxcScdtChart/getYearStatis',
|
||||
@ -34,4 +32,22 @@ export function queryJinriYuanyouShengchansj(params) { // 获取今日原油 污
|
||||
method: 'get',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 实时数据API
|
||||
|
||||
export function queryJldZcList(params) { // 获取计量点站场列表
|
||||
return https({
|
||||
url: '/sys/sysDepart/queryDepartsByzdjl',
|
||||
method: 'get',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
export function queryJldDataByZc(params) { // 获取站场计量点实时数据
|
||||
return https({
|
||||
url: 'http://10.75.166.6:9999/Gyk/sssj/GetJlByZc',
|
||||
method: 'get',
|
||||
data: params
|
||||
})
|
||||
}
|
241
manifest.json
241
manifest.json
@ -1,122 +1,123 @@
|
||||
{
|
||||
"name": "数智产销",
|
||||
"appid": "__UNI__9F097F0",
|
||||
"description": "",
|
||||
"versionName": "1.1.11",
|
||||
"versionCode": 20250303,
|
||||
"transformPx": false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"nvueStyleCompiler": "uni-app",
|
||||
"compilerVersion": 3,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
"compatible": {
|
||||
"ignoreVersion": true
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules": {
|
||||
"Geolocation": {},
|
||||
"Fingerprint": {},
|
||||
"Camera": {},
|
||||
"Barcode": {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute": {
|
||||
/* android打包配置 */
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios": {
|
||||
"dSYMs": false
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs": {
|
||||
"ad": {},
|
||||
"geolocation": {
|
||||
"system": {
|
||||
"__platform__": ["android"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"android": {
|
||||
"hdpi": "unpackage/res/icons/72x72.png",
|
||||
"xhdpi": "unpackage/res/icons/96x96.png",
|
||||
"xxhdpi": "unpackage/res/icons/144x144.png",
|
||||
"xxxhdpi": "unpackage/res/icons/192x192.png"
|
||||
},
|
||||
"ios": {
|
||||
"appstore": "unpackage/res/icons/1024x1024.png",
|
||||
"ipad": {
|
||||
"app": "unpackage/res/icons/76x76.png",
|
||||
"app@2x": "unpackage/res/icons/152x152.png",
|
||||
"notification": "unpackage/res/icons/20x20.png",
|
||||
"notification@2x": "unpackage/res/icons/40x40.png",
|
||||
"proapp@2x": "unpackage/res/icons/167x167.png",
|
||||
"settings": "unpackage/res/icons/29x29.png",
|
||||
"settings@2x": "unpackage/res/icons/58x58.png",
|
||||
"spotlight": "unpackage/res/icons/40x40.png",
|
||||
"spotlight@2x": "unpackage/res/icons/80x80.png"
|
||||
},
|
||||
"iphone": {
|
||||
"app@2x": "unpackage/res/icons/120x120.png",
|
||||
"app@3x": "unpackage/res/icons/180x180.png",
|
||||
"notification@2x": "unpackage/res/icons/40x40.png",
|
||||
"notification@3x": "unpackage/res/icons/60x60.png",
|
||||
"settings@2x": "unpackage/res/icons/58x58.png",
|
||||
"settings@3x": "unpackage/res/icons/87x87.png",
|
||||
"spotlight@2x": "unpackage/res/icons/80x80.png",
|
||||
"spotlight@3x": "unpackage/res/icons/120x120.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp": {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin": {
|
||||
"appid": "",
|
||||
"setting": {
|
||||
"urlCheck": false
|
||||
},
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-baidu": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-toutiao": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion": "3"
|
||||
"name" : "数智产销",
|
||||
"appid" : "__UNI__9F097F0",
|
||||
"description" : "",
|
||||
"versionName" : "1.1.13",
|
||||
"versionCode" : 20250321,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"Geolocation" : {},
|
||||
"Fingerprint" : {},
|
||||
"Camera" : {},
|
||||
"Barcode" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {
|
||||
"dSYMs" : false
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {
|
||||
"ad" : {},
|
||||
"geolocation" : {
|
||||
"system" : {
|
||||
"__platform__" : [ "android" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"icons" : {
|
||||
"android" : {
|
||||
"hdpi" : "unpackage/res/icons/72x72.png",
|
||||
"xhdpi" : "unpackage/res/icons/96x96.png",
|
||||
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
||||
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
||||
},
|
||||
"ios" : {
|
||||
"appstore" : "unpackage/res/icons/1024x1024.png",
|
||||
"ipad" : {
|
||||
"app" : "unpackage/res/icons/76x76.png",
|
||||
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||
"notification" : "unpackage/res/icons/20x20.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"proapp@2x" : "unpackage/res/icons/167x167.png",
|
||||
"settings" : "unpackage/res/icons/29x29.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"spotlight" : "unpackage/res/icons/40x40.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||
},
|
||||
"iphone" : {
|
||||
"app@2x" : "unpackage/res/icons/120x120.png",
|
||||
"app@3x" : "unpackage/res/icons/180x180.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"settings@3x" : "unpackage/res/icons/87x87.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
||||
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
}
|
||||
/* 模块配置 */
|
||||
/* 模块配置 */
|
||||
|
||||
|
1323
package-lock.json
generated
1323
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@ -1,8 +1,18 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-ui": "^1.5.6",
|
||||
"base-64": "^1.0.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.6.0"
|
||||
}
|
||||
"name": "your-project",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "vite build --config vite.config.js --format esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-ui": "^1.5.6",
|
||||
"base-64": "^1.0.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.6.0",
|
||||
"pinia": "^3.0.1",
|
||||
"js-base64": "^3.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^6.2.2"
|
||||
}
|
||||
}
|
||||
|
64
pages.json
64
pages.json
@ -102,6 +102,13 @@
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/document/onlinePreviewH5",
|
||||
"style": {
|
||||
"navigationBarTitleText": "在线预览",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/views/zhongheguanli/meeting/index",
|
||||
"style": {
|
||||
@ -185,6 +192,63 @@
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/index",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/trqSssj",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "天然气实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/gycsSssj",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "工艺参数实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/ysjSssj",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "压缩机实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/aqbjSssj",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "安全报警实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/views/shengchan/shishishuju/nyxhSssj",
|
||||
"style": {
|
||||
// "navigationStyle": "custom"
|
||||
"navigationBarTitleText": "能耗实时数据",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/userlist/index",
|
||||
"style": {
|
||||
|
@ -14,6 +14,14 @@
|
||||
</text>
|
||||
<view class="f-col">
|
||||
<view v-if="ifH5">
|
||||
<!-- 在线预览 by 闵 -->
|
||||
<view class="" style="padding: 5rpx 0;" @click="onlinePreview(`/pages/document/onlinePreviewH5?data=${JSON.stringify(item)}`)"
|
||||
v-for="item,i in detail?.pdf?.split(',')">
|
||||
{{item}}
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view v-esle>
|
||||
<!-- 在线预览 by 闵 -->
|
||||
<view class="" style="padding: 5rpx 0;" @click="onlinePreview(`/pages/document/onlinePreview?data=${JSON.stringify(item)}`)"
|
||||
v-for="item,i in detail?.pdf?.split(',')">
|
||||
@ -21,13 +29,13 @@
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<!-- <view v-else>
|
||||
<view class="" style="padding: 5rpx 0;" @click="opendocument(item)"
|
||||
v-for="item,i in detail?.pdf?.split(',')">
|
||||
{{item}}
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view :class="['content',{'gray':store.isgray==1}]">
|
||||
<iframe id="bdIframe" :src="fileUrl" ref="bdIframe" style="border: none;" class="iframe" />
|
||||
<view :class="['content',{'gray':store.isgray==1}]" >
|
||||
<iframe id="bdIframe" :src="fileUrl" ref="bdIframe" style="border: none;" class="iframe"/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import Base64 from '@/utils/code.js';
|
||||
const baseUrl = import.meta.env.VITE_REQUEST_BASE_URL + '/jeecg-boot/sys/common/static/'
|
||||
const requestUrl = import.meta.env.VITE_REQUEST_BASE_URL;
|
||||
const baseUrl = 'https://10.75.166.6/jeecg-boot/sys/common/static/';
|
||||
const store = useStore();
|
||||
|
||||
var fileUrl = "";
|
||||
@ -21,7 +22,9 @@
|
||||
let base64 = new Base64();
|
||||
var url= JSON.parse(options.data)
|
||||
url = baseUrl + url;
|
||||
fileUrl = 'https://10.75.166.6/preview/onlinePreview' + '?url=' + encodeURIComponent(base64.encode(url))
|
||||
console.log(url)
|
||||
fileUrl =requestUrl+ '/preview/onlinePreview' + '?url=' + encodeURIComponent(base64.encode(url))
|
||||
console.log(fileUrl)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
46
pages/document/onlinePreviewH5.vue
Normal file
46
pages/document/onlinePreviewH5.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<view :class="['content',{'gray':store.isgray==1}]">
|
||||
<iframe id="bdIframe" :src="fileUrl" ref="bdIframe" style="border: none;" class="iframe" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
useStore
|
||||
} from '@/store';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
const requestUrl = import.meta.env.VITE_REQUEST_BASE_URL;
|
||||
const baseUrl = 'https://10.75.166.6/jeecg-boot/sys/common/static/';
|
||||
const store = useStore();
|
||||
import {Base64} from 'js-base64'
|
||||
var fileUrl = "";
|
||||
|
||||
onLoad((options) => {
|
||||
var url= JSON.parse(options.data)
|
||||
url = baseUrl + url;
|
||||
console.log(url)
|
||||
console.log(Base64.encode(url))
|
||||
fileUrl =requestUrl+ '/preview/onlinePreview' + '?url=' + encodeURIComponent(Base64.encode(url))
|
||||
console.log(fileUrl)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
|
||||
}
|
||||
#bdIframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
}
|
||||
</style>
|
@ -23,42 +23,22 @@
|
||||
<view class="title">
|
||||
请假类型:
|
||||
</view>
|
||||
<tree-select :dataSource="dataSource" v-model="type" dataValue="name" />
|
||||
<tree-select :dataSource="dataSource" v-model="type" dataValue="name" @change="queryHisDate" />
|
||||
</view>
|
||||
<picker mode="date" fields="day" @change="chooseStart" :value="beginTime" :start="startDate" :end="endTime">
|
||||
<view class="f-row aic jcb box">
|
||||
<view class="title">
|
||||
开始时间:
|
||||
</view>
|
||||
<view class="f-row aic">
|
||||
<view :class="[{'choose':!beginTime},{'choosed':beginTime}]">
|
||||
{{beginTime?beginTime:'请选择'}}
|
||||
</view>
|
||||
<uni-icons type="bottom" color="#333333"></uni-icons>
|
||||
</view>
|
||||
<view class="f-row aic jcb input_box">
|
||||
<view class="title">
|
||||
请假时间:
|
||||
</view>
|
||||
</picker>
|
||||
<picker mode="date" fields="day" @change="chooseEnd" :value="endTime" :start="beginTime">
|
||||
<view class="f-row aic jcb box">
|
||||
<view class="title">
|
||||
截止时间:
|
||||
</view>
|
||||
<view class="f-row aic">
|
||||
<view :class="[{'choose':!endTime},{'choosed':endTime}]">
|
||||
{{endTime?endTime:'请选择'}}
|
||||
</view>
|
||||
<uni-icons type="bottom" color="#333333"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</picker>
|
||||
<picker @change="bindType" :value="typeIndex" :range="typeArr" range-key="realname">
|
||||
<cxc-szcx-dateRangeSelect mode="range" v-model="rangeDate" :startDate="startDate" :isSearch="false"></cxc-szcx-dateRangeSelect>
|
||||
</view>
|
||||
<picker @change="bindType" :value="leaderIndex" :range="leaderArr" range-key="realname">
|
||||
<view class="f-row aic jcb box">
|
||||
<view class="title">
|
||||
{{examineleader}}:
|
||||
</view>
|
||||
<view class="f-row aic">
|
||||
<view :class="[{'choose':typeIndex==null},{'choosed':typeIndex!=null}]">
|
||||
{{typeIndex!=null?typeArr[typeIndex].realname:'请选择'}}
|
||||
<view :class="[{'choose':leaderIndex==null},{'choosed':leaderIndex!=null}]">
|
||||
{{leaderIndex!=null?leaderArr[leaderIndex].realname:'请选择'}}
|
||||
</view>
|
||||
<uni-icons type="bottom" color="#333333"></uni-icons>
|
||||
</view>
|
||||
@ -140,22 +120,13 @@
|
||||
/**请假类型*/
|
||||
const type = ref('')
|
||||
const dataSource = ref([])
|
||||
/**开始时间*/
|
||||
const beginTime = ref('')
|
||||
const chooseStart = (e) => {
|
||||
beginTime.value = e.detail.value
|
||||
}
|
||||
/**请假开始时间 绑定start*/
|
||||
/**请假时间*/
|
||||
const rangeDate = ref([null, null])
|
||||
const startDate = ref('')
|
||||
/**结束时间*/
|
||||
const endTime = ref('')
|
||||
const chooseEnd = (e) => {
|
||||
endTime.value = e.detail.value
|
||||
}
|
||||
/**审批领导*/
|
||||
const typeArr = ref([])
|
||||
const typeIndex = ref(null)
|
||||
/**判断显示审批 / 分管 领导*/
|
||||
const leaderArr = ref([])
|
||||
const leaderIndex = ref(null)
|
||||
/**判断显示审批 / 分管领导*/
|
||||
const examineleader = ref(true)
|
||||
/**职位层级*/
|
||||
const zwcj = ref('')
|
||||
@ -178,6 +149,9 @@
|
||||
radius: '2px'
|
||||
}
|
||||
}
|
||||
/**返回的最新一条请假结束时间*/
|
||||
const resDate = ref('')
|
||||
|
||||
onLoad(() => {
|
||||
loadData()
|
||||
})
|
||||
@ -203,11 +177,8 @@
|
||||
const qjAdd = () => {
|
||||
if (!phone.value.trim()) return proxy.$toast('请输入联系方式')
|
||||
if (!type.value) return proxy.$toast('请选择请假类型')
|
||||
if (!beginTime.value) return proxy.$toast('请选择开始时间')
|
||||
if (!endTime.value) return proxy.$toast('请选择结束时间')
|
||||
if (typeIndex.value == null) { //副职、员工需要选择审批领导
|
||||
return proxy.$toast('请选择' + examineleader.value)
|
||||
}
|
||||
if (!rangeDate.value || rangeDate.value.every(item => item === null)) return proxy.$toast('请选择请假时间')
|
||||
if (leaderIndex.value == null) return proxy.$toast('请选择' + examineleader.value)
|
||||
if (!departure.value.trim()) return proxy.$toast('请输入出发地')
|
||||
if (!destination.value.trim()) return proxy.$toast('请输入目的地')
|
||||
if (!reason.value.trim()) return proxy.$toast('请输入请假事由')
|
||||
@ -217,9 +188,9 @@
|
||||
username: store.userinfo.username,
|
||||
phone: phone.value,
|
||||
type: type.value,
|
||||
begintime: beginTime.value,
|
||||
endtime: endTime.value,
|
||||
examineleader: typeArr.value[typeIndex.value] ? typeArr.value[typeIndex.value].username : '',
|
||||
begintime: rangeDate.value[0],
|
||||
endtime: rangeDate.value[1],
|
||||
examineleader: leaderArr.value[leaderIndex.value].username,
|
||||
departure: departure.value,
|
||||
destination: destination.value,
|
||||
reason: reason.value,
|
||||
@ -265,11 +236,11 @@
|
||||
|
||||
queryZwmcAndExaApi(store.userinfo.username).then((res) => { //本人职位及审批领导列表
|
||||
if (res.success) {
|
||||
typeArr.value = res.result.list
|
||||
leaderArr.value = res.result.list
|
||||
zwcj.value = res.result.zwmc
|
||||
if (zwcj.value == '单位专家' || zwcj.value == '基层正职' || zwcj.value == '高级主管') {
|
||||
examineleader.value = '分管领导';
|
||||
}else{
|
||||
} else {
|
||||
examineleader.value = '审批领导';
|
||||
}
|
||||
} else {
|
||||
@ -277,39 +248,43 @@
|
||||
}
|
||||
})
|
||||
|
||||
queryHisDateApi(store.userinfo.username).then((res) => { // 最新请假结束日期
|
||||
if (res) {
|
||||
getTomorrowDate(res);
|
||||
startDate.value = beginTime.value; // 如果有最新请假日期,设置startDate为该日期
|
||||
} else {
|
||||
getTomorrowDate();
|
||||
startDate.value = '1900-01-01';
|
||||
}
|
||||
})
|
||||
queryHisDateApi(store.userinfo.username).then((res) => {
|
||||
resDate.value = res ? new Date(res) : null; // 如果 res 存在,转换为 Date 对象
|
||||
queryHisDate();
|
||||
});
|
||||
}
|
||||
|
||||
const queryHisDate = () => {
|
||||
const today = new Date(); // 获取当前日期
|
||||
if (resDate.value) {
|
||||
// 如果 res 存在
|
||||
if (type.value != '干部离返濮报备') {
|
||||
startDate.value = getNextDay(resDate.value); // startDate 为 res 的第二天
|
||||
}else{
|
||||
startDate.value = null;
|
||||
}
|
||||
rangeDate.value = [getNextDay(resDate.value < today ? today : resDate.value), getNextDay(getNextDay(
|
||||
resDate.value < today ? today : resDate.value))]
|
||||
} else {
|
||||
// 如果 res 不存在
|
||||
rangeDate.value = [getNextDay(today), getNextDay(today)]
|
||||
}
|
||||
}
|
||||
|
||||
// 获取传入日期的第二天
|
||||
const getNextDay = (date) => {
|
||||
const nextDay = new Date(date);
|
||||
nextDay.setDate(nextDay.getDate() + 1); // 设置为第二天
|
||||
const year = nextDay.getFullYear();
|
||||
const month = (nextDay.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = nextDay.getDate().toString().padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
const bindType = (e) => {
|
||||
typeIndex.value = e.detail.value
|
||||
leaderIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
const getTomorrowDate = (e) => {
|
||||
let tomorrow;
|
||||
if (e) {
|
||||
// 将传入的日期字符串转换为Date对象
|
||||
const dateParts = e.split('-').map(Number);
|
||||
tomorrow = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
|
||||
} else {
|
||||
// 如果没有提供日期,则使用当前日期
|
||||
tomorrow = new Date();
|
||||
}
|
||||
// 设置为明天的日期
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
// 格式化日期
|
||||
const year = tomorrow.getFullYear();
|
||||
const month = (tomorrow.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = tomorrow.getDate().toString().padStart(2, '0');
|
||||
beginTime.value = `${year}-${month}-${day}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -5,6 +5,9 @@
|
||||
<uni-card :is-shadow="false">
|
||||
<button type="primary" @click="toTaizhang">人员台账</button>
|
||||
</uni-card>
|
||||
<uni-card :is-shadow="false">
|
||||
<button v-if="roleDetail" type="primary" @click="toSzcs">通过素质测试</button>
|
||||
</uni-card>
|
||||
</uni-section>
|
||||
<uni-section title="统计信息" type="line">
|
||||
<uni-card :is-shadow="false">
|
||||
@ -16,10 +19,37 @@
|
||||
</uni-card>
|
||||
</uni-section>
|
||||
</uni-card>
|
||||
<uni-popup ref="popup" type="bottom" background-color="#fff">
|
||||
<cxc-szcx-jsonDataViewer :username="username" :persionalKey="persionalKey"
|
||||
:type="type"></cxc-szcx-jsonDataViewer>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
} from 'vue';
|
||||
|
||||
import {
|
||||
useStore
|
||||
} from '@/store';
|
||||
const store = useStore();
|
||||
const roleDetail = ref(store.userinfo.realname === '廖德云' || store.userinfo.realname === '马敬朝');
|
||||
|
||||
// 定义要传入的参数
|
||||
const username = ref('');
|
||||
const persionalKey = ref('');
|
||||
const type = ref('');
|
||||
const popup = ref(null);
|
||||
|
||||
function toSzcs() {
|
||||
username.value = 'liaody'
|
||||
persionalKey.value = 'szcsRy'
|
||||
type.value = '5'
|
||||
popup.value.open();
|
||||
}
|
||||
|
||||
function toTaizhang() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/views/renliziyuan/renyuanxinxi/taizhang'
|
||||
|
@ -15,7 +15,7 @@
|
||||
@change="onFieldChange"></uni-data-select>
|
||||
</uni-col>
|
||||
<uni-col style="margin-left:5px" :span="6" v-if="selectedField==='zjmc'"><button type="primary"
|
||||
size="mini" @click="showPopup=!showPopup">筛选</button></uni-col>
|
||||
size="mini" @click="openZhengshu">筛选</button></uni-col>
|
||||
</uni-row>
|
||||
|
||||
</view>
|
||||
@ -408,6 +408,11 @@
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
function openZhengshu() {
|
||||
showPopup.value.open()
|
||||
}
|
||||
|
||||
//根据一个键值查找数据
|
||||
//查找人员劳动合同号
|
||||
function findRyByOrgCode(treeData, targetOrgCode) {
|
||||
@ -595,7 +600,7 @@
|
||||
|
||||
// 递归计算每个根节点的data
|
||||
rootNodes.forEach((root) => computeData(root));
|
||||
|
||||
|
||||
console.log(rootNodes)
|
||||
return rootNodes;
|
||||
// console.log('rootNodes', rootNodes);
|
||||
@ -719,9 +724,9 @@
|
||||
try {
|
||||
//这里添加一个层级字段,并避免 厂机关A01A01A01 orgType by 闵
|
||||
var tempOrgType = '1';
|
||||
if(selectedOrgCode.value.includes('A01A01A01')){
|
||||
if (selectedOrgCode.value.includes('A01A01A01')) {
|
||||
tempOrgType = '1';
|
||||
}else{
|
||||
} else {
|
||||
tempOrgType = orgType
|
||||
}
|
||||
if (selectedField.value === 'zjmc') {
|
||||
@ -769,7 +774,7 @@
|
||||
} else {
|
||||
var tempArr = [];
|
||||
tempArr.push(temp[0])
|
||||
chartData.value =tempArr;
|
||||
chartData.value = tempArr;
|
||||
}
|
||||
updateChart(chartData.value);
|
||||
}
|
||||
@ -800,7 +805,7 @@
|
||||
selectedOrgCode.value = e;
|
||||
console.log(e)
|
||||
console.log(data);
|
||||
orgType.value = data.value.orgType; //赋值层级 by 闵
|
||||
orgType.value = data.value.orgType; //赋值层级 by 闵
|
||||
selectedOrgCodeLabel.value = data.value.title;
|
||||
fetchStatisticsData();
|
||||
};
|
||||
|
@ -5,57 +5,189 @@
|
||||
<view style="width: 100%; display: grid; place-items: center">
|
||||
<uni-title :title="dateDate + ':生产经营情况'" type="h1" color="blue" />
|
||||
</view>
|
||||
<view style="margin: 0 10px;">
|
||||
<uni-segmented-control style="margin-top: 10px;margin-bottom: 10px" :current="current" :values="items"
|
||||
@clickItem="onClickItem" styleType="button" activeColor="#0055ff"></uni-segmented-control>
|
||||
</view>
|
||||
<view class="content">
|
||||
<view v-show="current === 0">
|
||||
<view style="padding: 0 10px">
|
||||
<view class="progress-bartime">
|
||||
<!-- 动态设置宽度和颜色 -->
|
||||
<view class="progressTime" :style="{ width: `${timePercent}%`, 'background-color': '#0055ff' }">
|
||||
</view>
|
||||
<!-- 显示带符号的百分比 -->
|
||||
<text class="progress-text">全年时间进度:{{ timePercent }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y :style="{ height: scrollViewHeight + 'px' }">
|
||||
<trq-data></trq-data>
|
||||
<yy-data></yy-data>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-show="current === 1">
|
||||
<scroll-view scroll-y :style="{ height: scrollViewHeight + 'px' }">
|
||||
<sssjForm></sssjForm>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-show="current === 2">
|
||||
<scroll-view scroll-y :style="{ height: scrollViewHeight + 'px' }">
|
||||
选项卡2的内容
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<trq-data></trq-data>
|
||||
<yy-data></yy-data>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
|
||||
import {
|
||||
formatDate,
|
||||
getDateAfterDays
|
||||
} from '@/utils/dateTime.js';
|
||||
import {
|
||||
getYearProgress
|
||||
} from '@/utils/dateTime.js';
|
||||
|
||||
import { ref, onMounted, computed, nextTick, watchEffect } from 'vue';
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed,
|
||||
nextTick,
|
||||
watchEffect,
|
||||
onUnmounted
|
||||
} from 'vue';
|
||||
const items = ref(['日报数据', '实时数据', '经营数据'])
|
||||
const current = ref(0)
|
||||
const res = wx.getSystemInfoSync();
|
||||
const statusHeight = res.statusBarHeight; //状态栏高度
|
||||
const cusnavbarheight = statusHeight + 44 + 'px';
|
||||
|
||||
const res = wx.getSystemInfoSync();
|
||||
const statusHeight = res.statusBarHeight; //状态栏高度
|
||||
const cusnavbarheight = statusHeight + 44 + 'px';
|
||||
const scrollViewHeight = ref(0); //状态栏高度
|
||||
|
||||
const dateDate = ref('');
|
||||
|
||||
import trqData from './ribaoshuju/trqRbsj.vue';
|
||||
import yyData from './ribaoshuju/yyRbsj.vue';
|
||||
const timePercent = ref(0);
|
||||
const dateDate = ref('');
|
||||
|
||||
const strDate = () => {
|
||||
const now = new Date();
|
||||
if (now.getHours() < 11) {
|
||||
return formatDate(getDateAfterDays(now, -1)); //11点之前 头一天的数据
|
||||
} else {
|
||||
return formatDate(now);
|
||||
import trqData from './ribaoshuju/trqRbsj.vue';
|
||||
import yyData from './ribaoshuju/yyRbsj.vue';
|
||||
import sssjForm from './shishishuju/index.vue';
|
||||
|
||||
function onClickItem(e) {
|
||||
if (current.value != e.currentIndex) {
|
||||
current.value = e.currentIndex;
|
||||
}
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
dateDate.value = strDate();
|
||||
});
|
||||
|
||||
const strDate = () => {
|
||||
const now = new Date();
|
||||
if (now.getHours() < 11) {
|
||||
return formatDate(getDateAfterDays(now, -1)); //11点之前 头一天的数据
|
||||
} else {
|
||||
return formatDate(now);
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
dateDate.value = strDate();
|
||||
timePercent.value = getYearProgress();
|
||||
calculateScrollViewHeight();
|
||||
// 监听窗口大小变化事件,当窗口大小改变时重新计算高度
|
||||
window.addEventListener('resize', calculateScrollViewHeight);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// 移除窗口大小变化事件监听器
|
||||
window.removeEventListener('resize', calculateScrollViewHeight);
|
||||
});
|
||||
|
||||
const calculateScrollViewHeight = () => {
|
||||
// 获取屏幕的总高度
|
||||
const screenHeight = uni.getSystemInfoSync().windowHeight;
|
||||
// 创建一个选择器查询对象
|
||||
const query = uni.createSelectorQuery();
|
||||
// 选择所有需要计算高度的元素
|
||||
query
|
||||
.select('.nav')
|
||||
.boundingClientRect();
|
||||
query
|
||||
.select('.placeholder')
|
||||
.boundingClientRect();
|
||||
query
|
||||
.select('.uni-title')
|
||||
.boundingClientRect();
|
||||
query
|
||||
.select('.uni-segmented-control')
|
||||
.boundingClientRect();
|
||||
query
|
||||
.select('.progress-bartime')
|
||||
.boundingClientRect();
|
||||
// 执行查询操作
|
||||
query.exec((res) => {
|
||||
let totalHeight = 0;
|
||||
res.forEach((element) => {
|
||||
if (element) {
|
||||
totalHeight += element.height;
|
||||
}
|
||||
});
|
||||
// 计算 scroll-view 的高度
|
||||
scrollViewHeight.value = screenHeight - totalHeight - 80;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nav {
|
||||
width: calc(100% - 60rpx);
|
||||
padding: 0 30rpx;
|
||||
height: v-bind(cusnavbarheight);
|
||||
.nav {
|
||||
width: calc(100% - 60rpx);
|
||||
padding: 0 30rpx;
|
||||
height: v-bind(cusnavbarheight);
|
||||
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
background-image: url('../../static/my/navbg.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 750rpx 458rpx;
|
||||
}
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
background-image: url('../../static/my/navbg.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 750rpx 458rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
height: v-bind(cusnavbarheight);
|
||||
}
|
||||
</style>
|
||||
.placeholder {
|
||||
height: v-bind(cusnavbarheight);
|
||||
}
|
||||
|
||||
.progress-bartime {
|
||||
position: relative;
|
||||
height: 25px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.progressTime {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: red;
|
||||
/* 保持红色 */
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
/* 提升可读性 */
|
||||
}
|
||||
</style>
|
@ -1,19 +1,10 @@
|
||||
<template>
|
||||
<view :class="{ gray: store.isgray == 1 }">
|
||||
<view style="padding: 0 10px">
|
||||
<view class="progress-bartime">
|
||||
<!-- 动态设置宽度和颜色 -->
|
||||
<view class="progressTime" :style="{ width: `${timePercent}%`, 'background-color': '#00aaff' }"></view>
|
||||
<!-- 显示带符号的百分比 -->
|
||||
<text class="progress-text">全年时间进度:{{ timePercent }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<!-- 标题行 -->
|
||||
<view class="header-row">
|
||||
<view class="title">天然气产量</view>
|
||||
<view class="more" @click="selectMore">更多 →</view>
|
||||
<view class="more" @click="selectMore">更多>></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="container">
|
||||
@ -32,7 +23,9 @@
|
||||
<!-- 动态设置宽度和颜色 -->
|
||||
<view class="progress" :style="{ width: `${Math.abs(item.yearPerCent)}%`, 'background-color': item.yearPerCent < 0 ? '#ff4444' : '#007aff' }"></view>
|
||||
<!-- 显示带符号的百分比 -->
|
||||
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')" class="progress-text">{{ item.yearPerCent }}%</text>
|
||||
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')" class="progress-text" :style="{ color: item.yearPerCent < 0 ? '#007aff' : '#ff4444' }">
|
||||
{{ item.yearPerCent }}%
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -41,14 +34,22 @@
|
||||
<uni-popup ref="popupSelect" type="top" background-color="#fff">
|
||||
<view style="margin-top: 50px">
|
||||
<view class="titlepopup">选择显示更多生产数据</view>
|
||||
<uni-data-checkbox
|
||||
style="font-size: 14px"
|
||||
@change="onselectionchange"
|
||||
:localdata="shishiArr"
|
||||
v-model="shishiArrDisplay"
|
||||
multiple
|
||||
:map="{ value: 'gas', text: 'gas' }"
|
||||
></uni-data-checkbox>
|
||||
|
||||
<view class="popupBtn">
|
||||
<button size="mini" @click="selectDefault" style="padding: 8px 16px">默认</button>
|
||||
<button size="mini" @click="selectAll" style="padding: 8px 16px">全选</button>
|
||||
<button size="mini" @click="selectNo" style="padding: 8px 16px">全不选</button>
|
||||
</view>
|
||||
<view class="popupcheckbox">
|
||||
<uni-data-checkbox
|
||||
style="font-size: 14px"
|
||||
@change="onselectionchange"
|
||||
:localdata="shishiArr"
|
||||
v-model="shishiArrDisplay"
|
||||
multiple
|
||||
:map="{ value: 'gas', text: 'gas' }"
|
||||
></uni-data-checkbox>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
<!-- 数据弹窗 -->
|
||||
@ -98,25 +99,28 @@ import { queryJinriShengchansj, queryYearShengchansj, queryJinriTrqShengchansj }
|
||||
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
|
||||
import { beforeJump } from '@/utils/index.js';
|
||||
import { useStore } from '@/store';
|
||||
import { getYearProgress } from '@/utils/dateTime.js';
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const shishiArr = ref([]);
|
||||
const shishiArrSelect = ref([]);
|
||||
const shishiArrDisplay = ref(['气井气', '站线综合输差']);
|
||||
const shishiArrDisplay = ref(['气井气', '商品量', '站线综合输差']);
|
||||
const dataJinriUnit = ref([]);
|
||||
const selectedGas = ref('');
|
||||
const filteredData = ref([]);
|
||||
const popup = ref(null);
|
||||
const popupSelect = ref(null);
|
||||
const strDate = ref('');
|
||||
const timePercent = ref(0);
|
||||
|
||||
const dataJinri = ref([]);
|
||||
const dataJinriSum = ref([]);
|
||||
const dataJinriSumUnit = ref([]);
|
||||
|
||||
const qjqNdjs = ref(7500);
|
||||
const splNdjs = ref(7220);
|
||||
const zhqNdjs = ref(300);
|
||||
const zhscNdjs = ref(50);
|
||||
|
||||
// 点击卡片处理
|
||||
// const handleCardClick = (gas) => {
|
||||
// selectedGas.value = gas;
|
||||
@ -135,9 +139,33 @@ const dataJinriSumUnit = ref([]);
|
||||
|
||||
// popup.value.open();
|
||||
// };
|
||||
|
||||
function selectMore() {
|
||||
popupSelect.value.open();
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
shishiArrDisplay.value = [];
|
||||
// console.log(9, shishiArr.value)
|
||||
shishiArr.value.forEach((item) => {
|
||||
// console.log(10, item)
|
||||
shishiArrDisplay.value.push(item.gas);
|
||||
});
|
||||
onselectionchange();
|
||||
popup.value.close();
|
||||
}
|
||||
|
||||
function selectNo() {
|
||||
shishiArrDisplay.value = [];
|
||||
onselectionchange();
|
||||
popup.value.close();
|
||||
}
|
||||
|
||||
function selectDefault() {
|
||||
shishiArrDisplay.value = ['气井气', '商品量', '站线综合输差'];
|
||||
onselectionchange();
|
||||
popup.value.close();
|
||||
}
|
||||
const onselectionchange = () => {
|
||||
shishiArrSelect.value = [];
|
||||
shishiArrDisplay.value.forEach((item) => {
|
||||
@ -157,7 +185,7 @@ const closePopup = () => {
|
||||
};
|
||||
onMounted(() => {
|
||||
getJinriTrqShengchansj();
|
||||
timePercent.value = getYearProgress();
|
||||
|
||||
getJinriShengchansj();
|
||||
});
|
||||
|
||||
@ -202,7 +230,15 @@ function calcZhsc(tempArray) {
|
||||
yearVolume: 0,
|
||||
yearPlan: '100',
|
||||
yearPerCent: 0
|
||||
}; // 综合输差
|
||||
};
|
||||
const trqSpl = {
|
||||
gas: '商品量',
|
||||
dailyVolume: 0,
|
||||
yearVolume: 0,
|
||||
yearPlan: '7220',
|
||||
yearPerCent: 0
|
||||
};
|
||||
// 综合输差
|
||||
tempArray.forEach((item) => {
|
||||
if (item.gas === '站输差' || item.gas === '线输差') {
|
||||
compositeZx.dailyVolume += parseFloat(item.dailyVolume) || 0;
|
||||
@ -216,16 +252,26 @@ function calcZhsc(tempArray) {
|
||||
totalChuqi.dailyVolume += parseFloat(item.dailyVolume) || 0;
|
||||
totalChuqi.yearVolume += parseFloat(item.yearVolume) || 0;
|
||||
}
|
||||
if (item.gas === '气井气' || item.gas === '站输差' || item.gas === '线输差') {
|
||||
trqSpl.dailyVolume += parseFloat(item.dailyVolume) || 0;
|
||||
trqSpl.yearVolume += parseFloat(item.yearVolume) || 0;
|
||||
}
|
||||
if (item.gas === '自耗气') {
|
||||
trqSpl.dailyVolume -= parseFloat(item.dailyVolume) || 0;
|
||||
trqSpl.yearVolume -= parseFloat(item.yearVolume) || 0;
|
||||
}
|
||||
});
|
||||
|
||||
compositeZx.yearPerCent = calcPercent(compositeZx.yearPlan, compositeZx.yearVolume);
|
||||
|
||||
trqSpl.yearPerCent = calcPercent(trqSpl.yearPlan, trqSpl.yearVolume);
|
||||
|
||||
compositeJc.dailyVolume = (-totalJinqi.dailyVolume + totalChuqi.dailyVolume).toFixed(4);
|
||||
compositeJc.yearVolume = (-totalJinqi.yearVolume + totalChuqi.yearVolume).toFixed(4);
|
||||
compositeJc.yearPerCent = calcPercent(compositeJc.yearPlan, compositeJc.yearVolume);
|
||||
|
||||
tempArray.push(compositeZx);
|
||||
// tempArray.push(compositeJc);
|
||||
tempArray.push(trqSpl);
|
||||
|
||||
return tempArray;
|
||||
|
||||
@ -421,6 +467,8 @@ function sumByUnit(records) {
|
||||
align-items: center;
|
||||
padding: 10 10rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
@ -428,13 +476,46 @@ function sumByUnit(records) {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.titlepopup {
|
||||
font-size: 30rpx;
|
||||
font-size: 35rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 给包裹按钮的容器设置样式 */
|
||||
.popupBtn {
|
||||
display: grid;
|
||||
/* 创建三个等宽的列 */
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
/* 设置列与列之间的间距 */
|
||||
gap: 2px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 添加按钮按下效果 */
|
||||
.popupBtn button:active {
|
||||
opacity: 0.8;
|
||||
transform: scale(0.98);
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
/* 给按钮设置通用样式 */
|
||||
.popupBtn button {
|
||||
border: none;
|
||||
padding: 0px 10px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 鼠标悬停在按钮上时的样式 */
|
||||
.popupBtn button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.more {
|
||||
@ -458,6 +539,23 @@ function sumByUnit(records) {
|
||||
.more:hover {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.popupcheckbox {
|
||||
/* 使用 Flexbox 布局 */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* 允许换行 */
|
||||
gap: 2px;
|
||||
/* 设置复选框之间的间距 */
|
||||
margin-left: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.popupcheckbox .uni-data-checkbox__item {
|
||||
flex-basis: calc((100% / var(4)) - 10px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -612,25 +710,11 @@ function sumByUnit(records) {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.progress-bartime {
|
||||
position: relative;
|
||||
height: 20px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.progress {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.progressTime {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
@ -643,4 +727,16 @@ function sumByUnit(records) {
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
/* 提升可读性 */
|
||||
}
|
||||
.progress-textFs {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: red;
|
||||
/* 保持红色 */
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
/* 提升可读性 */
|
||||
}
|
||||
</style>
|
||||
|
@ -29,15 +29,13 @@
|
||||
|
||||
<view class="progress-bar">
|
||||
<!-- 动态设置宽度和颜色 -->
|
||||
<view
|
||||
class="progress"
|
||||
:style="{
|
||||
<view class="progress" :style="{
|
||||
width: `${Math.abs(item.yearPerCent)}%`,
|
||||
'background-color': item.yearPerCent < 0 ? '#ff4444' : '#007aff'
|
||||
}"
|
||||
></view>
|
||||
}"></view>
|
||||
<!-- 显示带符号的百分比 -->
|
||||
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')" class="progress-text">{{ item.yearPerCent }}%</text>
|
||||
<text v-if="!(item.yearPlan === '' || item.yearPlan === '0')"
|
||||
class="progress-text">{{ item.yearPerCent }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -63,7 +61,8 @@
|
||||
</view>
|
||||
|
||||
<!-- 表格内容 -->
|
||||
<view class="tr" v-for="(item, index) in dataJinri" :key="index" :class="{ even: index % 2 === 0 }">
|
||||
<view class="tr" v-for="(item, index) in dataJinri" :key="index"
|
||||
:class="{ even: index % 2 === 0 }">
|
||||
<view class="td1">{{ index }}</view>
|
||||
<view class="td">{{ item.dw }}</view>
|
||||
<view class="td">
|
||||
@ -86,327 +85,353 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed, nextTick, watchEffect } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { queryJinriYuanyouShengchansj } from '@/api/shengchan.js';
|
||||
import { formatDate, getDateAfterDays } from '@/utils/dateTime.js';
|
||||
import { beforeJump } from '@/utils/index.js';
|
||||
import { useStore } from '@/store';
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed,
|
||||
nextTick,
|
||||
watchEffect
|
||||
} from 'vue';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
queryJinriYuanyouShengchansj
|
||||
} from '@/api/shengchan.js';
|
||||
import {
|
||||
formatDate,
|
||||
getDateAfterDays
|
||||
} from '@/utils/dateTime.js';
|
||||
import {
|
||||
beforeJump
|
||||
} from '@/utils/index.js';
|
||||
import {
|
||||
useStore
|
||||
} from '@/store';
|
||||
|
||||
const store = useStore();
|
||||
import dataCom from '@/bpm/dataCom.vue';
|
||||
const store = useStore();
|
||||
import dataCom from '@/bpm/dataCom.vue';
|
||||
|
||||
const shishiArr = ref([
|
||||
{
|
||||
const shishiArr = ref([{
|
||||
gas: '原油产量',
|
||||
rcwy: '',
|
||||
yl: '',
|
||||
nl: '',
|
||||
yearPlan: '1500',
|
||||
yearPerCent: ''
|
||||
}
|
||||
]);
|
||||
}]);
|
||||
|
||||
const dataJinri = ref([]);
|
||||
const dataJinriSum = ref([]);
|
||||
const popup = ref(null);
|
||||
// 点击卡片处理
|
||||
const handleCardClick = () => {
|
||||
popup.value.open();
|
||||
};
|
||||
const dataJinri = ref([]);
|
||||
const dataJinriSum = ref([]);
|
||||
const popup = ref(null);
|
||||
// 点击卡片处理
|
||||
const handleCardClick = () => {
|
||||
popup.value.open();
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const closePopup = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
onMounted(() => {
|
||||
getJinriYuanyouShengchansj();
|
||||
// getYearShengchansj();
|
||||
});
|
||||
|
||||
const strDate = ref('');
|
||||
// 数字格式化
|
||||
const formatNumber = (num) => {
|
||||
if (typeof num !== 'number') return '-';
|
||||
return num.toFixed(4).replace(/\.?0+$/, '');
|
||||
};
|
||||
function goHistory(val) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/views/shengchan/ribaoshuju/rbsjLsxq?data=' + JSON.stringify(val) + '&type=yy'
|
||||
// 关闭弹窗
|
||||
const closePopup = () => {
|
||||
popup.value.close();
|
||||
};
|
||||
onMounted(() => {
|
||||
getJinriYuanyouShengchansj();
|
||||
// getYearShengchansj();
|
||||
});
|
||||
}
|
||||
const getJinriYuanyouShengchansj = () => {
|
||||
const now = new Date();
|
||||
if (now.getHours() < 11) {
|
||||
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11点之前 头一天的数据
|
||||
} else {
|
||||
strDate.value = formatDate(now).toString();
|
||||
}
|
||||
let queryParms = {};
|
||||
dataJinri.value = [];
|
||||
dataJinriSum.value = [];
|
||||
queryParms.scrq = strDate.value;
|
||||
queryParms.pageSize = 100;
|
||||
// // console.log(queryParms);
|
||||
queryJinriYuanyouShengchansj(queryParms).then((res) => {
|
||||
if (res.success) {
|
||||
// // console.log(res);
|
||||
dataJinri.value = res.result.records;
|
||||
dataJinriSum.value = sumByOil(dataJinri.value); //包含gas unit rq cq totalGas
|
||||
// // console.log(dataJinriSum.value);
|
||||
nextTick();
|
||||
shishiArr.value.forEach((item) => {
|
||||
dataJinriSum.value.forEach((itemjinri) => {
|
||||
item.rcwy = itemjinri.rcwy.toFixed(4);
|
||||
item.nl = itemjinri.nl.toFixed(4);
|
||||
item.yl = itemjinri.yl.toFixed(4);
|
||||
item.yearPerCent = calcPercent(item.yearPlan, item.nl);
|
||||
});
|
||||
});
|
||||
// getYearShengchansj(); //再获取今年以来的数据
|
||||
}
|
||||
});
|
||||
};
|
||||
function calcPercent(yearJihua, yearShiji) {
|
||||
// 计算进度百分比,避免除数为 0
|
||||
// 确保进度百分比不超过 100
|
||||
let plan = parseFloat(yearJihua === '' ? 0 : yearJihua);
|
||||
let shiji = parseFloat(yearShiji);
|
||||
let percent = 0;
|
||||
// 修改原始计算代码
|
||||
if (plan > 0) {
|
||||
percent = (shiji / plan) * 100;
|
||||
percent = Math.min(percent, 100); // 限制最大100%
|
||||
}
|
||||
return parseFloat(percent.toFixed(2)); // 转为数值
|
||||
}
|
||||
function sumByOil(records) {
|
||||
// console.log(records);
|
||||
const summaryMap = {};
|
||||
try {
|
||||
records.forEach((record) => {
|
||||
const gas = record.gas;
|
||||
if (!summaryMap[gas]) {
|
||||
// 初始化该 gas 类型的汇总对象
|
||||
summaryMap[gas] = {
|
||||
rcwy: 0,
|
||||
yl: 0,
|
||||
nl: 0
|
||||
};
|
||||
}
|
||||
// 无论是否是第一次遇到该 gas 类型,都进行累加操作
|
||||
summaryMap[gas].rcwy += record.rcwy || 0;
|
||||
summaryMap[gas].yl += record.yl || 0;
|
||||
summaryMap[gas].nl += record.nl || 0;
|
||||
|
||||
const strDate = ref('');
|
||||
// 数字格式化
|
||||
const formatNumber = (num) => {
|
||||
if (typeof num !== 'number') return '-';
|
||||
return num.toFixed(4).replace(/\.?0+$/, '');
|
||||
};
|
||||
|
||||
function goHistory(val) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/views/shengchan/ribaoshuju/rbsjLsxq?data=' + JSON.stringify(val) + '&type=yy'
|
||||
});
|
||||
return Object.values(summaryMap);
|
||||
} catch (error) {
|
||||
//TODO handle the exception
|
||||
// console.log(error);
|
||||
}
|
||||
}
|
||||
const getJinriYuanyouShengchansj = () => {
|
||||
const now = new Date();
|
||||
if (now.getHours() < 11) {
|
||||
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11点之前 头一天的数据
|
||||
} else {
|
||||
strDate.value = formatDate(now).toString();
|
||||
}
|
||||
let queryParms = {};
|
||||
dataJinri.value = [];
|
||||
dataJinriSum.value = [];
|
||||
queryParms.scrq = strDate.value;
|
||||
queryParms.pageSize = 100;
|
||||
// // console.log(queryParms);
|
||||
queryJinriYuanyouShengchansj(queryParms).then((res) => {
|
||||
if (res.success) {
|
||||
// // console.log(res);
|
||||
dataJinri.value = res.result.records;
|
||||
dataJinriSum.value = sumByOil(dataJinri.value); //包含gas unit rq cq totalGas
|
||||
// // console.log(dataJinriSum.value);
|
||||
nextTick();
|
||||
shishiArr.value.forEach((item) => {
|
||||
dataJinriSum.value.forEach((itemjinri) => {
|
||||
item.rcwy = itemjinri.rcwy.toFixed(4);
|
||||
item.nl = itemjinri.nl.toFixed(4);
|
||||
item.yl = itemjinri.yl.toFixed(4);
|
||||
item.yearPerCent = calcPercent(item.yearPlan, item.nl);
|
||||
});
|
||||
});
|
||||
// getYearShengchansj(); //再获取今年以来的数据
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function calcPercent(yearJihua, yearShiji) {
|
||||
// 计算进度百分比,避免除数为 0
|
||||
// 确保进度百分比不超过 100
|
||||
let plan = parseFloat(yearJihua === '' ? 0 : yearJihua);
|
||||
let shiji = parseFloat(yearShiji);
|
||||
let percent = 0;
|
||||
// 修改原始计算代码
|
||||
if (plan > 0) {
|
||||
percent = (shiji / plan) * 100;
|
||||
percent = Math.min(percent, 100); // 限制最大100%
|
||||
}
|
||||
return parseFloat(percent.toFixed(2)); // 转为数值
|
||||
}
|
||||
|
||||
function sumByOil(records) {
|
||||
// console.log(records);
|
||||
const summaryMap = {};
|
||||
try {
|
||||
records.forEach((record) => {
|
||||
const gas = record.gas;
|
||||
if (!summaryMap[gas]) {
|
||||
// 初始化该 gas 类型的汇总对象
|
||||
summaryMap[gas] = {
|
||||
rcwy: 0,
|
||||
yl: 0,
|
||||
nl: 0
|
||||
};
|
||||
}
|
||||
// 无论是否是第一次遇到该 gas 类型,都进行累加操作
|
||||
summaryMap[gas].rcwy += record.rcwy || 0;
|
||||
summaryMap[gas].yl += record.yl || 0;
|
||||
summaryMap[gas].nl += record.nl || 0;
|
||||
});
|
||||
return Object.values(summaryMap);
|
||||
} catch (error) {
|
||||
//TODO handle the exception
|
||||
// console.log(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.more {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.more::after {
|
||||
content: '';
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-top: 2rpx solid #666;
|
||||
border-right: 2rpx solid #666;
|
||||
transform: rotate(45deg);
|
||||
margin-left: 8rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 鼠标悬停效果 */
|
||||
.more:hover {
|
||||
color: #007aff;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 30rpx;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table {
|
||||
min-width: 100%;
|
||||
border: 2rpx solid #e8e8e8;
|
||||
|
||||
.tr {
|
||||
display: flex;
|
||||
border-bottom: 2rpx solid #e8e8e8;
|
||||
|
||||
&.header {
|
||||
background-color: #fafafa;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.even {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.th,
|
||||
.td {
|
||||
flex: 1;
|
||||
min-width: 80rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.th1,
|
||||
.td1 {
|
||||
flex: 1;
|
||||
max-width: 40rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
height: 30rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.th {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.td.negative {
|
||||
color: #ff4444;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 16rpx;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
flex: 1 1 200rpx; // 基础宽度300rpx,自动伸缩 selectedGas formatNumber
|
||||
min-width: 200rpx;
|
||||
max-width: calc(50% - 10rpx); // 最大不超过容器一半(考虑间距)
|
||||
|
||||
@media (min-width: 768px) {
|
||||
max-width: calc(33.33% - 14rpx); // 大屏显示3列
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #ececec;
|
||||
border-radius: 16rpx;
|
||||
padding: 15rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(197, 197, 197, 0.1);
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.content {
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
padding: 15rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.more {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.more::after {
|
||||
content: '';
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-top: 2rpx solid #666;
|
||||
border-right: 2rpx solid #666;
|
||||
transform: rotate(45deg);
|
||||
margin-left: 8rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 鼠标悬停效果 */
|
||||
.more:hover {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 30rpx;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table {
|
||||
min-width: 100%;
|
||||
border: 2rpx solid #e8e8e8;
|
||||
|
||||
.tr {
|
||||
display: flex;
|
||||
border-bottom: 2rpx solid #e8e8e8;
|
||||
|
||||
&.header {
|
||||
background-color: #fafafa;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.even {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
.th,
|
||||
.td {
|
||||
flex: 1;
|
||||
min-width: 80rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #0000ff;
|
||||
.th1,
|
||||
.td1 {
|
||||
flex: 1;
|
||||
max-width: 40rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
height: 30rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.th {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.td.negative {
|
||||
color: #ff4444;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
.progress-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
position: relative;
|
||||
height: 20px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.empty {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 16rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.card-item {
|
||||
flex: 1 1 200rpx; // 基础宽度300rpx,自动伸缩 selectedGas formatNumber
|
||||
min-width: 200rpx;
|
||||
max-width: calc(50% - 10rpx); // 最大不超过容器一半(考虑间距)
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: red; /* 保持红色 */
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); /* 提升可读性 */
|
||||
}
|
||||
</style>
|
||||
@media (min-width: 768px) {
|
||||
max-width: calc(33.33% - 14rpx); // 大屏显示3列
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #ececec;
|
||||
border-radius: 16rpx;
|
||||
padding: 15rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(197, 197, 197, 0.1);
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #0000ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
position: relative;
|
||||
height: 20px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: red;
|
||||
/* 保持红色 */
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
/* 提升可读性 */
|
||||
}
|
||||
</style>
|
8
pages/views/shengchan/shishishuju/aqbjSssj.vue
Normal file
8
pages/views/shengchan/shishishuju/aqbjSssj.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
8
pages/views/shengchan/shishishuju/gycsSssj.vue
Normal file
8
pages/views/shengchan/shishishuju/gycsSssj.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
44
pages/views/shengchan/shishishuju/index.vue
Normal file
44
pages/views/shengchan/shishishuju/index.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<view :class="{ gray: store.isgray == 1 }">
|
||||
<trqSssjVue></trqSssjVue>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed,
|
||||
nextTick,
|
||||
watchEffect
|
||||
} from 'vue';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
queryJinriShengchansj,
|
||||
queryYearShengchansj,
|
||||
queryJinriTrqShengchansj
|
||||
} from '@/api/shengchan.js';
|
||||
import {
|
||||
formatDate,
|
||||
getDateAfterDays
|
||||
} from '@/utils/dateTime.js';
|
||||
import {
|
||||
beforeJump
|
||||
} from '@/utils/index.js';
|
||||
import {
|
||||
useStore
|
||||
} from '@/store';
|
||||
|
||||
import trqSssjVue from './trqSssj.vue';
|
||||
|
||||
|
||||
|
||||
const store = useStore();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
8
pages/views/shengchan/shishishuju/nyxhSssj.vue
Normal file
8
pages/views/shengchan/shishishuju/nyxhSssj.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
315
pages/views/shengchan/shishishuju/trqSssj.vue
Normal file
315
pages/views/shengchan/shishishuju/trqSssj.vue
Normal file
@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<view :class="{ gray: store.isgray == 1 }">
|
||||
|
||||
|
||||
<view>
|
||||
<!-- 标题行 -->
|
||||
<view class="header-row">
|
||||
<view class="title">天然气实时数据</view>
|
||||
<view style="min-width: 200px;"><cxc-szcx-stationJl-select v-model="stationID" returnCodeOrID="id"
|
||||
@change="onChange"></cxc-szcx-stationJl-select></view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<button size="mini" @click="getData">连接WebSocket</button>
|
||||
|
||||
<view class="container">
|
||||
<view v-for="(item, index) in jlData" :key="index" class="card">
|
||||
<view class="field-item">
|
||||
<text class="titlejl">{{ stationName }}--{{ item.jldname }}</text>
|
||||
<view class="status-circle"
|
||||
:style="{ backgroundColor: item.yxzt==='运行' ? '#4CAF50' : '#F44336' }">
|
||||
{{item.yxzt}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="field-list">
|
||||
<!-- 压力 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">压力(MPa)</text>
|
||||
<text class="field-value">{{ formatNumber(item.yl) || '-' }}</text>
|
||||
</view>
|
||||
<!-- 差压 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">差压(kPa)</text>
|
||||
<text class="field-value">{{ formatNumber(item.yc) || '-' }}</text>
|
||||
</view>
|
||||
<!-- 温度 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">温度(℃)</text>
|
||||
<text class="field-value">{{ formatNumber(item.wd) || '-' }}</text>
|
||||
</view>
|
||||
<!-- 瞬时流量 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">瞬时流量(m³/d)</text>
|
||||
<text class="field-value">{{ formatNumber(item.ssll) || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 今日流量 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">今日流量(m³)</text>
|
||||
<text class="field-value">{{ formatNumber(item.jrl) || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 昨日流量 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">昨日流量(m³)</text>
|
||||
<text class="field-value">{{ formatNumber(item.zrl) || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 昨日时间 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">昨日时间(min)</text>
|
||||
<text class="field-value">{{ formatNumber(item.zrsj) || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 今日时间 -->
|
||||
<view class="field-item">
|
||||
<text class="field-label">今日时间(min)</text>
|
||||
<text class="field-value">{{ formatNumber(item.jrsj) || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
computed,
|
||||
nextTick,
|
||||
watchEffect
|
||||
} from 'vue';
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
queryJldZcList,
|
||||
queryJldDataByZc
|
||||
} from '@/api/shengchan.js';
|
||||
import {
|
||||
formatDate,
|
||||
getDateAfterDays
|
||||
} from '@/utils/dateTime.js';
|
||||
import {
|
||||
beforeJump
|
||||
} from '@/utils/index.js';
|
||||
import {
|
||||
useStore
|
||||
} from '@/store';
|
||||
const store = useStore();
|
||||
|
||||
const stationList = ref([])
|
||||
// 控制弹窗显示与隐藏
|
||||
const popupSelect = ref(null);
|
||||
const stationID = ref("")
|
||||
const stationName = ref("")
|
||||
|
||||
const jlData = ref([])
|
||||
|
||||
const sssjUrl = ref('wss://36.112.48.190/Gyk/websocket/')
|
||||
const jlByzc = ref('https://36.112.48.190/Gyk/sssj/GetJlByZc')
|
||||
|
||||
//首先链接的地址要先拿在websocket在线调试去调试是否能连接通 不然下面的操作就不知道错误
|
||||
// 建立websocket
|
||||
function connectSocketInit() {
|
||||
console.log(11, )
|
||||
let userID = '1412198011559055361'
|
||||
// 创建一个this.socketTask对象【发送、接收、关闭socket都由这个对象操作】
|
||||
uni.connectSocket({
|
||||
// 【非常重要】必须确保你的服务器是成功的,如果是手机测试千万别使用ws://127.0.0.1:9099【特别容易犯的错误】
|
||||
// url: 'wss://'+this.$api.sellerWebsocket+'/'+this.userinfo.id,
|
||||
url: sssjUrl.value + userID,
|
||||
success(data) {
|
||||
console.log(data);
|
||||
console.log('websocket连接成功');
|
||||
}
|
||||
});
|
||||
// 消息的发送和接收必须在正常连接打开中,才能发送或接收【否则会失败】
|
||||
uni.onSocketOpen(function(res) {
|
||||
console.log('WebSocket连接已打开!');
|
||||
});
|
||||
uni.onSocketMessage(function(res) {
|
||||
console.log('收到服务器内容:' + res.data);
|
||||
// 语音播放 start
|
||||
const innerAudioContext = uni.createInnerAudioContext();
|
||||
innerAudioContext.autoplay = true;
|
||||
innerAudioContext.src = 'https://wzs1.oss-cn-beijing.aliyuncs.com/music.mp3';
|
||||
innerAudioContext.onPlay(() => {
|
||||
console.log('开始播放');
|
||||
});
|
||||
innerAudioContext.onError(res => {
|
||||
console.log(res.errMsg);
|
||||
console.log(res.errCode);
|
||||
});
|
||||
//语音播放 end
|
||||
});
|
||||
// 这里仅是事件监听【如果socket关闭了会执行】
|
||||
uni.onSocketClose(function(res) {
|
||||
console.log('WebSocket 已关闭!');
|
||||
});
|
||||
}
|
||||
|
||||
function getData() {
|
||||
connectSocketInit()
|
||||
}
|
||||
|
||||
function onChange(e, data) {
|
||||
console.log(2, e, data.value);
|
||||
stationID.value = e
|
||||
stationName.value = data.value.title
|
||||
uni.request({
|
||||
url: jlByzc.value + '?zhanc=' + stationID.value + '&jldLx=0',
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
console.log(3, res, stationName.value)
|
||||
jlData.value = JSON.parse(res.data.result).JlData;
|
||||
console.log(4, jlData.value)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
const websock = ref(null);
|
||||
const timer2 = ref(null);
|
||||
// 封装心跳函数
|
||||
const websocketheart = () => {
|
||||
timer2.value = setInterval(() => {
|
||||
if (websock.value && websock.value.readyState === 1) {
|
||||
// 如果连接正常,发送心跳消息
|
||||
connectSocketInit()
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
queryJldZcList({
|
||||
pId: '1267633406031953921'
|
||||
}).then((res) => {
|
||||
|
||||
if (res.success) {
|
||||
stationList.value = res.result
|
||||
console.log(1, stationList.value)
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
websocketheart()
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 数字格式化
|
||||
const formatNumber = (num) => {
|
||||
let temp = 0;
|
||||
try {
|
||||
temp = parseFloat(num);
|
||||
} catch (error) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
|
||||
return temp.toFixed(4).replace(/\.?0+$/, '');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10 10rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.titlejl {
|
||||
font-size: 20rpx;
|
||||
vertical-align: middle;
|
||||
font-weight: bold;
|
||||
color: #0055ff;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 5px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.field-list {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* 允许子元素换行 */
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.field-item {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 5px 5px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
flex-basis: calc(50%-10px);
|
||||
/* 每个元素占据约一半宽度,减去间隙 */
|
||||
box-sizing: border-box;
|
||||
/* 包含内边距和边框 */
|
||||
}
|
||||
|
||||
/* 当屏幕宽度较小时,每个元素占据整行 */
|
||||
@media (max-width: 200px) {
|
||||
.field-item {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.field-label {
|
||||
color: #666;
|
||||
font-size: 8px;
|
||||
flex: 1;
|
||||
margin-right: 2px;
|
||||
width: 80px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.field-value {
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
width: 60px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.status-circle {
|
||||
width: 70rpx;
|
||||
height: 30rpx;
|
||||
font-size: 12px;
|
||||
vertical-align: middle;
|
||||
|
||||
|
||||
}
|
||||
</style>
|
8
pages/views/shengchan/shishishuju/ysjSssj.vue
Normal file
8
pages/views/shengchan/shishishuju/ysjSssj.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
947
static/data/nlszcs.json
Normal file
947
static/data/nlszcs.json
Normal file
@ -0,0 +1,947 @@
|
||||
[{
|
||||
"序号": "1",
|
||||
"单位职务": "安全环保室主管",
|
||||
"姓名": "方超",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239603",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "90.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "2",
|
||||
"单位职务": "安全环保督查中心(工程监督中心)助理员",
|
||||
"姓名": "孔玉",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239616",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "87.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "3",
|
||||
"单位职务": "人力资源服务中心副主任",
|
||||
"姓名": "陈康朝",
|
||||
"性别": "男",
|
||||
"劳动合同号": "103333",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "88.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "4",
|
||||
"单位职务": "人力资源服务中心主管师",
|
||||
"姓名": "韩斌",
|
||||
"性别": "男",
|
||||
"劳动合同号": "018733",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "84.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "5",
|
||||
"单位职务": "治安保卫中心主办",
|
||||
"姓名": "齐显琛",
|
||||
"性别": "男",
|
||||
"劳动合同号": "100496",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "87.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "6",
|
||||
"单位职务": "柳屯输气管理区主管师",
|
||||
"姓名": "殷丽丽",
|
||||
"性别": "女",
|
||||
"劳动合同号": "008925",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "87.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "7",
|
||||
"单位职务": "东濮采气管理区副经理",
|
||||
"姓名": "王全超",
|
||||
"性别": "男",
|
||||
"劳动合同号": "009115",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "82.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "8",
|
||||
"单位职务": "东濮采气管理项目部副经理",
|
||||
"姓名": "彭江苏",
|
||||
"性别": "男",
|
||||
"劳动合同号": "018645",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "86.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "9",
|
||||
"单位职务": "天然气计量化验中心助理师",
|
||||
"姓名": "张海波",
|
||||
"性别": "男",
|
||||
"劳动合同号": "237229",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "90.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "10",
|
||||
"单位职务": "开发研究所助理师",
|
||||
"姓名": "王瑞浩",
|
||||
"性别": "男",
|
||||
"劳动合同号": "241327",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "86.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "11",
|
||||
"单位职务": "天津LNG项目部助理师",
|
||||
"姓名": "史航",
|
||||
"性别": "男",
|
||||
"劳动合同号": "100474",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "88.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "12",
|
||||
"单位职务": "通南巴项目主管师",
|
||||
"姓名": "黄卓",
|
||||
"性别": "男",
|
||||
"劳动合同号": "039385",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "87.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "13",
|
||||
"单位职务": "输气管理项目部助理师",
|
||||
"姓名": "孙宇明",
|
||||
"性别": "男",
|
||||
"劳动合同号": "102625",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "85.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "14",
|
||||
"单位职务": "输气管理项目部助理师",
|
||||
"姓名": "张艺皓",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240971",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "83.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2025年8月"
|
||||
},
|
||||
{
|
||||
"序号": "15",
|
||||
"单位职务": "生产调度室主管",
|
||||
"姓名": "向龙",
|
||||
"性别": "男",
|
||||
"劳动合同号": "103812",
|
||||
"2024.02考试成绩": "98.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "16",
|
||||
"单位职务": "计划财务室助理员",
|
||||
"姓名": "吴曾科",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236709",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "86.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "17",
|
||||
"单位职务": "经营管理室主办",
|
||||
"姓名": "穆丽",
|
||||
"性别": "女",
|
||||
"劳动合同号": "001334",
|
||||
"2024.02考试成绩": "87.0",
|
||||
"2024.08考试成绩": "82.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "18",
|
||||
"单位职务": "综合办公室助理员",
|
||||
"姓名": "杨非非",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236635",
|
||||
"2024.02考试成绩": "93.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "19",
|
||||
"单位职务": "群众工作办公室助理员",
|
||||
"姓名": "余杰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236739",
|
||||
"2024.02考试成绩": "95.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "20",
|
||||
"单位职务": "群众工作办公室助理员",
|
||||
"姓名": "马婷",
|
||||
"性别": "女",
|
||||
"劳动合同号": "239720",
|
||||
"2024.02考试成绩": "94.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "21",
|
||||
"单位职务": "市场开发室主管",
|
||||
"姓名": "靳丽娟",
|
||||
"性别": "女",
|
||||
"劳动合同号": "022648",
|
||||
"2024.02考试成绩": "95.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "22",
|
||||
"单位职务": "安全环保督查中心(工程监督中心)主办",
|
||||
"姓名": "杨家田",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239723",
|
||||
"2024.02考试成绩": "91.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "23",
|
||||
"单位职务": "安全环保督查中心(工程监督中心)主办",
|
||||
"姓名": "罗继勇",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239766",
|
||||
"2024.02考试成绩": "92.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "24",
|
||||
"单位职务": "天然气计量化验中心副主任",
|
||||
"姓名": "张杰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240802",
|
||||
"2024.02考试成绩": "93.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "25",
|
||||
"单位职务": "天然气计量化验中心主管师",
|
||||
"姓名": "姜文峰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "237664",
|
||||
"2024.02考试成绩": "94.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "26",
|
||||
"单位职务": "治安保卫中心助理员",
|
||||
"姓名": "李巍",
|
||||
"性别": "男",
|
||||
"劳动合同号": "098529",
|
||||
"2024.02考试成绩": "97.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "27",
|
||||
"单位职务": "开发研究所助理师",
|
||||
"姓名": "王志远",
|
||||
"性别": "男",
|
||||
"劳动合同号": "241278",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "80.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "28",
|
||||
"单位职务": "东濮采气管理区副经理",
|
||||
"姓名": "王鹏",
|
||||
"性别": "男",
|
||||
"劳动合同号": "237338",
|
||||
"2024.02考试成绩": "98.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "29",
|
||||
"单位职务": "东濮采气管理区主管师",
|
||||
"姓名": "于蔚兰",
|
||||
"性别": "女",
|
||||
"劳动合同号": "101355",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "83.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "30",
|
||||
"单位职务": "东濮采气管理区主管师",
|
||||
"姓名": "何战波",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239771",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "87.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "31",
|
||||
"单位职务": "东濮采气管理区助理师",
|
||||
"姓名": "裴昱赫",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239561",
|
||||
"2024.02考试成绩": "92.0",
|
||||
"2024.08考试成绩": "83.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "32",
|
||||
"单位职务": "东濮采气管理区助理师",
|
||||
"姓名": "李锡原",
|
||||
"性别": "男",
|
||||
"劳动合同号": "241174",
|
||||
"2024.02考试成绩": "94.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "33",
|
||||
"单位职务": "文留输气管理区副经理",
|
||||
"姓名": "王京健",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239543",
|
||||
"2024.02考试成绩": "100.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "34",
|
||||
"单位职务": "文留输气管理区副经理",
|
||||
"姓名": "胡海",
|
||||
"性别": "男",
|
||||
"劳动合同号": "095325",
|
||||
"2024.02考试成绩": "98.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "35",
|
||||
"单位职务": "文留输气管理区主管",
|
||||
"姓名": "刘先振",
|
||||
"性别": "男",
|
||||
"劳动合同号": "013995",
|
||||
"2024.02考试成绩": "96.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "36",
|
||||
"单位职务": "文留输气管理区主管师",
|
||||
"姓名": "张琦",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239530",
|
||||
"2024.02考试成绩": "97.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "37",
|
||||
"单位职务": "柳屯输气管理区主管师",
|
||||
"姓名": "韩宣春",
|
||||
"性别": "男",
|
||||
"劳动合同号": "022645",
|
||||
"2024.02考试成绩": "98.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "38",
|
||||
"单位职务": "巡线大队主管师",
|
||||
"姓名": "王斌",
|
||||
"性别": "男",
|
||||
"劳动合同号": "025333",
|
||||
"2024.02考试成绩": "100.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "39",
|
||||
"单位职务": "压缩机维保项目部副经理",
|
||||
"姓名": "郭阳",
|
||||
"性别": "男",
|
||||
"劳动合同号": "013992",
|
||||
"2024.02考试成绩": "94.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "40",
|
||||
"单位职务": "压缩机维保项目部副经理",
|
||||
"姓名": "张恒立",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240655",
|
||||
"2024.02考试成绩": "93.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "41",
|
||||
"单位职务": "压缩机维保项目部助理师",
|
||||
"姓名": "张博",
|
||||
"性别": "男",
|
||||
"劳动合同号": "241196",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "89.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "42",
|
||||
"单位职务": "普光项目部副经理",
|
||||
"姓名": "王宝华",
|
||||
"性别": "男",
|
||||
"劳动合同号": "017889",
|
||||
"2024.02考试成绩": "97.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "43",
|
||||
"单位职务": "普光项目部党支部副书记",
|
||||
"姓名": "杨申",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239677",
|
||||
"2024.02考试成绩": "100.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "44",
|
||||
"单位职务": "普光项目部主管师",
|
||||
"姓名": "周峰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "095931",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "89.0",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "45",
|
||||
"单位职务": "普光项目部助理师",
|
||||
"姓名": "安克法",
|
||||
"性别": "男",
|
||||
"劳动合同号": "239718",
|
||||
"2024.02考试成绩": "92.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "46",
|
||||
"单位职务": "输气管理项目部副主任师",
|
||||
"姓名": "蔡小虎",
|
||||
"性别": "男",
|
||||
"劳动合同号": "043004",
|
||||
"2024.02考试成绩": "96.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "47",
|
||||
"单位职务": "人力资源服务中心主管师",
|
||||
"姓名": "熊文",
|
||||
"性别": "男",
|
||||
"劳动合同号": "041870",
|
||||
"2024.02考试成绩": "98.0",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年2月"
|
||||
},
|
||||
{
|
||||
"序号": "48",
|
||||
"单位职务": "生产调度室主管",
|
||||
"姓名": "孙东阳",
|
||||
"性别": "男",
|
||||
"劳动合同号": "013998",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "94.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "49",
|
||||
"单位职务": "综合办公室主办",
|
||||
"姓名": "王谦",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236681",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "92.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "50",
|
||||
"单位职务": "综合办公室助理师",
|
||||
"姓名": "王云尧",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240974",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "95.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "51",
|
||||
"单位职务": "安全环保室助理员",
|
||||
"姓名": "高晨峰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240477",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "94.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "52",
|
||||
"单位职务": "组织人事室助理员",
|
||||
"姓名": "吕晓路",
|
||||
"性别": "男",
|
||||
"劳动合同号": "237039",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "92.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "53",
|
||||
"单位职务": "市场开发室主办",
|
||||
"姓名": "郑慧研",
|
||||
"性别": "男",
|
||||
"劳动合同号": "101099",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "100.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "54",
|
||||
"单位职务": "安全环保督查中心(工程监督中心)主办",
|
||||
"姓名": "张龙超",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236628",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "94.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "55",
|
||||
"单位职务": "安全环保督查中心(工程监督中心)助理师",
|
||||
"姓名": "杨高峰",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240973",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "91.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "56",
|
||||
"单位职务": "生产服务中心党支部副书记",
|
||||
"姓名": "柳彬",
|
||||
"性别": "男",
|
||||
"劳动合同号": "098107",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "95.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "57",
|
||||
"单位职务": "治安保卫中心副主任",
|
||||
"姓名": "杨舜",
|
||||
"性别": "男",
|
||||
"劳动合同号": "100521",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "93.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "58",
|
||||
"单位职务": "天然气计量化验中心主管",
|
||||
"姓名": "程志伟",
|
||||
"性别": "男",
|
||||
"劳动合同号": "101359",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "91.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "59",
|
||||
"单位职务": "开发研究所副所长",
|
||||
"姓名": "曹正安",
|
||||
"性别": "男",
|
||||
"劳动合同号": "039383",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "93.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "60",
|
||||
"单位职务": "开发研究所主管师",
|
||||
"姓名": "龙一慧",
|
||||
"性别": "女",
|
||||
"劳动合同号": "240318",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "93.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "61",
|
||||
"单位职务": "开发研究所主管师",
|
||||
"姓名": "李香芹",
|
||||
"性别": "女",
|
||||
"劳动合同号": "040224",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "92.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "62",
|
||||
"单位职务": "文留输气管理区副经理",
|
||||
"姓名": "张海波",
|
||||
"性别": "男",
|
||||
"劳动合同号": "042449",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "98.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "63",
|
||||
"单位职务": "柳屯输气管理区党支部副书记、副经理",
|
||||
"姓名": "张超",
|
||||
"性别": "男",
|
||||
"劳动合同号": "103814",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "94.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "64",
|
||||
"单位职务": "通南巴项目助理师",
|
||||
"姓名": "梁鹏辉",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240534",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "98.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2026年8月"
|
||||
},
|
||||
{
|
||||
"序号": "65",
|
||||
"单位职务": "市场开发室主管",
|
||||
"姓名": "徐胜愿",
|
||||
"性别": "男",
|
||||
"劳动合同号": "043083",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "96.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "66",
|
||||
"单位职务": "安全环保室主办",
|
||||
"姓名": "鲍灵云",
|
||||
"性别": "女",
|
||||
"劳动合同号": "098095",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "95.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "67",
|
||||
"单位职务": "组织人事室主办",
|
||||
"姓名": "高俊华",
|
||||
"性别": "女",
|
||||
"劳动合同号": "097139",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "99.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "68",
|
||||
"单位职务": "人力资源服务中心助理师",
|
||||
"姓名": "周正葳",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240970",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "99.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "69",
|
||||
"单位职务": "人力资源服务中心业务员",
|
||||
"姓名": "武文斌",
|
||||
"性别": "男",
|
||||
"劳动合同号": "236789",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "94.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "70",
|
||||
"单位职务": "纪检监督室助理员",
|
||||
"姓名": "屈倩竹",
|
||||
"性别": "女",
|
||||
"劳动合同号": "240735",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "93.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "71",
|
||||
"单位职务": "天然气计量化验中心副主任",
|
||||
"姓名": "郭照祥",
|
||||
"性别": "男",
|
||||
"劳动合同号": "237637",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "92.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "72",
|
||||
"单位职务": "天然气计量化验中心副主任师",
|
||||
"姓名": "段善友",
|
||||
"性别": "男",
|
||||
"劳动合同号": "096248",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "92.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "73",
|
||||
"单位职务": "东濮采气管理区主管",
|
||||
"姓名": "张凯",
|
||||
"性别": "男",
|
||||
"劳动合同号": "018913",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "98.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "74",
|
||||
"单位职务": "东濮采气管理区主办",
|
||||
"姓名": "胡小光",
|
||||
"性别": "男",
|
||||
"劳动合同号": "097043",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "95.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "75",
|
||||
"单位职务": "东濮采气管理项目部主管",
|
||||
"姓名": "贾福东",
|
||||
"性别": "男",
|
||||
"劳动合同号": "026356",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "93.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "76",
|
||||
"单位职务": "柳屯输气管理区助理师",
|
||||
"姓名": "刘子敬",
|
||||
"性别": "男",
|
||||
"劳动合同号": "240638",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "95.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "77",
|
||||
"单位职务": "柳屯输气管理区助理师",
|
||||
"姓名": "马天娇",
|
||||
"性别": "女",
|
||||
"劳动合同号": "241155",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "93.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "78",
|
||||
"单位职务": "压缩机维保项目部助理师",
|
||||
"姓名": "王帅",
|
||||
"性别": "男",
|
||||
"劳动合同号": "103322",
|
||||
"2024.02考试成绩": "83.0",
|
||||
"2024.08考试成绩": "93.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "79",
|
||||
"单位职务": "山东管道项目部业务员",
|
||||
"姓名": "侯明路",
|
||||
"性别": "男",
|
||||
"劳动合同号": "238781",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "91.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "80",
|
||||
"单位职务": "普光项目部副经理",
|
||||
"姓名": "姚文涛",
|
||||
"性别": "男",
|
||||
"劳动合同号": "073696",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "99.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "81",
|
||||
"单位职务": "普光项目部主管师",
|
||||
"姓名": "彭端勇",
|
||||
"性别": "男",
|
||||
"劳动合同号": "101106",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "98.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "82",
|
||||
"单位职务": "普光项目部助理师",
|
||||
"姓名": "陈饷",
|
||||
"性别": "男",
|
||||
"劳动合同号": "023239",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "96.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "83",
|
||||
"单位职务": "通南巴项目部主管",
|
||||
"姓名": "李鹏辉",
|
||||
"性别": "男",
|
||||
"劳动合同号": "101104",
|
||||
"2024.02考试成绩": "87.0",
|
||||
"2024.08考试成绩": "96.0",
|
||||
"2025.02考试成绩": "",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "84",
|
||||
"单位职务": "通南巴项目部助理师",
|
||||
"姓名": "付小波",
|
||||
"性别": "男",
|
||||
"劳动合同号": "013974",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "93.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "85",
|
||||
"单位职务": "天津LNG项目部技术员",
|
||||
"姓名": "江嘉俊",
|
||||
"性别": "男",
|
||||
"劳动合同号": "103317",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "99.0",
|
||||
"截止有效期": "2027年2月"
|
||||
},
|
||||
{
|
||||
"序号": "86",
|
||||
"单位职务": "天津LNG项目部业务员",
|
||||
"姓名": "周晓亮",
|
||||
"性别": "男",
|
||||
"劳动合同号": "026622",
|
||||
"2024.02考试成绩": "",
|
||||
"2024.08考试成绩": "",
|
||||
"2025.02考试成绩": "93.0",
|
||||
"截止有效期": "2027年2月"
|
||||
}
|
||||
]
|
0
uni_modules/cxc-szcx-dateRangeSelect/changelog.md
Normal file
0
uni_modules/cxc-szcx-dateRangeSelect/changelog.md
Normal file
@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<view class="compact-datetime-picker">
|
||||
<!-- 输入框区域 -->
|
||||
<view class="input-container">
|
||||
<view class="compact-input" @click="openPicker">
|
||||
{{ dateRange[0] || '开始日期' }}
|
||||
</view>
|
||||
<text v-if="mode==='range'" class="separator">至</text>
|
||||
<view v-if="mode==='range'" class="compact-input" @click="openPicker">
|
||||
{{ dateRange[1] || '结束日期' }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<wu-calendar ref="calendar" :mode="mode" :date="dateRange" @confirm="calendarConfirm"
|
||||
slideSwitchMode="horizontal" type="month" :fold="false" :insert="false" :rangeSameDay="true" :lunar="true"
|
||||
:monthShowCurrentMonth="false" :range-end-repick="true" :item-height="60" :rangeEndRepick="true"
|
||||
:startDate="startDate" :endDate="endDate" :isSearch="isSearch"></wu-calendar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
formatDate,
|
||||
getDateAfterDays,
|
||||
getDateAfterMonths
|
||||
} from '@/utils/dateTime.js';
|
||||
export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => [null, null]
|
||||
},
|
||||
// 日期选择模式
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'single'
|
||||
},
|
||||
//日期可选范围
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//日期可选范围
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isSearch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dateRange: null
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
modelValue: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
let dateType = Object.prototype.toString.call(newVal);
|
||||
if (this.mode == 'single' && dateType != '[object String]') {
|
||||
return console.error(`类型错误,mode=${this.mode}时,date=String`);
|
||||
} else if (this.mode != 'single' && dateType != '[object Array]') {
|
||||
return console.error(`类型错误,mode=${this.mode}时,date=Array`);
|
||||
}
|
||||
if (this.mode == 'single') {
|
||||
this.dateRange = ''
|
||||
this.dateRange = newVal;
|
||||
}
|
||||
// 根据类型默认选中不同的值
|
||||
if (this.mode == 'multiple') {
|
||||
this.dateRange = []
|
||||
this.dateRange = newVal;
|
||||
} else if (this.mode == 'range') {
|
||||
if (newVal[1] == 'NaN-NaN-NaN') newVal[1] = newVal[0]
|
||||
this.dateRange = []
|
||||
this.dateRange.push(formatDate(new Date(newVal[0])));
|
||||
this.dateRange.push(formatDate(new Date(newVal[1])));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openPicker() {
|
||||
this.$refs.calendar.open();
|
||||
},
|
||||
calendarConfirm(e) {
|
||||
this.dateRange = [];
|
||||
try {
|
||||
this.dateRange.push(formatDate(new Date(e.range.before)));
|
||||
this.dateRange.push(formatDate(new Date(e.range.after)));
|
||||
} catch (error) {
|
||||
return;
|
||||
//TODO handle the exception
|
||||
}
|
||||
this.$emit('update:modelValue', this.dateRange);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
/* 紧凑型输入框 */
|
||||
.compact-input {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
font-size: 16px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.compact-input.active {
|
||||
border-color: #409eff;
|
||||
background-color: #f5f7ff;
|
||||
}
|
||||
</style>
|
83
uni_modules/cxc-szcx-dateRangeSelect/package.json
Normal file
83
uni_modules/cxc-szcx-dateRangeSelect/package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "cxc-szcx-dateRangeSelect",
|
||||
"displayName": "cxc-szcx-dateRangeSelect",
|
||||
"version": "1.0.0",
|
||||
"description": "cxc-szcx-dateRangeSelect",
|
||||
"keywords": [
|
||||
"cxc-szcx-dateRangeSelect"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "",
|
||||
"data": "",
|
||||
"permissions": ""
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "u",
|
||||
"aliyun": "u",
|
||||
"alipay": "u"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "u",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u",
|
||||
"app-uvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
168
uni_modules/cxc-szcx-dateRangeSelect/readme.md
Normal file
168
uni_modules/cxc-szcx-dateRangeSelect/readme.md
Normal file
@ -0,0 +1,168 @@
|
||||
|
||||
### 紧凑型日期时间选择器组件说明
|
||||
|
||||
|
||||
#### 一、组件功能
|
||||
该组件是基于 UniApp 开发的紧凑型日期选择器,支持以下功能:
|
||||
1. **三种选择模式**:
|
||||
- 单选(single)
|
||||
- 范围选择(range)
|
||||
- 多选(multiple)
|
||||
2. **弹出式日历选择**:
|
||||
- 支持月份滑动切换
|
||||
- 显示农历日期
|
||||
- 支持同天范围选择
|
||||
3. **数据双向绑定**:
|
||||
- 通过 `modelValue` 实现父子组件数据同步
|
||||
4. **自定义样式**:
|
||||
- 紧凑型输入框设计
|
||||
- 支持自定义主题颜色
|
||||
- 响应式布局适配
|
||||
5. **支持自定义日期禁用范围**
|
||||
- 限制用户选择的日期范围。只能选择在 startDate 和 endDate 之间的日期,超出该范围的日期将被禁用,无法选择。
|
||||
- startDate:设置可选日期的起始日期,用户不能选择早于该日期的日期。
|
||||
- endDate:设置可选日期的结束日期,用户不能选择晚于该日期的日期。
|
||||
|
||||
|
||||
#### 二、组件Props
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|--------------|------------|----------|-------------------------------- |
|
||||
| `modelValue` | Array/Date | `[null]` | 双向绑定的值(根据模式变化) |
|
||||
| `mode` | String | `single` | 选择模式(single/range/multiple |
|
||||
| `startDate` | String | ` ` | 设置可选日期的起始日期 |
|
||||
| `endDate` | String | ` ` | 设置可选日期的结束日期 |
|
||||
| `isSearch` | Boolean | `true` | 设置快速选择日期样式 |
|
||||
|
||||
|
||||
#### 三、组件数据
|
||||
|
||||
| 名称 | 类型 | 说明 |
|
||||
|------------|--------|--------------------------|
|
||||
| `dateRange` | Array | 当前选中的日期范围(内部状态) |
|
||||
|
||||
|
||||
#### 四、组件方法
|
||||
|
||||
| 方法名 | 参数 | 说明 |
|
||||
|----------------|------------|--------------------------|
|
||||
| `openPicker` | 无 | 打开日历选择器 |
|
||||
| `calendarConfirm` | `e` | 日历确认回调(处理选中数据) |
|
||||
|
||||
|
||||
#### 五、事件说明
|
||||
|
||||
| 事件名 | 说明 | 返回值 |
|
||||
|--------------|--------------------------|----------------------|
|
||||
| `update:modelValue` | 数据更新时触发 | 当前选中的日期数组 |
|
||||
|
||||
|
||||
#### 六、样式说明
|
||||
```vue
|
||||
<style scoped>
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.compact-input {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
font-size: 16px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.compact-input.active {
|
||||
border-color: #409eff;
|
||||
background-color: #f5f7ff;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**关键样式点**:
|
||||
1. 输入框宽度固定为 120px
|
||||
2. 紧凑型设计(height: 20px)
|
||||
3. 活动状态样式增强
|
||||
4. 水平排列布局
|
||||
|
||||
|
||||
#### 七、使用示例
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<!-- 单选模式 -->
|
||||
<compact-datetime-picker
|
||||
v-model="singleDate"
|
||||
mode="single"
|
||||
/>
|
||||
|
||||
<!-- 范围选择模式 -->
|
||||
<compact-datetime-picker
|
||||
v-model="rangeDate"
|
||||
mode="range"
|
||||
/>
|
||||
|
||||
<!-- 多选模式 -->
|
||||
<compact-datetime-picker
|
||||
v-model="multipleDate"
|
||||
mode="multiple"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
singleDate: null,
|
||||
rangeDate: [null, null],
|
||||
multipleDate: []
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
#### 八、注意事项
|
||||
1. **日期格式要求**:
|
||||
- 单选模式:`YYYY-MM-DD` 字符串格式
|
||||
- 范围模式:`[startDate, endDate]` 数组格式
|
||||
- 多选模式:`[date1, date2, ...]` 数组格式
|
||||
2. **依赖组件**:
|
||||
- 需安装 `wu-calendar` 组件(第三方库)
|
||||
3. **异常处理**:
|
||||
```javascript
|
||||
calendarConfirm(e) {
|
||||
this.dateRange = [];
|
||||
try {
|
||||
this.dateRange.push(formatDate(new Date(e.range.before)));
|
||||
this.dateRange.push(formatDate(new Date(e.range.after)));
|
||||
} catch (error) {
|
||||
return; // 异常处理
|
||||
}
|
||||
this.$emit('update:modelValue', this.dateRange);
|
||||
}
|
||||
```
|
||||
4. **性能优化**:
|
||||
- 建议使用 `:range-end-repick="true"` 开启范围重新选择
|
||||
- 通过 `:item-height="45"` 控制日历行高
|
||||
|
||||
|
||||
#### 九、扩展功能建议
|
||||
1. 添加时间选择功能
|
||||
2. 增加国际化支持
|
||||
3. 添加动画过渡效果
|
||||
4. 支持预设常用日期范围
|
||||
|
||||
如果需要进一步定制化,可以修改以下部分:
|
||||
1. 日历组件配置(`wu-calendar` 参数)
|
||||
2. 日期格式化函数(`formatDate`)
|
||||
3. 输入框样式和交互逻辑
|
||||
4. 异常处理机制
|
0
uni_modules/cxc-szcx-dictSelect/changelog.md
Normal file
0
uni_modules/cxc-szcx-dictSelect/changelog.md
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-data-checkbox v-model="selectedValuesArray" :localdata="dictItems" :multiple="true" data-key="value"
|
||||
data-value="label"></uni-data-checkbox>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
watch
|
||||
} from 'vue';
|
||||
import {
|
||||
getDictItemsApi
|
||||
} from '@/api/api.js';
|
||||
|
||||
// 定义 props 和 emits
|
||||
const props = defineProps({
|
||||
dictCode: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
// 定义数据
|
||||
const dictItems = ref([]);
|
||||
const selectedValuesArray = ref(props.modelValue ? props.modelValue.split(',') : []);
|
||||
|
||||
// 加载字典数据
|
||||
const loadDictItems = async () => {
|
||||
try {
|
||||
const response = await getDictItemsApi(props.dictCode);
|
||||
dictItems.value = response.result; // 假设响应数据的格式为 { data: [...] }
|
||||
} catch (error) {
|
||||
console.error('加载字典数据失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听选中值的变化并通知父组件
|
||||
watch(selectedValuesArray, (newValue) => {
|
||||
console.log('selectedValuesArray 变化:', newValue);
|
||||
const selectedValuesString = newValue.join(',');
|
||||
emits('update:modelValue', selectedValuesString);
|
||||
emits('change', selectedValuesString);
|
||||
}, {
|
||||
deep: true
|
||||
});
|
||||
|
||||
// 监听 props.modelValue 的变化
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
console.log('props.modelValue 变化:', newValue);
|
||||
selectedValuesArray.value = newValue ? newValue.split(',') : [];
|
||||
}, {
|
||||
immediate: true
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
loadDictItems();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 可以添加组件的样式 */
|
||||
</style>
|
83
uni_modules/cxc-szcx-dictSelect/package.json
Normal file
83
uni_modules/cxc-szcx-dictSelect/package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "cxc-szcx-dictSelect",
|
||||
"displayName": "cxc-szcx-dictSelect",
|
||||
"version": "1.0.0",
|
||||
"description": "cxc-szcx-dictSelect",
|
||||
"keywords": [
|
||||
"cxc-szcx-dictSelect"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "",
|
||||
"data": "",
|
||||
"permissions": ""
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "u",
|
||||
"aliyun": "u",
|
||||
"alipay": "u"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "u",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u",
|
||||
"app-uvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
uni_modules/cxc-szcx-dictSelect/readme.md
Normal file
90
uni_modules/cxc-szcx-dictSelect/readme.md
Normal file
@ -0,0 +1,90 @@
|
||||
# cxc-szcx-dictSelect
|
||||
### 组件说明:`uni-data-checkbox` 多选字典项选择组件
|
||||
|
||||
#### 一、组件概述
|
||||
该组件基于 Vue 3 和 `uni-data-checkbox` 实现了一个多选的字典项选择器。它通过传入字典编码(`dictCode`)从后端接口获取字典项数据,并将其展示为多选框列表。组件支持双向数据绑定,可将选中的值同步给父组件,同时在选中值发生变化时触发 `change` 事件。
|
||||
|
||||
#### 二、组件使用的技术栈
|
||||
- **框架**:Vue 3(使用组合式 API)
|
||||
- **UI 组件**:`uni-data-checkbox`(用于展示多选框列表)
|
||||
- **请求库**:假设使用了自定义的 `getDictItemsApi` 函数进行后端数据请求
|
||||
|
||||
#### 三、组件输入(Props)
|
||||
|
||||
| 属性名 | 类型 | 是否必填 | 默认值 | 说明 |
|
||||
| ---- | ---- | ---- | ---- | ---- |
|
||||
| `dictCode` | String | 是 | 无 | 用于从后端获取字典项数据的字典编码 |
|
||||
| `modelValue` | String | 否 | '' | 双向绑定的选中值,多个值以逗号分隔 |
|
||||
|
||||
#### 四、组件输出(Emits)
|
||||
|
||||
| 事件名 | 说明 | 参数 |
|
||||
| ---- | ---- | ---- |
|
||||
| `update:modelValue` | 当选中值发生变化时,用于更新父组件的 `modelValue` | 选中值的字符串,多个值以逗号分隔 |
|
||||
| `change` | 当选中值发生变化时触发 | 选中值的字符串,多个值以逗号分隔 |
|
||||
|
||||
#### 五、组件内部数据
|
||||
|
||||
| 变量名 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- |
|
||||
| `dictItems` | Ref<Array> | 存储从后端获取的字典项数据 |
|
||||
| `selectedValuesArray` | Ref<Array> | 存储当前选中的值,以数组形式存储 |
|
||||
|
||||
#### 六、组件方法
|
||||
|
||||
##### 1. `loadDictItems`
|
||||
- **功能**:异步从后端接口获取字典项数据,并将其赋值给 `dictItems`。
|
||||
- **实现逻辑**:
|
||||
- 调用 `getDictItemsApi` 函数,传入 `props.dictCode` 进行数据请求。
|
||||
- 若请求成功,将响应数据的 `result` 字段赋值给 `dictItems.value`。
|
||||
- 若请求失败,在控制台输出错误信息。
|
||||
|
||||
##### 2. 监听 `selectedValuesArray` 的变化
|
||||
- **功能**:当 `selectedValuesArray` 发生变化时,将选中的值转换为字符串,并触发 `update:modelValue` 和 `change` 事件通知父组件。
|
||||
- **实现逻辑**:
|
||||
- 使用 `watch` 函数监听 `selectedValuesArray` 的变化。
|
||||
- 当变化发生时,将新的选中值数组使用 `join(',')` 方法转换为字符串。
|
||||
- 触发 `update:modelValue` 和 `change` 事件,将转换后的字符串作为参数传递。
|
||||
|
||||
##### 3. 监听 `props.modelValue` 的变化
|
||||
- **功能**:当父组件传递的 `modelValue` 发生变化时,更新 `selectedValuesArray`。
|
||||
- **实现逻辑**:
|
||||
- 使用 `watch` 函数监听 `props.modelValue` 的变化。
|
||||
- 当变化发生时,将新的 `modelValue` 使用 `split(',')` 方法转换为数组,并赋值给 `selectedValuesArray.value`。
|
||||
- `immediate: true` 表示在组件初始化时就会执行一次监听回调,确保初始值能正确同步。
|
||||
|
||||
#### 七、组件生命周期钩子
|
||||
|
||||
##### `onMounted`
|
||||
- **功能**:在组件挂载后调用 `loadDictItems` 函数,从后端获取字典项数据。
|
||||
|
||||
#### 八、使用示例
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<MyDictCheckbox
|
||||
:dictCode="myDictCode"
|
||||
v-model="selectedValues"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<p>当前选中的值: {{ selectedValues }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import MyDictCheckbox from './MyDictCheckbox.vue';
|
||||
|
||||
const myDictCode = 'exampleDictCode';
|
||||
const selectedValues = ref('');
|
||||
|
||||
const handleChange = (newValue) => {
|
||||
console.log('选中值发生变化:', newValue);
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 九、注意事项
|
||||
- 确保 `getDictItemsApi` 函数能正确获取后端数据,且响应数据的格式符合 `{ result: [...] }`。
|
||||
- 若 `modelValue` 初始值为空字符串,`selectedValuesArray` 会初始化为空数组。
|
||||
- 由于使用了 `watch` 的 `deep: true` 选项,在 `selectedValuesArray` 内部元素发生变化时也会触发监听回调,可能会影响性能,需注意。
|
0
uni_modules/cxc-szcx-lineChart/changelog.md
Normal file
0
uni_modules/cxc-szcx-lineChart/changelog.md
Normal file
@ -0,0 +1,274 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- ECharts图表 -->
|
||||
<view class="chart-container">
|
||||
<l-echart ref="chart" @finished="initChart" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import { formatDate, getDateAfterDays, getDateAfterMonths } from '@/utils/dateTime.js';
|
||||
const props = defineProps({
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true
|
||||
},
|
||||
xField: {
|
||||
type: String,
|
||||
default: 'rqDate'
|
||||
},
|
||||
yField: {
|
||||
type: String,
|
||||
default: 'rq'
|
||||
},
|
||||
legendField: {
|
||||
type: String,
|
||||
default: 'unit'
|
||||
},
|
||||
referenceValue: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
const chart = ref(null);
|
||||
const chartOption = ref({});
|
||||
const chartTitle = ref('');
|
||||
|
||||
//、数据处理
|
||||
const processSeriesData = () => {
|
||||
const legendItems = [...new Set(props.dataList.map((item) => item[props.legendField]?.trim() || '未命名'))];
|
||||
|
||||
return legendItems.map((legend) => {
|
||||
const items = props.dataList
|
||||
.filter((item) => item[props.legendField] === legend)
|
||||
.sort((a, b) => new Date(a[props.xField]) - new Date(b[props.xField]))
|
||||
.map((item) => ({
|
||||
name: item[props.xField],
|
||||
value: [
|
||||
formatDate(item[props.xField]), // X轴时间戳
|
||||
parseFloat(item[props.yField]) || 0 // Y轴数值
|
||||
]
|
||||
}));
|
||||
|
||||
return {
|
||||
name: legend,
|
||||
type: 'line',
|
||||
showSymbol: true,
|
||||
smooth: true,
|
||||
data: items
|
||||
};
|
||||
});
|
||||
};
|
||||
// 监听数据变化
|
||||
watch(
|
||||
() => props.dataList,
|
||||
() => {
|
||||
chartTitle.value = '历史趋势';
|
||||
updateChart();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 生命周期管理
|
||||
onMounted(() => {});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chart.value) {
|
||||
chart.value.dispose();
|
||||
chart.value = null;
|
||||
}
|
||||
});
|
||||
// 更新图表 formatDate
|
||||
const updateChart = () => {
|
||||
if (!chart.value) return;
|
||||
chartOption.value = generateOptions();
|
||||
chart.value.setOption(chartOption.value, true);
|
||||
};
|
||||
// 生成图表配置
|
||||
const generateOptions = () => ({
|
||||
title: {
|
||||
text: chartTitle.value,
|
||||
padding: [0, 0, 0, 30]
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: '#eee',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#333',
|
||||
fontSize: 14
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
lineStyle: {
|
||||
color: '#FF6B6B',
|
||||
width: 1,
|
||||
type: 'dashed'
|
||||
}
|
||||
},
|
||||
confine: true // 将 tooltip 限制在图表区域内
|
||||
},
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.8)',
|
||||
textStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
},
|
||||
xAxis: {
|
||||
type: 'time',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#ddd'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
formatter: '{MM}-{dd}',
|
||||
rotate: 30
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#f5f5f5'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#ddd'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f5f5f5'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
formatter: (value) => `${value.toFixed(2)}`
|
||||
}
|
||||
},
|
||||
series: [
|
||||
...processSeriesData().map((series) => ({
|
||||
...series,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 6,
|
||||
shadowOffsetY: 3
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#00007f', // 建议改为动态颜色
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
}
|
||||
})),
|
||||
{
|
||||
type: 'line',
|
||||
markLine: {
|
||||
silent: true,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#FF4757',
|
||||
width: 2
|
||||
},
|
||||
data: [{ yAxis: props.referenceValue }],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'end',
|
||||
formatter: `参考值: ${props.referenceValue}`,
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
data: [] // 空数据系列仅用于显示参考线
|
||||
}
|
||||
],
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
bottom: 5,
|
||||
textStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
},
|
||||
pageIconColor: '#FF6B6B',
|
||||
pageTextStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 30,
|
||||
bottom: 40,
|
||||
left: 20,
|
||||
containLabel: true
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
minValueSpan: 3600 * 24 * 1000 * 7 // 最小缩放范围7天
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
setTimeout(async () => {
|
||||
if (!chart.value) return;
|
||||
const myChart = await chart.value.init(echarts);
|
||||
myChart.setOption(chartOption.value);
|
||||
}, 300);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 容器样式 */
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
min-height: 200px;
|
||||
padding: 20rpx;
|
||||
background: linear-gradient(145deg, #f8f9fa 0%, #ffffff 100%);
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 图表加载占位 */
|
||||
.chart-container::before {
|
||||
/* content: '数据加载中...'; */
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 图表主体样式 */
|
||||
.chart-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
/* 移动端优化 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 30vh;
|
||||
min-height: 200px;
|
||||
padding: 10rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
83
uni_modules/cxc-szcx-lineChart/package.json
Normal file
83
uni_modules/cxc-szcx-lineChart/package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "cxc-szcx-lineChart",
|
||||
"displayName": "cxc-szcx-lineChart",
|
||||
"version": "1.0.0",
|
||||
"description": "cxc-szcx-lineChart",
|
||||
"keywords": [
|
||||
"cxc-szcx-lineChart"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "",
|
||||
"data": "",
|
||||
"permissions": ""
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "u",
|
||||
"aliyun": "u",
|
||||
"alipay": "u"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "u",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u",
|
||||
"app-uvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
179
uni_modules/cxc-szcx-lineChart/readme.md
Normal file
179
uni_modules/cxc-szcx-lineChart/readme.md
Normal file
@ -0,0 +1,179 @@
|
||||
# cxc-szcx-lineChart
|
||||
# # `line-chart.vue` 组件说明书
|
||||
|
||||
## 一、组件概述
|
||||
`line-chart.vue` 是一个基于 ECharts 实现的折线图组件,用于在 UniApp 项目中展示数据的折线图。该组件接收一系列数据和配置参数,支持动态更新数据,并展示参考线。
|
||||
|
||||
## 二、组件依赖
|
||||
- **Vue 3**:使用 Vue 3 的组合式 API 进行开发。
|
||||
- **ECharts**:用于绘制折线图。
|
||||
- **`lime-echart`**:UniApp 插件,提供 ECharts 的渲染支持。
|
||||
|
||||
## 三、组件使用方法
|
||||
|
||||
### 1. 引入组件
|
||||
在需要使用该组件的页面中引入 `line-chart.vue` 组件。
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<line-chart
|
||||
:dataList="dataList"
|
||||
:xField="xField"
|
||||
:yField="yField"
|
||||
:legendField="legendField"
|
||||
:referenceValue="referenceValue"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import LineChart from '@/components/line-chart.vue';
|
||||
|
||||
const dataList = [
|
||||
{ date: '2023-01-01', value: 10, category: 'A' },
|
||||
// 更多数据...
|
||||
];
|
||||
const xField = 'date';
|
||||
const yField = 'value';
|
||||
const legendField = 'category';
|
||||
const referenceValue = 15;
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 组件属性
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 描述 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| `dataList` | `Object` | `[]` | 包含图表数据的数组,每个元素是一个对象,包含 `xField`、`yField` 和 `legendField` 对应的数据。 |
|
||||
| `xField` | `String` | `''` | 数据中用于表示 x 轴的字段名。 |
|
||||
| `yField` | `String` | `''` | 数据中用于表示 y 轴的字段名。 |
|
||||
| `legendField` | `String` | `''` | 数据中用于表示图例的字段名。 |
|
||||
| `referenceValue` | `Number` | `10` | 图表中参考线的数值。 |
|
||||
|
||||
## 四、组件内部实现
|
||||
|
||||
### 1. 模板部分
|
||||
```vue
|
||||
<template>
|
||||
<view class="chart-container">
|
||||
<l-echart ref="chart" @init="initChart"></l-echart>
|
||||
</view>
|
||||
</template>
|
||||
```
|
||||
- 使用 `l-echart` 组件渲染图表,通过 `ref` 绑定到 `chart`,并在初始化完成时调用 `initChart` 方法。
|
||||
|
||||
### 2. 脚本部分
|
||||
|
||||
#### 2.1 引入必要的模块
|
||||
```javascript
|
||||
import { ref, watch } from 'vue';
|
||||
```
|
||||
引入 Vue 3 的 `ref` 和 `watch` 函数。
|
||||
|
||||
#### 2.2 定义组件属性
|
||||
```javascript
|
||||
const props = defineProps({
|
||||
dataList: {
|
||||
type: Object,
|
||||
default: () => []
|
||||
},
|
||||
// 其他属性...
|
||||
});
|
||||
```
|
||||
定义组件接收的属性。
|
||||
|
||||
#### 2.3 初始化图表
|
||||
```javascript
|
||||
const chart = ref(null);
|
||||
let echarts = null;
|
||||
|
||||
const initChart = async (canvas) => {
|
||||
await initEcharts(canvas);
|
||||
updateChart();
|
||||
};
|
||||
|
||||
const initEcharts = async (canvas) => {
|
||||
echarts = await import('echarts');
|
||||
const { init } = await import('@/uni_modules/lime-echart/static/echarts.min');
|
||||
echarts = init(canvas, echarts);
|
||||
};
|
||||
```
|
||||
- `chart` 用于引用 `l-echart` 组件。
|
||||
- `initChart` 方法在图表初始化时调用,先初始化 ECharts 实例,再更新图表。
|
||||
- `initEcharts` 方法异步加载 ECharts 并初始化实例。
|
||||
|
||||
#### 2.4 处理数据
|
||||
```javascript
|
||||
const processData = () => {
|
||||
const legendData = [...new Set(props.dataList.map((item) => item[props.legendField]))];
|
||||
|
||||
return legendData.map((legendItem) => {
|
||||
const seriesData = props.dataList
|
||||
.filter((item) => item[props.legendField] === legendItem)
|
||||
.sort((a, b) => new Date(a[props.xField]) - new Date(b[props.xField]))
|
||||
.map((item) => ({
|
||||
name: item[props.xField],
|
||||
value: [item[props.xField], item[props.yField]]
|
||||
}));
|
||||
|
||||
return {
|
||||
name: legendItem,
|
||||
type: 'line',
|
||||
showSymbol: true,
|
||||
data: seriesData
|
||||
};
|
||||
});
|
||||
};
|
||||
```
|
||||
处理传入的数据,根据 `legendField` 分组,对每组数据按 `xField` 排序,并转换为 ECharts 所需的格式。
|
||||
|
||||
#### 2.5 获取图表配置
|
||||
```javascript
|
||||
const getOption = () => ({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params) => {
|
||||
return `${params[0].axisValue}<br/>` + params.map((item) => `${item.marker} ${item.seriesName}: ${item.value[1]}`).join('<br/>');
|
||||
}
|
||||
},
|
||||
// 其他配置...
|
||||
});
|
||||
```
|
||||
返回 ECharts 的配置对象,包括 tooltip、x 轴、y 轴、系列数据、图例和网格等配置。
|
||||
|
||||
#### 2.6 更新图表
|
||||
```javascript
|
||||
const updateChart = () => {
|
||||
if (!chart.value) return;
|
||||
|
||||
const option = getOption();
|
||||
chart.value.setOption(option);
|
||||
};
|
||||
```
|
||||
如果 `chart` 实例存在,获取最新的图表配置并更新图表。
|
||||
|
||||
#### 2.7 监听数据变化
|
||||
```javascript
|
||||
watch(
|
||||
() => props.dataList,
|
||||
() => {
|
||||
updateChart();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
```
|
||||
当 `props.dataList` 发生变化时,调用 `updateChart` 方法更新图表。
|
||||
|
||||
### 3. 样式部分
|
||||
```css
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
}
|
||||
```
|
||||
设置图表容器的宽度为 100%,高度为 30vh。
|
||||
|
||||
## 五、注意事项
|
||||
- 确保项目中已经正确安装并配置了 `lime-echart` 插件。
|
||||
- 传入的 `dataList` 数据格式要符合要求,包含 `xField`、`yField` 和 `legendField` 对应的数据。
|
||||
- 由于使用了异步加载 ECharts,可能会有一定的延迟,需要确保在合适的时机初始化图表。
|
33
uni_modules/lime-drag/changelog.md
Normal file
33
uni_modules/lime-drag/changelog.md
Normal file
@ -0,0 +1,33 @@
|
||||
## 0.1.3(2023-08-19)
|
||||
- fix: 修复使用remove导致样式错乱
|
||||
## 0.1.2(2023-08-09)
|
||||
- fix: 修复nvue没有获取节点的问题
|
||||
- fix: 修复因延时导致卡在中途
|
||||
- fix: 修复change事件有时失效的问题
|
||||
## 0.1.1(2023-07-03)
|
||||
- chore: 更新文档
|
||||
## 0.1.0(2023-07-03)
|
||||
- fix: 外面的事件冒泡导致点击调动内部移动方法错乱
|
||||
## 0.0.9(2023-05-30)
|
||||
- fix: 修复因手机事件为`onLongpress`导致,在手机上无法长按
|
||||
- fix: 无法因css导致滚动
|
||||
## 0.0.8(2023-04-23)
|
||||
- feat: 更新文档
|
||||
## 0.0.7(2023-04-23)
|
||||
- feat: 由于删除是一个危险的动作,故把方法暴露出来,而不在内部处理。如果之前有使用删除的,需要注意
|
||||
- feat: 原来的`add`变更为`push`,增加`unshift`
|
||||
## 0.0.6(2023-04-12)
|
||||
- fix: 修复`handle`不生效问题
|
||||
- feat: 增加 `to`方法
|
||||
## 0.0.5(2023-04-11)
|
||||
- chore: `grid` 插槽增加 `nindex`、`oindex`
|
||||
## 0.0.4(2023-04-04)
|
||||
- chore: 去掉 script-setup 语法糖
|
||||
- chore: 文档增加 vue2 使用方法
|
||||
## 0.0.3(2023-03-30)
|
||||
- feat: 重要说明 更新 list 只会再次初始化
|
||||
- feat: 更新文档
|
||||
## 0.0.2(2023-03-29)
|
||||
- 修改文档
|
||||
## 0.0.1(2023-03-29)
|
||||
- 初次提交
|
93
uni_modules/lime-drag/components/l-drag/index.scss
Normal file
93
uni_modules/lime-drag/components/l-drag/index.scss
Normal file
@ -0,0 +1,93 @@
|
||||
$drag-handle-size: var(--l-drag-handle-size, 50rpx);
|
||||
$drag-delete-size: var(--l-drag-delete-size, 32rpx);
|
||||
.l-drag {
|
||||
// min-height: 100rpx;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
margin: 24rpx 30rpx 0 30rpx;
|
||||
// padding: 30rpx 0;
|
||||
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
// flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
// width: 100%;
|
||||
/* #endif */
|
||||
}
|
||||
.l-drag__inner {
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
min-height: 100rpx;
|
||||
}
|
||||
.l-drag__view {
|
||||
// touch-action: none;
|
||||
// user-select: none;
|
||||
// -webkit-user-select: auto;
|
||||
z-index: 2;
|
||||
transition: opacity 300ms ease;
|
||||
.mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: transparent;
|
||||
z-index: 9;
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
> view {
|
||||
&:last-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
|
||||
}
|
||||
.l-drag-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
.l-drag__ghost {
|
||||
/* #ifndef APP-NVUE */
|
||||
> view {
|
||||
&:last-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
.l-is-active {
|
||||
z-index: 3;
|
||||
}
|
||||
.l-is-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
.l-drag__delete {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: $drag-delete-size;
|
||||
height: $drag-delete-size;
|
||||
}
|
||||
.l-drag__handle {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: $drag-handle-size;
|
||||
height: $drag-handle-size;
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
.l-drag__delete::before,.l-drag__handle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
/* #endif */
|
532
uni_modules/lime-drag/components/l-drag/l-drag.vue
Normal file
532
uni_modules/lime-drag/components/l-drag/l-drag.vue
Normal file
@ -0,0 +1,532 @@
|
||||
<template>
|
||||
<view class="l-drag l-class" :style="[areaStyles]" ref="dragRef" @touchstart="setDisabled">
|
||||
<movable-area class="l-drag__inner" v-if="isReset" :style="[innerStyles]">
|
||||
<slot></slot>
|
||||
<movable-view class="l-drag__ghost" v-if="isDrag && props.ghost" :animation="true" :style="[viewStyles]" direction="all" :x="ghostEl.x" :y="ghostEl.y" key="l-drag-clone">
|
||||
<slot name="ghost"></slot>
|
||||
</movable-view>
|
||||
<movable-view v-if="props.before" class="l-drag__before" disabled :animation="false" :style="[viewStyles]" :x="beforeEl.x" :y="beforeEl.y">
|
||||
<slot name="before"></slot>
|
||||
</movable-view>
|
||||
<movable-view
|
||||
v-for="(item, oindex) in cloneList" :key="item.id"
|
||||
direction="all"
|
||||
:data-oindex="oindex"
|
||||
:style="[viewStyles]"
|
||||
class="l-drag__view"
|
||||
:class="[{'l-is-active': oindex == active, 'l-is-hidden': !item.show}, item.class]"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:friction="friction"
|
||||
:damping="damping"
|
||||
:animation="animation"
|
||||
:disabled="isDisabled || props.disabled"
|
||||
@touchstart="touchStart"
|
||||
@change="touchMove"
|
||||
@touchend="touchEnd"
|
||||
@touchcancel="touchEnd"
|
||||
@longpress="setDisabled"
|
||||
>
|
||||
<!-- <view v-if="props.remove" class="l-drag__remove" :style="removeStyle" data-remove="true">
|
||||
<slot name="remove" :oindex="oindex" data-remove="true" />
|
||||
</view> -->
|
||||
<!-- <view v-if="props.handle" class="l-drag__handle" :style="handleStyle" data-handle="true">
|
||||
<slot name="handle" :oindex="oindex" :active="!isDisabled && !isDisabled && oindex == active" />
|
||||
</view> -->
|
||||
<slot name="grid" :oindex="oindex" :index="item.index" :oldindex="item.oldindex" :content="item.content" :active="!isDisabled && !isDisabled && oindex == active" />
|
||||
<view class="mask" v-if="!(isDisabled || props.disabled) && props.longpress"></view>
|
||||
</movable-view>
|
||||
|
||||
|
||||
<movable-view v-if="props.after" class="l-drag__after" disabled :animation="true" direction="all" :style="[viewStyles]" :x="afterEl.x" :y="afterEl.y">
|
||||
<slot name="after"></slot>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { computed, onMounted, ref, getCurrentInstance, watch, nextTick, reactive , triggerRef, onUnmounted, defineComponent} from "./vue";
|
||||
import DragProps from './props';
|
||||
import type {GridRect, Grid, Position} from './type'
|
||||
// #ifdef APP-NVUE
|
||||
const dom = weex.requireModule('dom')
|
||||
// #endif
|
||||
|
||||
export default defineComponent({
|
||||
name: 'l-drag',
|
||||
externalClasses: ['l-class'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
props: DragProps,
|
||||
emits: ['change'],
|
||||
setup(props, {emit, expose}) {
|
||||
const res = wx.getSystemInfoSync();
|
||||
const statusHeight = res.statusBarHeight; //状态栏高度
|
||||
const cusnavbarheight = (statusHeight + 44) + "px";
|
||||
// #ifdef APP-NVUE
|
||||
const dragRef = ref(null)
|
||||
// #endif
|
||||
const app = getCurrentInstance()
|
||||
const isDrag = ref(false)
|
||||
const isInit = ref(false)
|
||||
const isReset = ref(true)
|
||||
const colmunId = ref(-1)
|
||||
/** 选中项原始下标 */
|
||||
const active = ref(-1)
|
||||
const maxIndex = ref(-1)
|
||||
const animation = ref(true)
|
||||
const isDisabled = ref(props.handle || props.longpress ? true: false)
|
||||
|
||||
const dragEl = reactive({
|
||||
content: null,
|
||||
/** 当前视图下标*/
|
||||
index: 0,
|
||||
/** 旧视图下标 */
|
||||
oldindex: -1,
|
||||
/** 上次原始下标 */
|
||||
lastindex: -1
|
||||
})
|
||||
|
||||
const ghostEl = reactive({
|
||||
content: null,
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
const beforeEl = reactive({
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
const afterEl = reactive({
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
|
||||
let gridRects = [] //ref<GridRect[]>([])
|
||||
const areaWidth = ref(0)
|
||||
const cloneList = ref<Grid[]>([])
|
||||
// 删除项时可能会减少行数影响到删除过渡动画,故增加此值在删除时保持高度不变,等动画完成后再归零
|
||||
const leaveRow = ref(0)
|
||||
const extra = computed(() => (props.before ? 1 :0) + (props.after ? 1 : 0))
|
||||
const rows = computed(() => Math.ceil( ((isInit.value ? cloneList.value.length : props.list.length) + extra.value) / props.column ))
|
||||
const gridHeight = computed(() => props.aspectRatio ? girdWidth.value / props.aspectRatio : (/rpx$/.test(`${props.gridHeight}`) ? uni.upx2px(parseInt(`${props.gridHeight}`)) : parseInt(`${props.gridHeight}`)))
|
||||
const girdWidth = computed(() => areaWidth.value / props.column)
|
||||
const viewStyles = computed(() => ({width: girdWidth.value + 'px',height: gridHeight.value + 'px'}))
|
||||
const areaStyles = computed(() => ({height: (rows.value + leaveRow.value ) * gridHeight.value + 'px'}))
|
||||
const innerStyles = computed(() => ({
|
||||
// #ifdef APP-NVUE
|
||||
width: areaWidth.value + 'px',
|
||||
// #endif
|
||||
height: (rows.value + props.extraRow + leaveRow.value) * gridHeight.value + 'px'}))
|
||||
|
||||
const sleep = (cb: Function, time = 1000/60) => setTimeout(cb, time)
|
||||
const createGrid = (content: any, position?:Position|null): Grid => {
|
||||
colmunId.value++
|
||||
maxIndex.value++
|
||||
const index = maxIndex.value
|
||||
const colmun = gridRects[index]
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
if(colmun) {
|
||||
if(props.after) {
|
||||
let nxet = gridRects[index + 1]
|
||||
if(!nxet) {
|
||||
nxet = createGridRect(gridRects.length + (props.before ? 1 : 0))
|
||||
gridRects.push(nxet)
|
||||
}
|
||||
setReset(() => setAfter(nxet))
|
||||
} else {
|
||||
setReset()
|
||||
}
|
||||
x = colmun.x
|
||||
y = colmun.y
|
||||
} else {
|
||||
const nxet = createGridRect(gridRects.length + (props.before ? 1 : 0))
|
||||
gridRects.push(nxet)
|
||||
setReset()
|
||||
x = nxet.x
|
||||
y = nxet.y
|
||||
}
|
||||
if(position) {
|
||||
x = position.x
|
||||
y = position.y
|
||||
}
|
||||
return {id: `l-drag-item-${colmunId.value}`, index, oldindex: index, content, x, y, class: '', show: true}
|
||||
}
|
||||
const setReset = (cb?: any) => {
|
||||
// const newRow = (cloneList.value.length + extra.value) % (props.column)
|
||||
if(isInit.value) {
|
||||
cb&&sleep(cb)
|
||||
}
|
||||
}
|
||||
const setAfter = ({x, y} = {x: 0, y: 0}) => {
|
||||
if(props.after) {
|
||||
afterEl.x = x
|
||||
afterEl.y = y
|
||||
}
|
||||
}
|
||||
const setDisabled = (e: any, flag?: boolean= false) => {
|
||||
// e?.preventDefault()
|
||||
const type = `${e.type}`.toLowerCase()
|
||||
const {handle = props.touchHandle} = e.target.dataset
|
||||
if(props.handle && !handle) {
|
||||
isDisabled.value = true
|
||||
} else if(props.handle && handle && !props.longpress) {
|
||||
isDisabled.value = flag
|
||||
} else if(props.handle && handle && props.longpress && type.includes('longpress')) {
|
||||
isDisabled.value = false
|
||||
} else if(props.longpress && type.includes('longpress') && !props.handle) {
|
||||
isDisabled.value = false
|
||||
}
|
||||
if(type.includes('touchend') && props.longpress) {
|
||||
isDisabled.value = true
|
||||
}
|
||||
}
|
||||
const createGridRect = (i: number, last?: GridRect): GridRect => {
|
||||
let { row } = last || gridRects[gridRects.length - 1] || { row: 0 }
|
||||
const col = i % (props.column)
|
||||
const grid = (row: number, x: number, y: number):GridRect => {
|
||||
return {row, x, y, x1: x + girdWidth.value, y1: y + gridHeight.value}
|
||||
}
|
||||
if(col == 0 && i != 0) {row++}
|
||||
return grid(row, col * girdWidth.value, row * gridHeight.value)
|
||||
}
|
||||
const createGridRects = () => {
|
||||
let rects: GridRect[] = []
|
||||
const length = rows.value * props.column + extra.value
|
||||
gridRects = []
|
||||
for (var i = 0; i < length; i++) {
|
||||
const item = createGridRect(i, rects[rects.length - 1])
|
||||
rects.push(item)
|
||||
}
|
||||
if(props.before) {
|
||||
const {x, y} = rects.shift()
|
||||
beforeEl.x = x
|
||||
beforeEl.y = y
|
||||
}
|
||||
setAfter(rects[props.list.length])
|
||||
gridRects = rects as GridRect[]
|
||||
}
|
||||
const updateList = (v: any[]) => {
|
||||
cloneList.value = v.map((content) => createGrid(content))
|
||||
}
|
||||
|
||||
const touchStart = (e: any) => {
|
||||
if(e.target.dataset.remove) return
|
||||
// 选中项原始下标
|
||||
const {oindex} = e.currentTarget?.dataset || e.target?.dataset || {}
|
||||
if(typeof oindex !== 'number') return
|
||||
const target = cloneList.value[oindex]
|
||||
isDrag.value = true
|
||||
// 选中项原始下标
|
||||
active.value = oindex
|
||||
// 选中项的当前下标
|
||||
dragEl.index = dragEl.oldindex = target.index
|
||||
ghostEl.x = target.x||0
|
||||
ghostEl.y = target.y||0
|
||||
dragEl.content = ghostEl.content = target.content
|
||||
}
|
||||
|
||||
const touchEnd = (e: any) => {
|
||||
setTimeout(() => {
|
||||
if(e.target.dataset.remove || active.value==-1) return
|
||||
setDisabled(e, true)
|
||||
isDrag.value = false
|
||||
const isEmit = dragEl.index !== dragEl.oldindex && dragEl.oldindex > -1 // active.value !== dragEl.index
|
||||
dragEl.lastindex = active.value
|
||||
dragEl.oldindex = active.value = -1
|
||||
const last = cloneList.value[dragEl.lastindex]
|
||||
const position = gridRects[dragEl.index]
|
||||
nextTick(() => {
|
||||
last.x = position.x + 0.001
|
||||
last.y = position.y + 0.001
|
||||
sleep(() => {
|
||||
last.x = position.x
|
||||
last.y = position.y
|
||||
isEmit && emitting()
|
||||
})
|
||||
})
|
||||
},80)
|
||||
|
||||
}
|
||||
const emitting = () => {
|
||||
const clone = [...cloneList.value].sort((a, b) => a.index - b.index)//.map(item => ref(item.content))
|
||||
emit('change', clone)
|
||||
}
|
||||
|
||||
const touchMove = (e: any) => {
|
||||
if(!isDrag.value) return
|
||||
// #ifndef APP-NVUE
|
||||
let {oindex} = e.currentTarget.dataset
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
oindex = e.currentTarget.dataset['-oindex']
|
||||
// #endif
|
||||
if(oindex != active.value) return
|
||||
const {x, y} = e.detail
|
||||
const centerX = x + girdWidth.value / 2
|
||||
const centerY = y + gridHeight.value / 2
|
||||
for (let i = 0; i < cloneList.value.length; i++) {
|
||||
const item = gridRects[i]
|
||||
if(centerX > item.x && centerX < item.x1 && centerY > item.y && centerY < item.y1) {
|
||||
ghostEl.x = item.x
|
||||
ghostEl.y = item.y
|
||||
if(dragEl.index != i) {
|
||||
_move(active.value, i)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const getDragEl = (oindex: number) => {
|
||||
if(isDrag.value) {return dragEl}
|
||||
return cloneList.value[oindex]
|
||||
}
|
||||
|
||||
/**
|
||||
* 把原始数据中排序为index的项 移动到 toIndex
|
||||
* @param oindex 原始数据的下标
|
||||
* @param toIndex 视图中的下标
|
||||
* @param position 指定坐标
|
||||
*/
|
||||
const _move = (oindex: number, toIndex: number, position?: Position|null, emit: boolean = true) => {
|
||||
const length = cloneList.value.length - 1
|
||||
if(toIndex > length || toIndex < 0) return
|
||||
// 获取oIdnex在视图中的项目
|
||||
const dragEl = getDragEl(oindex)
|
||||
let speed = 0
|
||||
let start = dragEl.index
|
||||
// 比较开始index和终点index,设置方向
|
||||
if(start < toIndex) {speed = 1}
|
||||
if(start > toIndex) {speed = -1}
|
||||
if(!speed) return
|
||||
// 距离
|
||||
let distance = start - toIndex
|
||||
// 找到区间所有的项
|
||||
while(distance) {
|
||||
distance += speed
|
||||
// 目标
|
||||
const target = isDrag.value ? (dragEl.index += speed) : (start += speed)
|
||||
let targetOindex = cloneList.value.findIndex(item => item.index == target && item.content != dragEl.content)
|
||||
if (targetOindex == oindex) return
|
||||
if (targetOindex < 0) {targetOindex = cloneList.value.length - 1}
|
||||
let targetEl = cloneList.value[targetOindex]
|
||||
if(!targetEl) return;
|
||||
// 上一个index
|
||||
const lastIndex = target - speed
|
||||
const activeEl = cloneList.value[oindex]
|
||||
const rect = gridRects[lastIndex]
|
||||
targetEl.x = rect.x
|
||||
targetEl.y = rect.y
|
||||
targetEl.oldindex = targetEl.index
|
||||
targetEl.index = lastIndex
|
||||
activeEl.oldindex = activeEl.index //oIndex
|
||||
activeEl.index = toIndex
|
||||
// 到达终点,如果是拖拽则不处理
|
||||
if(!distance && !isDrag.value) {
|
||||
const rect = gridRects[toIndex]
|
||||
const {x, y} = position||rect
|
||||
activeEl.x = dragEl.x = x
|
||||
activeEl.y = dragEl.y = y
|
||||
// triggerRef(cloneList)
|
||||
if(emit) {
|
||||
emitting()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 为区分是主动调用还是内部方法
|
||||
*/
|
||||
const move = (oindex: number, toIndex: number) => {
|
||||
active.value = -1
|
||||
isDrag.value = false
|
||||
_move(oindex, toIndex)
|
||||
}
|
||||
// 临时处理 待有空再完善
|
||||
const REMOVE_TIME = 400
|
||||
let removeTimer = null
|
||||
const remove = (oindex: number) => {
|
||||
active.value = -1
|
||||
isDrag.value = false
|
||||
|
||||
clearTimeout(removeTimer)
|
||||
const item = cloneList.value[oindex]
|
||||
if(props.disabled || !item) return
|
||||
item.show = false
|
||||
const after = cloneList.value.length - 1
|
||||
_move(oindex, after, item, false)
|
||||
setAfter(gridRects[after])
|
||||
maxIndex.value--
|
||||
const _remove = (_index = oindex) => {
|
||||
// 小程序 删除会闪一下 所以先关闭动画再开启
|
||||
// animation.value = false
|
||||
const row = Math.ceil((cloneList.value.length - 1 + extra.value) / props.column)
|
||||
if( row < rows.value) {
|
||||
leaveRow.value = (rows.value - row)
|
||||
}
|
||||
cloneList.value.splice(_index, 1)[0]
|
||||
emitting()
|
||||
removeTimer = setTimeout(() => {
|
||||
leaveRow.value = 0
|
||||
}, REMOVE_TIME)
|
||||
}
|
||||
_remove()
|
||||
}
|
||||
const push = (...args: any) => {
|
||||
if(props.disabled) return
|
||||
if(Array.isArray(args)) {
|
||||
Promise.all(args.map(async item => await add(item, true))).then(emitting)
|
||||
}
|
||||
}
|
||||
const add = (content: any, after: boolean) => {
|
||||
return new Promise((resolve) => {
|
||||
const item = createGrid(content, after ? null : {x: -100, y:0})
|
||||
item.class = 'l-drag-enter'
|
||||
cloneList.value.push(item)
|
||||
const length = cloneList.value.length - 1
|
||||
nextTick(() => {
|
||||
sleep(() => {
|
||||
item.class = 'l-drag-leave'
|
||||
_move(length, (after ? length : 0), null, false)
|
||||
triggerRef(cloneList)
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
const unshift = (...args: any) => {
|
||||
if(props.disabled) return
|
||||
if(Array.isArray(args)) {
|
||||
Promise.all(args.map(async (item) => await add(item))).then(emitting)
|
||||
}
|
||||
}
|
||||
|
||||
// 暂时先简单处理,待有空再完善
|
||||
const shift = () => {
|
||||
if(!cloneList.value.length) return
|
||||
remove(cloneList.value.findIndex(item => item.index == 0) || 0)
|
||||
}
|
||||
const pop = () => {
|
||||
const length = cloneList.value.length-1
|
||||
if(length < 0 ) return
|
||||
remove(cloneList.value.findIndex(item => item.index == length) || length)
|
||||
}
|
||||
// const splice = (start, count, ...context) => {
|
||||
// // 暂未实现
|
||||
// }
|
||||
const clear = () => {
|
||||
isInit.value = isDrag.value = false
|
||||
maxIndex.value = colmunId.value = active.value = -1
|
||||
cloneList.value = []
|
||||
gridRects = []
|
||||
}
|
||||
const init = () => {
|
||||
clear()
|
||||
createGridRects()
|
||||
nextTick(() => {
|
||||
updateList(props.list)
|
||||
isInit.value = true
|
||||
})
|
||||
}
|
||||
let count = 0
|
||||
const getRect = () => {
|
||||
count++
|
||||
// #ifndef APP-NVUE
|
||||
uni.createSelectorQuery().in(app.proxy).select('.l-drag').boundingClientRect((res: UniNamespace.NodeInfo) => {
|
||||
if(res) {
|
||||
areaWidth.value = res.width || 0
|
||||
// 小程序居然无法响应式?
|
||||
init()
|
||||
}
|
||||
}).exec()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
sleep(() => {
|
||||
nextTick(() => {
|
||||
dom.getComponentRect(dragRef.value, (res) => {
|
||||
if(!res.size.width && count < 5) {
|
||||
getRect()
|
||||
} else {
|
||||
areaWidth.value = res.size.width || 0
|
||||
init()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
onMounted(getRect)
|
||||
onUnmounted(clear)
|
||||
watch(() => props.list, init)
|
||||
|
||||
// #ifdef VUE3
|
||||
expose({
|
||||
remove,
|
||||
// add,
|
||||
move,
|
||||
push,
|
||||
unshift,
|
||||
shift,
|
||||
pop
|
||||
})
|
||||
// #endif
|
||||
return {
|
||||
// #ifdef APP-NVUE
|
||||
dragRef,
|
||||
// #endif
|
||||
cloneList,
|
||||
|
||||
areaStyles,
|
||||
innerStyles,
|
||||
viewStyles,
|
||||
|
||||
setDisabled,
|
||||
isDisabled,
|
||||
isReset,
|
||||
isDrag,
|
||||
|
||||
active,
|
||||
animation,
|
||||
|
||||
afterEl,
|
||||
ghostEl,
|
||||
beforeEl,
|
||||
|
||||
touchStart,
|
||||
touchMove,
|
||||
touchEnd,
|
||||
|
||||
remove,
|
||||
// add,
|
||||
move,
|
||||
push,
|
||||
unshift,
|
||||
// shift,
|
||||
// pop,
|
||||
props
|
||||
// isDelete: props.delete,
|
||||
// ...toRefs(props)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-drag{
|
||||
margin-top: v-bind(cusnavbarheight);
|
||||
|
||||
}
|
||||
@import './index';
|
||||
|
||||
</style>
|
47
uni_modules/lime-drag/components/l-drag/props.ts
Normal file
47
uni_modules/lime-drag/components/l-drag/props.ts
Normal file
@ -0,0 +1,47 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
column: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
/**宽高比 填写这项, gridHeight 失效*/
|
||||
aspectRatio: Number,
|
||||
gridHeight: {
|
||||
type: [Number, String],
|
||||
default: '120rpx'
|
||||
},
|
||||
// removeStyle: String,
|
||||
// handleStyle: String,
|
||||
damping: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
friction: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
/**
|
||||
* 由于 movable-area 无法动态设置高度,故增加额外的行数。用于增加动态项时,高度不够无法正确显示
|
||||
*/
|
||||
extraRow: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* 由于 movable-area 无法动态设置高度,但vif 重染可以,另一种实现动态高度的方式, 这BUG uni官方好像修复了。
|
||||
*/
|
||||
// reset: Boolean,
|
||||
// sort: Boolean,
|
||||
// remove: Boolean,
|
||||
ghost: Boolean,
|
||||
handle: Boolean,
|
||||
touchHandle: Boolean,
|
||||
before: Boolean,
|
||||
after: Boolean,
|
||||
disabled: Boolean,
|
||||
longpress: Boolean,
|
||||
}
|
21
uni_modules/lime-drag/components/l-drag/type.ts
Normal file
21
uni_modules/lime-drag/components/l-drag/type.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export interface Position {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
export interface GridRect extends Position{
|
||||
row : number
|
||||
// x : number
|
||||
// y : number
|
||||
x1 : number
|
||||
y1 : number
|
||||
}
|
||||
export interface Grid extends Position{
|
||||
id : string
|
||||
index : number
|
||||
oldindex : number
|
||||
content : any
|
||||
// x : number
|
||||
// y : number
|
||||
class : string
|
||||
show: boolean
|
||||
}
|
9
uni_modules/lime-drag/components/l-drag/vue.ts
Normal file
9
uni_modules/lime-drag/components/l-drag/vue.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// export * from '@/uni_modules/lime-vue'
|
||||
|
||||
// #ifdef VUE3
|
||||
export * from 'vue';
|
||||
// #endif
|
||||
// #ifndef VUE3
|
||||
export * from '@vue/composition-api';
|
||||
// #endif
|
268
uni_modules/lime-drag/components/lime-drag/lime-drag.vue
Normal file
268
uni_modules/lime-drag/components/lime-drag/lime-drag.vue
Normal file
@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<demo-block type="ultra" title="拖拽">
|
||||
<demo-block title="基础">
|
||||
<l-drag :list="list">
|
||||
<template #grid="{active, index}">
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{index}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
</demo-block>
|
||||
<demo-block title="多列 长按">
|
||||
<!-- 列后 删除 幽灵 长按 -->
|
||||
<l-drag ref="dragRef2" :list="list" @change="change2" :aspectRatio="1" :column="4" after ghost longpress>
|
||||
<template #grid="{oindex, content, active}">
|
||||
<view class="grid">
|
||||
<view class="remove" @click="onRemove2(oindex)"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #ghost>
|
||||
<view class="grid">
|
||||
<!-- 幽灵样式 -->
|
||||
<view class="inner ghost"></view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 示例未设置 before -->
|
||||
<template #before>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd2">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #after>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd2">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
<button @click="refresh2">更新列表</button>
|
||||
<button @click="onUnshift2">向前增加</button>
|
||||
<button @click="onPush2">向后增加</button>
|
||||
<button @click="onShift2">shift</button>
|
||||
<button @click="onPop2">pop</button>
|
||||
</demo-block>
|
||||
<demo-block title="单列 按手柄">
|
||||
<!-- 幽灵 手柄 -->
|
||||
<view class="inputs">
|
||||
<text>把原始下标为</text>
|
||||
<input type="text" v-model="move3.index">
|
||||
<text>的项移动到</text>
|
||||
<input type="text" v-model="move3.nindex">
|
||||
</view>
|
||||
<view style="height: 600rpx; overflow: auto;">
|
||||
<l-drag ref="dragRef3" :list="list3" @change="change3" grid-height="200rpx" :column="1" :touchHandle="touchHandle3" ghost handle>
|
||||
<template #grid="{active, content, index, oindex}">
|
||||
<view class="grid">
|
||||
<view class="mover" @touchstart="touchHandle3 = true" @touchend="touchHandle3 = false" style="left: 100rpx; top: 50%; transform: translateY(-50%); position: absolute; z-index: 1;"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
<view @click.stop.prevent="to(oindex, index - 1)">上移</view>
|
||||
<view @click.stop.prevent="to(oindex, index + 1)">下移</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #ghost>
|
||||
<view class="grid">
|
||||
<!-- 幽灵样式 -->
|
||||
<view class="inner ghost"></view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
</view>
|
||||
</demo-block>
|
||||
</demo-block>
|
||||
</template>
|
||||
<script>
|
||||
import {ref, watch, defineComponent, reactive} from '../l-drag/vue'
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
// 示例1和2共用list
|
||||
const list = ref(new Array(7).fill(0).map((v,i) => i));
|
||||
// 示例2 多列 长按
|
||||
const dragRef2 = ref(null)
|
||||
const newList2 = ref([])
|
||||
const change2 = v => {
|
||||
console.log('示例2数据发生变化::', v)
|
||||
newList2.value = [...v]
|
||||
}
|
||||
const onRemove2 = (index) => {
|
||||
if(dragRef2.value && index >= 0) {
|
||||
dragRef2.value.remove(index)
|
||||
}
|
||||
}
|
||||
const onAdd2 = () => {
|
||||
dragRef2.value.push(Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onShift2 = () => {
|
||||
dragRef2.value.shift()
|
||||
}
|
||||
const onPop2 = () => {
|
||||
dragRef2.value.pop()
|
||||
}
|
||||
const onUnshift2 = () => {
|
||||
dragRef2.value.unshift(Math.round(Math.random() * 1000), Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onPush2 = () => {
|
||||
dragRef2.value.push(Math.round(Math.random() * 1000), Math.round(Math.random() * 1000))
|
||||
}
|
||||
const refresh2 = () => {
|
||||
list.value = new Array(10).fill(0).map((v,i) => i);
|
||||
}
|
||||
|
||||
|
||||
// 示例3
|
||||
const list3 = new Array(5).fill(0).map((v,i) => i);
|
||||
const dragRef3 = ref(null)
|
||||
const newList3 = ref([])
|
||||
const touchHandle3 = ref(false)
|
||||
|
||||
const change3 = v => {
|
||||
newList3.value = v
|
||||
}
|
||||
const move3 = reactive({
|
||||
index: 0,
|
||||
nindex: 0
|
||||
})
|
||||
watch(() => move3.nindex, (v, o) => {
|
||||
dragRef3.value.move(move3.index*1, move3.nindex*1)
|
||||
})
|
||||
|
||||
const to = (oindex, index) => {
|
||||
dragRef3.value.move(oindex, index)
|
||||
}
|
||||
|
||||
return {
|
||||
list,
|
||||
// 示例2
|
||||
dragRef2,
|
||||
change2,
|
||||
onRemove2,
|
||||
onAdd2,
|
||||
refresh2,
|
||||
onUnshift2,
|
||||
onPush2,
|
||||
onShift2,
|
||||
onPop2,
|
||||
// 示例3
|
||||
list3,
|
||||
dragRef3,
|
||||
change3,
|
||||
move3,
|
||||
touchHandle3,
|
||||
to
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
.grid {
|
||||
height: 100%;
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
padding: 16rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
.remove {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
background-color: red;
|
||||
border-radius: 50%;
|
||||
font-size: 16rpx;
|
||||
color: white;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.inner {
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
|
||||
border: 1rpx solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: white;
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: blue;
|
||||
transition: all 300ms ease;
|
||||
position: relative;
|
||||
}
|
||||
.extra {
|
||||
color: #ddd
|
||||
}
|
||||
.mover {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
margin-top: 10rpx;
|
||||
height: 30rpx;
|
||||
border: 2px solid #ddd;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
/* background-color: #ddd; */
|
||||
}
|
||||
.mover::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 50rpx;
|
||||
top: 15rpx;
|
||||
border-top: 2px solid #ddd;
|
||||
}
|
||||
.active {
|
||||
box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
background-color: blue;
|
||||
color: white;
|
||||
border: 1rpx solid blue;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
/* #ifdef APP-NVUE */
|
||||
.text {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.text-active {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
/* #endif */
|
||||
.ghost {
|
||||
background-color: rgba(0, 0, 255, 0.1);
|
||||
}
|
||||
.inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
input {
|
||||
background-color: #fff;
|
||||
width: 80rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
padding: 5rpx 10rpx;
|
||||
margin: 0 8rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
87
uni_modules/lime-drag/package.json
Normal file
87
uni_modules/lime-drag/package.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "lime-drag",
|
||||
"displayName": "拖拽排序-拖动排序-LimeUI",
|
||||
"version": "0.1.3",
|
||||
"description": "uniapp vue3 拖拽排序插件,用于图片或列表的拖动排序,可设置列数、增加删除等功能, vue2只要配置@vue/composition-api",
|
||||
"keywords": [
|
||||
"拖拽",
|
||||
"拖拽排序",
|
||||
"排序",
|
||||
"拖动",
|
||||
"拖动排序"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.7.12"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "n",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
170
uni_modules/lime-drag/readme.md
Normal file
170
uni_modules/lime-drag/readme.md
Normal file
@ -0,0 +1,170 @@
|
||||
# lime-drag 拖拽排序
|
||||
- 当前为初版 可能会有BUG
|
||||
- 基于uniapp vue3
|
||||
- Q群 1169785031
|
||||
|
||||
|
||||
### 安装
|
||||
- 在市场导入插件即可在任意页面使用,无须再`import`
|
||||
|
||||
|
||||
### 使用
|
||||
- 提供简单的使用示例,更多请查看下方的demo
|
||||
|
||||
```html
|
||||
<l-drag :list="list" @change="change">
|
||||
<!-- // 每一项的插槽 grid 的 content 您传入的数据 -->
|
||||
<template #grid="{active, content}">
|
||||
<!-- // grid.active 是否为当前拖拽项目 根据自己需要写样式 -->
|
||||
<view class="inner" :class="{active: active}">
|
||||
<text class="text" :class="{'text-active': active}">{{grid.content}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
```
|
||||
|
||||
```js
|
||||
const list = new Array(7).fill(0).map((v,i) => i);
|
||||
// 拖拽后新的数据
|
||||
const newList = ref([])
|
||||
const change = v => newList.value = v
|
||||
```
|
||||
#### 增删
|
||||
- 不要给list赋值,这样只会重新初始化
|
||||
- 增加数据 调用暴露的`push`
|
||||
- 删除某条数据调用暴露的`remove`方法,需要传入`oindex`
|
||||
|
||||
```html
|
||||
<l-drag :list="list" @change="change" ref="dragRef" after remove>
|
||||
<!-- 每一项插槽 grid 的 content 是您传入的数据 -->
|
||||
<template #grid="{active, index, oldindex, oindex}">
|
||||
<!-- active 是否为当前拖拽项目 根据自己需要写样式 -->
|
||||
<!-- index 排序后列表下标 -->
|
||||
<!-- oldindex 排序后列表旧下标 -->
|
||||
<!-- oindex 列表原始下标,输入的数据排位不会因为排序而改变 -->
|
||||
<view class="remove" @click="onRemove(oindex)"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template #after>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
```
|
||||
```js
|
||||
const dragRef = ref(null)
|
||||
const list = new Array(7).fill(0).map((v,i) => i);
|
||||
const onAdd = () => {
|
||||
dragRef.value.push(Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onRemove = (oindex) => {
|
||||
if(dragRef.value && oindex >= 0) {
|
||||
// 记得oindex为数组的原始index
|
||||
dragRef.value.remove(oindex)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 插槽
|
||||
```html
|
||||
<l-drag :list="list">
|
||||
<!-- 每一项的插槽 -->
|
||||
<template #grid="{active, index, oldindex, oindex, content}"></template>
|
||||
<!-- 当前拖拽项幽灵插槽 设置`ghost`后使用 主要为实现拖拽时 有个影子跟着 -->
|
||||
<template #ghots></template>
|
||||
|
||||
<!-- 前后方插槽为固定在列表前方和后方,不能拖动 -->
|
||||
<!-- 列表前方的插槽 设置`before`后使用 -->
|
||||
<template #before></template>
|
||||
<!-- 列表后方的插槽 设置`after`后使用 -->
|
||||
<template #after></template>
|
||||
</l-drag>
|
||||
```
|
||||
|
||||
|
||||
### 查看示例
|
||||
- 导入后直接使用这个标签查看演示效果
|
||||
|
||||
```html
|
||||
<!-- // 代码位于 uni_modules/lime-drag/compoents/lime-drag -->
|
||||
<lime-drag />
|
||||
```
|
||||
|
||||
|
||||
### 插件标签
|
||||
- 默认 l-drag 为 component
|
||||
- 默认 lime-drag 为 demo
|
||||
|
||||
### 关于vue2的使用方式
|
||||
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||
- 关键代码是: 在main.js中 在vue2部分加上这一段即可,官方是把它单独成了一个文件.
|
||||
```js
|
||||
// vue2
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
```
|
||||
|
||||
- 另外插件也用到了TS,vue2可能会遇过官方的TS版本过低的问题,找到HX目录下的`compile-typescript`目录
|
||||
```cmd
|
||||
// \HBuilderX\plugins\compile-typescript
|
||||
yarn add typescript -D
|
||||
- or -
|
||||
npm install typescript -D
|
||||
```
|
||||
|
||||
- 小程序需要在`manifest.json`启用`slotMultipleInstance`
|
||||
```json
|
||||
"mp-weixin" : {
|
||||
"slotMultipleInstance" : true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||
| list | 列表数组,不可变化,变化后会重新初始化 | <em>array</em> | `[]` |
|
||||
| column | 列数 | <em>number</em> | `2` |
|
||||
| gridHeight | 行高,宫格高度 | <em>string</em> | `120rpx` |
|
||||
| damping | 阻尼系数,用于控制x或y改变时的动画和过界回弹的动画,值越大移动越快 | <em>string</em> | `-` |
|
||||
| friction | 摩擦系数,用于控制惯性滑动的动画,值越大摩擦力越大,滑动越快停止;必须大于0,否则会被设置成默认值 | <em>number</em> | `2` |
|
||||
| extraRow | 额外行数 | <em>number</em> | `0` |
|
||||
| ghost | 开启幽灵插槽 | <em>boolean</em> | `false` |
|
||||
| before | 开启列前插槽 | <em>boolean</em> | `false` |
|
||||
| after | 开启列后插槽 | <em>boolean</em> | `false` |
|
||||
| disabled | 是否禁用 | <em>boolean</em> | `false` |
|
||||
| longpress | 是否长按 | <em>boolean</em> | `false` |
|
||||
|
||||
### Events
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| change | 返回新数据 | list |
|
||||
|
||||
### Expose
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| remove | 删除, 传入`oindex`,即数据列表原始的index | |
|
||||
| push | 向后增加,可以是数组或单数据 | |
|
||||
| unshift | 向前增加,可以是数组或单数据 | |
|
||||
| move | 移动, 传入(`oindex`, `toindex`),将数据列表原始的index项移到视图中的目标位置 | |
|
||||
|
||||
|
||||
### TODO
|
||||
将来实现的功能
|
||||
- splice
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
205
uni_modules/lime-echart/changelog.md
Normal file
205
uni_modules/lime-echart/changelog.md
Normal file
@ -0,0 +1,205 @@
|
||||
## 0.9.8(2024-12-20)
|
||||
- fix: 修复 APP 无法放大问题
|
||||
## 0.9.7(2024-12-02)
|
||||
- feat: uniapp 增加`landscape`,当`landscape`为`true`时旋转90deg达到横屏效果。
|
||||
- feat: 支持uniapp x 微信小程序
|
||||
## 0.9.6(2024-07-23)
|
||||
- fix: 修复 uni is not defined
|
||||
## 0.9.5(2024-07-19)
|
||||
- chore: 鸿蒙`measureText`为异步,异步字体不正常,使用模拟方式。
|
||||
## 0.9.4(2024-07-18)
|
||||
- chore: 更新文档
|
||||
## 0.9.3(2024-07-16)
|
||||
- feat: 鸿蒙 canvas 事件缺失,待官方修复,如何在鸿蒙使用请看文档`常见问题 vue3`
|
||||
## 0.9.2(2024-07-12)
|
||||
- chore: 删除多余文件
|
||||
## 0.9.1(2024-07-12)
|
||||
- fix: 修复 安卓5不显示图表问题
|
||||
## 0.9.0(2024-06-13)
|
||||
- chore: 合并nvue和uvue
|
||||
## 0.8.9(2024-05-19)
|
||||
- chore: 更新文档
|
||||
## 0.8.8(2024-05-13)
|
||||
- chore: 更新文档和uvue示例
|
||||
## 0.8.7(2024-04-26)
|
||||
- fix: uniapp x需要HBX 4.13以上
|
||||
## 0.8.6(2024-04-10)
|
||||
- feat: 支持 uniapp x ios
|
||||
## 0.8.5(2024-04-03)
|
||||
- fix: 修复 nvue `reset`传值不生效问题
|
||||
- feat: 支持 uniapp x web
|
||||
## 0.8.4(2024-01-27)
|
||||
- chore: 更新文档
|
||||
## 0.8.3(2024-01-21)
|
||||
- chore: 更新文档
|
||||
## 0.8.2(2024-01-21)
|
||||
- feat: 支持 `uvue`
|
||||
## 0.8.1(2023-08-24)
|
||||
- fix: app 的`touch`事件为`object` 导致无法显示 `tooltip`
|
||||
## 0.8.0(2023-08-22)
|
||||
- fix: 离屏 报错问题
|
||||
- fix: 微信小程序PC无法使用事件
|
||||
- chore: 更新文档
|
||||
## 0.7.9(2023-07-29)
|
||||
- chore: 更新文档
|
||||
## 0.7.8(2023-07-29)
|
||||
- fix: 离屏 报错问题
|
||||
## 0.7.7(2023-07-27)
|
||||
- chore: 更新文档
|
||||
- chore: lime-echart 里的示例使用自定tooltips
|
||||
- feat: 对支持离屏的使用离屏创建(微信、字节、支付宝)
|
||||
## 0.7.6(2023-06-30)
|
||||
- fix: vue3 报`width`的错
|
||||
## 0.7.5(2023-05-25)
|
||||
- chore: 更新文档 和 demo, 使用`lime-echart`这个标签即可查看示例
|
||||
## 0.7.4(2023-05-22)
|
||||
- chore: 增加关于钉钉小程序上传时提示安全问题的说明及修改建议
|
||||
## 0.7.3(2023-05-16)
|
||||
- chore: 更新 vue3 非微信小程序平台可能缺少`wx`的说明
|
||||
## 0.7.2(2023-05-16)
|
||||
- chore: 更新 vue3 非微信小程序平台的可以缺少`wx`的说明
|
||||
## 0.7.1(2023-04-26)
|
||||
- chore: 更新demo,使用`lime-echart`这个标签即可查看示例
|
||||
- chore:微信小程序的`tooltip`文字有阴影,怀疑是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
|
||||
## 0.7.0(2023-04-24)
|
||||
- fix: 修复`setAttribute is not a function`
|
||||
## 0.6.9(2023-04-15)
|
||||
- chore: 更新文档,vue3请使用echarts esm的包
|
||||
## 0.6.8(2023-03-22)
|
||||
- feat: mac pc无法使用canvas 2d
|
||||
## 0.6.7(2023-03-17)
|
||||
- feat: 更新文档
|
||||
## 0.6.6(2023-03-17)
|
||||
- feat: 微信小程序PC已经支持canvas 2d,故去掉判断PC
|
||||
## 0.6.5(2022-11-03)
|
||||
- fix: 某些手机touches为对象,导致无法交互。
|
||||
## 0.6.4(2022-10-28)
|
||||
- fix: 优化点击事件的触发条件
|
||||
## 0.6.3(2022-10-26)
|
||||
- fix: 修复 dataZoom 拖动问题
|
||||
## 0.6.2(2022-10-23)
|
||||
- fix: 修复 飞书小程序 尺寸问题
|
||||
## 0.6.1(2022-10-19)
|
||||
- fix: 修复 PC mousewheel 事件 鼠标位置不准确的BUG,不兼容火狐!
|
||||
- feat: showLoading 增加传参
|
||||
## 0.6.0(2022-09-16)
|
||||
- feat: 增加PC的mousewheel事件
|
||||
## 0.5.4(2022-09-16)
|
||||
- fix: 修复 nvue 动态数据不显示问题
|
||||
## 0.5.3(2022-09-16)
|
||||
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||
- chore: 更新文档
|
||||
## 0.5.2(2022-09-16)
|
||||
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||
## 0.5.1(2022-09-16)
|
||||
- fix: 修复nvue报错
|
||||
## 0.5.0(2022-09-15)
|
||||
- feat: init(echarts, theme?:string, opts?:{}, callback: function(chart))
|
||||
## 0.4.8(2022-09-11)
|
||||
- feat: 增加 @finished
|
||||
## 0.4.7(2022-08-24)
|
||||
- chore: 去掉 stylus
|
||||
## 0.4.6(2022-08-24)
|
||||
- feat: 增加 beforeDelay
|
||||
## 0.4.5(2022-08-12)
|
||||
- chore: 更新文档
|
||||
## 0.4.4(2022-08-12)
|
||||
- fix: 修复 resize 无参数时报错
|
||||
## 0.4.3(2022-08-07)
|
||||
# 评论有说本插件对新手不友好,让我做不好就不要发出来。 还有的说跟官网一样,发出来做什么,给我整无语了。
|
||||
# 所以在此提醒一下准备要下载的你,如果你从未使用过 echarts 请不要下载 或 谨慎下载。
|
||||
# 如果你确认要下载,麻烦看完文档。还有请注意插件是让echarts在uniapp能运行,API 配置请自行去官网查阅!
|
||||
# 如果你不会echarts 但又需要图表,市场上有个很优秀的图表插件 uchart 你可以去使用这款插件,uchart的作者人很好,也热情。
|
||||
# 每个人都有自己的本职工作,如果你能力强可以自行兼容,如果使用了他人的插件也麻烦尊重他人的成果和劳动时间。谢谢。
|
||||
# 为了心情愉悦,本人已经使用插件屏蔽差评。
|
||||
- chore: 更新文档
|
||||
## 0.4.2(2022-07-20)
|
||||
- feat: 增加 resize
|
||||
## 0.4.1(2022-06-07)
|
||||
- fix: 修复 canvasToTempFilePath 不生效问题
|
||||
## 0.4.0(2022-06-04)
|
||||
- chore 为了词云 增加一个canvas 标签
|
||||
- 词云下载地址[echart-wordcloud](https://ext.dcloud.net.cn/plugin?id=8430)
|
||||
## 0.3.9(2022-06-02)
|
||||
- chore: 更新文档
|
||||
- tips: lines 不支持 `trailLength`
|
||||
## 0.3.8(2022-05-31)
|
||||
- fix: 修复 因mouse事件冲突tooltip跳动问题
|
||||
## 0.3.7(2022-05-26)
|
||||
- chore: 更新文档
|
||||
- chore: 设置默认宽高300px
|
||||
- fix: 修复 vue3 微信小程序 拖影BUG
|
||||
- chore: 支持PC
|
||||
## 0.3.5(2022-04-28)
|
||||
- chore: 更新使用方式
|
||||
- 🔔 必须使用hbuilderx 3.4.8-alpha以上
|
||||
## 0.3.4(2021-08-03)
|
||||
- chore: 增加 setOption的参数值
|
||||
## 0.3.3(2021-07-22)
|
||||
- fix: 修复 径向渐变报错的问题
|
||||
## 0.3.2(2021-07-09)
|
||||
- chore: 统一命名规范,无须主动引入组件
|
||||
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.3.1(2021-06-21)
|
||||
- fix: 修复 app-nvue ios is-enable 无效的问题
|
||||
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.3.0(2021-06-14)
|
||||
- fix: 修复 头条系小程序 2d 报 JSON.stringify 的问题
|
||||
- 目前 头条系小程序 2d 无法在开发工具上预览,划动图表页面无法滚动,axisLabel 字体颜色无法更改,建议使用非2d。
|
||||
## 0.2.9(2021-06-06)
|
||||
- fix: 修复 头条系小程序 2d 放大的BUG
|
||||
- 头条系小程序 2d 无法在开发工具上预览,也存在划动图表页面无法滚动的问题。
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.8(2021-05-19)
|
||||
- fix: 修复 微信小程序 PC 显示过大的问题
|
||||
## 0.2.7(2021-05-19)
|
||||
- fix: 修复 微信小程序 PC 不显示问题
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.6(2021-05-14)
|
||||
- feat: 支持 `image`
|
||||
- feat: props 增加 `ec.clear`,更新时是否先删除图表样式
|
||||
- feat: props 增加 `isDisableScroll` ,触摸图表时是否禁止页面滚动
|
||||
- feat: props 增加 `webviewStyles` ,webview 的样式, 仅nvue有效
|
||||
## 0.2.5(2021-05-13)
|
||||
- docs: 插件用到了css 预编译器 [stylus](https://ext.dcloud.net.cn/plugin?name=compile-stylus) 请安装它
|
||||
## 0.2.4(2021-05-12)
|
||||
- fix: 修复 百度平台 多个图表ctx 和 渐变色 bug
|
||||
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.3(2021-05-10)
|
||||
- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
|
||||
```js
|
||||
this.$refs.chart.canvasToTempFilePath({success: (res) => {
|
||||
console.log('tempFilePath:', res.tempFilePath)
|
||||
}})
|
||||
```
|
||||
## 0.2.2(2021-05-10)
|
||||
- feat: 增加 `dispose` 方法,用于销毁实例
|
||||
- feat: 增加 `isClickable` 是否派发点击
|
||||
- feat: 实验性的支持 `nvue` 使用要慎重考虑
|
||||
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.1(2021-05-06)
|
||||
- fix:修复 微信小程序 json 报错
|
||||
- chore: `reset` 更改为 `setChart`
|
||||
- feat: 增加 `isEnable` 开启初始化 启用这个后 无须再使用`init`方法
|
||||
```html
|
||||
<l-echart ref="chart" is-enable />
|
||||
```
|
||||
```js
|
||||
// 显示加载
|
||||
this.$refs.chart.showLoading()
|
||||
// 使用实例回调
|
||||
this.$refs.chart.setChart(chart => ...code)
|
||||
// 直接设置图表配置
|
||||
this.$refs.chart.setOption(data)
|
||||
```
|
||||
## 0.2.0(2021-05-05)
|
||||
- fix:修复 头条 百度 偏移的问题
|
||||
- docs: 更新文档
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.1.0(2021-05-02)
|
||||
- chore: 第一次上传,基本全端兼容,使用方法与官网一致。
|
||||
- 已知BUG:非2d 无法使用背景色,已反馈官方
|
||||
- 已知BUG:头条 百度 有许些偏移
|
||||
- 后期计划:兼容nvue
|
395
uni_modules/lime-echart/components/l-echart/canvas.js
Normal file
395
uni_modules/lime-echart/components/l-echart/canvas.js
Normal file
@ -0,0 +1,395 @@
|
||||
import {getDeviceInfo} from './utils';
|
||||
|
||||
const cacheChart = {}
|
||||
const fontSizeReg = /([\d\.]+)px/;
|
||||
class EventEmit {
|
||||
constructor() {
|
||||
this.__events = {};
|
||||
}
|
||||
on(type, listener) {
|
||||
if (!type || !listener) {
|
||||
return;
|
||||
}
|
||||
const events = this.__events[type] || [];
|
||||
events.push(listener);
|
||||
this.__events[type] = events;
|
||||
}
|
||||
emit(type, e) {
|
||||
if (type.constructor === Object) {
|
||||
e = type;
|
||||
type = e && e.type;
|
||||
}
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
const events = this.__events[type];
|
||||
if (!events || !events.length) {
|
||||
return;
|
||||
}
|
||||
events.forEach((listener) => {
|
||||
listener.call(this, e);
|
||||
});
|
||||
}
|
||||
off(type, listener) {
|
||||
const __events = this.__events;
|
||||
const events = __events[type];
|
||||
if (!events || !events.length) {
|
||||
return;
|
||||
}
|
||||
if (!listener) {
|
||||
delete __events[type];
|
||||
return;
|
||||
}
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
if (events[i] === listener) {
|
||||
events.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Image {
|
||||
constructor() {
|
||||
this.currentSrc = null
|
||||
this.naturalHeight = 0
|
||||
this.naturalWidth = 0
|
||||
this.width = 0
|
||||
this.height = 0
|
||||
this.tagName = 'IMG'
|
||||
}
|
||||
set src(src) {
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
class OffscreenCanvas {
|
||||
constructor(ctx, com, canvasId) {
|
||||
this.tagName = 'canvas'
|
||||
this.com = com
|
||||
this.canvasId = canvasId
|
||||
this.ctx = ctx
|
||||
}
|
||||
set width(w) {
|
||||
this.com.offscreenWidth = w
|
||||
}
|
||||
set height(h) {
|
||||
this.com.offscreenHeight = h
|
||||
}
|
||||
get width() {
|
||||
return this.com.offscreenWidth || 0
|
||||
}
|
||||
get height() {
|
||||
return this.com.offscreenHeight || 0
|
||||
}
|
||||
getContext(type) {
|
||||
return this.ctx
|
||||
}
|
||||
getImageData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.com.$nextTick(() => {
|
||||
uni.canvasGetImageData({
|
||||
x:0,
|
||||
y:0,
|
||||
width: this.com.offscreenWidth,
|
||||
height: this.com.offscreenHeight,
|
||||
canvasId: this.canvasId,
|
||||
success: (res) => {
|
||||
resolve(res)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
}, this.com)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
export class Canvas {
|
||||
constructor(ctx, com, isNew, canvasNode={}) {
|
||||
cacheChart[com.canvasId] = {ctx}
|
||||
this.canvasId = com.canvasId;
|
||||
this.chart = null;
|
||||
this.isNew = isNew
|
||||
this.tagName = 'canvas'
|
||||
this.canvasNode = canvasNode;
|
||||
this.com = com;
|
||||
if (!isNew) {
|
||||
this._initStyle(ctx)
|
||||
}
|
||||
this._initEvent();
|
||||
this._ee = new EventEmit()
|
||||
}
|
||||
getContext(type) {
|
||||
if (type === '2d') {
|
||||
return this.ctx;
|
||||
}
|
||||
}
|
||||
setAttribute(key, value) {
|
||||
if(key === 'aria-label') {
|
||||
this.com['ariaLabel'] = value
|
||||
}
|
||||
}
|
||||
setChart(chart) {
|
||||
this.chart = chart;
|
||||
}
|
||||
createOffscreenCanvas(param){
|
||||
if(!this.children) {
|
||||
this.com.isOffscreenCanvas = true
|
||||
this.com.offscreenWidth = param.width||300
|
||||
this.com.offscreenHeight = param.height||300
|
||||
const com = this.com
|
||||
const canvasId = this.com.offscreenCanvasId
|
||||
const context = uni.createCanvasContext(canvasId, this.com)
|
||||
this._initStyle(context)
|
||||
this.children = new OffscreenCanvas(context, com, canvasId)
|
||||
}
|
||||
return this.children
|
||||
}
|
||||
appendChild(child) {
|
||||
console.log('child', child)
|
||||
}
|
||||
dispatchEvent(type, e) {
|
||||
if(typeof type == 'object') {
|
||||
this._ee.emit(type.type, type);
|
||||
} else {
|
||||
this._ee.emit(type, e);
|
||||
}
|
||||
return true
|
||||
}
|
||||
attachEvent() {
|
||||
}
|
||||
detachEvent() {
|
||||
}
|
||||
addEventListener(type, listener) {
|
||||
this._ee.on(type, listener)
|
||||
}
|
||||
removeEventListener(type, listener) {
|
||||
this._ee.off(type, listener)
|
||||
}
|
||||
_initCanvas(zrender, ctx) {
|
||||
// zrender.util.getContext = function() {
|
||||
// return ctx;
|
||||
// };
|
||||
// zrender.util.$override('measureText', function(text, font) {
|
||||
// ctx.font = font || '12px sans-serif';
|
||||
// return ctx.measureText(text, font);
|
||||
// });
|
||||
}
|
||||
_initStyle(ctx, child) {
|
||||
const styles = [
|
||||
'fillStyle',
|
||||
'strokeStyle',
|
||||
'fontSize',
|
||||
'globalAlpha',
|
||||
'opacity',
|
||||
'textAlign',
|
||||
'textBaseline',
|
||||
'shadow',
|
||||
'lineWidth',
|
||||
'lineCap',
|
||||
'lineJoin',
|
||||
'lineDash',
|
||||
'miterLimit',
|
||||
// #ifdef H5
|
||||
'font',
|
||||
// #endif
|
||||
];
|
||||
const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
|
||||
styles.forEach(style => {
|
||||
Object.defineProperty(ctx, style, {
|
||||
set: value => {
|
||||
// #ifdef H5
|
||||
if (style === 'font' && fontSizeReg.test(value)) {
|
||||
const match = fontSizeReg.exec(value);
|
||||
ctx.setFontSize(match[1]);
|
||||
return;
|
||||
}
|
||||
// #endif
|
||||
|
||||
if (style === 'opacity') {
|
||||
ctx.setGlobalAlpha(value)
|
||||
return;
|
||||
}
|
||||
if (style !== 'fillStyle' && style !== 'strokeStyle' || value !== 'none' && value !== null) {
|
||||
// #ifdef H5 || APP-PLUS || MP-BAIDU
|
||||
if(typeof value == 'object') {
|
||||
if (value.hasOwnProperty('colorStop') || value.hasOwnProperty('colors')) {
|
||||
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||
}
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(colorReg.test(value)) {
|
||||
value = value.replace(colorReg, '#$1$1$2$2$3$3')
|
||||
}
|
||||
// #endif
|
||||
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if(!this.isNew && !child) {
|
||||
ctx.uniDrawImage = ctx.drawImage
|
||||
ctx.drawImage = (...a) => {
|
||||
a[0] = a[0].src
|
||||
ctx.uniDrawImage(...a)
|
||||
}
|
||||
}
|
||||
if(!ctx.createRadialGradient) {
|
||||
ctx.createRadialGradient = function() {
|
||||
return ctx.createCircularGradient(...[...arguments].slice(-3))
|
||||
};
|
||||
}
|
||||
// 字节不支持
|
||||
if (!ctx.strokeText) {
|
||||
ctx.strokeText = (...a) => {
|
||||
ctx.fillText(...a)
|
||||
}
|
||||
}
|
||||
|
||||
// 钉钉不支持 , 鸿蒙是异步
|
||||
if (!ctx.measureText || getDeviceInfo().osName == 'harmonyos') {
|
||||
ctx._measureText = ctx.measureText
|
||||
const strLen = (str) => {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
|
||||
len++;
|
||||
} else {
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
ctx.measureText = (text, font) => {
|
||||
let fontSize = ctx?.state?.fontSize || 12;
|
||||
if (font) {
|
||||
fontSize = parseInt(font.match(/([\d\.]+)px/)[1])
|
||||
}
|
||||
fontSize /= 2;
|
||||
let isBold = fontSize >= 16;
|
||||
const widthFactor = isBold ? 1.3 : 1;
|
||||
// ctx._measureText(text, (res) => {})
|
||||
return {
|
||||
width: strLen(text) * fontSize * widthFactor
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_initEvent(e) {
|
||||
this.event = {};
|
||||
const eventNames = [{
|
||||
wxName: 'touchStart',
|
||||
ecName: 'mousedown'
|
||||
}, {
|
||||
wxName: 'touchMove',
|
||||
ecName: 'mousemove'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'mouseup'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'click'
|
||||
}];
|
||||
|
||||
eventNames.forEach(name => {
|
||||
this.event[name.wxName] = e => {
|
||||
const touch = e.touches[0];
|
||||
this.chart.getZr().handler.dispatch(name.ecName, {
|
||||
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
|
||||
zrY: name.wxName === 'tap' ? touch.clientY : touch.y
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
set width(w) {
|
||||
this.canvasNode.width = w
|
||||
}
|
||||
set height(h) {
|
||||
this.canvasNode.height = h
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.canvasNode.width || 0
|
||||
}
|
||||
get height() {
|
||||
return this.canvasNode.height || 0
|
||||
}
|
||||
get ctx() {
|
||||
return cacheChart[this.canvasId]['ctx'] || null
|
||||
}
|
||||
set chart(chart) {
|
||||
cacheChart[this.canvasId]['chart'] = chart
|
||||
}
|
||||
get chart() {
|
||||
return cacheChart[this.canvasId]['chart'] || null
|
||||
}
|
||||
}
|
||||
|
||||
export function dispatch(name, {x,y, wheelDelta}) {
|
||||
this.dispatch(name, {
|
||||
zrX: x,
|
||||
zrY: y,
|
||||
zrDelta: wheelDelta,
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () =>{}
|
||||
});
|
||||
}
|
||||
export function setCanvasCreator(echarts, {canvas, node}) {
|
||||
// echarts.setCanvasCreator(() => canvas);
|
||||
if(echarts && !echarts.registerPreprocessor) {
|
||||
return console.warn('echarts 版本不对或未传入echarts,vue3请使用esm格式')
|
||||
}
|
||||
echarts.registerPreprocessor(option => {
|
||||
if (option && option.series) {
|
||||
if (option.series.length > 0) {
|
||||
option.series.forEach(series => {
|
||||
series.progressive = 0;
|
||||
});
|
||||
} else if (typeof option.series === 'object') {
|
||||
option.series.progressive = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
function loadImage(src, onload, onerror) {
|
||||
let img = null
|
||||
if(node && node.createImage) {
|
||||
img = node.createImage()
|
||||
img.onload = onload.bind(img);
|
||||
img.onerror = onerror.bind(img);
|
||||
img.src = src;
|
||||
return img
|
||||
} else {
|
||||
img = new Image()
|
||||
img.onload = onload.bind(img)
|
||||
img.onerror = onerror.bind(img);
|
||||
img.src = src
|
||||
return img
|
||||
}
|
||||
}
|
||||
if(echarts.setPlatformAPI) {
|
||||
echarts.setPlatformAPI({
|
||||
loadImage: canvas.setChart ? loadImage : null,
|
||||
createCanvas(){
|
||||
const key = 'createOffscreenCanvas'
|
||||
return uni.canIUse(key) && uni[key] ? uni[key]({type: '2d'}) : canvas
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
310
uni_modules/lime-echart/components/l-echart/l-echart.uvue
Normal file
310
uni_modules/lime-echart/components/l-echart/l-echart.uvue
Normal file
@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<!-- #ifdef APP -->
|
||||
<web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[customStyle]"
|
||||
:webview-styles="[webviewStyles]" src="/uni_modules/lime-echart/static/uvue.html?v=10112">
|
||||
</web-view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<div class="lime-echart" ref="chartRef"></div>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || APP-->
|
||||
<canvas class="lime-echart" :id="canvasid" :canvas-id="canvasid"
|
||||
@touchstart="touchstart"
|
||||
@touchmove="touchmove"
|
||||
@touchend="touchend">
|
||||
</canvas>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
// @ts-nocheck
|
||||
import { getCurrentInstance, nextTick } from "vue";
|
||||
import { Echarts } from './uvue';
|
||||
// #ifdef WEB
|
||||
import { dispatch } from './canvas';
|
||||
// #endif
|
||||
// #ifndef APP || WEB
|
||||
import {Canvas, setCanvasCreator, dispatch} from './canvas';
|
||||
import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect} from './utils';
|
||||
// #endif
|
||||
type EchartsResolve = (value : Echarts) => void
|
||||
defineOptions({
|
||||
name: 'l-echart'
|
||||
})
|
||||
const emits = defineEmits(['finished'])
|
||||
const props = defineProps({
|
||||
// #ifdef APP
|
||||
webviewStyles: {
|
||||
type: Object
|
||||
},
|
||||
customStyle: {
|
||||
type: Object
|
||||
},
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
webviewStyles: {
|
||||
type: Object
|
||||
},
|
||||
customStyle: {
|
||||
type: [String, Object]
|
||||
},
|
||||
// #endif
|
||||
isDisableScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isClickable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
enableHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
beforeDelay: {
|
||||
type: Number,
|
||||
default: 30
|
||||
}
|
||||
})
|
||||
const instance = getCurrentInstance()!;
|
||||
const canvasid = `lime-echart-${instance.uid}`
|
||||
const finished = ref(false)
|
||||
const map = [] as EchartsResolve[]
|
||||
const callbackMap = [] as EchartsResolve[]
|
||||
// let context = null as UniWebViewElement | null
|
||||
let chart = null as Echarts | null
|
||||
let chartRef = ref<UniWebViewElement | null>(null)
|
||||
|
||||
const trigger = () => {
|
||||
// #ifdef APP
|
||||
if (finished.value) {
|
||||
if (chart == null) {
|
||||
chart = new Echarts(chartRef.value!)
|
||||
}
|
||||
while (map.length > 0) {
|
||||
const resolve = map.pop() as EchartsResolve
|
||||
resolve(chart!)
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
while (map.length > 0) {
|
||||
if(chart != null){
|
||||
const resolve = map.pop() as EchartsResolve
|
||||
resolve(chart!)
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
if(chart != null){
|
||||
while(callbackMap.length > 0){
|
||||
const callback = callbackMap.pop() as EchartsResolve
|
||||
callback(chart!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef APP
|
||||
const loaded = (event : UniWebViewLoadEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
finished.value = true
|
||||
trigger()
|
||||
emits('finished')
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
const _next = () : boolean => {
|
||||
if (chart == null) {
|
||||
console.warn(`组件还未初始化,请先使用 init`)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
const setOption = (option : UTSJSONObject) => {
|
||||
if (_next()) return
|
||||
chart!.setOption(option);
|
||||
}
|
||||
const showLoading = () => {
|
||||
if (_next()) return
|
||||
chart!.showLoading();
|
||||
}
|
||||
const hideLoading = () => {
|
||||
if (_next()) return
|
||||
chart!.hideLoading();
|
||||
}
|
||||
const clear = () => {
|
||||
if (_next()) return
|
||||
chart!.clear();
|
||||
}
|
||||
const dispose = () => {
|
||||
if (_next()) return
|
||||
chart!.dispose();
|
||||
}
|
||||
const resize = (size : UTSJSONObject) => {
|
||||
if (_next()) return
|
||||
chart!.resize(size);
|
||||
}
|
||||
const canvasToTempFilePath = (opt : UTSJSONObject) => {
|
||||
if (_next()) return
|
||||
chart!.canvasToTempFilePath(opt);
|
||||
}
|
||||
|
||||
// #ifdef APP
|
||||
function init(callback : ((chart : Echarts) => void) | null) : Promise<Echarts> {
|
||||
|
||||
if(callback!=null){
|
||||
callbackMap.push(callback)
|
||||
}
|
||||
return new Promise<Echarts>((resolve) => {
|
||||
map.push(resolve)
|
||||
trigger()
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
// #ifndef WEB
|
||||
let use2dCanvas = canIUseCanvas2d()
|
||||
const getContext = async () =>{
|
||||
return getRect(`#${canvasid}`, {context: instance.proxy!, type: use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
|
||||
if(res) {
|
||||
let dpr = uni.getWindowInfo().pixelRatio
|
||||
let {width, height, node} = res
|
||||
let canvas;
|
||||
if(node) {
|
||||
const ctx = node.getContext('2d');
|
||||
canvas = new Canvas(ctx, instance.proxy, true, node);
|
||||
} else {
|
||||
const ctx = uni.createCanvasContext(canvasid, instance.proxy);
|
||||
canvas = new Canvas(ctx, instance.proxy, false);
|
||||
}
|
||||
|
||||
return { canvas, width, height, devicePixelRatio: dpr, node };
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
const getTouch = (e) => {
|
||||
const touches = e.touches[0]
|
||||
// #ifdef WEB
|
||||
const rect = chart!.getZr().dom.getBoundingClientRect();
|
||||
const touch = {
|
||||
x: touches.clientX - rect.left,
|
||||
y: touches.clientY - rect.top
|
||||
}
|
||||
// #endif
|
||||
// #ifndef WEB
|
||||
const touch = {
|
||||
x: touches.x,
|
||||
y: touches.y
|
||||
}
|
||||
// #endif
|
||||
return touch
|
||||
}
|
||||
const touchstart = (e) => {
|
||||
if(chart == null) return
|
||||
const handler = chart.getZr().handler;
|
||||
const touch = getTouch(e)
|
||||
dispatch.call(handler, 'mousedown', touch)
|
||||
dispatch.call(handler, 'click', touch)
|
||||
}
|
||||
const touchmove = (e) => {
|
||||
if(chart == null) return
|
||||
const handler = chart.getZr().handler;
|
||||
const touch = getTouch(e)
|
||||
dispatch.call(handler, 'mousemove', touch)
|
||||
// const rect = chart.getZr().dom.getBoundingClientRect()
|
||||
// handler.dispatch('mousemove', {
|
||||
// zrX: e.touches[0].clientX - rect.left,
|
||||
// zrY: e.touches[0].clientY - rect.top
|
||||
// })
|
||||
}
|
||||
const touchend = (e) => {
|
||||
if(chart == null) return
|
||||
const handler = chart.getZr().handler;
|
||||
|
||||
const touch = {
|
||||
x: 999999999,
|
||||
y: 999999999
|
||||
}
|
||||
|
||||
dispatch.call(handler, 'mousemove', touch)
|
||||
dispatch.call(handler, 'touchend', touch)
|
||||
|
||||
}
|
||||
async function init(echarts: any, ...args: any[]): Promise<Echarts>{
|
||||
if(echarts == null){
|
||||
console.error('请确保已经引入了 ECharts 库');
|
||||
return Promise.reject('请确保已经引入了 ECharts 库');
|
||||
}
|
||||
let theme:string|null=null
|
||||
let opts={}
|
||||
let callback:Function|null=null;
|
||||
|
||||
args.forEach(item =>{
|
||||
if(typeof item === 'function') {
|
||||
callback = item
|
||||
} else if(['string'].includes(typeof item)){
|
||||
theme = item
|
||||
} else if(typeof item === 'object'){
|
||||
opts = item
|
||||
}
|
||||
})
|
||||
|
||||
// #ifdef WEB
|
||||
chart = echarts.init(chartRef.value, theme, opts)
|
||||
window.addEventListener('touchstart', touchstart)
|
||||
window.addEventListener('touchmove', touchmove)
|
||||
window.addEventListener('touchend', touchend)
|
||||
// #endif
|
||||
|
||||
// #ifndef WEB
|
||||
let config = await getContext();
|
||||
setCanvasCreator(echarts, config)
|
||||
chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
||||
// #endif
|
||||
console.log('chart', chart)
|
||||
if(callback!=null && typeof callback == 'function'){
|
||||
callbackMap.push(callback)
|
||||
}
|
||||
return new Promise<Echarts>((resolve) => {
|
||||
map.push(resolve)
|
||||
trigger()
|
||||
})
|
||||
}
|
||||
onMounted(()=>{
|
||||
nextTick(()=>{
|
||||
finished.value = true
|
||||
trigger()
|
||||
emits('finished')
|
||||
})
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
// #ifdef WEB
|
||||
window.removeEventListener('touchstart', touchstart)
|
||||
window.removeEventListener('touchmove', touchmove)
|
||||
window.removeEventListener('touchend', touchend)
|
||||
// #endif
|
||||
})
|
||||
// #endif
|
||||
|
||||
defineExpose({
|
||||
init,
|
||||
setOption,
|
||||
showLoading,
|
||||
hideLoading,
|
||||
clear,
|
||||
dispose,
|
||||
resize,
|
||||
canvasToTempFilePath
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.lime-echart {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
530
uni_modules/lime-echart/components/l-echart/l-echart.vue
Normal file
530
uni_modules/lime-echart/components/l-echart/l-echart.vue
Normal file
@ -0,0 +1,530 @@
|
||||
<template>
|
||||
<view class="lime-echart" :style="[customStyle]" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<canvas
|
||||
class="lime-echart__canvas"
|
||||
v-if="use2dCanvas"
|
||||
type="2d"
|
||||
:id="canvasId"
|
||||
:style="canvasStyle"
|
||||
:disable-scroll="isDisableScroll"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd"
|
||||
/>
|
||||
<canvas
|
||||
class="lime-echart__canvas"
|
||||
v-else
|
||||
:width="nodeWidth"
|
||||
:height="nodeHeight"
|
||||
:style="canvasStyle"
|
||||
:canvas-id="canvasId"
|
||||
:id="canvasId"
|
||||
:disable-scroll="isDisableScroll"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd"
|
||||
/>
|
||||
<view class="lime-echart__mask"
|
||||
v-if="isPC"
|
||||
@mousedown="touchStart"
|
||||
@mousemove="touchMove"
|
||||
@mouseup="touchEnd"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd">
|
||||
</view>
|
||||
<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<web-view
|
||||
class="lime-echart__canvas"
|
||||
:id="canvasId"
|
||||
:style="canvasStyle"
|
||||
:webview-styles="webviewStyles"
|
||||
ref="webview"
|
||||
src="/uni_modules/lime-echart/static/uvue.html?v=1"
|
||||
@pagefinish="finished = true"
|
||||
@onPostMessage="onMessage"
|
||||
></web-view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-NVUE
|
||||
import {Canvas, setCanvasCreator, dispatch} from './canvas';
|
||||
import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo} from './utils';
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
import { base64ToPath, sleep } from './utils';
|
||||
import {Echarts} from './nvue'
|
||||
// #endif
|
||||
const charts = {}
|
||||
const echartsObj = {}
|
||||
|
||||
|
||||
/**
|
||||
* LimeChart 图表
|
||||
* @description 全端兼容的eCharts
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=4899
|
||||
|
||||
* @property {String} customStyle 自定义样式
|
||||
* @property {String} type 指定 canvas 类型
|
||||
* @value 2d 使用canvas 2d,部分小程序支持
|
||||
* @value '' 使用原生canvas,会有层级问题
|
||||
* @value bottom right 不缩放图片,只显示图片的右下边区域
|
||||
* @property {Boolean} isDisableScroll
|
||||
* @property {number} beforeDelay = [30] 延迟初始化 (毫秒)
|
||||
* @property {Boolean} enableHover PC端使用鼠标悬浮
|
||||
|
||||
* @event {Function} finished 加载完成触发
|
||||
*/
|
||||
export default {
|
||||
name: 'lime-echart',
|
||||
props: {
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||
type: {
|
||||
type: String,
|
||||
default: '2d'
|
||||
},
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
webviewStyles: Object,
|
||||
// hybrid: Boolean,
|
||||
// #endif
|
||||
customStyle: String,
|
||||
isDisableScroll: Boolean,
|
||||
isClickable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
enableHover: Boolean,
|
||||
beforeDelay: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
landscape: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
use2dCanvas: true,
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
use2dCanvas: false,
|
||||
// #endif
|
||||
ariaLabel: '图表',
|
||||
width: null,
|
||||
height: null,
|
||||
nodeWidth: null,
|
||||
nodeHeight: null,
|
||||
// canvasNode: null,
|
||||
config: {},
|
||||
inited: false,
|
||||
finished: false,
|
||||
file: '',
|
||||
platform: '',
|
||||
isPC: false,
|
||||
isDown: false,
|
||||
isOffscreenCanvas: false,
|
||||
offscreenWidth: 0,
|
||||
offscreenHeight: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
rootStyle() {
|
||||
if(this.landscape) {
|
||||
return `transform: translate(-50%,-50%) rotate(90deg); top:50%; left:50%;`
|
||||
}
|
||||
},
|
||||
canvasId() {
|
||||
return `lime-echart${this._ && this._.uid || this._uid}`
|
||||
},
|
||||
offscreenCanvasId() {
|
||||
return `${this.canvasId}_offscreen`
|
||||
},
|
||||
offscreenStyle() {
|
||||
return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
|
||||
},
|
||||
canvasStyle() {
|
||||
return this.rootStyle + (this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : '')
|
||||
}
|
||||
},
|
||||
// #ifndef VUE3
|
||||
beforeDestroy() {
|
||||
this.clear()
|
||||
this.dispose()
|
||||
// #ifdef H5
|
||||
if(this.isPC) {
|
||||
document.removeEventListener('mousewheel', this.mousewheel)
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
beforeUnmount() {
|
||||
this.clear()
|
||||
this.dispose()
|
||||
// #ifdef H5
|
||||
if(this.isPC) {
|
||||
document.removeEventListener('mousewheel', this.mousewheel)
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
// #endif
|
||||
created() {
|
||||
// #ifdef H5
|
||||
if(!('ontouchstart' in window)) {
|
||||
this.isPC = true
|
||||
document.addEventListener('mousewheel', this.mousewheel)
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
// const { platform } = uni.getSystemInfoSync();
|
||||
const { platform } = getDeviceInfo();
|
||||
this.isPC = /windows/i.test(platform)
|
||||
// #endif
|
||||
this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('finished')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// #ifdef APP-NVUE
|
||||
onMessage(e) {
|
||||
const detail = e?.detail?.data[0] || null;
|
||||
const data = detail?.data
|
||||
const key = detail?.event
|
||||
const options = data?.options
|
||||
const event = data?.event
|
||||
const file = detail?.file
|
||||
if (key == 'log' && data) {
|
||||
console.log(data)
|
||||
}
|
||||
if(event) {
|
||||
this.chart.dispatchAction(event.replace(/"/g,''), options)
|
||||
}
|
||||
if(file) {
|
||||
thie.file = file
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
setChart(callback) {
|
||||
if(!this.chart) {
|
||||
console.warn(`组件还未初始化,请先使用 init`)
|
||||
return
|
||||
}
|
||||
if(typeof callback === 'function' && this.chart) {
|
||||
callback(this.chart);
|
||||
}
|
||||
// #ifdef APP-NVUE
|
||||
if(typeof callback === 'function') {
|
||||
this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
setOption() {
|
||||
if (!this.chart || !this.chart.setOption) {
|
||||
console.warn(`组件还未初始化,请先使用 init`)
|
||||
return
|
||||
}
|
||||
this.chart.setOption(...arguments);
|
||||
},
|
||||
showLoading() {
|
||||
if(this.chart) {
|
||||
this.chart.showLoading(...arguments)
|
||||
}
|
||||
},
|
||||
hideLoading() {
|
||||
if(this.chart) {
|
||||
this.chart.hideLoading()
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
if(this.chart) {
|
||||
this.chart.clear()
|
||||
}
|
||||
},
|
||||
dispose() {
|
||||
if(this.chart) {
|
||||
this.chart.dispose()
|
||||
}
|
||||
},
|
||||
resize(size) {
|
||||
if(size && size.width && size.height) {
|
||||
this.height = size.height
|
||||
this.width = size.width
|
||||
if(this.chart) {this.chart.resize(size)}
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`.lime-echart`)
|
||||
.boundingClientRect()
|
||||
.exec(res => {
|
||||
if (res) {
|
||||
let { width, height } = res[0];
|
||||
this.width = width = width || 300;
|
||||
this.height = height = height || 300;
|
||||
this.chart.resize({width, height})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
canvasToTempFilePath(args = {}) {
|
||||
// #ifndef APP-NVUE
|
||||
const { use2dCanvas, canvasId } = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
const copyArgs = Object.assign({
|
||||
canvasId,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
}, args);
|
||||
if (use2dCanvas) {
|
||||
delete copyArgs.canvasId;
|
||||
copyArgs.canvas = this.canvasNode;
|
||||
}
|
||||
uni.canvasToTempFilePath(copyArgs, this);
|
||||
});
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.file = ''
|
||||
this.$refs.webview.evalJs(`canvasToTempFilePath()`);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$watch('file', async (file) => {
|
||||
if(file) {
|
||||
const tempFilePath = await base64ToPath(file)
|
||||
resolve(args.success({tempFilePath}))
|
||||
} else {
|
||||
reject(args.fail({error: ``}))
|
||||
}
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
async init(echarts, ...args) {
|
||||
// #ifndef APP-NVUE
|
||||
if(args && args.length == 0 && !echarts) {
|
||||
console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
let theme=null,opts={},callback;
|
||||
|
||||
Array.from(arguments).forEach(item => {
|
||||
if(typeof item === 'function') {
|
||||
callback = item
|
||||
}
|
||||
if(['string'].includes(typeof item)) {
|
||||
theme = item
|
||||
}
|
||||
if(typeof item === 'object') {
|
||||
opts = item
|
||||
}
|
||||
})
|
||||
|
||||
if(this.beforeDelay) {
|
||||
await sleep(this.beforeDelay)
|
||||
}
|
||||
let config = await this.getContext();
|
||||
// #ifndef APP-NVUE
|
||||
setCanvasCreator(echarts, config)
|
||||
try {
|
||||
this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
||||
if(typeof callback === 'function') {
|
||||
callback(this.chart)
|
||||
} else {
|
||||
return this.chart
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(e.messges)
|
||||
return null
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.chart = new Echarts(this.$refs.webview)
|
||||
this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
|
||||
if(callback) {
|
||||
callback(this.chart)
|
||||
} else {
|
||||
return this.chart
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
getContext() {
|
||||
// #ifdef APP-NVUE
|
||||
if(this.finished) {
|
||||
return Promise.resolve(this.finished)
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
this.$watch('finished', (val) => {
|
||||
if(val) {
|
||||
resolve(this.finished)
|
||||
}
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
return getRect(`#${this.canvasId}`, {context: this, type: this.use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
|
||||
if(res) {
|
||||
let dpr = devicePixelRatio
|
||||
let {width, height, node} = res
|
||||
let canvas;
|
||||
this.width = width = width || 300;
|
||||
this.height = height = height || 300;
|
||||
if(node) {
|
||||
const ctx = node.getContext('2d');
|
||||
canvas = new Canvas(ctx, this, true, node);
|
||||
this.canvasNode = node
|
||||
} else {
|
||||
// #ifdef MP-TOUTIAO
|
||||
dpr = !this.isPC ? devicePixelRatio : 1// 1.25
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY || MP-TOUTIAO
|
||||
dpr = this.isPC ? devicePixelRatio : 1
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY || MP-LARK
|
||||
dpr = devicePixelRatio
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
dpr = 1
|
||||
// #endif
|
||||
this.rect = res
|
||||
this.nodeWidth = width * dpr;
|
||||
this.nodeHeight = height * dpr;
|
||||
const ctx = uni.createCanvasContext(this.canvasId, this);
|
||||
canvas = new Canvas(ctx, this, false);
|
||||
}
|
||||
|
||||
return { canvas, width, height, devicePixelRatio: dpr, node };
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
// #ifndef APP-NVUE
|
||||
getRelative(e, touches) {
|
||||
let { clientX, clientY } = e
|
||||
if(!(clientX && clientY) && touches && touches[0]) {
|
||||
clientX = touches[0].clientX
|
||||
clientY = touches[0].clientY
|
||||
}
|
||||
return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
|
||||
},
|
||||
getTouch(e, touches) {
|
||||
const {x} = touches && touches[0] || {}
|
||||
const touch = x ? touches[0] : this.getRelative(e, touches);
|
||||
if(this.landscape) {
|
||||
[touch.x, touch.y] = [touch.y, this.height - touch.x]
|
||||
}
|
||||
return touch;
|
||||
},
|
||||
touchStart(e) {
|
||||
this.isDown = true
|
||||
const next = () => {
|
||||
const touches = convertTouchesToArray(e.touches)
|
||||
if(this.chart) {
|
||||
const touch = this.getTouch(e, touches)
|
||||
this.startX = touch.x
|
||||
this.startY = touch.y
|
||||
this.startT = new Date()
|
||||
const handler = this.chart.getZr().handler;
|
||||
dispatch.call(handler, 'mousedown', touch)
|
||||
dispatch.call(handler, 'mousemove', touch)
|
||||
handler.processGesture(wrapTouch(e), 'start');
|
||||
clearTimeout(this.endTimer);
|
||||
}
|
||||
|
||||
}
|
||||
if(this.isPC) {
|
||||
getRect(`#${this.canvasId}`, {context: this}).then(res => {
|
||||
this.rect = res
|
||||
next()
|
||||
})
|
||||
return
|
||||
}
|
||||
next()
|
||||
},
|
||||
touchMove(e) {
|
||||
if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
|
||||
const touches = convertTouchesToArray(e.touches)
|
||||
if (this.chart && this.isDown) {
|
||||
const handler = this.chart.getZr().handler;
|
||||
dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
|
||||
handler.processGesture(wrapTouch(e), 'change');
|
||||
}
|
||||
|
||||
},
|
||||
touchEnd(e) {
|
||||
this.isDown = false
|
||||
if (this.chart) {
|
||||
const touches = convertTouchesToArray(e.changedTouches)
|
||||
const {x} = touches && touches[0] || {}
|
||||
const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
|
||||
if(this.landscape) {
|
||||
[touch.x, touch.y] = [touch.y, this.height - touch.x]
|
||||
}
|
||||
const handler = this.chart.getZr().handler;
|
||||
const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
|
||||
dispatch.call(handler, 'mouseup', touch)
|
||||
handler.processGesture(wrapTouch(e), 'end');
|
||||
if(isClick) {
|
||||
dispatch.call(handler, 'click', touch)
|
||||
} else {
|
||||
this.endTimer = setTimeout(() => {
|
||||
dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
|
||||
dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
|
||||
},50)
|
||||
}
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
mousewheel(e){
|
||||
if(this.chart) {
|
||||
// dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.lime-echart {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
}
|
||||
.lime-echart__canvas {
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
.lime-echart__mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
51
uni_modules/lime-echart/components/l-echart/nvue.js
Normal file
51
uni_modules/lime-echart/components/l-echart/nvue.js
Normal file
@ -0,0 +1,51 @@
|
||||
export class Echarts {
|
||||
eventMap = new Map()
|
||||
constructor(webview) {
|
||||
this.webview = webview
|
||||
this.options = null
|
||||
}
|
||||
setOption() {
|
||||
this.options = arguments
|
||||
this.webview.evalJs(`setOption(${JSON.stringify(arguments)})`);
|
||||
}
|
||||
getOption() {
|
||||
return this.options
|
||||
}
|
||||
showLoading() {
|
||||
this.webview.evalJs(`showLoading(${JSON.stringify(arguments)})`);
|
||||
}
|
||||
hideLoading() {
|
||||
this.webview.evalJs(`hideLoading()`);
|
||||
}
|
||||
clear() {
|
||||
this.webview.evalJs(`clear()`);
|
||||
}
|
||||
dispose() {
|
||||
this.webview.evalJs(`dispose()`);
|
||||
}
|
||||
resize(size) {
|
||||
if(size) {
|
||||
this.webview.evalJs(`resize(${JSON.stringify(size)})`);
|
||||
} else {
|
||||
this.webview.evalJs(`resize()`);
|
||||
}
|
||||
}
|
||||
on(type, ...args) {
|
||||
const query = args[0]
|
||||
const useQuery = query && typeof query != 'function'
|
||||
const param = useQuery ? [type, query] : [type]
|
||||
const key = `${type}${useQuery ? JSON.stringify(query): '' }`
|
||||
const callback = useQuery ? args[1]: args[0]
|
||||
if(typeof callback == 'function'){
|
||||
this.eventMap.set(key, callback)
|
||||
}
|
||||
this.webview.evalJs(`on(${JSON.stringify(param)})`);
|
||||
console.warn('nvue 暂不支持事件')
|
||||
}
|
||||
dispatchAction(type, options){
|
||||
const handler = this.eventMap.get(type)
|
||||
if(handler){
|
||||
handler(options)
|
||||
}
|
||||
}
|
||||
}
|
190
uni_modules/lime-echart/components/l-echart/utils.js
Normal file
190
uni_modules/lime-echart/components/l-echart/utils.js
Normal file
@ -0,0 +1,190 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 获取设备基础信息
|
||||
*
|
||||
* @see [uni.getDeviceInfo](https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html)
|
||||
*/
|
||||
export function getDeviceInfo() {
|
||||
if (uni.getDeviceInfo && uni.canIUse('getDeviceInfo')) {
|
||||
return uni.getDeviceInfo();
|
||||
} else {
|
||||
return uni.getSystemInfoSync();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取窗口信息
|
||||
*
|
||||
* @see [uni.getWindowInfo](https://uniapp.dcloud.net.cn/api/system/getWindowInfo.html)
|
||||
*/
|
||||
export function getWindowInfo() {
|
||||
if (uni.getWindowInfo && uni.canIUse('getWindowInfo')) {
|
||||
return uni.getWindowInfo();
|
||||
} else {
|
||||
return uni.getSystemInfoSync();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取APP基础信息
|
||||
*
|
||||
* @see [uni.getAppBaseInfo](https://uniapp.dcloud.net.cn/api/system/getAppBaseInfo.html)
|
||||
*/
|
||||
export function getAppBaseInfo() {
|
||||
if (uni.getAppBaseInfo && uni.canIUse('getAppBaseInfo')) {
|
||||
return uni.getAppBaseInfo();
|
||||
} else {
|
||||
return uni.getSystemInfoSync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #ifndef APP-NVUE
|
||||
// 计算版本
|
||||
export function compareVersion(v1, v2) {
|
||||
v1 = v1.split('.')
|
||||
v2 = v2.split('.')
|
||||
const len = Math.max(v1.length, v2.length)
|
||||
while (v1.length < len) {
|
||||
v1.push('0')
|
||||
}
|
||||
while (v2.length < len) {
|
||||
v2.push('0')
|
||||
}
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(v1[i], 10)
|
||||
const num2 = parseInt(v2[i], 10)
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// const systemInfo = uni.getSystemInfoSync();
|
||||
|
||||
function gte(version) {
|
||||
// 截止 2023-03-22 mac pc小程序不支持 canvas 2d
|
||||
// let {
|
||||
// SDKVersion,
|
||||
// platform
|
||||
// } = systemInfo;
|
||||
const { platform } = getDeviceInfo();
|
||||
let { SDKVersion } = getAppBaseInfo();
|
||||
// #ifdef MP-ALIPAY
|
||||
SDKVersion = my.SDKVersion
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
return platform !== 'mac' && compareVersion(SDKVersion, version) >= 0;
|
||||
// #endif
|
||||
return compareVersion(SDKVersion, version) >= 0;
|
||||
}
|
||||
|
||||
|
||||
export function canIUseCanvas2d() {
|
||||
// #ifdef MP-WEIXIN
|
||||
return gte('2.9.0');
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
return gte('2.7.0');
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
return gte('1.78.0');
|
||||
// #endif
|
||||
return false
|
||||
}
|
||||
|
||||
export function convertTouchesToArray(touches) {
|
||||
// 如果 touches 是一个数组,则直接返回它
|
||||
if (Array.isArray(touches)) {
|
||||
return touches;
|
||||
}
|
||||
// 如果touches是一个对象,则转换为数组
|
||||
if (typeof touches === 'object' && touches !== null) {
|
||||
return Object.values(touches);
|
||||
}
|
||||
// 对于其他类型,直接返回它
|
||||
return touches;
|
||||
}
|
||||
|
||||
export function wrapTouch(event) {
|
||||
event.touches = convertTouchesToArray(event.touches)
|
||||
for (let i = 0; i < event.touches.length; ++i) {
|
||||
const touch = event.touches[i];
|
||||
touch.offsetX = touch.x;
|
||||
touch.offsetY = touch.y;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
// export const devicePixelRatio = uni.getSystemInfoSync().pixelRatio
|
||||
export const devicePixelRatio = getWindowInfo().pixelRatio;
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
export function base64ToPath(base64) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
const time = new Date().getTime();
|
||||
const filePath = `_doc/uniapp_temp/${time}.${format}`
|
||||
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
console.error(`${JSON.stringify(error)}`)
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
console.error(`${JSON.stringify(error)}`)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
export function sleep(time) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true)
|
||||
}, time)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function getRect(selector, options = {}) {
|
||||
const typeDefault = 'boundingClientRect'
|
||||
const {
|
||||
context,
|
||||
type = typeDefault
|
||||
} = options
|
||||
return new Promise((resolve, reject) => {
|
||||
const dom = uni.createSelectorQuery().in(context).select(selector);
|
||||
const result = (rect) => {
|
||||
if (rect) {
|
||||
resolve(rect)
|
||||
} else {
|
||||
reject()
|
||||
}
|
||||
}
|
||||
if (type == typeDefault) {
|
||||
dom[type](result).exec()
|
||||
} else {
|
||||
dom[type]({
|
||||
node: true,
|
||||
size: true,
|
||||
rect: true
|
||||
}, result).exec()
|
||||
}
|
||||
});
|
||||
};
|
133
uni_modules/lime-echart/components/l-echart/uvue.uts
Normal file
133
uni_modules/lime-echart/components/l-echart/uvue.uts
Normal file
@ -0,0 +1,133 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP
|
||||
type EchartsEventHandler = (event: UTSJSONObject)=>void
|
||||
// type EchartsTempResolve = (obj : UTSJSONObject) => void
|
||||
// type EchartsTempOptions = UTSJSONObject
|
||||
export class Echarts {
|
||||
options: UTSJSONObject = {} as UTSJSONObject
|
||||
context: UniWebViewElement
|
||||
eventMap: Map<string, EchartsEventHandler> = new Map()
|
||||
private temp: UTSJSONObject[] = []
|
||||
constructor(context: UniWebViewElement){
|
||||
this.context = context
|
||||
this.init()
|
||||
}
|
||||
init(){
|
||||
this.context.evalJS(`init(null, null, ${JSON.stringify({})})`)
|
||||
|
||||
this.context.addEventListener('message', (e : UniWebViewMessageEvent) => {
|
||||
// event.stopPropagation()
|
||||
// event.preventDefault()
|
||||
|
||||
const detail = e.detail.data[0]
|
||||
const file = detail.getString('file')
|
||||
const data = detail.get('data')
|
||||
const key = detail.getString('event')
|
||||
const options = typeof data == 'object' ? (data as UTSJSONObject).getJSON('options'): null
|
||||
const event = typeof data == 'object' ? (data as UTSJSONObject).getString('event'): null
|
||||
if (key == 'log' && data != null) {
|
||||
console.log(data)
|
||||
}
|
||||
if (event != null && options != null) {
|
||||
this.dispatchAction(event.replace(/"/g,''), options)
|
||||
}
|
||||
if(file != null){
|
||||
while (this.temp.length > 0) {
|
||||
const opt = this.temp.pop()
|
||||
const success = opt?.get('success')
|
||||
if(typeof success == 'function'){
|
||||
success as (res: UTSJSONObject) => void
|
||||
success({tempFilePath: file})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
setOption(option: UTSJSONObject){
|
||||
this.options = option;
|
||||
this.context.evalJS(`setOption(${JSON.stringify([option])})`)
|
||||
}
|
||||
setOption(option: UTSJSONObject, notMerge: boolean = false, lazyUpdate: boolean = false){
|
||||
this.options = option;
|
||||
this.context.evalJS(`setOption(${JSON.stringify([option, notMerge, lazyUpdate])})`)
|
||||
}
|
||||
setOption(option: UTSJSONObject, notMerge: UTSJSONObject){
|
||||
this.options = option;
|
||||
this.context.evalJS(`setOption(${JSON.stringify([option, notMerge])})`)
|
||||
}
|
||||
getOption(): UTSJSONObject {
|
||||
return this.options
|
||||
}
|
||||
showLoading(){
|
||||
this.context.evalJS(`showLoading(${JSON.stringify([] as any[])})`);
|
||||
}
|
||||
showLoading(type: string, opts: UTSJSONObject){
|
||||
this.context.evalJS(`showLoading(${JSON.stringify([type, opts])})`);
|
||||
}
|
||||
hideLoading(){
|
||||
this.context.evalJS(`hideLoading()`);
|
||||
}
|
||||
clear(){
|
||||
this.context.evalJS(`clear()`);
|
||||
}
|
||||
dispose(){
|
||||
this.context.evalJS(`dispose()`);
|
||||
}
|
||||
resize(size:UTSJSONObject){
|
||||
setTimeout(()=>{
|
||||
this.context.evalJS(`resize(${JSON.stringify(size)})`);
|
||||
},0)
|
||||
}
|
||||
resize(){
|
||||
setTimeout(()=>{
|
||||
this.context.evalJS(`resize()`);
|
||||
},10)
|
||||
|
||||
}
|
||||
on(type:string, query: any, callback: EchartsEventHandler) {
|
||||
const key = `${type}${JSON.stringify(query)}`
|
||||
if(typeof callback == 'function'){
|
||||
this.eventMap.set(key, callback)
|
||||
}
|
||||
this.context.evalJS(`on(${JSON.stringify([type, query])})`);
|
||||
console.warn('uvue 暂不支持事件')
|
||||
}
|
||||
on(type:string, callback: EchartsEventHandler) {
|
||||
const key = `${type}`
|
||||
if(typeof callback == 'function'){
|
||||
this.eventMap.set(key, callback)
|
||||
}
|
||||
this.context.evalJS(`on(${JSON.stringify([type])})`);
|
||||
console.warn('uvue 暂不支持事件')
|
||||
}
|
||||
dispatchAction(type:string, options: UTSJSONObject){
|
||||
const handler = this.eventMap.get(type)
|
||||
if(handler!=null){
|
||||
handler(options)
|
||||
}
|
||||
}
|
||||
canvasToTempFilePath(opt: UTSJSONObject){
|
||||
// this.context.evalJS(`on(${JSON.stringify(opt)})`);
|
||||
this.context.evalJS(`canvasToTempFilePath(${JSON.stringify(opt)})`);
|
||||
this.temp.push(opt)
|
||||
}
|
||||
}
|
||||
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
export class Echarts {
|
||||
constructor() {}
|
||||
setOption(option: UTSJSONObject): void
|
||||
isDisposed(): boolean;
|
||||
clear(): void;
|
||||
resize(size:UTSJSONObject): void;
|
||||
resize(): void;
|
||||
canvasToTempFilePath(opt : UTSJSONObject): void;
|
||||
dispose(): void;
|
||||
showLoading(cfg?: UTSJSONObject): void;
|
||||
showLoading(name?: string, cfg?: UTSJSONObject): void;
|
||||
hideLoading(): void;
|
||||
getZr(): any
|
||||
}
|
||||
// #endif
|
159
uni_modules/lime-echart/components/lime-echart/lime-echart.nvue
Normal file
159
uni_modules/lime-echart/components/lime-echart/lime-echart.nvue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<view style="width: 100%; height: 408px;">
|
||||
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showTip: false,
|
||||
option: {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// shadowBlur: 0,
|
||||
textStyle: {
|
||||
textShadowBlur: 0
|
||||
},
|
||||
renderMode: 'richText',
|
||||
},
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [120, 132, 101, 134, 90, 230, 210]
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [220, 182, 191, 234, 290, 330, 310]
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [150, 232, 201, 154, 190, 330, 410]
|
||||
},
|
||||
{
|
||||
name: '直接访问',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [320, 332, 301, 334, 390, 330, 320]
|
||||
},
|
||||
{
|
||||
name: '搜索引擎',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log('lime echarts nvue')
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const chartRef = this.$refs['chartRef']
|
||||
chartRef.init(chart => {
|
||||
chart.setOption(this.option);
|
||||
|
||||
|
||||
setTimeout(()=>{
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// shadowBlur: 0,
|
||||
textStyle: {
|
||||
textShadowBlur: 0
|
||||
},
|
||||
renderMode: 'richText',
|
||||
},
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [120, 132, 101, 134, 90, 230, 210]
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [220, 182, 191, 234, 290, 330, 310]
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [150, 232, 201, 154, 190, 330, 410]
|
||||
},
|
||||
{
|
||||
name: '直接访问',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [320, 332, 301, 334, 390, 330, 320]
|
||||
},
|
||||
{
|
||||
name: '搜索引擎',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option);
|
||||
},1000)
|
||||
})
|
||||
},
|
||||
save() {
|
||||
// this.$refs.chart.canvasToTempFilePath({
|
||||
// success(res) {
|
||||
// console.log('res::::', res)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
160
uni_modules/lime-echart/components/lime-echart/lime-echart.uvue
Normal file
160
uni_modules/lime-echart/components/lime-echart/lime-echart.uvue
Normal file
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<view style="width: 100%; height: 408px;">
|
||||
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
// @ts-nocheck
|
||||
// #ifndef APP
|
||||
import * as echarts from 'echarts/dist/echarts.esm.js'
|
||||
// #endif
|
||||
const chartRef = ref<LEchartComponentPublicInstance|null>(null)
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// shadowBlur: 0,
|
||||
textStyle: {
|
||||
textShadowBlur: 0
|
||||
},
|
||||
renderMode: 'richText',
|
||||
},
|
||||
// formatter: async (params: any) => {
|
||||
// console.log('params', params)
|
||||
// return 1
|
||||
// },
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [120, 132, 101, 134, 90, 230, 210]
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [220, 182, 191, 234, 290, 330, 310]
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [150, 232, 201, 154, 190, 330, 410]
|
||||
},
|
||||
{
|
||||
name: '直接访问',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [320, 332, 301, 334, 390, 330, 320]
|
||||
},
|
||||
{
|
||||
name: '搜索引擎',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const init = async () =>{
|
||||
if(chartRef.value== null) return
|
||||
// #ifdef APP
|
||||
const chart = await chartRef.value!.init(null)
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
const chart = await chartRef.value!.init(echarts, null)
|
||||
// #endif
|
||||
chart.setOption(option)
|
||||
chart.on('mouseover', function (params) {
|
||||
console.log('params', params);
|
||||
});
|
||||
|
||||
|
||||
// setTimeout(()=> {
|
||||
// const option1 = {
|
||||
// tooltip: {
|
||||
// trigger: 'axis',
|
||||
// // shadowBlur: 0,
|
||||
// textStyle: {
|
||||
// textShadowBlur: 0
|
||||
// },
|
||||
// renderMode: 'richText',
|
||||
// },
|
||||
// legend: {
|
||||
// data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||
// },
|
||||
// grid: {
|
||||
// left: '3%',
|
||||
// right: '4%',
|
||||
// bottom: '3%',
|
||||
// containLabel: true
|
||||
// },
|
||||
// xAxis: {
|
||||
// type: 'category',
|
||||
// boundaryGap: false,
|
||||
// data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value'
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: '邮件营销',
|
||||
// type: 'line',
|
||||
// stack: '总量',
|
||||
// data: [820, 132, 101, 134, 90, 230, 210]
|
||||
// },
|
||||
// {
|
||||
// name: '联盟广告',
|
||||
// type: 'line',
|
||||
// stack: '总量',
|
||||
// data: [220, 182, 191, 234, 290, 330, 310]
|
||||
// },
|
||||
// {
|
||||
// name: '视频广告',
|
||||
// type: 'line',
|
||||
// stack: '总量',
|
||||
// data: [950, 232, 201, 154, 190, 330, 410]
|
||||
// },
|
||||
// {
|
||||
// name: '直接访问',
|
||||
// type: 'line',
|
||||
// stack: '总量',
|
||||
// data: [320, 332, 301, 334, 390, 330, 320]
|
||||
// },
|
||||
// {
|
||||
// name: '搜索引擎',
|
||||
// type: 'line',
|
||||
// stack: '总量',
|
||||
// data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// chart.setOption(option1)
|
||||
// },1000)
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
227
uni_modules/lime-echart/components/lime-echart/lime-echart.vue
Normal file
227
uni_modules/lime-echart/components/lime-echart/lime-echart.vue
Normal file
@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<view>
|
||||
<view style="height: 750rpx; position: relative">
|
||||
<l-echart ref="chart" @finished="init"></l-echart>
|
||||
<view
|
||||
class="customTooltips"
|
||||
:style="{ left: position[0] + 'px', top: position[1] + 'px' }"
|
||||
v-if="params.length && position.length && showTip"
|
||||
>
|
||||
<view>这是个自定的tooltips</view>
|
||||
<view>{{ params[0]['axisValue'] }}</view>
|
||||
<view v-for="item in params">
|
||||
<view>
|
||||
<text>{{ item.seriesName }}</text>
|
||||
<text>{{ item.value }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// nvue 不需要引入
|
||||
// #ifdef VUE2
|
||||
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
// #ifdef MP
|
||||
// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
|
||||
const echarts = require('../../static/echarts.min')
|
||||
// #endif
|
||||
// #ifndef MP
|
||||
// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
|
||||
import * as echarts from 'echarts/dist/echarts.esm'
|
||||
// #endif
|
||||
// #endif
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showTip: false,
|
||||
position: [],
|
||||
params: [],
|
||||
option: {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// shadowBlur: 0,
|
||||
textStyle: {
|
||||
textShadowBlur: 0,
|
||||
},
|
||||
renderMode: 'richText',
|
||||
position: (point, params, dom, rect, size) => {
|
||||
// 假设自定义的tooltips尺寸
|
||||
const box = [170, 170]
|
||||
// 偏移
|
||||
const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20
|
||||
const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20
|
||||
const x = point[0] + offsetX
|
||||
const y = point[1] + offsetY
|
||||
|
||||
this.position = [x, y]
|
||||
this.params = params
|
||||
},
|
||||
formatter: (params, ticket, callback) => {},
|
||||
},
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [150, 232, 201, 154, 190, 330, 410],
|
||||
},
|
||||
{
|
||||
name: '直接访问',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [320, 332, 301, 334, 390, 330, 320],
|
||||
},
|
||||
{
|
||||
name: '搜索引擎',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
// init(echarts, theme?:string, opts?:{}, chart => {})
|
||||
// echarts 必填, 非nvue必填,nvue不用填
|
||||
// theme 可选,应用的主题,目前只支持名称,如:'dark'
|
||||
// opts = { // 可选
|
||||
// locale?: string // 从 `5.0.0` 开始支持
|
||||
// }
|
||||
// chart => {} , callback 返回图表实例
|
||||
// setTimeout(()=>{
|
||||
// this.$refs.chart.init(echarts, chart => {
|
||||
// chart.setOption(this.option);
|
||||
// });
|
||||
// },300)
|
||||
this.$refs.chart.init(echarts, (chart) => {
|
||||
chart.setOption(this.option)
|
||||
|
||||
// 监听tooltip显示事件
|
||||
chart.on('showTip', (params) => {
|
||||
this.showTip = true
|
||||
console.log('showTip::')
|
||||
})
|
||||
chart.on('hideTip', (params) => {
|
||||
setTimeout(() => {
|
||||
this.showTip = false
|
||||
}, 300)
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// shadowBlur: 0,
|
||||
textStyle: {
|
||||
textShadowBlur: 0,
|
||||
},
|
||||
renderMode: 'richText',
|
||||
},
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [1120, 132, 101, 134, 90, 230, 210],
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [150, 632, 201, 154, 190, 330, 410],
|
||||
},
|
||||
{
|
||||
name: '直接访问',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 332, 301, 334, 390, 330, 320],
|
||||
},
|
||||
{
|
||||
name: '搜索引擎',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
},
|
||||
],
|
||||
}
|
||||
chart.setOption(option)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
save() {
|
||||
this.$refs.chart.canvasToTempFilePath({
|
||||
success(res) {
|
||||
console.log('res::::', res)
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.customTooltips {
|
||||
position: absolute;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
91
uni_modules/lime-echart/package.json
Normal file
91
uni_modules/lime-echart/package.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"id": "lime-echart",
|
||||
"displayName": "echarts",
|
||||
"version": "0.9.8",
|
||||
"description": "echarts 全端兼容,一款使echarts图表能跑在uniapp各端中的插件, 支持uniapp/uniappx(web,ios,安卓)",
|
||||
"keywords": [
|
||||
"echarts",
|
||||
"canvas",
|
||||
"图表",
|
||||
"可视化"
|
||||
],
|
||||
"repository": "https://gitee.com/liangei/lime-echart",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.6.4"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y",
|
||||
"app-uvue": "y",
|
||||
"app-harmony": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"echarts": "^5.4.1",
|
||||
"zrender": "^5.4.3"
|
||||
}
|
||||
}
|
407
uni_modules/lime-echart/readme.md
Normal file
407
uni_modules/lime-echart/readme.md
Normal file
@ -0,0 +1,407 @@
|
||||
# echarts 图表 <span style="font-size:16px;">👑👑👑👑👑 <span style="background:#ff9d00;padding:2px 4px;color:#fff;font-size:10px;border-radius: 3px;">全端</span></span>
|
||||
> 一个基于 JavaScript 的开源可视化图表库 [查看更多](https://limeui.qcoon.cn/#/echart) <br>
|
||||
> 基于 echarts 做了兼容处理,更多示例请访问 [uni示例](https://limeui.qcoon.cn/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html) <br>
|
||||
|
||||
|
||||
## 平台兼容
|
||||
|
||||
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
|
||||
| --- | ---------- | ------------ | ---------- | ---------- | --------- | ---- |
|
||||
| √ | √ | √ | √ | √ | √ | √ |
|
||||
|
||||
|
||||
## 安装
|
||||
- 第一步:在市场导入 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899)
|
||||
- 第二步:选择插件依赖:<br>
|
||||
1、可以选插件内的`echarts`包或自定义包,自定义包[下载地址](https://echarts.apache.org/zh/builder.html)<br>
|
||||
2、或者使用`npm`安装`echarts`
|
||||
|
||||
**注意**
|
||||
* 🔔 echarts 5.3.0及以上
|
||||
* 🔔 如果是 `cli` 项目请下载插件到`src`目录下的`uni_modules`,没有这个目录就创建一个
|
||||
|
||||
|
||||
## 代码演示
|
||||
|
||||
### Vue2
|
||||
- 引入依赖,可以是插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html),也可以是`npm`包
|
||||
|
||||
```html
|
||||
<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef" @finished="init"></l-echart></view>
|
||||
```
|
||||
|
||||
```js
|
||||
// 插件内的 三选一
|
||||
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||||
// 自定义的 三选一 下载后放入项目的路径
|
||||
import * as echarts from 'xxx/echarts.min'
|
||||
// npm包 三选一 需要在控制台 输入命令:npm install echarts
|
||||
import * as echarts from 'echarts'
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
option: {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
confine: true
|
||||
},
|
||||
legend: {
|
||||
data: ['热度', '正面', '负面']
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 15,
|
||||
top: 40,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
axisTick: { show: false },
|
||||
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '热度',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'inside'
|
||||
}
|
||||
},
|
||||
data: [300, 270, 340, 344, 300, 320, 310],
|
||||
},
|
||||
{
|
||||
name: '正面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [120, 102, 141, 174, 190, 250, 220]
|
||||
},
|
||||
{
|
||||
name: '负面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'left'
|
||||
}
|
||||
},
|
||||
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
||||
},
|
||||
// 组件能被调用必须是组件的节点已经被渲染到页面上
|
||||
methods: {
|
||||
async init() {
|
||||
// chart 图表实例不能存在data里
|
||||
const chart = await this.$refs.chartRef.init(echarts);
|
||||
chart.setOption(this.option)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Vue3
|
||||
- 小程序可以使用`require`引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
|
||||
- `require`仅支持相对路径,不支持路径别名
|
||||
- 非小程序使用 `npm` 包
|
||||
|
||||
|
||||
```html
|
||||
<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef"></l-echart></view>
|
||||
```
|
||||
|
||||
```js
|
||||
// 小程序 二选一
|
||||
// 插件内的 二选一
|
||||
const echarts = require('../../uni_modules/lime-echart/static/echarts.min');
|
||||
// 自定义的 二选一 下载后放入项目的路径
|
||||
const echarts = require('xxx/xxx/echarts');
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// 非小程序
|
||||
// 需要在控制台 输入命令:npm install echarts
|
||||
import * as echarts from 'echarts'
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
const chartRef = ref(null)
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
confine: true
|
||||
},
|
||||
legend: {
|
||||
data: ['热度', '正面', '负面']
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 15,
|
||||
top: 40,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
axisTick: { show: false },
|
||||
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '热度',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'inside'
|
||||
}
|
||||
},
|
||||
data: [300, 270, 340, 344, 300, 320, 310],
|
||||
},
|
||||
{
|
||||
name: '正面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [120, 102, 141, 174, 190, 250, 220]
|
||||
},
|
||||
{
|
||||
name: '负面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'left'
|
||||
}
|
||||
},
|
||||
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
onMounted( ()=>{
|
||||
// 组件能被调用必须是组件的节点已经被渲染到页面上
|
||||
setTimeout(async()=>{
|
||||
if(!chartRef.value) return
|
||||
const myChart = await chartRef.value.init(echarts)
|
||||
myChart.setOption(option)
|
||||
},300)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Uvue
|
||||
- Uvue和Nvue不需要引入`echarts`,因为它们的实现方式是`webview`
|
||||
- uniapp x需要HBX 4.13以上
|
||||
|
||||
```html
|
||||
<view style="width: 100%; height: 408px;">
|
||||
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||
</view>
|
||||
```
|
||||
|
||||
```js
|
||||
// @ts-nocheck
|
||||
// #ifdef H5
|
||||
import * as echarts from 'echarts/dist/echarts.esm.js'
|
||||
// #endif
|
||||
const chartRef = ref<LEchartComponentPublicInstance|null>(null);
|
||||
const init = async () => {
|
||||
if(chartRef.value== null) return
|
||||
// #ifdef APP
|
||||
const chart = await chartRef.value!.init(null)
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
const chart = await chartRef.value!.init(echarts, null)
|
||||
// #endif
|
||||
chart.setOption(option)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 数据更新
|
||||
- 1、使用 `ref` 可获取`setOption`设置更新
|
||||
- 2、也可以拿到图表实例`chart`设置`myChart.setOption(data)`
|
||||
|
||||
```js
|
||||
// ref
|
||||
this.$refs.chart.setOption(data)
|
||||
|
||||
// 图表实例
|
||||
myChart.setOption(data)
|
||||
```
|
||||
|
||||
## 图表大小
|
||||
- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
|
||||
|
||||
```js
|
||||
// 默认获取容器尺寸
|
||||
this.$refs.chart.resize()
|
||||
// 指定尺寸
|
||||
this.$refs.chart.resize({width: 375, height: 375})
|
||||
```
|
||||
|
||||
## 自定义Tooltips
|
||||
- uvue\nvue 不支持
|
||||
由于除H5之外都不存在dom,但又有tooltips个性化的需求,代码就不贴了,看示例吧
|
||||
```
|
||||
代码位于/uni_modules/lime-echart/component/lime-echart
|
||||
```
|
||||
|
||||
|
||||
## 插件标签
|
||||
- 默认 l-echart 为 component
|
||||
- 默认 lime-echart 为 demo
|
||||
```html
|
||||
// 在任意地方使用可查看domo, 代码位于/uni_modules/lime-echart/component/lime-echart
|
||||
<lime-echart></lime-echart>
|
||||
```
|
||||
|
||||
|
||||
## 常见问题
|
||||
- 钉钉小程序 由于没有`measureText`,模拟的`measureText`又无法得到当前字体的`fontWeight`,故可能存在估计不精细的问题
|
||||
- 微信小程序 `2d` 只支持 真机调试2.0
|
||||
- 微信开发工具会出现 `canvas` 不跟随页面的情况,真机不影响
|
||||
- 微信开发工具会出现 `canvas` 层级过高的问题,真机一般不受影响,可以先测只有两个元素的页面看是否会有层级问题。
|
||||
- toolbox 不支持 `saveImage`
|
||||
- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
|
||||
- dataZoom H5不要设置 `showDetail`
|
||||
- 如果微信小程序的`tooltip`文字有阴影,可能是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
|
||||
- 如果钉钉小程序上传时报安全问题`Uint8Clamped`,可以向钉钉反馈是安全代码扫描把Uint8Clamped数组错误识别了,也可以在 echarts 文件修改`Uint8Clamped`
|
||||
```js
|
||||
// 找到这段代码把代码中`Uint8Clamped`改成`Uint8_Clamped`,再把下划线去掉,不过直接去掉`Uint8Clamped`也是可行的
|
||||
// ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
|
||||
// 改成如下
|
||||
["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
|
||||
```
|
||||
|
||||
### vue3
|
||||
如果您是使用 **vite + vue3** 非微信小程序可能会遇到`echarts`文件缺少`wx`判断导致无法使用或缺少`tooltip`<br>
|
||||
|
||||
方式一:可以在`echarts.min.js`文件开头增加以下内容,参考插件内的echart.min.js的做法
|
||||
|
||||
```js
|
||||
let global = null
|
||||
let wx = uni
|
||||
```
|
||||
|
||||
方式二:在`vite.config.js`的`define`设置环境
|
||||
|
||||
```js
|
||||
// 或者在`vite.config.js`的`define`设置环境
|
||||
import { defineConfig } from 'vite';
|
||||
import uni from '@dcloudio/vite-plugin-uni';
|
||||
|
||||
const define = {}
|
||||
if(!["mp-weixin", "h5", "web"].includes(process.env.UNI_PLATFORM)) {
|
||||
define['global'] = null
|
||||
define['wx'] = 'uni'
|
||||
}
|
||||
export default defineConfig({
|
||||
plugins: [uni()],
|
||||
define
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------------- | -------- | ------- | ------------ | ----- |
|
||||
| custom-style | 自定义样式 | `string` | - | - |
|
||||
| type | 指定 canvas 类型 | `string` | `2d` | |
|
||||
| is-disable-scroll | 触摸图表时是否禁止页面滚动 | `boolean` | `false` | |
|
||||
| beforeDelay | 延迟初始化 (毫秒) | `number` | `30` | |
|
||||
| enableHover | PC端使用鼠标悬浮 | `boolean` | `false` | |
|
||||
| landscape | 是否旋转90deg,模拟横屏效果 | `boolean` | `false` | |
|
||||
|
||||
## 事件
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --------------- | --------------- |
|
||||
| init(echarts, chart => {}) | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例 |
|
||||
| setChart(chart => {}) | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例 |
|
||||
| setOption(data) | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option` |
|
||||
| clear() | 清空当前实例,会移除实例中所有的组件和图表。 |
|
||||
| dispose() | 销毁实例 |
|
||||
| showLoading() | 显示加载 |
|
||||
| hideLoading() | 隐藏加载 |
|
||||
| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt) | 用于生成图片,与官方使用方法一致,但不需要传`canvasId` |
|
||||
|
||||
|
||||
## 打赏
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
1
uni_modules/lime-echart/static/ecStat.min.js
vendored
Normal file
1
uni_modules/lime-echart/static/ecStat.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
61
uni_modules/lime-echart/static/echarts.min.js
vendored
Normal file
61
uni_modules/lime-echart/static/echarts.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
uni_modules/lime-echart/static/uni.webview.1.5.5.js
Normal file
1
uni_modules/lime-echart/static/uni.webview.1.5.5.js
Normal file
File diff suppressed because one or more lines are too long
177
uni_modules/lime-echart/static/uvue.html
Normal file
177
uni_modules/lime-echart/static/uvue.html
Normal file
@ -0,0 +1,177 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title></title>
|
||||
<style type="text/css">
|
||||
html,
|
||||
body,
|
||||
.canvas {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow-y: hidden;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="canvas" id="limeChart"></div>
|
||||
<script type="text/javascript" src="./uni.webview.1.5.5.js"></script>
|
||||
<script type="text/javascript" src="./echarts.min.js"></script>
|
||||
<script type="text/javascript" src="./ecStat.min.js"></script>
|
||||
<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
|
||||
<script>
|
||||
let chart = null;
|
||||
let cache = [];
|
||||
console.log = function() {
|
||||
emit('log', {
|
||||
log: arguments,
|
||||
})
|
||||
}
|
||||
|
||||
function emit(event, data) {
|
||||
postMessage({
|
||||
event,
|
||||
data
|
||||
})
|
||||
cache = []
|
||||
}
|
||||
|
||||
function postMessage(data) {
|
||||
uni.webView.postMessage({
|
||||
data
|
||||
})
|
||||
// window.__uniapp_x_.postMessage(JSON.stringify(data))
|
||||
};
|
||||
|
||||
function stringify(key, value) {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) {
|
||||
return;
|
||||
}
|
||||
cache.push(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function parse(name, callback, options) {
|
||||
const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
|
||||
if (optionNameReg.test(callback)) {
|
||||
const optionNames = callback.match(optionNameReg)
|
||||
if (optionNames[1]) {
|
||||
const _this = optionNames[1].split('.')[0]
|
||||
window[_this] = {}
|
||||
window[_this][optionNames[2]] = options
|
||||
return optionNames[2]
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function init(callback, options, opts, theme) {
|
||||
if (!chart) {
|
||||
chart = echarts.init(document.getElementById('limeChart'), theme, opts)
|
||||
|
||||
if (options) {
|
||||
chart.setOption(options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function on(data) {
|
||||
if (chart && data.length > 0) {
|
||||
const [type, query] = data
|
||||
const key = `${type}${JSON.stringify(query||'')}`
|
||||
if (query) {
|
||||
chart.on(type, query, function(options) {
|
||||
var obj = {};
|
||||
Object.keys(options).forEach(function(key) {
|
||||
if (key != 'event') {
|
||||
obj[key] = options[key];
|
||||
}
|
||||
});
|
||||
emit(key, {
|
||||
event: key,
|
||||
options: obj,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
chart.on(type, function(options) {
|
||||
var obj = {};
|
||||
Object.keys(options).forEach(function(key) {
|
||||
if (key != 'event') {
|
||||
obj[key] = options[key];
|
||||
}
|
||||
});
|
||||
emit(key, {
|
||||
event: key,
|
||||
options: obj,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setChart(callback, options) {
|
||||
if (!callback) return
|
||||
if (chart && callback && options) {
|
||||
var r = null
|
||||
const name = parse('r', callback, options)
|
||||
if (name) this[name] = options
|
||||
eval(`r = ${callback};`)
|
||||
if (r) {
|
||||
r(chart)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setOption(data) {
|
||||
if (chart) chart.setOption(data[0], data[1])
|
||||
}
|
||||
|
||||
function showLoading(data) {
|
||||
if (chart) chart.showLoading(data[0], data[1])
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
if (chart) chart.hideLoading()
|
||||
}
|
||||
|
||||
function clear() {
|
||||
if (chart) chart.clear()
|
||||
|
||||
}
|
||||
|
||||
function dispose() {
|
||||
if (chart) chart.dispose()
|
||||
}
|
||||
|
||||
function resize(size) {
|
||||
if (chart) chart.resize(size)
|
||||
}
|
||||
|
||||
function canvasToTempFilePath(opt) {
|
||||
if (chart) {
|
||||
delete opt.success
|
||||
const src = chart.getDataURL(opt)
|
||||
postMessage({
|
||||
// event: 'file',
|
||||
file: src
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('touchmove', () => {
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
// @ts-nocheck
|
||||
import {isNumeric} from '../isNumeric'
|
||||
import {isDef} from '../isDef'
|
||||
/**
|
||||
* 给一个值添加单位(像素 px)
|
||||
* @param value 要添加单位的值,可以是字符串或数字
|
||||
* @returns 添加了单位的值,如果值为 null 则返回 null
|
||||
*/
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export function addUnit(value?: string | number): string | null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = String(value); // 将值转换为字符串
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
function addUnit(value: string): string
|
||||
function addUnit(value: number): string
|
||||
function addUnit(value: any|null): string|null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = `${value}` //value.toString(); // 将值转换为字符串
|
||||
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
export {addUnit}
|
||||
// #endif
|
||||
|
||||
|
||||
// console.log(addUnit(100)); // 输出: "100px"
|
||||
// console.log(addUnit("200")); // 输出: "200px"
|
||||
// console.log(addUnit("300px")); // 输出: "300px"(已经包含单位)
|
||||
// console.log(addUnit()); // 输出: undefined(值为 undefined)
|
||||
// console.log(addUnit(null)); // 输出: undefined(值为 null)
|
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
@ -0,0 +1,82 @@
|
||||
export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
|
||||
const ZERO_LIMIT = 1e-6;
|
||||
// Calculate the polynomial coefficients,
|
||||
// implicit first and last control points are (0,0) and (1,1).
|
||||
const ax = 3 * p1x - 3 * p2x + 1;
|
||||
const bx = 3 * p2x - 6 * p1x;
|
||||
const cx = 3 * p1x;
|
||||
|
||||
const ay = 3 * p1y - 3 * p2y + 1;
|
||||
const by = 3 * p2y - 6 * p1y;
|
||||
const cy = 3 * p1y;
|
||||
|
||||
function sampleCurveDerivativeX(t : number) : number {
|
||||
// `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
|
||||
return (3 * ax * t + 2 * bx) * t + cx;
|
||||
}
|
||||
|
||||
function sampleCurveX(t : number) : number {
|
||||
return ((ax * t + bx) * t + cx) * t;
|
||||
}
|
||||
|
||||
function sampleCurveY(t : number) : number {
|
||||
return ((ay * t + by) * t + cy) * t;
|
||||
}
|
||||
|
||||
// Given an x value, find a parametric value it came from.
|
||||
function solveCurveX(x : number) : number {
|
||||
let t2 = x;
|
||||
let derivative : number;
|
||||
let x2 : number;
|
||||
|
||||
// https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
|
||||
// first try a few iterations of Newton's method -- normally very fast.
|
||||
// http://en.wikipedia.org/wikiNewton's_method
|
||||
for (let i = 0; i < 8; i++) {
|
||||
// f(t) - x = 0
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
derivative = sampleCurveDerivativeX(t2);
|
||||
// == 0, failure
|
||||
/* istanbul ignore if */
|
||||
if (Math.abs(derivative) < ZERO_LIMIT) {
|
||||
break;
|
||||
}
|
||||
t2 -= x2 / derivative;
|
||||
}
|
||||
|
||||
// Fall back to the bisection method for reliability.
|
||||
// bisection
|
||||
// http://en.wikipedia.org/wiki/Bisection_method
|
||||
let t1 = 1;
|
||||
/* istanbul ignore next */
|
||||
let t0 = 0;
|
||||
|
||||
/* istanbul ignore next */
|
||||
t2 = x;
|
||||
/* istanbul ignore next */
|
||||
while (t1 > t0) {
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
if (x2 > 0) {
|
||||
t1 = t2;
|
||||
} else {
|
||||
t0 = t2;
|
||||
}
|
||||
t2 = (t1 + t0) / 2;
|
||||
}
|
||||
|
||||
// Failure
|
||||
return t2;
|
||||
}
|
||||
|
||||
return function (x : number) : number {
|
||||
return sampleCurveY(solveCurveX(x));
|
||||
}
|
||||
|
||||
// return solve;
|
||||
}
|
3
uni_modules/lime-shared/animation/ease.ts
Normal file
3
uni_modules/lime-shared/animation/ease.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import {cubicBezier} from './bezier';
|
||||
export let ease = cubicBezier(0.25, 0.1, 0.25, 1);
|
||||
export let linear = cubicBezier(0,0,1,1);
|
10
uni_modules/lime-shared/animation/index.ts
Normal file
10
uni_modules/lime-shared/animation/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
100
uni_modules/lime-shared/animation/useTransition.ts
Normal file
100
uni_modules/lime-shared/animation/useTransition.ts
Normal file
@ -0,0 +1,100 @@
|
||||
// @ts-nocheck
|
||||
import type { ComponentPublicInstance } from 'vue'
|
||||
import { ease, linear } from './ease';
|
||||
import { Timeline, Animation } from './';
|
||||
export type UseTransitionOptions = {
|
||||
duration ?: number
|
||||
immediate ?: boolean
|
||||
context ?: ComponentPublicInstance
|
||||
}
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import { ref, watch, type Ref } from '@/uni_modules/lime-shared/vue'
|
||||
|
||||
export function useTransition(percent : Ref<number>|(() => number), options : UseTransitionOptions) : Ref<number> {
|
||||
const current = ref(0)
|
||||
const { immediate, duration = 300 } = options
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const isFunction = typeof percent === 'function'
|
||||
watch(isFunction ? percent : () => percent.value, (v) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl.start();
|
||||
tl.add(
|
||||
new Animation(
|
||||
current.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
current.value = nowValue
|
||||
clearTimeout(timer)
|
||||
if(current.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}, { immediate })
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
type UseTransitionReturnType = Ref<number>
|
||||
export function useTransition(source : any, options : UseTransitionOptions) : UseTransitionReturnType {
|
||||
const outputRef : Ref<number> = ref(0)
|
||||
const immediate = options.immediate ?? false
|
||||
const duration = options.duration ?? 300
|
||||
const context = options.context //as ComponentPublicInstance | null
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const watchFunc = (v : number) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl!.start();
|
||||
tl!.add(
|
||||
new Animation(
|
||||
outputRef.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
outputRef.value = nowValue
|
||||
clearTimeout(timer)
|
||||
if(outputRef.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if (context != null && typeof source == 'string') {
|
||||
context.$watch(source, watchFunc, { immediate } as WatchOptions)
|
||||
} else if(typeof source == 'function'){
|
||||
watch(source, watchFunc, { immediate })
|
||||
} else if(source instanceof Ref<number>){
|
||||
watch(source as Ref<number>, watchFunc, { immediate })
|
||||
}
|
||||
|
||||
const stop = ()=>{
|
||||
|
||||
}
|
||||
return outputRef //as UseTransitionReturnType
|
||||
}
|
||||
|
||||
// #endif
|
119
uni_modules/lime-shared/animation/uvue.uts
Normal file
119
uni_modules/lime-shared/animation/uvue.uts
Normal file
@ -0,0 +1,119 @@
|
||||
import { raf, cancelRaf} from '../raf'
|
||||
// @ts-nocheck
|
||||
export class Timeline {
|
||||
state : string
|
||||
animations : Set<Animation> = new Set<Animation>()
|
||||
delAnimations : Animation[] = []
|
||||
startTimes : Map<Animation, number> = new Map<Animation, number>()
|
||||
pauseTime : number = 0
|
||||
pauseStart : number = Date.now()
|
||||
tickHandler : number = 0
|
||||
tickHandlers : number[] = []
|
||||
tick : (() => void) | null = null
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
}
|
||||
start() {
|
||||
if (!(this.state == 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this.pauseTime = 0;
|
||||
this.tick = () => {
|
||||
let now = Date.now();
|
||||
this.animations.forEach((animation : Animation) => {
|
||||
let t:number;
|
||||
const ani = this.startTimes.get(animation)
|
||||
if (ani == null) return
|
||||
if (ani < startTime) {
|
||||
t = now - startTime - animation.delay - this.pauseTime;
|
||||
} else {
|
||||
t = now - ani - animation.delay - this.pauseTime;
|
||||
}
|
||||
if (t > animation.duration) {
|
||||
this.delAnimations.push(animation)
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
// this.animations.delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
while (this.delAnimations.length > 0) {
|
||||
const animation = this.delAnimations.pop();
|
||||
if (animation == null) return
|
||||
this.animations.delete(animation);
|
||||
}
|
||||
// cancelAnimationFrame(this.tickHandler);
|
||||
if (this.state != 'Started') return
|
||||
|
||||
this.tickHandler = raf(()=>{
|
||||
this.tick!()
|
||||
})
|
||||
|
||||
this.tickHandlers.push(this.tickHandler)
|
||||
}
|
||||
if(this.tick != null) {
|
||||
this.tick!()
|
||||
}
|
||||
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
this.pauseStart = Date.now();
|
||||
cancelRaf(this.tickHandler);
|
||||
// cancelRaf(this.tickHandler);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
this.pauseTime += Date.now() - this.pauseStart;
|
||||
this.tick!();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this.pauseTime = 0;
|
||||
this.pauseStart = 0;
|
||||
this.animations.clear()
|
||||
this.delAnimations.clear()
|
||||
this.startTimes.clear()
|
||||
this.tickHandler = 0;
|
||||
}
|
||||
add(animation : Animation, startTime ?: number | null) {
|
||||
if (startTime == null) startTime = Date.now();
|
||||
this.animations.add(animation);
|
||||
this.startTimes.set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue : number
|
||||
endValue : number
|
||||
duration : number
|
||||
timingFunction : (t : number) => number
|
||||
delay : number
|
||||
template : (t : number) => void
|
||||
constructor(
|
||||
startValue : number,
|
||||
endValue : number,
|
||||
duration : number,
|
||||
delay : number,
|
||||
timingFunction : (t : number) => number,
|
||||
template : (v : number) => void) {
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time : number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
123
uni_modules/lime-shared/animation/vue.ts
Normal file
123
uni_modules/lime-shared/animation/vue.ts
Normal file
@ -0,0 +1,123 @@
|
||||
// @ts-nocheck
|
||||
const TICK = Symbol('tick');
|
||||
const TICK_HANDLER = Symbol('tick-handler');
|
||||
const ANIMATIONS = Symbol('animations');
|
||||
const START_TIMES = Symbol('start-times');
|
||||
const PAUSE_START = Symbol('pause-start');
|
||||
const PAUSE_TIME = Symbol('pause-time');
|
||||
const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
|
||||
const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
|
||||
|
||||
// const TICK = 'tick';
|
||||
// const TICK_HANDLER = 'tick-handler';
|
||||
// const ANIMATIONS = 'animations';
|
||||
// const START_TIMES = 'start-times';
|
||||
// const PAUSE_START = 'pause-start';
|
||||
// const PAUSE_TIME = 'pause-time';
|
||||
// const _raf = function(callback):number|null {return setTimeout(callback, 1000/60)}
|
||||
// const _caf = function(id: number):void {clearTimeout(id)}
|
||||
|
||||
export class Timeline {
|
||||
state: string
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
}
|
||||
start() {
|
||||
if (!(this.state === 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[TICK] = () => {
|
||||
let now = Date.now();
|
||||
this[ANIMATIONS].forEach((animation) => {
|
||||
let t: number;
|
||||
if (this[START_TIMES].get(animation) < startTime) {
|
||||
t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
} else {
|
||||
t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
}
|
||||
|
||||
if (t > animation.duration) {
|
||||
this[ANIMATIONS].delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// for (let animation of this[ANIMATIONS]) {
|
||||
// let t: number;
|
||||
// console.log('animation', animation)
|
||||
// if (this[START_TIMES].get(animation) < startTime) {
|
||||
// t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
// } else {
|
||||
// t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
// }
|
||||
|
||||
// if (t > animation.duration) {
|
||||
// this[ANIMATIONS].delete(animation);
|
||||
// t = animation.duration;
|
||||
// }
|
||||
// if (t > 0) animation.run(t);
|
||||
// }
|
||||
this[TICK_HANDLER] = _raf(this[TICK]);
|
||||
};
|
||||
this[TICK]();
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
|
||||
this[PAUSE_START] = Date.now();
|
||||
_caf(this[TICK_HANDLER]);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
|
||||
this[TICK]();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[PAUSE_START] = 0;
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
this[TICK_HANDLER] = null;
|
||||
}
|
||||
add(animation: any, startTime?: number) {
|
||||
if (arguments.length < 2) startTime = Date.now();
|
||||
this[ANIMATIONS].add(animation);
|
||||
this[START_TIMES].set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue: number
|
||||
endValue: number
|
||||
duration: number
|
||||
timingFunction: (t: number) => number
|
||||
delay: number
|
||||
template: (t: number) => void
|
||||
constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
|
||||
timingFunction = timingFunction || (v => v);
|
||||
template = template || (v => v);
|
||||
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time: number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
3888
uni_modules/lime-shared/areaData/city-china.json
Normal file
3888
uni_modules/lime-shared/areaData/city-china.json
Normal file
File diff suppressed because it is too large
Load Diff
71
uni_modules/lime-shared/areaData/index.ts
Normal file
71
uni_modules/lime-shared/areaData/index.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// @ts-nocheck
|
||||
import _areaList from './city-china.json';
|
||||
export const areaList = _areaList
|
||||
// #ifndef UNI-APP-X
|
||||
type UTSJSONObject = Record<string, string>
|
||||
// #endif
|
||||
// #ifdef UNI-APP-X
|
||||
type Object = UTSJSONObject
|
||||
// #endif
|
||||
type AreaList = {
|
||||
province_list : Map<string, string>;
|
||||
city_list : Map<string, string>;
|
||||
county_list : Map<string, string>;
|
||||
}
|
||||
// type CascaderOption = {
|
||||
// text : string;
|
||||
// value : string;
|
||||
// children ?: CascaderOption[];
|
||||
// };
|
||||
|
||||
const makeOption = (
|
||||
label : string,
|
||||
value : string,
|
||||
children ?: UTSJSONObject[],
|
||||
) : UTSJSONObject => ({
|
||||
label,
|
||||
value,
|
||||
children,
|
||||
});
|
||||
|
||||
|
||||
|
||||
export function useCascaderAreaData() : UTSJSONObject[] {
|
||||
const city = areaList['city_list'] as UTSJSONObject
|
||||
const county = areaList['county_list'] as UTSJSONObject
|
||||
const province = areaList['province_list'] as UTSJSONObject
|
||||
const provinceMap = new Map<string, UTSJSONObject>();
|
||||
Object.keys(province).forEach((code) => {
|
||||
provinceMap.set(code.slice(0, 2), makeOption(`${province[code]}`, code, []));
|
||||
});
|
||||
|
||||
const cityMap = new Map<string, UTSJSONObject>();
|
||||
|
||||
Object.keys(city).forEach((code) => {
|
||||
const option = makeOption(`${city[code]}`, code, []);
|
||||
cityMap.set(code.slice(0, 4), option);
|
||||
|
||||
const _province = provinceMap.get(code.slice(0, 2));
|
||||
if (_province != null) {
|
||||
(_province['children'] as UTSJSONObject[]).push(option)
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(county).forEach((code) => {
|
||||
const _city = cityMap.get(code.slice(0, 4));
|
||||
if (_city != null) {
|
||||
(_city['children'] as UTSJSONObject[]).push(makeOption(`${county[code]}`, code, null));
|
||||
}
|
||||
});
|
||||
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
return Array.from(provinceMap.values());
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
const obj : UTSJSONObject[] = []
|
||||
provinceMap.forEach((value, code) => {
|
||||
obj.push(value)
|
||||
})
|
||||
return obj
|
||||
// #endif
|
||||
}
|
8
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
8
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// import {platform} from '../platform'
|
||||
/**
|
||||
* buffer转路径
|
||||
* @param {Object} buffer
|
||||
*/
|
||||
// @ts-nocheck
|
||||
export function arrayBufferToFile(buffer: ArrayBuffer, name?: string, format?:string):Promise<(File|string)> {
|
||||
console.error('[arrayBufferToFile] 当前环境不支持')
|
||||
}
|
63
uni_modules/lime-shared/arrayBufferToFile/vue.ts
Normal file
63
uni_modules/lime-shared/arrayBufferToFile/vue.ts
Normal file
@ -0,0 +1,63 @@
|
||||
// @ts-nocheck
|
||||
import {platform} from '../platform'
|
||||
/**
|
||||
* buffer转路径
|
||||
* @param {Object} buffer
|
||||
*/
|
||||
// @ts-nocheck
|
||||
export function arrayBufferToFile(buffer: ArrayBuffer | Blob, name?: string, format?:string):Promise<(File|string)> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP
|
||||
const fs = uni.getFileSystemManager()
|
||||
//自定义文件名
|
||||
if (!name && !format) {
|
||||
reject(new Error('ERROR_NAME_PARSE'))
|
||||
}
|
||||
const fileName = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||
let pre = platform()
|
||||
const filePath = `${pre.env.USER_DATA_PATH}/${fileName}`
|
||||
fs.writeFile({
|
||||
filePath,
|
||||
data: buffer,
|
||||
success() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail(err) {
|
||||
console.error(err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
const file = new File([buffer], name, {
|
||||
type: format,
|
||||
});
|
||||
resolve(file)
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
const base64 = uni.arrayBufferToBase64(buffer)
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!name && !format) {
|
||||
reject(new Error('ERROR_NAME_PARSE'))
|
||||
}
|
||||
const fileNmae = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||
const filePath = `_doc/uniapp_temp/${fileNmae}`
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
13
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
13
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// @ts-nocheck
|
||||
// 未完成
|
||||
export function base64ToArrayBuffer(base64 : string) {
|
||||
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||
if (!format) {
|
||||
new Error('ERROR_BASE64SRC_PARSE')
|
||||
}
|
||||
if(uni.base64ToArrayBuffer) {
|
||||
return uni.base64ToArrayBuffer(bodyData)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
9
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
9
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import { processFile, ProcessFileOptions } from '@/uni_modules/lime-file-utils'
|
||||
|
||||
/**
|
||||
* base64转路径
|
||||
* @param {Object} base64
|
||||
*/
|
||||
export function base64ToPath(base64: string, filename: string | null = null):Promise<string> {
|
||||
return new Promise((resolve,reject) => {
|
||||
processFile({
|
||||
type: 'toDataURL',
|
||||
path: base64,
|
||||
filename,
|
||||
success(res: string){
|
||||
resolve(res)
|
||||
},
|
||||
fail(err){
|
||||
reject(err)
|
||||
}
|
||||
} as ProcessFileOptions)
|
||||
})
|
||||
}
|
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
@ -0,0 +1,75 @@
|
||||
// @ts-nocheck
|
||||
import {platform} from '../platform'
|
||||
/**
|
||||
* base64转路径
|
||||
* @param {Object} base64
|
||||
*/
|
||||
export function base64ToPath(base64: string, filename?: string):Promise<string> {
|
||||
const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || [];
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP
|
||||
const fs = uni.getFileSystemManager()
|
||||
//自定义文件名
|
||||
if (!filename && !format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
// const time = new Date().getTime();
|
||||
const name = filename || `${new Date().getTime()}.${format}`;
|
||||
let pre = platform()
|
||||
const filePath = `${pre.env.USER_DATA_PATH}/${name}`
|
||||
fs.writeFile({
|
||||
filePath,
|
||||
data: base64.split(',')[1],
|
||||
encoding: 'base64',
|
||||
success() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail(err) {
|
||||
console.error(err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// mime类型
|
||||
let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
|
||||
//base64 解码
|
||||
let byteString = atob(base64.split(',')[1]);
|
||||
//创建缓冲数组
|
||||
let arrayBuffer = new ArrayBuffer(byteString.length);
|
||||
//创建视图
|
||||
let intArray = new Uint8Array(arrayBuffer);
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
intArray[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
resolve(URL.createObjectURL(new Blob([intArray], {
|
||||
type: mimeString
|
||||
})))
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!filename && !format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
// const time = new Date().getTime();
|
||||
const name = filename || `${new Date().getTime()}.${format}`;
|
||||
const filePath = `_doc/uniapp_temp/${name}`
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
21
uni_modules/lime-shared/camelCase/index.ts
Normal file
21
uni_modules/lime-shared/camelCase/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
|
||||
* @param str 要转换的字符串
|
||||
* @param isPascalCase 指示是否转换为 PascalCase 的布尔值,默认为 false
|
||||
* @returns 转换后的字符串
|
||||
*/
|
||||
export function camelCase(str: string, isPascalCase: boolean = false): string {
|
||||
// 将字符串分割成单词数组
|
||||
let words: string[] = str.split(/[\s_-]+/);
|
||||
|
||||
// 将数组中的每个单词首字母大写(除了第一个单词)
|
||||
let camelCased: string[] = words.map((word, index):string => {
|
||||
if (index == 0 && !isPascalCase) {
|
||||
return word.toLowerCase(); // 第一个单词全小写
|
||||
}
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
});
|
||||
|
||||
// 将数组中的单词拼接成一个字符串
|
||||
return camelCased.join('');
|
||||
};
|
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
@ -0,0 +1,67 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
interface My {
|
||||
SDKVersion: string
|
||||
}
|
||||
declare var my: My
|
||||
// #endif
|
||||
|
||||
function compareVersion(v1:string, v2:string) {
|
||||
let a1 = v1.split('.');
|
||||
let a2 = v2.split('.');
|
||||
const len = Math.max(a1.length, a2.length);
|
||||
|
||||
while (a1.length < len) {
|
||||
a1.push('0');
|
||||
}
|
||||
while (a2.length < len) {
|
||||
a2.push('0');
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(a1[i], 10);
|
||||
const num2 = parseInt(a2[i], 10);
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
}
|
||||
if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function gte(version: string) {
|
||||
let {SDKVersion} = uni.getSystemInfoSync();
|
||||
// #ifdef MP-ALIPAY
|
||||
SDKVersion = my.SDKVersion
|
||||
// #endif
|
||||
return compareVersion(SDKVersion, version) >= 0;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
/** 环境是否支持canvas 2d */
|
||||
export function canIUseCanvas2d(): boolean {
|
||||
// #ifdef MP-WEIXIN
|
||||
return gte('2.9.0');
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
return gte('2.7.0');
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
return gte('1.78.0');
|
||||
// #endif
|
||||
// #ifdef UNI-APP-X && WEB || UNI-APP-X && APP
|
||||
return true;
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
|
||||
return false
|
||||
// #endif
|
||||
|
||||
}
|
111
uni_modules/lime-shared/capitalizedAmount/index.ts
Normal file
111
uni_modules/lime-shared/capitalizedAmount/index.ts
Normal file
@ -0,0 +1,111 @@
|
||||
// @ts-nocheck
|
||||
import { isString } from "../isString";
|
||||
import { isNumber } from "../isNumber";
|
||||
/**
|
||||
* 将金额转换为中文大写形式
|
||||
* @param {number | string} amount - 需要转换的金额,可以是数字或字符串
|
||||
* @returns {string} 转换后的中文大写金额
|
||||
*/
|
||||
function capitalizedAmount(amount : number) : string
|
||||
function capitalizedAmount(amount : string) : string
|
||||
function capitalizedAmount(amount : any | null) : string {
|
||||
try {
|
||||
let _amountStr :string;
|
||||
let _amountNum :number = 0;
|
||||
// 如果输入是字符串,先将其转换为数字,并去除逗号
|
||||
if (typeof amount == 'string') {
|
||||
_amountNum = parseFloat((amount as string).replace(/,/g, ''));
|
||||
}
|
||||
if(isNumber(amount)) {
|
||||
_amountNum = amount as number
|
||||
}
|
||||
// 判断输入是否为有效的金额 || isNaN(amount)
|
||||
if (amount == null) throw new Error('不是有效的金额!');
|
||||
|
||||
let result = '';
|
||||
|
||||
// 处理负数情况
|
||||
if (_amountNum < 0) {
|
||||
result = '欠';
|
||||
_amountNum = Math.abs(_amountNum);
|
||||
}
|
||||
|
||||
// 金额不能超过千亿以上
|
||||
if (_amountNum >= 10e11) throw new Error('计算金额过大!');
|
||||
|
||||
// 保留两位小数并转换为字符串
|
||||
_amountStr = _amountNum.toFixed(2);
|
||||
|
||||
// 定义数字、单位和小数单位的映射
|
||||
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||
const units = ['', '拾', '佰', '仟'];
|
||||
const bigUnits = ['', '万', '亿'];
|
||||
const decimalUnits = ['角', '分'];
|
||||
|
||||
// 分离整数部分和小数部分
|
||||
const amountArray = _amountStr.split('.');
|
||||
let integerPart = amountArray[0]; // string| number[]
|
||||
const decimalPart = amountArray[1];
|
||||
|
||||
// 处理整数部分
|
||||
if (integerPart != '0') {
|
||||
let _integerPart = integerPart.split('').map((item):number => parseInt(item));
|
||||
|
||||
// 将整数部分按四位一级进行分组
|
||||
const levels = _integerPart.reverse().reduce((prev:string[][], item, index):string[][] => {
|
||||
// const level = prev?.[0]?.length < 4 ? prev[0] : [];
|
||||
const level = prev.length > 0 && prev[0].length < 4 ? prev[0]: []
|
||||
|
||||
const value = item == 0 ? digits[item] : digits[item] + units[index % 4];
|
||||
|
||||
level.unshift(value);
|
||||
|
||||
if (level.length == 1) {
|
||||
prev.unshift(level);
|
||||
} else {
|
||||
prev[0] = level;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, [] as string[][]);
|
||||
// 将分组后的整数部分转换为中文大写形式
|
||||
result += levels.reduce((prev, item, index):string => {
|
||||
let _level = bigUnits[levels.length - index - 1];
|
||||
let _item = item.join('').replace(/(零)\1+/g, '$1');
|
||||
|
||||
if (_item == '零') {
|
||||
_level = '';
|
||||
_item = '';
|
||||
} else if (_item.endsWith('零')) {
|
||||
_item = _item.slice(0, _item.length - 1);
|
||||
}
|
||||
|
||||
return prev + _item + _level;
|
||||
}, '');
|
||||
} else {
|
||||
result += '零';
|
||||
}
|
||||
|
||||
// 添加元
|
||||
result += '元';
|
||||
|
||||
// 处理小数部分
|
||||
if (decimalPart != '00') {
|
||||
if (result == '零元') result = '';
|
||||
|
||||
for (let i = 0; i < decimalPart.length; i++) {
|
||||
const digit = parseInt(decimalPart.charAt(i));
|
||||
|
||||
if (digit != 0) {
|
||||
result += digits[digit] + decimalUnits[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result += '整';
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error : Error) {
|
||||
return error.message;
|
||||
}
|
||||
};
|
59
uni_modules/lime-shared/changelog.md
Normal file
59
uni_modules/lime-shared/changelog.md
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
## 0.2.7(2025-01-17)
|
||||
- fix: 针对canvas 平台判断优化
|
||||
## 0.2.6(2025-01-09)
|
||||
- feat: 增加`areaData`中国省市区数据
|
||||
## 0.2.5(2025-01-07)
|
||||
- fix: animation在app上类型问题
|
||||
## 0.2.4(2025-01-04)
|
||||
- feat: getRect类型问题
|
||||
## 0.2.3(2025-01-01)
|
||||
- chore: unitConvert使用uni.rpx2px
|
||||
## 0.2.2(2024-12-11)
|
||||
- chore: 动画使用`requestAnimationFrame`
|
||||
## 0.2.1(2024-11-20)
|
||||
- feat: 增加`characterLimit`
|
||||
## 0.2.0(2024-11-14)
|
||||
- fix: vue2的类型问题
|
||||
## 0.1.9(2024-11-14)
|
||||
- feat: 增加`shuffle`
|
||||
## 0.1.8(2024-10-08)
|
||||
- fix: vue2 条件编译 // #ifdef APP-IOS || APP-ANDROID 会生效
|
||||
## 0.1.7(2024-09-23)
|
||||
- fix: raf 类型跟随版本变更
|
||||
## 0.1.6(2024-07-24)
|
||||
- fix: vue2 app ts需要明确的后缀,所有补全
|
||||
- chore: 减少依赖
|
||||
## 0.1.5(2024-07-21)
|
||||
- feat: 删除 Hooks
|
||||
- feat: 兼容uniappx
|
||||
## 0.1.4(2023-09-05)
|
||||
- feat: 增加 Hooks `useIntersectionObserver`
|
||||
- feat: 增加 `floatAdd`
|
||||
- feat: 因为本人插件兼容 vue2 需要使用 `composition-api`,故增加vue文件代码插件的条件编译
|
||||
## 0.1.3(2023-08-13)
|
||||
- feat: 增加 `camelCase`
|
||||
## 0.1.2(2023-07-17)
|
||||
- feat: 增加 `getClassStr`
|
||||
## 0.1.1(2023-07-06)
|
||||
- feat: 增加 `isNumeric`, 区别于 `isNumber`
|
||||
## 0.1.0(2023-06-30)
|
||||
- fix: `clamp`忘记导出了
|
||||
## 0.0.9(2023-06-27)
|
||||
- feat: 增加`arrayBufferToFile`
|
||||
## 0.0.8(2023-06-19)
|
||||
- feat: 增加`createAnimation`、`clamp`
|
||||
## 0.0.7(2023-06-08)
|
||||
- chore: 更新注释
|
||||
## 0.0.6(2023-06-08)
|
||||
- chore: 增加`createImage`为`lime-watermark`和`lime-qrcode`提供依赖
|
||||
## 0.0.5(2023-06-03)
|
||||
- chore: 更新注释
|
||||
## 0.0.4(2023-05-22)
|
||||
- feat: 增加`range`,`exif`,`selectComponent`
|
||||
## 0.0.3(2023-05-08)
|
||||
- feat: 增加`fillZero`,`debounce`,`throttle`,`random`
|
||||
## 0.0.2(2023-05-05)
|
||||
- chore: 更新文档
|
||||
## 0.0.1(2023-05-05)
|
||||
- 无
|
63
uni_modules/lime-shared/characterLimit/index.ts
Normal file
63
uni_modules/lime-shared/characterLimit/index.ts
Normal file
@ -0,0 +1,63 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 计算字符串字符的长度并可以截取字符串。
|
||||
* @param char 传入字符串(maxcharacter条件下,一个汉字表示两个字符)
|
||||
* @param max 规定最大字符串长度
|
||||
* @returns 当没有传入maxCharacter/maxLength 时返回字符串字符长度,当传入maxCharacter/maxLength时返回截取之后的字符串和长度。
|
||||
*/
|
||||
export type CharacterLengthResult = {
|
||||
length : number;
|
||||
characters : string;
|
||||
}
|
||||
// #ifdef APP-ANDROID
|
||||
type ChartType = any
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
type ChartType = string | number
|
||||
// #endif
|
||||
|
||||
export function characterLimit(type : string, char : ChartType, max : number) : CharacterLengthResult {
|
||||
const str = `${char}`;
|
||||
|
||||
if (str.length == 0) {
|
||||
return {
|
||||
length: 0,
|
||||
characters: '',
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
|
||||
if (type == 'maxcharacter') {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
let currentStringLength : number// = 0;
|
||||
const code = str.charCodeAt(i)!
|
||||
if (code > 127 || code == 94) {
|
||||
currentStringLength = 2;
|
||||
} else {
|
||||
currentStringLength = 1;
|
||||
}
|
||||
if (len + currentStringLength > max) {
|
||||
return {
|
||||
length: len,
|
||||
characters: str.slice(0, i),
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
len += currentStringLength;
|
||||
}
|
||||
return {
|
||||
length: len,
|
||||
characters: str,
|
||||
} as CharacterLengthResult
|
||||
} else if (type == 'maxlength') {
|
||||
const length = str.length > max ? max : str.length;
|
||||
return {
|
||||
length: length,
|
||||
characters: str.slice(0, length),
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
|
||||
return {
|
||||
length: str.length,
|
||||
characters: str,
|
||||
} as CharacterLengthResult
|
||||
};
|
16
uni_modules/lime-shared/clamp/index.ts
Normal file
16
uni_modules/lime-shared/clamp/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 将一个值限制在指定的范围内
|
||||
* @param val 要限制的值
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @returns 限制后的值
|
||||
*/
|
||||
export function clamp(val: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, val));
|
||||
}
|
||||
|
||||
|
||||
// console.log(clamp(5 ,0, 10)); // 输出: 5(在范围内,不做更改)
|
||||
// console.log(clamp(-5 ,0, 10)); // 输出: 0(小于最小值,被限制为最小值)
|
||||
// console.log(clamp(15 ,0, 10)); // 输出: 10(大于最大值,被限制为最大值)
|
10
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
10
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
17
uni_modules/lime-shared/cloneDeep/uvue.ts
Normal file
17
uni_modules/lime-shared/cloneDeep/uvue.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 深度克隆一个对象或数组
|
||||
* @param obj 要克隆的对象或数组
|
||||
* @returns 克隆后的对象或数组
|
||||
*/
|
||||
export function cloneDeep<T>(obj: any): T {
|
||||
// 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
|
||||
// if(['number', 'string'].includes(typeof obj) || Array.isArray(obj)){
|
||||
// return obj as T
|
||||
// }
|
||||
if(typeof obj == 'object'){
|
||||
return JSON.parse(JSON.stringify(obj as T)) as T;
|
||||
}
|
||||
return obj as T
|
||||
}
|
||||
|
103
uni_modules/lime-shared/cloneDeep/vue.ts
Normal file
103
uni_modules/lime-shared/cloneDeep/vue.ts
Normal file
@ -0,0 +1,103 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 深度克隆一个对象或数组
|
||||
* @param obj 要克隆的对象或数组
|
||||
* @returns 克隆后的对象或数组
|
||||
*/
|
||||
export function cloneDeep<T>(obj: any): T {
|
||||
// 如果传入的对象为空,返回空
|
||||
if (obj === null) {
|
||||
return null as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Set 类型,则将其转换为数组,并通过新的 Set 构造函数创建一个新的 Set 对象
|
||||
if (obj instanceof Set) {
|
||||
return new Set([...obj]) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Map 类型,则将其转换为数组,并通过新的 Map 构造函数创建一个新的 Map 对象
|
||||
if (obj instanceof Map) {
|
||||
return new Map([...obj]) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 WeakMap 类型,则直接用传入的 WeakMap 对象进行赋值
|
||||
if (obj instanceof WeakMap) {
|
||||
let weakMap = new WeakMap();
|
||||
weakMap = obj;
|
||||
return weakMap as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 WeakSet 类型,则直接用传入的 WeakSet 对象进行赋值
|
||||
if (obj instanceof WeakSet) {
|
||||
let weakSet = new WeakSet();
|
||||
weakSet = obj;
|
||||
return weakSet as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 RegExp 类型,则通过新的 RegExp 构造函数创建一个新的 RegExp 对象
|
||||
if (obj instanceof RegExp) {
|
||||
return new RegExp(obj) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 undefined 类型,则返回 undefined
|
||||
if (typeof obj === 'undefined') {
|
||||
return undefined as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是数组,则递归调用 cloneDeep 函数对数组中的每个元素进行克隆
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(cloneDeep) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Date 类型,则通过新的 Date 构造函数创建一个新的 Date 对象
|
||||
if (obj instanceof Date) {
|
||||
return new Date(obj.getTime()) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是普通对象,则使用递归调用 cloneDeep 函数对对象的每个属性进行克隆
|
||||
if (typeof obj === 'object') {
|
||||
const newObj: any = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
newObj[key] = cloneDeep(value);
|
||||
}
|
||||
const symbolKeys = Object.getOwnPropertySymbols(obj);
|
||||
for (const key of symbolKeys) {
|
||||
newObj[key] = cloneDeep(obj[key]);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
|
||||
// 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
|
||||
return obj;
|
||||
}
|
||||
|
||||
// 示例使用
|
||||
|
||||
// // 克隆一个对象
|
||||
// const obj = { name: 'John', age: 30 };
|
||||
// const clonedObj = cloneDeep(obj);
|
||||
|
||||
// console.log(clonedObj); // 输出: { name: 'John', age: 30 }
|
||||
// console.log(clonedObj === obj); // 输出: false (副本与原对象是独立的)
|
||||
|
||||
// // 克隆一个数组
|
||||
// const arr = [1, 2, 3];
|
||||
// const clonedArr = cloneDeep(arr);
|
||||
|
||||
// console.log(clonedArr); // 输出: [1, 2, 3]
|
||||
// console.log(clonedArr === arr); // 输出: false (副本与原数组是独立的)
|
||||
|
||||
// // 克隆一个包含嵌套对象的对象
|
||||
// const person = {
|
||||
// name: 'Alice',
|
||||
// age: 25,
|
||||
// address: {
|
||||
// city: 'New York',
|
||||
// country: 'USA',
|
||||
// },
|
||||
// };
|
||||
// const clonedPerson = cloneDeep(person);
|
||||
|
||||
// console.log(clonedPerson); // 输出: { name: 'Alice', age: 25, address: { city: 'New York', country: 'USA' } }
|
||||
// console.log(clonedPerson === person); // 输出: false (副本与原对象是独立的)
|
||||
// console.log(clonedPerson.address === person.address); // 输出: false (嵌套对象的副本也是独立的)
|
22
uni_modules/lime-shared/closest/index.ts
Normal file
22
uni_modules/lime-shared/closest/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 在给定数组中找到最接近目标数字的元素。
|
||||
* @param arr 要搜索的数字数组。
|
||||
* @param target 目标数字。
|
||||
* @returns 最接近目标数字的数组元素。
|
||||
*/
|
||||
export function closest(arr: number[], target: number):number {
|
||||
return arr.reduce((pre: number, cur: number):number =>
|
||||
Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
|
||||
);
|
||||
}
|
||||
|
||||
// 示例
|
||||
// // 定义一个数字数组
|
||||
// const numbers = [1, 3, 5, 7, 9];
|
||||
|
||||
// // 在数组中找到最接近目标数字 6 的元素
|
||||
// const closestNumber = closest(numbers, 6);
|
||||
|
||||
// console.log(closestNumber); // 输出结果: 5
|
156
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
156
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<view id="shared" style="height: 500px; width: 300px; background-color: aqua;">
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { getRect, getAllRect } from '@/uni_modules/lime-shared/getRect'
|
||||
|
||||
import { camelCase } from '@/uni_modules/lime-shared/camelCase'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
import { clamp } from '@/uni_modules/lime-shared/clamp'
|
||||
import { cloneDeep } from '@/uni_modules/lime-shared/cloneDeep'
|
||||
import { closest } from '@/uni_modules/lime-shared/closest'
|
||||
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||
import { fillZero } from '@/uni_modules/lime-shared/fillZero'
|
||||
import { floatAdd } from '@/uni_modules/lime-shared/floatAdd'
|
||||
import { floatMul } from '@/uni_modules/lime-shared/floatMul'
|
||||
import { floatDiv } from '@/uni_modules/lime-shared/floatDiv'
|
||||
import { floatSub } from '@/uni_modules/lime-shared/floatSub'
|
||||
import { getClassStr } from '@/uni_modules/lime-shared/getClassStr'
|
||||
import { getCurrentPage } from '@/uni_modules/lime-shared/getCurrentPage'
|
||||
import { getStyleStr } from '@/uni_modules/lime-shared/getStyleStr'
|
||||
import { hasOwn } from '@/uni_modules/lime-shared/hasOwn'
|
||||
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||
import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
|
||||
import { isDef } from '@/uni_modules/lime-shared/isDef'
|
||||
import { isEmpty } from '@/uni_modules/lime-shared/isEmpty'
|
||||
import { isFunction } from '@/uni_modules/lime-shared/isFunction'
|
||||
import { isNumber } from '@/uni_modules/lime-shared/isNumber'
|
||||
import { isNumeric } from '@/uni_modules/lime-shared/isNumeric'
|
||||
import { isObject } from '@/uni_modules/lime-shared/isObject'
|
||||
import { isPromise } from '@/uni_modules/lime-shared/isPromise'
|
||||
import { isString } from '@/uni_modules/lime-shared/isString'
|
||||
import { kebabCase } from '@/uni_modules/lime-shared/kebabCase'
|
||||
import { raf, doubleRaf } from '@/uni_modules/lime-shared/raf'
|
||||
import { random } from '@/uni_modules/lime-shared/random'
|
||||
import { range } from '@/uni_modules/lime-shared/range'
|
||||
import { sleep } from '@/uni_modules/lime-shared/sleep'
|
||||
import { throttle } from '@/uni_modules/lime-shared/throttle'
|
||||
import { toArray } from '@/uni_modules/lime-shared/toArray'
|
||||
import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
|
||||
import { toNumber } from '@/uni_modules/lime-shared/toNumber'
|
||||
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
import { getCurrentInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { capitalizedAmount } from '@/uni_modules/lime-shared/capitalizedAmount'
|
||||
|
||||
// #ifdef VUE2
|
||||
type UTSJSONObject = any
|
||||
// #endif
|
||||
|
||||
const context = getCurrentInstance()
|
||||
// getRect('#shared', context!).then(res =>{
|
||||
// console.log('res', res.bottom)
|
||||
// })
|
||||
// getAllRect('#shared', context).then(res =>{
|
||||
// console.log('res', res)
|
||||
// })
|
||||
|
||||
|
||||
// console.log('camelCase::', camelCase("hello world"));
|
||||
// console.log('camelCase::', camelCase("my_name_is_john", true));
|
||||
// console.log('canIUseCanvas2d::', canIUseCanvas2d());
|
||||
// console.log('clamp::', clamp(5 ,0, 10));
|
||||
// console.log('cloneDeep::', cloneDeep<UTSJSONObject>({a:5}));
|
||||
// console.log('closest::', closest([1, 3, 5, 7, 9], 6));
|
||||
|
||||
|
||||
|
||||
|
||||
// const saveData = (data: any) => {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
// debouncedSaveData('Data 1');
|
||||
// debouncedSaveData('Data 2');
|
||||
|
||||
// console.log('fillZero', fillZero(1))
|
||||
// console.log('floatAdd', floatAdd(0.1, 0.2), floatAdd(1.05, 0.05), floatAdd(0.1, 0.7), floatAdd(0.0001, 0.0002), floatAdd(123.456 , 789.012))
|
||||
// console.log('floatMul', floatMul(0.1, 0.02), floatMul(1.0255, 100))
|
||||
// console.log('floatDiv', floatDiv(10.44, 100), floatDiv(1.0255, 100), floatDiv(5.419909340994699, 0.2))
|
||||
// console.log('floatSub', floatSub(0.4, 0.1), floatSub(1.0255, 100))
|
||||
const now = () : number => System.nanoTime() / 1_000_000.0
|
||||
console.log('capitalizedAmount', capitalizedAmount(0.4))
|
||||
console.log('capitalizedAmount', capitalizedAmount(100))
|
||||
console.log('capitalizedAmount', capitalizedAmount(100000000))
|
||||
console.log('capitalizedAmount', capitalizedAmount('2023.04'))
|
||||
console.log('capitalizedAmount', capitalizedAmount(-1024))
|
||||
console.log('now', now(), Date.now())
|
||||
// console.log('getClassStr', getClassStr({hover: true}))
|
||||
// console.log('getStyleStr', getStyleStr({ color: 'red', fontSize: '16px', backgroundColor: '', border: null }))
|
||||
// console.log('hasOwn', hasOwn({a: true}, 'key'))
|
||||
// console.log('isBase64::', isBase64("SGVsbG8sIFdvcmxkIQ=="));
|
||||
// console.log('isBrowser::', isBrowser);
|
||||
// console.log('isDef::', isDef('6'));
|
||||
// console.log('isEmpty::', isEmpty({a: true}));
|
||||
|
||||
// const b = () =>{}
|
||||
// console.log('isFunction::', isFunction(b));
|
||||
// console.log('isNumber::', isNumber('6'));
|
||||
// console.log('isNumeric::', isNumeric('6'));
|
||||
// console.log('isObject::', isObject({}));
|
||||
|
||||
// const promise = ():Promise<boolean> => {
|
||||
// return new Promise((resolve) => {
|
||||
// resolve(true)
|
||||
// })
|
||||
// }
|
||||
// const a = promise()
|
||||
// console.log('isPromise::', isPromise(a));
|
||||
// console.log('isString::', isString('null'));
|
||||
// console.log('kebabCase::', kebabCase('my love'));
|
||||
// console.log('raf::', raf(()=>{
|
||||
// console.log('raf:::1')
|
||||
// }));
|
||||
// console.log('doubleRaf::', doubleRaf(()=>{
|
||||
// console.log('doubleRaf:::1')
|
||||
// }));
|
||||
// console.log('random', random(0, 10))
|
||||
// console.log('random', random(0, 1, 2))
|
||||
// console.log('range', range(0, 10, 2))
|
||||
// console.log('sleep', sleep(300).then(res => {
|
||||
// console.log('log')
|
||||
// }))
|
||||
|
||||
// const handleScroll = (a: string) => {
|
||||
// console.log("Scroll event handled!", a);
|
||||
// }
|
||||
|
||||
// // // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
|
||||
// const throttledScroll = throttle(handleScroll, 500);
|
||||
// throttledScroll('5');
|
||||
// const page = getCurrentPage()
|
||||
// console.log('getCurrentPage::', page)
|
||||
|
||||
// console.log('toArray', toArray<number>(5))
|
||||
// console.log('toBoolean', toBoolean(5))
|
||||
// console.log('toNumber', toNumber('5'))
|
||||
// console.log('unitConvert', unitConvert('5'))
|
||||
|
||||
// uni.getImageInfo({
|
||||
// src: '/static/logo.png',
|
||||
// success(res) {
|
||||
// console.log('res', res)
|
||||
// }
|
||||
// })
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
9
uni_modules/lime-shared/createAnimation/index.ts
Normal file
9
uni_modules/lime-shared/createAnimation/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
export * from './type.ts'
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export type CreateAnimationOptions = {
|
||||
/**
|
||||
* 动画持续时间,单位ms
|
||||
*/
|
||||
duration ?: number;
|
||||
/**
|
||||
* 定义动画的效果
|
||||
* - linear: 动画从头到尾的速度是相同的
|
||||
* - ease: 动画以低速开始,然后加快,在结束前变慢
|
||||
* - ease-in: 动画以低速开始
|
||||
* - ease-in-out: 动画以低速开始和结束
|
||||
* - ease-out: 动画以低速结束
|
||||
* - step-start: 动画第一帧就跳至结束状态直到结束
|
||||
* - step-end: 动画一直保持开始状态,最后一帧跳到结束状态
|
||||
*/
|
||||
timingFunction ?: string //'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out' | 'step-start' | 'step-end';
|
||||
/**
|
||||
* 动画延迟时间,单位 ms
|
||||
*/
|
||||
delay ?: number;
|
||||
/**
|
||||
* 设置transform-origin
|
||||
*/
|
||||
transformOrigin ?: string;
|
||||
}
|
5
uni_modules/lime-shared/createAnimation/uvue.ts
Normal file
5
uni_modules/lime-shared/createAnimation/uvue.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
// export * from '@/uni_modules/lime-animateIt'
|
||||
export function createAnimation() {
|
||||
console.error('当前环境不支持,请使用:lime-animateIt')
|
||||
}
|
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
@ -0,0 +1,148 @@
|
||||
// @ts-nocheck
|
||||
// nvue 需要在节点上设置ref或在export里传入
|
||||
// const animation = createAnimation({
|
||||
// ref: this.$refs['xxx'],
|
||||
// duration: 0,
|
||||
// timingFunction: 'linear'
|
||||
// })
|
||||
// animation.opacity(1).translate(x, y).step({duration})
|
||||
// animation.export(ref)
|
||||
|
||||
// 抹平nvue 与 uni.createAnimation的使用差距
|
||||
// 但是nvue动画太慢
|
||||
|
||||
|
||||
|
||||
import { CreateAnimationOptions } from './type'
|
||||
// #ifdef APP-NVUE
|
||||
const nvueAnimation = uni.requireNativePlugin('animation')
|
||||
|
||||
type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
|
||||
| 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'
|
||||
|
||||
interface Styles {
|
||||
[key : string] : any
|
||||
}
|
||||
|
||||
interface StepConfig {
|
||||
duration?: number
|
||||
timingFunction?: string
|
||||
delay?: number
|
||||
needLayout?: boolean
|
||||
transformOrigin?: string
|
||||
}
|
||||
interface StepAnimate {
|
||||
styles?: Styles
|
||||
config?: StepConfig
|
||||
}
|
||||
interface StepAnimates {
|
||||
[key: number]: StepAnimate
|
||||
}
|
||||
// export interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
|
||||
// ref?: string
|
||||
// }
|
||||
|
||||
type Callback = (time: number) => void
|
||||
const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
|
||||
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
|
||||
'translateZ'
|
||||
]
|
||||
const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
|
||||
const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']
|
||||
|
||||
class LimeAnimation {
|
||||
ref : any
|
||||
context : any
|
||||
options : UniApp.CreateAnimationOptions
|
||||
// stack : any[] = []
|
||||
next : number = 0
|
||||
currentStepAnimates : StepAnimates = {}
|
||||
duration : number = 0
|
||||
constructor(options : CreateAnimationOptions) {
|
||||
const {ref} = options
|
||||
this.ref = ref
|
||||
this.options = options
|
||||
}
|
||||
addAnimate(type : AnimationTypes, args: (string | number)[]) {
|
||||
let aniObj = this.currentStepAnimates[this.next]
|
||||
let stepAnimate:StepAnimate = {}
|
||||
if (!aniObj) {
|
||||
stepAnimate = {styles: {}, config: {}}
|
||||
} else {
|
||||
stepAnimate = aniObj
|
||||
}
|
||||
|
||||
if (animateTypes1.includes(type)) {
|
||||
if (!stepAnimate.styles.transform) {
|
||||
stepAnimate.styles.transform = ''
|
||||
}
|
||||
let unit = ''
|
||||
if (type === 'rotate') {
|
||||
unit = 'deg'
|
||||
}
|
||||
stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
|
||||
} else {
|
||||
stepAnimate.styles[type] = `${args.join(',')}`
|
||||
}
|
||||
this.currentStepAnimates[this.next] = stepAnimate
|
||||
}
|
||||
animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
|
||||
const el = ref || this.ref
|
||||
if (!el) return
|
||||
return new Promise((resolve) => {
|
||||
const time = +new Date()
|
||||
nvueAnimation.transition(el, {
|
||||
styles,
|
||||
...config
|
||||
}, () => {
|
||||
resolve(+new Date() - time)
|
||||
})
|
||||
})
|
||||
}
|
||||
nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
|
||||
let obj = animates[step]
|
||||
if (obj) {
|
||||
let { styles, config } = obj
|
||||
// this.duration += config.duration
|
||||
this.animateRun(styles, config, ref).then((time: number) => {
|
||||
step += 1
|
||||
this.duration += time
|
||||
this.nextAnimate(animates, step, ref, cb)
|
||||
})
|
||||
} else {
|
||||
this.currentStepAnimates = {}
|
||||
cb && cb(this.duration)
|
||||
}
|
||||
}
|
||||
step(config:StepConfig = {}) {
|
||||
this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
|
||||
this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
|
||||
this.next++
|
||||
return this
|
||||
}
|
||||
export(ref: any, cb?: Callback) {
|
||||
ref = ref || this.ref
|
||||
if(!ref) return
|
||||
this.duration = 0
|
||||
this.next = 0
|
||||
this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
|
||||
LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
|
||||
this.addAnimate(type, args)
|
||||
return this
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
export function createAnimation(options : CreateAnimationOptions) {
|
||||
// #ifndef APP-NVUE
|
||||
return uni.createAnimation({ ...options })
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
return new LimeAnimation(options)
|
||||
// #endif
|
||||
}
|
73
uni_modules/lime-shared/createCanvas/index.ts
Normal file
73
uni_modules/lime-shared/createCanvas/index.ts
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { getRect } from '@/uni_modules/lime-shared/getRect'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
export const isCanvas2d = canIUseCanvas2d()
|
||||
// #endif
|
||||
|
||||
|
||||
export function createCanvas(canvasId : string, component : ComponentInternalInstance) {
|
||||
// #ifdef UNI-APP-X
|
||||
uni.createCanvasContextAsync({
|
||||
canvasId,
|
||||
component,
|
||||
success(context : CanvasContext) {
|
||||
|
||||
},
|
||||
fail(error : UniError) {
|
||||
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
// #ifndef UNI-APP-X
|
||||
const isCanvas2d = canIUseCanvas2d()
|
||||
getRect('#' + canvasId, context, isCanvas2d).then(res => {
|
||||
if (res.node) {
|
||||
res.node.width = res.width
|
||||
res.node.height = res.height
|
||||
return res.node
|
||||
} else {
|
||||
const ctx = uni.createCanvasContext(canvasId, context)
|
||||
if (!ctx._drawImage) {
|
||||
ctx._drawImage = ctx.drawImage
|
||||
ctx.drawImage = function (...args) {
|
||||
const { path } = args.shift()
|
||||
ctx._drawImage(path, ...args)
|
||||
}
|
||||
}
|
||||
if (!ctx.getImageData) {
|
||||
ctx.getImageData = function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.canvasGetImageData({
|
||||
canvasId,
|
||||
x: parseInt(arguments[0]),
|
||||
y: parseInt(arguments[1]),
|
||||
width: parseInt(arguments[2]),
|
||||
height: parseInt(arguments[3]),
|
||||
success(res) {
|
||||
resolve(res)
|
||||
},
|
||||
fail(err) {
|
||||
reject(err)
|
||||
}
|
||||
}, context)
|
||||
})
|
||||
|
||||
}
|
||||
return {
|
||||
getContext(type: string) {
|
||||
if(type == '2d') {
|
||||
return ctx
|
||||
}
|
||||
},
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
createImage
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
}
|
71
uni_modules/lime-shared/createImage/index.ts
Normal file
71
uni_modules/lime-shared/createImage/index.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import {isBrowser} from '../isBrowser'
|
||||
class Image {
|
||||
currentSrc: string | null = null
|
||||
naturalHeight: number = 0
|
||||
naturalWidth: number = 0
|
||||
width: number = 0
|
||||
height: number = 0
|
||||
tagName: string = 'IMG'
|
||||
path: string = ''
|
||||
crossOrigin: string = ''
|
||||
referrerPolicy: string = ''
|
||||
onload: () => void = () => {}
|
||||
onerror: () => void = () => {}
|
||||
complete: boolean = false
|
||||
constructor() {}
|
||||
set src(src: string) {
|
||||
console.log('src', src)
|
||||
if(!src) {
|
||||
return this.onerror()
|
||||
}
|
||||
src = src.replace(/^@\//,'/')
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
const localReg = /^\.|^\/(?=[^\/])/;
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
|
||||
res.path = localReg.test(src) ? `/${res.path}` : res.path;
|
||||
// #endif
|
||||
this.complete = true
|
||||
this.path = res.path
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
interface UniImage extends WechatMiniprogram.Image {
|
||||
complete?: boolean
|
||||
naturalHeight?: number
|
||||
naturalWidth?: number
|
||||
}
|
||||
/** 创建用于 canvas 的 img */
|
||||
export function createImage(canvas?: any): HTMLImageElement | UniImage {
|
||||
if(canvas && canvas.createImage) {
|
||||
return (canvas as WechatMiniprogram.Canvas).createImage()
|
||||
} else if(this && this['tagName'] == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
|
||||
return new Image()
|
||||
} else if(isBrowser) {
|
||||
return new window.Image()
|
||||
}
|
||||
return new Image()
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export function createImage():Image{
|
||||
// console.error('当前环境不支持')
|
||||
return new Image()
|
||||
}
|
||||
// #endif
|
10
uni_modules/lime-shared/debounce/index.ts
Normal file
10
uni_modules/lime-shared/debounce/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.ts'
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
36
uni_modules/lime-shared/debounce/uvue.ts
Normal file
36
uni_modules/lime-shared/debounce/uvue.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any>(fn : (args: A)=> void, wait = 300): (args: A)=> void {
|
||||
let timer = -1
|
||||
|
||||
return (args: A) => {
|
||||
if (timer >-1) {clearTimeout(timer)};
|
||||
|
||||
timer = setTimeout(()=>{
|
||||
fn(args)
|
||||
}, wait)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 示例
|
||||
// 定义一个函数
|
||||
// function saveData(data: string) {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
|
||||
// // 连续调用防抖函数
|
||||
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
|
||||
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
|
||||
|
||||
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
|
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
type Timeout = ReturnType<typeof setTimeout> | null;
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any, R>(
|
||||
fn : (...args : A) => R,
|
||||
wait : number = 300) : (...args : A) => void {
|
||||
let timer : Timeout = null;
|
||||
|
||||
return function (...args : A) {
|
||||
if (timer) clearTimeout(timer); // 如果上一个 setTimeout 存在,则清除它
|
||||
|
||||
// 设置一个新的 setTimeout,在指定的等待时间后调用防抖函数
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args); // 使用提供的参数调用原始函数
|
||||
}, wait);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 示例
|
||||
// 定义一个函数
|
||||
// function saveData(data: string) {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
|
||||
// // 连续调用防抖函数
|
||||
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
|
||||
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
|
||||
|
||||
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
|
9
uni_modules/lime-shared/exif/index.ts
Normal file
9
uni_modules/lime-shared/exif/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
7
uni_modules/lime-shared/exif/uvue.ts
Normal file
7
uni_modules/lime-shared/exif/uvue.ts
Normal file
@ -0,0 +1,7 @@
|
||||
class EXIF {
|
||||
constructor(){
|
||||
console.error('当前环境不支持')
|
||||
}
|
||||
}
|
||||
|
||||
export const exif = new EXIF()
|
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
File diff suppressed because it is too large
Load Diff
11
uni_modules/lime-shared/fillZero/index.ts
Normal file
11
uni_modules/lime-shared/fillZero/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 在数字前填充零,返回字符串形式的结果
|
||||
* @param number 要填充零的数字
|
||||
* @param length 填充零后的字符串长度,默认为2
|
||||
* @returns 填充零后的字符串
|
||||
*/
|
||||
export function fillZero(number: number, length: number = 2): string {
|
||||
// 将数字转换为字符串,然后使用 padStart 方法填充零到指定长度
|
||||
return `${number}`.padStart(length, '0');
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user