Merge remote-tracking branch 'remotes/origin/master' into minJeecg
# Conflicts: # env/.env.development
This commit is contained in:
commit
39dd44aa98
@ -33,10 +33,10 @@ export default defineUniPages({
|
|||||||
text: '首页',
|
text: '首页',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
iconPath: 'static/tabbar/tabbar-message-2.png',
|
"iconPath": "static/tabbar/tabbar-produce.png",
|
||||||
selectedIconPath: 'static/tabbar/tabbar-message.png',
|
"selectedIconPath": "static/tabbar/tabbar-produce-2.png",
|
||||||
pagePath: 'pages/message/message',
|
"pagePath": "pages/produce/index",
|
||||||
text: '消息',
|
"text": "生产"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
iconPath: 'static/tabbar/tabbar-workHome-2.png',
|
iconPath: 'static/tabbar/tabbar-workHome-2.png',
|
||||||
|
|||||||
68
src/api/humanResource/absence/index.ts
Normal file
68
src/api/humanResource/absence/index.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { http } from '@/utils/http';
|
||||||
|
|
||||||
|
/*根据username获取职位名称和审批领导列表*/
|
||||||
|
export function queryZwmcAndExaApi(username : string) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/queryZwmcByUsername',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
username
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*新增请假申请*/
|
||||||
|
export function addApi(config : Object) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/add',
|
||||||
|
method: 'POST',
|
||||||
|
data: config
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*根据username获取最新请假结束日期*/
|
||||||
|
export function queryHisDateApi(username : string) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/queryHisDate',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
username
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*获取请假列表*/
|
||||||
|
export function listApi(params : object) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/list',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*获取请假数据分析*/
|
||||||
|
export function countByOrgApi(params : object) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/countByOrg',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*通过id查询请假数据*/
|
||||||
|
export function queryByIdApi(id : string) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/queryById',
|
||||||
|
method: 'GET',
|
||||||
|
data: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*销假*/
|
||||||
|
export function editApi(config : object ) {
|
||||||
|
return http({
|
||||||
|
url: '/CxcQxj/cxcQxj/edit',
|
||||||
|
method: 'PUT',
|
||||||
|
data: config
|
||||||
|
})
|
||||||
|
}
|
||||||
115
src/api/humanResource/personnel/index.ts
Normal file
115
src/api/humanResource/personnel/index.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import { http } from '@/utils/http';
|
||||||
|
|
||||||
|
/* 获取部门所有人员信息 */
|
||||||
|
export function listApi(config : object) {
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/list',
|
||||||
|
method: 'GET',
|
||||||
|
data: config
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 获取工作经历 */
|
||||||
|
export function workExperienceListApi(ldhth : string) {
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/queryLl',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryGzjlByRyLdhth(ldhth) { // 获取人员工作经历信息
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/queryLl',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryQzqkByRyLdhth(ldhth) { // 获取人员证件台账
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/queryZjtz',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryJtzycyByRyLdhth(ldhth) { // 获取人员家庭主要成员
|
||||||
|
return http({
|
||||||
|
url: '/cxchrygxxtj/cxcHrYgxxtj/queryJtzycy',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function queryXlxxByRyLdhth(ldhth) { // 获取人员学历信息
|
||||||
|
return http({
|
||||||
|
url: '/cxchrygxxtj/cxcHrYgxxtj/listCxcXlxwxxFbByMainId',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryGbxxByRyLdhth(ldhth) { // 获取人员干部信息 专业技术等级信息
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.gbxx/cxcRlzyGbxx/queryGbxx',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryZyzgdjByRyLdhth(ldhth) { // 获取人员职业资格等级
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/queryZyzgdj',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function queryJxkhByRyLdhth(ldhth) { // 绩效考核信息
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/listCxcRlzyJxkhByMainId',
|
||||||
|
method: 'GET',
|
||||||
|
data: ldhth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cxcHrYgxxtj(parm) { // 获取员工信息统计
|
||||||
|
return http({
|
||||||
|
url: '/cxchrygxxtj/cxcHrYgxxtj/list',
|
||||||
|
method: 'GET',
|
||||||
|
data: parm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cxcRyDataTongji(url, parm) { // 员工信息统计
|
||||||
|
return http({
|
||||||
|
url: url,
|
||||||
|
method: 'GET',
|
||||||
|
data: parm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cxcRyDatAstatistics(parm) { // 员工分组统计
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/statistics',
|
||||||
|
method: 'GET',
|
||||||
|
data: parm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cxcRyDatAstatisticsCertificate(parm) { // 员工按证件分组统计
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/getStatisticsCertificate',
|
||||||
|
method: 'GET',
|
||||||
|
data: parm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cxcRyDatAstatisticsDetails(parm) { // 员工信息统计
|
||||||
|
return http({
|
||||||
|
url: '/cxc_rlzy.zb/cxcRlzyZb/details',
|
||||||
|
method: 'GET',
|
||||||
|
data: parm
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { http } from '@/utils/http';
|
|
||||||
|
|
||||||
/*根据username获取职位名称和审批领导列表*/
|
|
||||||
export function queryZwmcAndExaApi(username : string) {
|
|
||||||
return http({
|
|
||||||
url: '/CxcQxj/cxcQxj/queryZwmcByUsername',
|
|
||||||
method: 'GET',
|
|
||||||
data: {
|
|
||||||
username
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*新增请假申请*/
|
|
||||||
export function addApi(config : Object) {
|
|
||||||
return http({
|
|
||||||
url: '/CxcQxj/cxcQxj/add',
|
|
||||||
method: 'POST',
|
|
||||||
data: config
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*根据username获取最新请假结束日期*/
|
|
||||||
export function queryHisDateApi(username : string) {
|
|
||||||
return http({
|
|
||||||
url: '/CxcQxj/cxcQxj/queryHisDate',
|
|
||||||
method: 'GET',
|
|
||||||
data: {
|
|
||||||
username
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
51
src/api/produce/index.ts
Normal file
51
src/api/produce/index.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { http } from '@/utils/http';
|
||||||
|
|
||||||
|
export function queryJinriShengchansj(params : object) { // 获取今日天然气生产数据
|
||||||
|
return http({
|
||||||
|
url: '/scdt.CxcScdtChart/cxcScdtChart/list',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryJinriTrqShengchansj(params : object) { // 获取当前日期、今年以来天然气的生产数据 day gas unit
|
||||||
|
return http({
|
||||||
|
url: '/scdt.CxcScdtChart/cxcScdtChart/getStatisticsData',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryYearShengchansj(params : object) { // 获取今年以来天然气的生产数据
|
||||||
|
return http({
|
||||||
|
url: '/scdt.CxcScdtChart/cxcScdtChart/getYearStatis',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryJinriYuanyouShengchansj(params : object) { // 获取今日原油 污油产量
|
||||||
|
return http({
|
||||||
|
url: '/scdt.cxcscdtwyrb/cxcScdtWyRb/list',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实时数据API
|
||||||
|
|
||||||
|
export function queryJldZcList(params : object) { // 获取计量点站场列表
|
||||||
|
return http({
|
||||||
|
url: '/sys/sysDepart/queryDepartsByzdjl',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryJldDataByZc(params : object) { // 获取站场计量点实时数据
|
||||||
|
return http({
|
||||||
|
url: 'http://10.75.166.6:9999/Gyk/sssj/GetJlByZc',
|
||||||
|
method: 'GET',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -24,4 +24,12 @@ export function queryDepsByUserIdApi() {
|
|||||||
url: '/sys/user/getCurrentUserDeparts',
|
url: '/sys/user/getCurrentUserDeparts',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryMyDeptTreeListApi(config : object) { // 部门
|
||||||
|
return http({
|
||||||
|
url: '/sys/sysDepart/queryTreeList',
|
||||||
|
method: 'GET',
|
||||||
|
data: config
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { http } from '@/utils/http'; // @/ 已经映射到 ./src/
|
import { http } from '@/utils/http'; // @/ 已经映射到 ./src/
|
||||||
// ts对 HTTP 方法名称的大小写敏感。在 TypeScript 的类型定义中,HTTP 方法通常被定义为全大写的字符串字面量类型,如 "POST",而非"post"。
|
// ts对 HTTP 方法名称的大小写敏感。在 TypeScript 的类型定义中,HTTP 方法通常被定义为全大写的字符串字面量类型,如 "POST",而非"post"。
|
||||||
interface LoginParams {
|
interface LoginParams {
|
||||||
username: string;
|
username : string;
|
||||||
password: string;
|
password : string;
|
||||||
captcha?: string; //非必填字段
|
captcha ?: string; //非必填字段
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,13 +12,13 @@ interface LoginParams {
|
|||||||
* @returns 登录请求的 Promise
|
* @returns 登录请求的 Promise
|
||||||
*/
|
*/
|
||||||
export function loginApi(config : LoginParams) {
|
export function loginApi(config : LoginParams) {
|
||||||
// 如果传了 captcha,走本地登录(/sys/login),否则走单点登录(/sys/sinopecLogin)
|
// 如果传了 captcha,走本地登录(/sys/login),否则走单点登录(/sys/sinopecLogin)
|
||||||
const url = config.captcha ? '/sys/login' : '/sys/sinopecLogin';
|
const url = config.captcha ? '/sys/login' : '/sys/sinopecLogin';
|
||||||
return http({
|
return http({
|
||||||
url,
|
url,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: config,
|
data: config,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +48,7 @@ export function jurisdictionApi(id : string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserPermissionApi(config) { // 获取权限
|
export function getUserPermissionApi(config : object) { // 获取权限
|
||||||
return http({
|
return http({
|
||||||
url: '/sys/permission/getUserPermissionByToken',
|
url: '/sys/permission/getUserPermissionByToken',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@ -59,7 +59,7 @@ export function getUserPermissionApi(config) { // 获取权限
|
|||||||
/**
|
/**
|
||||||
* 获取首页轮播图
|
* 获取首页轮播图
|
||||||
*/
|
*/
|
||||||
export function queryCarouselApi(config) {
|
export function queryCarouselApi(config : object) {
|
||||||
return http({
|
return http({
|
||||||
url: '/CxcDaping/cxcDaping/list',
|
url: '/CxcDaping/cxcDaping/list',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@ -70,7 +70,7 @@ export function queryCarouselApi(config) {
|
|||||||
/**
|
/**
|
||||||
* 获取分类字典
|
* 获取分类字典
|
||||||
*/
|
*/
|
||||||
export function getCategoryItemsApi(pid) { // 分类字典专用
|
export function getCategoryItemsApi(pid : string) {
|
||||||
return http({
|
return http({
|
||||||
url: '/sys/category/findtree',
|
url: '/sys/category/findtree',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@ -78,4 +78,11 @@ export function getCategoryItemsApi(pid) { // 分类字典专用
|
|||||||
pid
|
pid
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDictItemsApi(dictCode : string) { // 字典标签专用
|
||||||
|
return http({
|
||||||
|
url: `/sys/dict/getDictItems/${dictCode}`,
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view :class="['pageLayout', { 'gray': appStore.isGray == 1 }]">
|
<view :class="['pageLayout', { 'gray': appStore.isGray == 1 }]">
|
||||||
|
<wd-watermark :content="userStore.userInfo.realname + ' '+ userStore.userInfo.username"
|
||||||
|
:width="200" :height="200" :opacity="0.2"></wd-watermark>
|
||||||
<view v-if="navbarShow" :class="{ pageNav: true, transparent: navBgTransparent, fixed: navFixed }"
|
<view v-if="navbarShow" :class="{ pageNav: true, transparent: navBgTransparent, fixed: navFixed }"
|
||||||
:style="{ height: `${statusBarHeight + navHeight}px` }">
|
:style="{ height: `${statusBarHeight + navHeight}px` }">
|
||||||
<view class="statusBar" :style="{ height: `${statusBarHeight}px` }"></view>
|
<view class="statusBar" :style="{ height: `${statusBarHeight}px` }"></view>
|
||||||
@ -26,7 +28,7 @@
|
|||||||
import { useRouter } from '@/plugin/uni-mini-router'
|
import { useRouter } from '@/plugin/uni-mini-router'
|
||||||
import { useParamsStore } from '@/store/page-params'
|
import { useParamsStore } from '@/store/page-params'
|
||||||
import { useAppStore } from '@/store'
|
import { useAppStore } from '@/store'
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'pageLayout',
|
name: 'pageLayout',
|
||||||
options: {
|
options: {
|
||||||
@ -36,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
const paramsStore = useParamsStore()
|
const paramsStore = useParamsStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|||||||
@ -62,7 +62,7 @@
|
|||||||
queryZwmcAndExaApi,
|
queryZwmcAndExaApi,
|
||||||
addApi,
|
addApi,
|
||||||
queryHisDateApi
|
queryHisDateApi
|
||||||
} from '@/api/pages/absence'
|
} from '@/api/humanResource/absence'
|
||||||
import {
|
import {
|
||||||
queryPostByUserIdApi
|
queryPostByUserIdApi
|
||||||
} from '@/api/system/user'
|
} from '@/api/system/user'
|
||||||
@ -103,8 +103,9 @@
|
|||||||
const minEndtime = ref(0)
|
const minEndtime = ref(0)
|
||||||
/**返回的最新一条请假结束时间*/
|
/**返回的最新一条请假结束时间*/
|
||||||
const resDate = ref('')
|
const resDate = ref('')
|
||||||
const uploadUrl = ref(getEnvBaseUrl() + '/sys/common/upload?appPath=职工请假/' + userStore.userInfo.department + '/' +
|
const loading = ref(false)
|
||||||
userStore.userInfo.realname)
|
const uploadUrl = getEnvBaseUrl() + '/sys/common/upload?appPath=职工请假/' + userStore.userInfo.department + '/' +
|
||||||
|
userStore.userInfo.realname
|
||||||
const columnChange = ({
|
const columnChange = ({
|
||||||
selectedItem,
|
selectedItem,
|
||||||
resolve,
|
resolve,
|
||||||
@ -154,6 +155,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
|
if (loading.value) return
|
||||||
form.value.validate().then(({
|
form.value.validate().then(({
|
||||||
valid,
|
valid,
|
||||||
errors
|
errors
|
||||||
@ -176,6 +178,7 @@
|
|||||||
title: '提示',
|
title: '提示',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
loading.value = true
|
||||||
addApi(submitData).then(res => {
|
addApi(submitData).then(res => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
startMutilProcess(res.message)
|
startMutilProcess(res.message)
|
||||||
@ -184,7 +187,9 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
128
src/pages-humanResource/absence/detail.vue
Normal file
128
src/pages-humanResource/absence/detail.vue
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<route lang="json5" type="page">
|
||||||
|
{
|
||||||
|
layout: 'default',
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarTitleText: '请假详情',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
<template>
|
||||||
|
<PageLayout navTitle="请假详情">
|
||||||
|
<wd-cell-group border>
|
||||||
|
<wd-cell title="职工姓名" :value="info.username_dictText" />
|
||||||
|
<wd-cell title="所属单位" :value="info.sysOrgCode_dictText" />
|
||||||
|
<wd-cell title="联系方式" :value="info.phone" />
|
||||||
|
<wd-cell title="请假类型" :value="info.type" />
|
||||||
|
<wd-cell title="请假开始时间" :value="info.begintime" />
|
||||||
|
<wd-cell title="请假结束时间" :value="info.endtime" />
|
||||||
|
<wd-cell title="请假天数" :value="info.days + '天'" />
|
||||||
|
<wd-cell title="出发地" :value="info.departure" />
|
||||||
|
<wd-cell title="目的地" :value="info.destination" />
|
||||||
|
<wd-cell title="请假原因" :value="info.reason" />
|
||||||
|
<wd-cell title="附件" v-if="info.path">
|
||||||
|
<template v-for="(img, index) in joy" :key="index">
|
||||||
|
<wd-img :width="100" :height="100" :src="img" :enable-preview="true" />
|
||||||
|
</template>
|
||||||
|
</wd-cell>
|
||||||
|
<wd-cell title="销假时间" :value="info.resumptiontime" v-if="info.resumptiontime && info.bpmStatus == '3'" />
|
||||||
|
<view v-if="!info.resumptiontime && info.bpmStatus == '3'">
|
||||||
|
<wd-calendar label="销假时间" prop="resumptiontime" v-model="resumptiontime" :min-date="minDate"/>
|
||||||
|
<view class="footer">
|
||||||
|
<wd-button type="primary" size="large" @click="handleSubmit" block>销假</wd-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</wd-cell-group>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
useMessage,
|
||||||
|
useToast
|
||||||
|
} from 'wot-design-uni'
|
||||||
|
import {
|
||||||
|
queryByIdApi,
|
||||||
|
editApi
|
||||||
|
} from '@/api/humanResource/absence'
|
||||||
|
import {
|
||||||
|
imgUrl
|
||||||
|
} from '@/utils/index'
|
||||||
|
import {
|
||||||
|
useUserStore
|
||||||
|
} from '@/store/user'
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
const toast = useToast()
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const info = ref({})
|
||||||
|
const path = ref([])
|
||||||
|
const joy = ref([])
|
||||||
|
const resumptiontime = ref(0)
|
||||||
|
const minDate = ref(0)
|
||||||
|
const queryById = (e) => {
|
||||||
|
queryByIdApi(e).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
info.value = res.result.records[0]
|
||||||
|
minDate.value = dateStringToTimestamp(info.value.begintime)
|
||||||
|
joy.value = info.value.path.split(',').map(path => imgUrl(path))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
if (!resumptiontime.value) return toast.warning('请选择销假时间!')
|
||||||
|
editApi({
|
||||||
|
id: info.value.id,
|
||||||
|
begintime: formatDate(info.value.begintime),
|
||||||
|
endtime: formatDate(info.value.endtime),
|
||||||
|
resumptiontime: formatDate(resumptiontime.value),
|
||||||
|
type: info.value.type
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
toast.success(res.message)
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack()
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
toast.warning(res.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(date) {
|
||||||
|
date = new Date(date)
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将日期字符串转换为13位时间戳(支持yyyymmdd和yyyy-mm-dd格式)
|
||||||
|
* @param {string} dateStr
|
||||||
|
* @returns {number} 13位时间戳(毫秒)
|
||||||
|
*/
|
||||||
|
function dateStringToTimestamp(dateStr) {
|
||||||
|
const date = new Date();
|
||||||
|
const normalized = dateStr.replace(/-/g, '');
|
||||||
|
date.setFullYear(
|
||||||
|
parseInt(normalized.substring(0, 4)),
|
||||||
|
parseInt(normalized.substring(4, 6)) - 1,
|
||||||
|
parseInt(normalized.substring(6, 8))
|
||||||
|
);
|
||||||
|
date.setHours(0, 0, 0, 0);
|
||||||
|
return date.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
queryById(options.id)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.footer {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,8 +1,190 @@
|
|||||||
|
<route lang="json5" type="page">
|
||||||
|
{
|
||||||
|
layout: 'default',
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarTitleText: '请假信息',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</route>
|
||||||
<template>
|
<template>
|
||||||
|
<PageLayout navTitle="请假信息">
|
||||||
|
<wd-card style="margin-top: 10px;">
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="12"><uni-title title="所属单位" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
<wd-col :span="12"><uni-title title="重置" align="right" type="h5" color="#666666"
|
||||||
|
@click="reset"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="24">
|
||||||
|
<SelectDept label="" v-model="orgCode" @change="queryLeave" rowKey="orgCode" :multiple="false">
|
||||||
|
</SelectDept>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="12"><uni-title title="姓名" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
<wd-col :span="12"><uni-title title="劳动合同号" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="12">
|
||||||
|
<uni-easyinput v-model="realname" placeholder="姓名模糊查询" @change="queryLeave" @clear="queryLeave" />
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="12">
|
||||||
|
<uni-easyinput v-model="contractNumber" placeholder="劳动合同号查询" @change="queryLeave" @clear="queryLeave" />
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="24"><uni-title title="请假时间" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="24">
|
||||||
|
<uni-datetime-picker v-model="range" type="daterange" rangeSeparator="至" @input="queryLeave" />
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<l-echart ref="chart" />
|
||||||
|
</wd-card>
|
||||||
|
<view v-for="(item, i) in list" :key="i" @click="jump(`./detail?id=${item.id}`)">
|
||||||
|
<wd-card :title="item.username_dictText+'的'+item.type+'申请'">
|
||||||
|
<view class="card-content">
|
||||||
|
<view class="meta-info">
|
||||||
|
<wd-icon name="usergroup" size="14px" color="#999"></wd-icon>
|
||||||
|
<text class="meta-text">{{item.sysOrgCode_dictText}}</text>
|
||||||
|
<wd-icon name="time" size="14px" color="#999" style="margin-left: auto;"></wd-icon>
|
||||||
|
<text class="meta-text">
|
||||||
|
{{item.begintime}}至{{item.endtime}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-card>
|
||||||
|
</view>
|
||||||
|
</PageLayout>
|
||||||
</template>
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
listApi,
|
||||||
|
countByOrgApi
|
||||||
|
} from '@/api/humanResource/absence'
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import SelectDept from '@/components/SelectDept/SelectDept'
|
||||||
|
const chart = ref(null);
|
||||||
|
const chartOption = ref({});
|
||||||
|
const list = ref([]) //请假信息列表
|
||||||
|
const realname = ref('') //姓名查询
|
||||||
|
const contractNumber = ref('') //劳动合同号查询
|
||||||
|
const orgCode = ref('') //单位查询
|
||||||
|
const type = ref('') //图表点击事件 请假类别
|
||||||
|
const range = ref([]) //日期查询
|
||||||
|
const timeout = ref(null)
|
||||||
|
let pageNo = 1
|
||||||
|
let pageSize = 10
|
||||||
|
let loading = false
|
||||||
|
|
||||||
<script>
|
const queryLeave = (e) => {
|
||||||
|
let param = {
|
||||||
|
sysOrgCode: orgCode.value,
|
||||||
|
begin: range.value[0],
|
||||||
|
end: range.value[1],
|
||||||
|
type: type.value,
|
||||||
|
// username: username.value,
|
||||||
|
realname: realname.value,
|
||||||
|
contractNumbers: contractNumber.value
|
||||||
|
}
|
||||||
|
if (e == 1) { // 下拉刷新时,pageNo++
|
||||||
|
pageNo++;
|
||||||
|
} else { // list置空,pageNo置1
|
||||||
|
list.value = [];
|
||||||
|
pageNo = 1;
|
||||||
|
if (e != 2) {
|
||||||
|
// 如果不是图表点击事件,更新图表
|
||||||
|
setChartOption(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新数据
|
||||||
|
getList(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getList = (params = {}) => {
|
||||||
|
setChartOption(params)
|
||||||
|
loading = true
|
||||||
|
listApi({
|
||||||
|
...params,
|
||||||
|
pageNo,
|
||||||
|
pageSize
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
list.value = [...list.value, ...res.result.records]
|
||||||
|
}
|
||||||
|
loading = false
|
||||||
|
}).catch((err) => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const setChartOption = (e) => {
|
||||||
|
countByOrgApi(e).then(res => {
|
||||||
|
chartOption.value = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'pie',
|
||||||
|
radius: '50%',
|
||||||
|
data: res.result
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
initChart()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = () => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (!chart.value) return;
|
||||||
|
const myChart = await chart.value.init(echarts);
|
||||||
|
myChart.setOption(chartOption.value);
|
||||||
|
myChart.on('click', (params) => {
|
||||||
|
// 根据 params 处理点击事件
|
||||||
|
type.value = params.name
|
||||||
|
queryLeave(2);
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
orgCode.value = ''
|
||||||
|
range.value = []
|
||||||
|
type.value = ''
|
||||||
|
// username.value = ''
|
||||||
|
realname.value = ''
|
||||||
|
contractNumber.value = ''
|
||||||
|
queryLeave()
|
||||||
|
}
|
||||||
|
|
||||||
|
const jump = (url) => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
getList()
|
||||||
|
});
|
||||||
|
onReachBottom(() => {
|
||||||
|
if (loading) return
|
||||||
|
queryLeave(1); //下拉刷新传1
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
|
.card-content {
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
.meta-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
.meta-text {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
511
src/pages-humanResource/personnel/ageStatistics.vue
Normal file
511
src/pages-humanResource/personnel/ageStatistics.vue
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
<template>
|
||||||
|
<PageLayout :navbarShow="false">
|
||||||
|
<wd-card style="margin: 10px;" id="top1">
|
||||||
|
<wd-row style="margin-bottom: 10rpx; margin-left: 30rpx; margin-right: 30rpx">
|
||||||
|
<wd-col :span="24"><uni-title :title="'所选单位'" align="left" type="h4"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row style="margin-bottom: 20rpx; margin-left: 30rpx; margin-right: 30rpx">
|
||||||
|
<wd-col :span="24">
|
||||||
|
<SelectDept label="" v-model="orgCode" @change="departChange" rowKey="orgCode" :multiple="false">
|
||||||
|
</SelectDept>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<!-- 概览统计 -->
|
||||||
|
<view class="stats-box" v-if="summary.total">
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="label">总人数</text>
|
||||||
|
<text class="value">{{ summary.total }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="label">平均年龄</text>
|
||||||
|
<text class="value">{{ summary.avgAge.toFixed(1) }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-card>
|
||||||
|
<!-- ECharts图表 -->
|
||||||
|
<view class="chart-container">
|
||||||
|
<l-echart ref="chart" @finished="initChart" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
|
||||||
|
<wd-row style="margin-top: 10px; margin-left: 30rpx; margin-right: 30rpx" v-if="tableData.length > 0">
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="titleStyle">序号</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">姓名</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">性别</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">年龄</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="titleStyle">操作</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
|
||||||
|
<scroll-view scroll-y :style="{ height: bottomHeight + 'px' }">
|
||||||
|
<wd-row style="margin-bottom: 10rpx; margin-left: 30rpx; margin-right: 30rpx">
|
||||||
|
<view v-for="(item, index) in tableData">
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.xm }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.xb_dictText }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.nl }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="dataStyle">
|
||||||
|
<span @click="detail(item)" style="color: red">详情</span>
|
||||||
|
<!-- <button size="mini" type="primary" @click="detail(item)">详情</button> -->
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
</scroll-view>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
useMessage,
|
||||||
|
useToast
|
||||||
|
} from 'wot-design-uni'
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import SelectDept from '@/components/SelectDept/SelectDept'
|
||||||
|
import {
|
||||||
|
listApi
|
||||||
|
} from '@/api/humanResource/personnel';
|
||||||
|
const message = useMessage()
|
||||||
|
const toast = useToast()
|
||||||
|
// 存储下方组件的高度
|
||||||
|
const bottomHeight = ref(0);
|
||||||
|
// 新增加载状态
|
||||||
|
const orgCode = ref('');
|
||||||
|
const rawData = ref([]);
|
||||||
|
const tableData = ref([]);
|
||||||
|
const summary = reactive({
|
||||||
|
total: 0,
|
||||||
|
avgAge: 0
|
||||||
|
});
|
||||||
|
const chart = ref(null);
|
||||||
|
const chartOption = ref({});
|
||||||
|
const drillPopup = ref(null);
|
||||||
|
const drillList = ref([]);
|
||||||
|
const drillTitle = ref('');
|
||||||
|
|
||||||
|
function detail(record) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/views/renliziyuan/renyuanxinxi/detail?data=' + encodeURIComponent(JSON.stringify(record))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 计算年龄
|
||||||
|
const calculateAge = (birthDate) => {
|
||||||
|
const today = new Date();
|
||||||
|
const birth = new Date(birthDate);
|
||||||
|
let age = today.getFullYear() - birth.getFullYear();
|
||||||
|
const monthDiff = today.getMonth() - birth.getMonth();
|
||||||
|
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
|
||||||
|
age--;
|
||||||
|
}
|
||||||
|
return age;
|
||||||
|
};
|
||||||
|
// 加载数据
|
||||||
|
const departChange = async (e, data) => {
|
||||||
|
tableData.value = [];
|
||||||
|
orgCode.value = e;
|
||||||
|
try {
|
||||||
|
// 显示加载状态
|
||||||
|
if (orgCode.value.length <= 6) {
|
||||||
|
toast.warning('全厂数据较多,请选下一层级...')
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
toast.loading('数据加载中...')
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
pageSize: 3000,
|
||||||
|
fields: ['xm', 'nl', 'xb', 'xb_dictText', 'orgCode', 'jcdw', 'jcxd', 'jcxdCode']
|
||||||
|
};
|
||||||
|
if (orgCode.value.length <= 9) {
|
||||||
|
params.orgCode = orgCode.value + '*';
|
||||||
|
} else {
|
||||||
|
params.jcxd_code = orgCode.value;
|
||||||
|
}
|
||||||
|
listApi(params)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
toast.close()
|
||||||
|
processData(res.result.records);
|
||||||
|
// 隐藏加载状态
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
toast.error('数据加载失败')
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('数据加载失败')
|
||||||
|
} finally {
|
||||||
|
// 隐藏加载状态
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 数据处理
|
||||||
|
const processData = (data) => {
|
||||||
|
// 添加年龄字段并过滤有效数据
|
||||||
|
const validData = data
|
||||||
|
.map((item) => ({
|
||||||
|
...item,
|
||||||
|
nl: calculateAge(item.cssj)
|
||||||
|
}))
|
||||||
|
.filter((item) => item.nl >= 21 && item.nl <= 64);
|
||||||
|
// 计算概览数据
|
||||||
|
summary.total = validData.length;
|
||||||
|
summary.avgAge = validData.reduce((sum, cur) => sum + cur.nl, 0) / summary.total || 0;
|
||||||
|
// 生成表格数据
|
||||||
|
// tableData.value = validData;
|
||||||
|
|
||||||
|
groupsData(validData);
|
||||||
|
// 生成图表数据
|
||||||
|
generateChartData(validData);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算统计信息...
|
||||||
|
const subOrgStaffs = ref({}); // 按下级单位存储所有人员
|
||||||
|
const ageGroupStaffs = ref({}); // 按年龄段存储所有人员
|
||||||
|
|
||||||
|
const groupsData = (data) => {
|
||||||
|
// 清空旧数据
|
||||||
|
subOrgStaffs.value = {};
|
||||||
|
ageGroupStaffs.value = {};
|
||||||
|
data.reduce((acc, cur) => {
|
||||||
|
// console.log(cur)
|
||||||
|
let subOrg = '';
|
||||||
|
let ageRange = getAgeRange(cur.nl);
|
||||||
|
// console.log(cur.orgCode, cur.jcxdCode)
|
||||||
|
if (cur.orgCode <= 6) {
|
||||||
|
subOrg = cur.orgCode;
|
||||||
|
} else {
|
||||||
|
subOrg = cur.jcxdCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储到subOrgStaffs
|
||||||
|
if (!subOrgStaffs.value[subOrg]) {
|
||||||
|
subOrgStaffs.value[subOrg] = [];
|
||||||
|
}
|
||||||
|
subOrgStaffs.value[subOrg].push(cur);
|
||||||
|
|
||||||
|
// 存储到ageGroupStaffs
|
||||||
|
if (!ageGroupStaffs.value[ageRange]) {
|
||||||
|
ageGroupStaffs.value[ageRange] = [];
|
||||||
|
}
|
||||||
|
ageGroupStaffs.value[ageRange].push(cur);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增年龄范围计算方法
|
||||||
|
const getAgeRange = (age) => {
|
||||||
|
const ranges = ['21-30岁', '31-40岁', '41-50岁', '51-60岁', '61-64岁'];
|
||||||
|
const index = Math.floor((age - 21) / 10);
|
||||||
|
return ranges[index] || '其他';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改后的显示人员列表方法
|
||||||
|
const showStaffList = (subOrg, ageRange) => {
|
||||||
|
// 从结构化数据中直接获取
|
||||||
|
const targetStaffs = subOrgStaffs.value[subOrg].filter((staff) => getAgeRange(staff.nl) === ageRange);
|
||||||
|
|
||||||
|
staffList.value = targetStaffs;
|
||||||
|
popupTitle.value = `${subOrg} ${ageRange}人员列表(共${targetStaffs.length}人)`;
|
||||||
|
popup.value.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增获取指定单位人员的方法
|
||||||
|
const getSubOrgStaffs = (subOrgCode) => {
|
||||||
|
return subOrgStaffs.value[subOrgCode] || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增获取指定年龄段人员的方法
|
||||||
|
const getAgeGroupStaffs = (ageRange) => {
|
||||||
|
return ageGroupStaffs.value[ageRange] || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成图表数据(修改部分)
|
||||||
|
const generateChartData = (data) => {
|
||||||
|
// 按基层单位分组
|
||||||
|
const ageRanges = ['21-30岁', '31-40岁', '41-50岁', '51-60岁', '61-64岁'];
|
||||||
|
const jcdwGroups = data.reduce((acc, cur) => {
|
||||||
|
if (!acc[cur.jcdw]) {
|
||||||
|
acc[cur.jcdw] = {
|
||||||
|
ageGroups: [0, 0, 0, 0, 0] // 21-30,31-40,41-50,51-60,61-64
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const ageGroup = Math.floor((cur.nl - 21) / 10);
|
||||||
|
// console.log(ageGroup, cur.jcdw)
|
||||||
|
if (ageGroup >= 0 && ageGroup <= 4) {
|
||||||
|
acc[cur.jcdw].ageGroups[ageGroup]++;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// 生成分组柱状图配置
|
||||||
|
const xData = Object.keys(jcdwGroups);
|
||||||
|
|
||||||
|
const seriesData = ageRanges.map((range, index) => ({
|
||||||
|
name: range,
|
||||||
|
type: 'bar',
|
||||||
|
data: xData.map((jcdw) => jcdwGroups[jcdw].ageGroups[index] || 0),
|
||||||
|
itemStyle: {
|
||||||
|
color: ['#5470C6', '#91CC75', '#FAC858', '#EE6666', '#73C0DE'][index]
|
||||||
|
},
|
||||||
|
// 显示数值标签
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
// 设置柱宽为 20 像素
|
||||||
|
// barWidth: 20
|
||||||
|
}));
|
||||||
|
chartOption.value = {
|
||||||
|
title: {
|
||||||
|
text: '人员年龄分组统计',
|
||||||
|
padding: [0, 0, 0, 30]
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
padding: [0, 30, 0, 0],
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
//工具配置项
|
||||||
|
|
||||||
|
restore: {
|
||||||
|
show: true //是否显示该工具
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true //是否显示该工具
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// tooltip: {
|
||||||
|
// trigger: 'axis',
|
||||||
|
// axisPointer: {
|
||||||
|
// type: 'shadow',
|
||||||
|
// label: {
|
||||||
|
// show: false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
grid: {
|
||||||
|
top: '15%',
|
||||||
|
left: '4%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '10%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ageRanges,
|
||||||
|
itemGap: 5,
|
||||||
|
padding: [0, 15, 0, 15],
|
||||||
|
y: 'bottom',
|
||||||
|
itemHeight: 8, //高
|
||||||
|
itemWidth: 8, //宽
|
||||||
|
type: 'scroll'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xData,
|
||||||
|
axisLabel: {
|
||||||
|
color: '#7F84B5',
|
||||||
|
fontWeight: 300,
|
||||||
|
interval: 0,
|
||||||
|
rotate: 0
|
||||||
|
},
|
||||||
|
padding: [0, 10, 0, 10],
|
||||||
|
axisTick: {
|
||||||
|
show: false //刻度线
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false //不显示坐标轴线
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{
|
||||||
|
show: true,
|
||||||
|
boundaryGap: false, //解决数据与线不对应问题
|
||||||
|
type: 'value',
|
||||||
|
// name: 'Budget (million USD)',
|
||||||
|
// data: this.yList,
|
||||||
|
minInterval: 1,
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
//背景网格线
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
axisTick: {
|
||||||
|
show: true //刻度线
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false //不显示坐标轴线
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
|
series: seriesData
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (!chart.value) return;
|
||||||
|
const myChart = await chart.value.init(echarts);
|
||||||
|
myChart.setOption(chartOption.value);
|
||||||
|
myChart.on('click', (params) => {
|
||||||
|
console.log(params.seriesName);
|
||||||
|
tableData.value = getAgeGroupStaffs(params.seriesName);
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
// #ifdef APP
|
||||||
|
getHeight();
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
toast.warning('全厂数据较多,请选下一层级...')
|
||||||
|
// #ifdef APP
|
||||||
|
getHeight();
|
||||||
|
// #endif
|
||||||
|
});
|
||||||
|
// #ifdef APP
|
||||||
|
|
||||||
|
const getHeight = () => {
|
||||||
|
// 获取屏幕高度
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
const screenHeight = systemInfo.screenHeight;
|
||||||
|
// 创建选择器查询对象
|
||||||
|
const query = uni.createSelectorQuery();
|
||||||
|
// 获取上方组件的高度
|
||||||
|
query
|
||||||
|
.select('#top1')
|
||||||
|
.boundingClientRect((rect1) => {
|
||||||
|
// 计算上方组件高度总和
|
||||||
|
const topComponentsHeight = rect1.height;
|
||||||
|
// 计算下方组件的高度
|
||||||
|
bottomHeight.value = screenHeight - topComponentsHeight - 415;
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
};
|
||||||
|
|
||||||
|
// #endif
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = () => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (!chart.value) return;
|
||||||
|
const myChart = await chart.value.init(echarts);
|
||||||
|
myChart.setOption(chartOption.value);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
flex: 1;
|
||||||
|
border: 1rpx solid #ddd;
|
||||||
|
padding: 15rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-btn {
|
||||||
|
background: #007aff;
|
||||||
|
color: white;
|
||||||
|
padding: 0 40rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin: 30rpx 0;
|
||||||
|
padding: 20rpx;
|
||||||
|
background: #f8f8f8;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0000ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 400rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleStyle {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #747474;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: #f2f9fc;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle {
|
||||||
|
max-font-size: 14px;
|
||||||
|
/* 最大字体限制 */
|
||||||
|
min-font-size: 10px;
|
||||||
|
/* 最小字体限制 */
|
||||||
|
font-size: 12px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
615
src/pages-humanResource/personnel/detail.vue
Normal file
615
src/pages-humanResource/personnel/detail.vue
Normal file
@ -0,0 +1,615 @@
|
|||||||
|
<route lang="json5" type="page">
|
||||||
|
{
|
||||||
|
layout: 'default',
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarTitleText: '人员详情',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
<template>
|
||||||
|
<PageLayout navTitle="人员详情">
|
||||||
|
<scroll-view :scroll-x="true" :scroll-y="true">
|
||||||
|
<view style="padding: 10px 10px 10px 10px">
|
||||||
|
<uni-title title="基本信息" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="18"><yjly-row-cell :cellData="cellData" :rowDataCount="2"></yjly-row-cell></wd-col>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="img">
|
||||||
|
<image mode="aspectFit"
|
||||||
|
:src="'https://36.112.48.190/jeecg-boot/sys/common/static/' + imgUrl"></image>
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<yjly-row-cell :cellData="cellData1" :rowDataCount="3"></yjly-row-cell>
|
||||||
|
<view v-if="roleDetail">
|
||||||
|
<uni-title title="年度绩效考核" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">序号</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="10">
|
||||||
|
<view class="titleStyle">绩效考核年份</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="10">
|
||||||
|
<view class="titleStyle">绩效考核成绩</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<view v-for="(item, index) in jxkhxxList">
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="10">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.nf }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="10">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.khcj + '---' + item.khcj_dictText }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
</view>
|
||||||
|
<uni-title title="工作简历" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">起始时间</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">终止时间</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="11">
|
||||||
|
<view class="titleStyle">工作职务</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">岗位职务</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<view v-for="(item, index) in gzjlList">
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.kssj }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.jssj }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="11">
|
||||||
|
<view class="dataStyle2" ref="dataView">
|
||||||
|
{{ item.jlms }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.jlms2 }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
<!-- <uni-segmented-control></uni-segmented-control> -->
|
||||||
|
<view>
|
||||||
|
<uni-title title="学历信息" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">类别</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">毕业院校</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">所学专业</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">学历</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">学位</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">毕业时间</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<view v-for="(item, index) in xlxxList">
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.xllb }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.byyx }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2" ref="dataView">
|
||||||
|
{{ item.sxzy }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.qdxl }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.qdxw }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.bytime }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
</view>
|
||||||
|
<uni-title title="取证信息" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="titleStyle">证书名称</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">证书等级</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">取证时间</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">复审时间</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="titleStyle">备注</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<view v-for="(item, index) in zjtzList">
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="dataStyle2" ref="dataView">
|
||||||
|
{{ item.zjmc }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.zsdj }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.fzrq }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.fssj }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.bz }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
<view v-if="roleDetail">
|
||||||
|
<uni-title title="家庭信息" type="h1" color="blue"></uni-title>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">称谓</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="titleStyle">姓名</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="titleStyle">出生年月</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">政治面貌</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="7">
|
||||||
|
<view class="titleStyle">工作单位及职务</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<view v-for="(item, index) in zyjtcyList">
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle2">
|
||||||
|
{{ item.ybrgx }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="3">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.gxname }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="6">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.cstime }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.cyzzmm }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="7">
|
||||||
|
<view class="dataStyle2" ref="dataView">
|
||||||
|
{{ item.cygzdw }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryGzjlByRyLdhth,
|
||||||
|
queryQzqkByRyLdhth,
|
||||||
|
queryJtzycyByRyLdhth,
|
||||||
|
queryXlxxByRyLdhth,
|
||||||
|
queryGbxxByRyLdhth,
|
||||||
|
queryZyzgdjByRyLdhth,
|
||||||
|
queryJxkhByRyLdhth
|
||||||
|
} from '@/api/humanResource/personnel'
|
||||||
|
import {
|
||||||
|
useUserStore
|
||||||
|
} from '@/store/user'
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
|
||||||
|
const tempCellData = ref({
|
||||||
|
title: '',
|
||||||
|
value: '',
|
||||||
|
titleSpan: 4,
|
||||||
|
valueSpan: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
const roleDetail = ref(store.userInfo.realname === '廖德云' || store.userInfo.realname === '马敬朝');
|
||||||
|
|
||||||
|
const ldhth = ref('');
|
||||||
|
const imgUrl = ref('');
|
||||||
|
const renyuanData = ref({});
|
||||||
|
const cellData = ref([]);
|
||||||
|
const cellData1 = ref([]);
|
||||||
|
|
||||||
|
const gzjlList = ref([]); // 人员其他子表信息-工作经历
|
||||||
|
const zjtzList = ref([]); // 人员其他子表信息-证件台账
|
||||||
|
const zyjtcyList = ref([]); // 人员其他子表信息-主要家庭成员
|
||||||
|
const xlxxList = ref([]); // 人员其他子表信息-学历证书
|
||||||
|
const gbxxList = ref([]); // 人员其他子表信息-干部信息
|
||||||
|
const zyzgdjList = ref([]); // 人员其他子表信息-职业资格等级
|
||||||
|
const jxkhxxList = ref([]); // 人员其他子表信息-绩效考核信息
|
||||||
|
|
||||||
|
function getChildTable() {
|
||||||
|
console.log(ldhth.value);
|
||||||
|
|
||||||
|
queryJxkhByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
jxkhxxList.value = res.result.records;
|
||||||
|
// console.log(jxkhxxList.value)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
queryGbxxByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
gbxxList.value = res;
|
||||||
|
// console.log(gbxxList.value)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
queryZyzgdjByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
zyzgdjList.value = res;
|
||||||
|
// console.log(zyzgdjList.value)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
queryGzjlByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
if (res.length > 0) {
|
||||||
|
gzjlList.value = res;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
queryQzqkByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
if (res.length > 0) {
|
||||||
|
zjtzList.value = res;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
queryJtzycyByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
// console.log(res);
|
||||||
|
if (res.length > 0) {
|
||||||
|
zyjtcyList.value = res;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
queryXlxxByRyLdhth({
|
||||||
|
ldhth: ldhth.value
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
xlxxList.value = [];
|
||||||
|
if (res.result.records.length > 0) {
|
||||||
|
var rress = res.result.records;
|
||||||
|
// console.log(rress);
|
||||||
|
for (let i = 0; i < rress.length; i++) {
|
||||||
|
if ((rress[i].onexl == 1) & (rress[i].zgxl == 1)) {
|
||||||
|
rress[i].xllb = '第一学历';
|
||||||
|
xlxxList.value.push(JSON.parse(JSON.stringify(rress[i])));
|
||||||
|
// console.log(xlxxList.value)
|
||||||
|
rress[i].xllb = '最高学历';
|
||||||
|
xlxxList.value.push(JSON.parse(JSON.stringify(rress[i])));
|
||||||
|
// console.log(xlxxList.value)
|
||||||
|
}
|
||||||
|
if ((rress[i].onexl == 1) & (rress[i].zgxl != 1)) {
|
||||||
|
rress[i].xllb = '第一学历';
|
||||||
|
xlxxList.value.push(rress[i]);
|
||||||
|
}
|
||||||
|
if ((rress[i].onexl != 1) & (rress[i].zgxl == 1)) {
|
||||||
|
rress[i].xllb = '最高学历';
|
||||||
|
xlxxList.value.push(rress[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjustFontSize()
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getJbxx() {
|
||||||
|
cellData.value.push({
|
||||||
|
title: '姓名',
|
||||||
|
value: renyuanData.value.xm,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '性别',
|
||||||
|
value: renyuanData.value.xb_dictText,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
|
||||||
|
cellData.value.push({
|
||||||
|
title: '出生年月',
|
||||||
|
value: renyuanData.value.cssj,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '民族',
|
||||||
|
value: renyuanData.value.mz,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '籍贯',
|
||||||
|
value: renyuanData.value.jg,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '出生地',
|
||||||
|
value: renyuanData.value.csd,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '工作时间',
|
||||||
|
value: renyuanData.value.cjgzsj,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '现专业',
|
||||||
|
value: '',
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '政治面貌',
|
||||||
|
value: renyuanData.value.zzmm === '群众' ? renyuanData.value.zzmm : renyuanData.value.zzmm + renyuanData
|
||||||
|
.value.jrsj,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData.value.push({
|
||||||
|
title: '用工形式',
|
||||||
|
value: renyuanData.value.rylb1_dictText,
|
||||||
|
titleSpan: 6,
|
||||||
|
valueSpan: 6,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData1.value.push({
|
||||||
|
title: '所在单位',
|
||||||
|
value: renyuanData.value.orgCode_dictText,
|
||||||
|
titleSpan: 4,
|
||||||
|
valueSpan: 7,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData1.value.push({
|
||||||
|
title: '专业技术资格',
|
||||||
|
value: gbxxList.value.zc === 0 ? '/' : gbxxList.value.zc + gbxxList.value.zcsj,
|
||||||
|
titleSpan: 5,
|
||||||
|
valueSpan: 7,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData1.value.push({
|
||||||
|
title: '职业资格等级',
|
||||||
|
value: zyzgdjList.value.ztgz === '0' ? '/' : zyzgdjList.value.ztgz + zyzgdjList.value.ztgzdj,
|
||||||
|
titleSpan: 4,
|
||||||
|
valueSpan: 4,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData1.value.push({
|
||||||
|
title: '职务(岗位)',
|
||||||
|
value: gbxxList.value.zw,
|
||||||
|
titleSpan: 4,
|
||||||
|
valueSpan: 4,
|
||||||
|
class: 'dataStyle1'
|
||||||
|
});
|
||||||
|
cellData1.value.push({
|
||||||
|
title: '职位级别',
|
||||||
|
value: gbxxList.value.zwcj,
|
||||||
|
titleSpan: 4,
|
||||||
|
valueSpan: 4,
|
||||||
|
class: 'dataStyle'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((e) => {
|
||||||
|
console.log(store.userinfo);
|
||||||
|
renyuanData.value = JSON.parse(decodeURIComponent(e.data));
|
||||||
|
imgUrl.value = renyuanData.value.zplj;
|
||||||
|
console.log(imgUrl.value, renyuanData.value);
|
||||||
|
ldhth.value = renyuanData.value.ldhth;
|
||||||
|
getChildTable();
|
||||||
|
setTimeout(function() {
|
||||||
|
getJbxx();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.renyuanInfo {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 98vh;
|
||||||
|
width: 900px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleStyle {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #747474;
|
||||||
|
line-height: 35px;
|
||||||
|
height: 35px;
|
||||||
|
background: #f2f9fc;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 25px;
|
||||||
|
height: 50px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
text-align: center;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle1 {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle2 {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 15px;
|
||||||
|
height: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
text-align: center;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
height: 154px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
/* 仅用于展示容器范围,可根据需要移除 */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
/* 水平居中 */
|
||||||
|
align-items: center;
|
||||||
|
/* 垂直居中 */
|
||||||
|
overflow: hidden;
|
||||||
|
/* 防止图片溢出容器 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
890
src/pages-humanResource/personnel/generalFieldStatistics.vue
Normal file
890
src/pages-humanResource/personnel/generalFieldStatistics.vue
Normal file
@ -0,0 +1,890 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container" id="top1">
|
||||||
|
<wd-row style="margin-bottom: 10px">
|
||||||
|
<wd-col :span="5"><uni-title :title="'选择单位'" align="left" type="h4"></uni-title></wd-col>
|
||||||
|
<wd-col :span="19">
|
||||||
|
<SelectDept label="" v-model="selectedOrgCode" @change="onOrgCodeChange" rowKey="orgCode"
|
||||||
|
:multiple="false">
|
||||||
|
</SelectDept>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row style="margin-bottom: 10px">
|
||||||
|
<wd-col :span="5"><uni-title :title="'选择字段'" align="left" type="h4"></uni-title></wd-col>
|
||||||
|
<wd-col :span="12">
|
||||||
|
<wd-picker :columns="fieldList" v-model="selectedField" @confirm="onFieldChange" />
|
||||||
|
</wd-col>
|
||||||
|
<wd-col style="margin-left:5px" :span="6" v-if="selectedField==='zjmc'"><button type="primary" size="mini"
|
||||||
|
@click="openZhengshu">筛选</button></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<!-- ECharts图表 -->
|
||||||
|
<view class="chart-container">
|
||||||
|
<l-echart ref="chart" @finished="initChart" />
|
||||||
|
</view>
|
||||||
|
<!-- 翻页按钮 -->
|
||||||
|
<!-- <view style="display: flex; justify-content: center; margin-top: 10px">
|
||||||
|
<button @click="prevPage" :disabled="currentPage === 1" size="mini">上一页</button>
|
||||||
|
<button @click="nextPage" :disabled="currentPage * pageSize >= chartDataCount.value" size="mini">下一页</button>
|
||||||
|
</view> -->
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<wd-row style="margin-top: 10px; margin-left: 20px; margin-right: 20px" v-if="personnelList.length > 0">
|
||||||
|
<wd-col :span="2">
|
||||||
|
<view class="titleStyle">序号</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">姓名</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="titleStyle">基层单位</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5" v-if="selectedField !== 'zjmc'">
|
||||||
|
<view class="titleStyle">基层班组</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5" v-else>
|
||||||
|
<view class="titleStyle">岗位</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">年龄</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="titleStyle">操作</view>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<!-- <scroll-view scroll-y :style="{ height: bottomHeight + 'px' }"> -->
|
||||||
|
<scroll-view scroll-y >
|
||||||
|
<wd-row style="margin-bottom: 10px; margin-left: 20px; margin-right: 20px; font-size: 12px">
|
||||||
|
<view v-for="(item, index) in personnelList">
|
||||||
|
<wd-col :span="2">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.xm }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
|
||||||
|
<wd-col :span="5">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.jcdw }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="5" v-if="selectedField != 'zjmc'">
|
||||||
|
<view class="dataStyle1">
|
||||||
|
{{ item.jcxd }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4" v-else>
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.sdgw }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle">
|
||||||
|
{{ item.nl }}
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
|
||||||
|
<wd-col :span="4">
|
||||||
|
<view class="dataStyle">
|
||||||
|
<span @click="detail(item)" style="color: red;">详情</span>
|
||||||
|
</view>
|
||||||
|
</wd-col>
|
||||||
|
</view>
|
||||||
|
</wd-row>
|
||||||
|
</scroll-view>
|
||||||
|
<wd-popup v-model="showPopup" position="bottom">
|
||||||
|
<wd-card>
|
||||||
|
<uni-title :title="'已选证书:'" align="left" type="h4"></uni-title>
|
||||||
|
<view style="color: red;font-weight: 300;margin-bottom: 10px;">{{dictData}}</view>
|
||||||
|
<scroll-view scroll-y style="height: 40vh;">
|
||||||
|
<cxc-szcx-dictSelect :dictCode="dictCode" @change="dictChange"></cxc-szcx-dictSelect>
|
||||||
|
</scroll-view>
|
||||||
|
</wd-card>
|
||||||
|
</wd-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import {
|
||||||
|
cxcRyDatAstatistics,
|
||||||
|
cxcRyDatAstatisticsCertificate,
|
||||||
|
cxcRyDatAstatisticsDetails
|
||||||
|
} from '@/api/humanResource/personnel';
|
||||||
|
import SelectDept from '@/components/SelectDept/SelectDept'
|
||||||
|
|
||||||
|
// 存储下方组件的高度 tableData
|
||||||
|
// const bottomHeight = ref(0);
|
||||||
|
// 新增加载状态
|
||||||
|
const chart = ref(null);
|
||||||
|
const chartDataCount = ref(0);
|
||||||
|
const fieldList = ref([{
|
||||||
|
label: '取证情况',
|
||||||
|
value: 'zjmc',
|
||||||
|
isDict: false,
|
||||||
|
dictCode: 'gzrlzy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位类别',
|
||||||
|
value: 'gwlb',
|
||||||
|
isDict: false,
|
||||||
|
dictCode: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '性别',
|
||||||
|
value: 'xb',
|
||||||
|
isDict: true,
|
||||||
|
dictCode: 'sex'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '政治面貌',
|
||||||
|
value: 'zzmm',
|
||||||
|
isDict: true,
|
||||||
|
dictCode: 'zzmm'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '民族',
|
||||||
|
value: 'mz',
|
||||||
|
isDict: true,
|
||||||
|
dictCode: 'mz'
|
||||||
|
}
|
||||||
|
]); // 字段列表
|
||||||
|
|
||||||
|
const dictCode = ref('');
|
||||||
|
const dictData = ref('');
|
||||||
|
const showPopup = ref(false);
|
||||||
|
const fieldisDict = ref(true);
|
||||||
|
const selectedOrgCode = ref(''); // 当前选择的单位 orgCode
|
||||||
|
const selectedField = ref(''); // 当前选择的字段
|
||||||
|
const orgCodeGroupData = ref([]); //按照orgcode进行分组的数据 含劳动合同号
|
||||||
|
const chartData = ref({}); // 图表数据
|
||||||
|
const personnelList = ref([]); // 人员列表 initChart
|
||||||
|
const fieldValues = ref([]); //字段值
|
||||||
|
const fieldTexts = ref([]); //字段值
|
||||||
|
const chartOption = ref({});
|
||||||
|
const orgType = ref(''); //记录单位层级 by 闵
|
||||||
|
|
||||||
|
//图标翻页
|
||||||
|
const pageSize = ref(3); // 每页显示的项目数量
|
||||||
|
const currentPage = ref(1); // 当前页码
|
||||||
|
|
||||||
|
function detail(record) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: './detail?data=' + encodeURIComponent(JSON.stringify(record))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// onMounted(() => {
|
||||||
|
// getHeight();
|
||||||
|
// });
|
||||||
|
|
||||||
|
const dictChange = (e) => {
|
||||||
|
dictData.value = e
|
||||||
|
fetchStatisticsData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// const getHeight = () => {
|
||||||
|
// // 获取屏幕高度
|
||||||
|
// const systemInfo = uni.getSystemInfoSync();
|
||||||
|
// const screenHeight = systemInfo.screenHeight;
|
||||||
|
// // 创建选择器查询对象
|
||||||
|
// const query = uni.createSelectorQuery();
|
||||||
|
// // 获取上方组件的高度
|
||||||
|
// query
|
||||||
|
// .select('#top1')
|
||||||
|
// .boundingClientRect((rect1) => {
|
||||||
|
// // 计算上方组件高度总和
|
||||||
|
// const topComponentsHeight = rect1.height;
|
||||||
|
// // 计算下方组件的高度
|
||||||
|
// bottomHeight.value = screenHeight - topComponentsHeight - 415;
|
||||||
|
// })
|
||||||
|
// .exec();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initChart = () => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (!chart.value) return;
|
||||||
|
const myChart = await chart.value.init(echarts);
|
||||||
|
myChart.setOption(chartOption.value);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
// const prevPage = () => {
|
||||||
|
// if (currentPage.value > 1) {
|
||||||
|
// currentPage.value--;
|
||||||
|
// }
|
||||||
|
// updateChart(chartData.value);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const nextPage = () => {
|
||||||
|
// if (currentPage.value * pageSize.value < chartDataCount.value) {
|
||||||
|
// currentPage.value++;
|
||||||
|
// // 计算当前页数据的起始和结束索引
|
||||||
|
// const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
// const endIndex = startIndex + pageSize.value;
|
||||||
|
// updateChart(chartData.value);
|
||||||
|
// // const tempChartData = temp.slice(startIndex, endIndex);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// 更具数据生成图标的option
|
||||||
|
const getChartOption = (ChartData) => {
|
||||||
|
// let temp = JSON.parse(JSON.stringify(tempchartData[0].children));
|
||||||
|
// chartDataCount.value = temp.length;
|
||||||
|
// 计算当前页数据的起始和结束索引
|
||||||
|
|
||||||
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
// 截取当前页的数据
|
||||||
|
const tempChartData = ChartData.slice(startIndex, endIndex);
|
||||||
|
try {
|
||||||
|
let xData = [];
|
||||||
|
let seriesData = [];
|
||||||
|
//当前机构下的数据 transformDataForEcharts
|
||||||
|
|
||||||
|
let legendData = [];
|
||||||
|
for (let i = 0; i < fieldValues.value.length; i++) {
|
||||||
|
legendData.push(fieldValues.value[i].fieldText);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempChartData.forEach((item) => {
|
||||||
|
xData.push(item.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < fieldValues.value.length; i++) {
|
||||||
|
let tempData = [];
|
||||||
|
tempChartData.forEach((item) => {
|
||||||
|
if (item.data[i]) {
|
||||||
|
tempData.push(item.data[i]);
|
||||||
|
} else {
|
||||||
|
tempData.push(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
seriesData.push({
|
||||||
|
name: fieldValues.value[i].fieldText,
|
||||||
|
type: 'bar',
|
||||||
|
label: {
|
||||||
|
show: true, // 显示数值标签
|
||||||
|
position: 'top' // 数值标签位置
|
||||||
|
},
|
||||||
|
data: tempData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tempOption = {
|
||||||
|
toolbox: {
|
||||||
|
padding: [0, 30, 0, 0],
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
//工具配置项
|
||||||
|
restore: {
|
||||||
|
show: true //是否显示该工具
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true //是否显示该工具
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xData,
|
||||||
|
axisLabel: {
|
||||||
|
color: '#7F84B5',
|
||||||
|
fontWeight: 300,
|
||||||
|
interval: 0,
|
||||||
|
rotate: 0
|
||||||
|
},
|
||||||
|
padding: [0, 10, 0, 10],
|
||||||
|
axisTick: {
|
||||||
|
show: false //刻度线
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false //不显示坐标轴线
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{
|
||||||
|
show: true,
|
||||||
|
boundaryGap: false, //解决数据与线不对应问题
|
||||||
|
type: 'value',
|
||||||
|
// name: 'Budget (million USD)',
|
||||||
|
// data: this.yList,
|
||||||
|
minInterval: 1,
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
//背景网格线
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
axisTick: {
|
||||||
|
show: true //刻度线
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false //不显示坐标轴线
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
series: seriesData,
|
||||||
|
|
||||||
|
legend: {
|
||||||
|
data: legendData,
|
||||||
|
itemGap: 1,
|
||||||
|
padding: [0, 0, 0, 0],
|
||||||
|
y: 'bottom',
|
||||||
|
itemHeight: 8, //高
|
||||||
|
itemWidth: 18, //宽
|
||||||
|
type: 'scroll'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return tempOption;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
|
const updateChart = (tempchartData) => {
|
||||||
|
// 初始化图表
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (!chart.value) return;
|
||||||
|
const myChart = await chart.value.init(echarts);
|
||||||
|
let tempOption = getChartOption(tempchartData);
|
||||||
|
|
||||||
|
myChart.setOption(tempOption);
|
||||||
|
// 点击钻取事件
|
||||||
|
myChart.on('click', (params) => {
|
||||||
|
|
||||||
|
let ldhth = '';
|
||||||
|
//这里判断有没有孩子元素,有查找下一级,没有查看本级目录ldhth
|
||||||
|
if (orgCodeGroupData.value.children.length > 0) {
|
||||||
|
let updateData = findRyByOrgCode(orgCodeGroupData.value.children, params.name);
|
||||||
|
ldhth = updateData.fieldValues[params.seriesIndex].ldhth;
|
||||||
|
} else {
|
||||||
|
ldhth = orgCodeGroupData.value.fieldValues[params.seriesIndex].ldhth.join(',');
|
||||||
|
}
|
||||||
|
if (ldhth && ldhth.length > 0) {
|
||||||
|
fetchPersonnelList(ldhth);
|
||||||
|
}
|
||||||
|
// updateChart(updateData);
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
function openZhengshu() {
|
||||||
|
showPopup.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据一个键值查找数据
|
||||||
|
//查找人员劳动合同号
|
||||||
|
function findRyByOrgCode(treeData, targetOrgCode) {
|
||||||
|
for (const node of treeData) {
|
||||||
|
// 如果当前节点匹配,直接返回该节点及其子节点
|
||||||
|
if (node.orgText === targetOrgCode) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
// 递归检查子节点
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
const found = findNodeByOrgCode(node.children, targetOrgCode);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从echart图标的树状数据中根据 orgCode 获取节点及其子节点数据
|
||||||
|
* @param {Array} treeData 树状数据
|
||||||
|
* @param {string} targetOrgCode 目标 orgCode
|
||||||
|
* @returns {Object|null} 匹配的节点及其子节点数据,未找到返回 null
|
||||||
|
*/
|
||||||
|
function findNodeByOrgCode(treeData, targetOrgCode) {
|
||||||
|
for (const node of treeData) {
|
||||||
|
// 如果当前节点匹配,直接返回该节点及其子节点
|
||||||
|
if (node.name === targetOrgCode) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
// 递归检查子节点
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
const found = findNodeByOrgCode(node.children, targetOrgCode);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取所有的fieldValue
|
||||||
|
function collectUniqueKeyFieldValues(tree) {
|
||||||
|
const uniqueMap = new Map();
|
||||||
|
tree.forEach((item) => {
|
||||||
|
const {
|
||||||
|
fieldValue,
|
||||||
|
fieldText
|
||||||
|
} = item;
|
||||||
|
const key = `${fieldValue}-${fieldText}`;
|
||||||
|
|
||||||
|
if (!uniqueMap.has(key)) {
|
||||||
|
uniqueMap.set(key, {
|
||||||
|
fieldValue,
|
||||||
|
fieldText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = Array.from(uniqueMap.values());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装一个类来管理组织代码和组织名称的映射
|
||||||
|
class OrgCodeMapper {
|
||||||
|
constructor(data) {
|
||||||
|
// 初始化一个空对象用于存储映射关系
|
||||||
|
this.orgCodeToOrgTextMap = {};
|
||||||
|
// 遍历传入的数据数组
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const item = data[i];
|
||||||
|
// 将 orgCode 作为键,orgText 作为值存入映射对象
|
||||||
|
this.orgCodeToOrgTextMap[item.orgCode] = item.orgText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找指定 orgCode 对应的 orgText 的方法
|
||||||
|
findOrgText(orgCode) {
|
||||||
|
return this.orgCodeToOrgTextMap[orgCode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例用法
|
||||||
|
/**
|
||||||
|
* 转换数据为支持钻取的ECharts格式
|
||||||
|
* @param {Array} data 原始数据
|
||||||
|
* @param {string} selectOrgCode 当前选择的组织编码
|
||||||
|
* @returns {Object} 包含当前层级数据和子节点信息的对象 符合echart的格式
|
||||||
|
*/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
function transformData(selectOrgCode, data) {
|
||||||
|
const nodes = new Map();
|
||||||
|
//获取所有的fieldValue 用于图例和钻取和data[]中的数据顺序保持一致 动态建立fieldValue的数据
|
||||||
|
fieldValues.value = collectUniqueKeyFieldValues(data);
|
||||||
|
const orgMapper = new OrgCodeMapper(data); //用于快速查找orgtext
|
||||||
|
// 获取orgCode的所有层级
|
||||||
|
function getHierarchy(orgCode) {
|
||||||
|
const hierarchy = [];
|
||||||
|
for (let i = selectOrgCode.length; i <= orgCode.length; i += 3) {
|
||||||
|
hierarchy.push(orgCode.substring(0, i));
|
||||||
|
}
|
||||||
|
return hierarchy;
|
||||||
|
}
|
||||||
|
// 获取父级orgCode
|
||||||
|
function getParentCode(code) {
|
||||||
|
if (code.length <= 3) return null;
|
||||||
|
return code.substring(0, code.length - 3);
|
||||||
|
}
|
||||||
|
// 动态赋值series的数据长度
|
||||||
|
let tempArrayValue = new Array(fieldValues.value.length).fill(0);
|
||||||
|
// 创建所有节点并建立父子关系
|
||||||
|
data.forEach((entry) => {
|
||||||
|
const hierarchy = getHierarchy(entry.orgCode);
|
||||||
|
hierarchy.forEach((code) => {
|
||||||
|
let tempOrgText = orgMapper.findOrgText(code) === undefined ? '' : orgMapper.findOrgText(
|
||||||
|
code);
|
||||||
|
if (!nodes.has(code)) {
|
||||||
|
nodes.set(code, {
|
||||||
|
orgCode: code,
|
||||||
|
name: tempOrgText,
|
||||||
|
type: 'bar',
|
||||||
|
data: JSON.parse(JSON.stringify(tempArrayValue)), // 初始化data为[0, 0] 动态
|
||||||
|
children: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 更新当前节点的data
|
||||||
|
const node = nodes.get(entry.orgCode);
|
||||||
|
const fieldValue = entry.fieldValue;
|
||||||
|
|
||||||
|
for (let i = 0; i < fieldValues.value.length; i++) {
|
||||||
|
if (fieldValue === fieldValues.value[i].fieldValue) {
|
||||||
|
node.data[i] += entry.number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 建立父子关系
|
||||||
|
for (let i = 0; i < hierarchy.length - 1; i++) {
|
||||||
|
const parentCode = hierarchy[i];
|
||||||
|
const childCode = hierarchy[i + 1];
|
||||||
|
const parentNode = nodes.get(parentCode);
|
||||||
|
const childNode = nodes.get(childCode);
|
||||||
|
if (!parentNode.children.some((c) => c.orgCode === childCode)) {
|
||||||
|
parentNode.children.push(childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算非叶子节点的data(子节点之和)
|
||||||
|
function computeData(node) {
|
||||||
|
if (node.children.length === 0) return;
|
||||||
|
node.data = JSON.parse(JSON.stringify(tempArrayValue));
|
||||||
|
node.children.forEach((child) => {
|
||||||
|
computeData(child);
|
||||||
|
for (let i = 0; i < fieldValues.value.length; i++) {
|
||||||
|
node.data[i] += child.data[i];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有根节点(没有父节点或父节点不存在)
|
||||||
|
const rootNodes = [];
|
||||||
|
nodes.forEach((node, code) => {
|
||||||
|
const parentCode = getParentCode(code);
|
||||||
|
if (!parentCode || !nodes.has(parentCode)) {
|
||||||
|
rootNodes.push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 递归计算每个根节点的data
|
||||||
|
rootNodes.forEach((root) => computeData(root));
|
||||||
|
return rootNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//根据 orgCode 的分级格式,递归地汇总本级及其所有下级的数据,并将下级数据放在本级的 children 属性中。 deepseek
|
||||||
|
|
||||||
|
const groupByOrgCode = (orgCode, data) => {
|
||||||
|
// 过滤出本级和所有下级的数据
|
||||||
|
const filteredData = data.filter((item) => item.orgCode.startsWith(orgCode));
|
||||||
|
const orgMapper = new OrgCodeMapper(data);
|
||||||
|
// 如果过滤后的数据为空,返回 null
|
||||||
|
if (filteredData.length === 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '过滤后数据为空',
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 按照 fieldValue 分组
|
||||||
|
const groupedByFieldValue = {};
|
||||||
|
try {
|
||||||
|
filteredData.forEach((item) => {
|
||||||
|
if (!groupedByFieldValue[item.fieldValue]) {
|
||||||
|
groupedByFieldValue[item.fieldValue] = {
|
||||||
|
orgCode: item.orgCode,
|
||||||
|
orgText: item.orgText,
|
||||||
|
fieldText: item.fieldText,
|
||||||
|
number: 0,
|
||||||
|
ldhth: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
groupedByFieldValue[item.fieldValue].number += item.number;
|
||||||
|
groupedByFieldValue[item.fieldValue].ldhth.push(...item.ldhth.split(','));
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
// 构建本级结果
|
||||||
|
const result = {
|
||||||
|
orgCode: orgCode,
|
||||||
|
orgText: orgMapper.findOrgText(orgCode),
|
||||||
|
fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => {
|
||||||
|
const {
|
||||||
|
fieldText,
|
||||||
|
orgCode,
|
||||||
|
orgText
|
||||||
|
} = groupedByFieldValue[fieldValue] || {};
|
||||||
|
return {
|
||||||
|
fieldValue: fieldValue,
|
||||||
|
fieldText: fieldText,
|
||||||
|
orgCode: orgCode,
|
||||||
|
orgText: orgText,
|
||||||
|
number: groupedByFieldValue[fieldValue].number,
|
||||||
|
ldhth: [...new Set(groupedByFieldValue[fieldValue].ldhth)] // 去重
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取所有下一级的 orgCode
|
||||||
|
const nextLevelOrgCodes = new Set();
|
||||||
|
try {
|
||||||
|
filteredData.forEach((item) => {
|
||||||
|
if (item.orgCode !== orgCode && item.orgCode.startsWith(orgCode)) {
|
||||||
|
const nextLevelOrgCode = item.orgCode.substring(0, orgCode.length + 3);
|
||||||
|
nextLevelOrgCodes.add(nextLevelOrgCode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
// 递归处理下一级数据
|
||||||
|
try {
|
||||||
|
nextLevelOrgCodes.forEach((nextLevelOrgCode) => {
|
||||||
|
const child = groupByOrgCode(nextLevelOrgCode, data);
|
||||||
|
if (child) {
|
||||||
|
result.children.push(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
// 获取统计数据 then filter
|
||||||
|
const fetchStatisticsData = async () => {
|
||||||
|
if (!selectedOrgCode.value || !selectedField.value) return;
|
||||||
|
let res = [];
|
||||||
|
chartData.value = [];
|
||||||
|
try {
|
||||||
|
//这里添加一个层级字段,并避免 厂机关A01A01A01 orgType by 闵
|
||||||
|
var tempOrgType = '1';
|
||||||
|
if (selectedOrgCode.value.includes('A01A01A01')) {
|
||||||
|
tempOrgType = '1';
|
||||||
|
} else {
|
||||||
|
tempOrgType = orgType
|
||||||
|
}
|
||||||
|
if (selectedField.value === 'zjmc') {
|
||||||
|
res = await cxcRyDatAstatisticsCertificate({
|
||||||
|
orgCode: selectedOrgCode.value + '*',
|
||||||
|
field: selectedField.value,
|
||||||
|
dictCode: dictCode.value,
|
||||||
|
fieldisDict: fieldisDict.value,
|
||||||
|
typeOfWorkList: dictData.value,
|
||||||
|
orgType: tempOrgType.value
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res = await cxcRyDatAstatistics({
|
||||||
|
orgCode: selectedOrgCode.value,
|
||||||
|
field: selectedField.value,
|
||||||
|
dictCode: dictCode.value,
|
||||||
|
fieldisDict: fieldisDict.value,
|
||||||
|
orgType: tempOrgType.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
if (res.result.length < 1) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '查询数据为空'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//按单位进行分组
|
||||||
|
orgCodeGroupData.value = groupByOrgCode(selectedOrgCode.value, res.result);
|
||||||
|
//将数据转换成echart格式
|
||||||
|
const temp = transformData(selectedOrgCode.value, res.result);
|
||||||
|
|
||||||
|
if (temp[0].children.length > 0) {
|
||||||
|
chartData.value = JSON.parse(JSON.stringify(temp[0].children));
|
||||||
|
|
||||||
|
chartDataCount.value = chartData.value.length;
|
||||||
|
} else {
|
||||||
|
var tempArr = [];
|
||||||
|
tempArr.push(temp[0])
|
||||||
|
chartData.value = tempArr;
|
||||||
|
}
|
||||||
|
updateChart(chartData.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取统计数据失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取人员列表 delimiter
|
||||||
|
const fetchPersonnelList = async (ldhthList) => {
|
||||||
|
personnelList.value = [];
|
||||||
|
try {
|
||||||
|
const res = await cxcRyDatAstatisticsDetails({
|
||||||
|
ldhth: ldhthList
|
||||||
|
});
|
||||||
|
if (res.success) {
|
||||||
|
personnelList.value = res.result;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取人员列表失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 事件处理
|
||||||
|
const onOrgCodeChange = (e, data) => {
|
||||||
|
personnelList.value = [];
|
||||||
|
// selectedOrgCode.value = e;
|
||||||
|
// orgType.value = data.value.orgType; //赋值层级 by 闵
|
||||||
|
fetchStatisticsData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFieldChange = (e) => {
|
||||||
|
personnelList.value = [];
|
||||||
|
try {
|
||||||
|
selectedField.value = e.value;
|
||||||
|
for (var index = 0; index < fieldList.value.length; index++) {
|
||||||
|
var element = fieldList.value[index];
|
||||||
|
if (element.value == e.value) {
|
||||||
|
dictCode.value = element.dictCode;
|
||||||
|
fieldisDict.value = element.isDict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedField.value === 'zjmc') {
|
||||||
|
showPopup.value = true
|
||||||
|
} else {
|
||||||
|
fetchStatisticsData();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
//TODO handle the exception
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChartClick = (e) => {
|
||||||
|
personnelList.value = [];
|
||||||
|
const {
|
||||||
|
ldhth
|
||||||
|
} = chartData.value;
|
||||||
|
if (ldhth && ldhth.length > 0) {
|
||||||
|
fetchPersonnelList(ldhth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
/* 颜色变量 */
|
||||||
|
:root {
|
||||||
|
--primary-blue: #409eff;
|
||||||
|
--deep-blue: #2c7be5;
|
||||||
|
--light-blue: #ecf5ff;
|
||||||
|
--gradient-start: #6b8cff;
|
||||||
|
--gradient-end: #4364f7;
|
||||||
|
--hover-blue: #66b1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
margin: 10px 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background: linear-gradient(145deg, #f5f9ff, var(--light-blue));
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
||||||
|
border: 1px solid rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表容器 */
|
||||||
|
.chart-container {
|
||||||
|
height: 250px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.12);
|
||||||
|
border: 1px solid rgba(64, 158, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格标题行 */
|
||||||
|
|
||||||
|
.titleStyle {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #747474;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: #f2f9fc;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容样式 */
|
||||||
|
.dataStyle1 {
|
||||||
|
font-size: 8px;
|
||||||
|
color: #00007f;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid #919191;
|
||||||
|
border-left: 1px solid #919191;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动区域 */
|
||||||
|
scroll-view {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 35, 111, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框聚焦效果 */
|
||||||
|
.trq-depart-select:focus-within {
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||||
|
border-color: var(--primary-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载动画优化 */
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container>* {
|
||||||
|
animation: fadeIn 0.6s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义滚动条美化 */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
background: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: linear-gradient(45deg, var(--primary-blue), var(--deep-blue));
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选行间距优化 */
|
||||||
|
.filter-row {
|
||||||
|
margin: 15px 0;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整优化 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.chart-container {
|
||||||
|
height: 250px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数据行高亮效果 */
|
||||||
|
.data-row:nth-child(even) {
|
||||||
|
background: rgba(236, 245, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-row:hover {
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
30
src/pages-humanResource/personnel/index.vue
Normal file
30
src/pages-humanResource/personnel/index.vue
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<route lang="json5" type="page">
|
||||||
|
{
|
||||||
|
layout: 'default',
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarTitleText: '人员信息',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
<template>
|
||||||
|
<PageLayout navTitle="人员信息">
|
||||||
|
<wd-tabs v-model="tab" animated swipeable>
|
||||||
|
<block v-for="item,key in tabs" :key="item">
|
||||||
|
<wd-tab :title="`${item}`" :name="item">
|
||||||
|
<standingbook v-if="key == 0"></standingbook>
|
||||||
|
<ageStatistics v-if="key == 1"></ageStatistics>
|
||||||
|
<generalFieldStatistics v-if="key == 2"></generalFieldStatistics>
|
||||||
|
</wd-tab>
|
||||||
|
</block>
|
||||||
|
</wd-tabs>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import standingbook from './standingbook'
|
||||||
|
import ageStatistics from './ageStatistics'
|
||||||
|
import generalFieldStatistics from './generalFieldStatistics'
|
||||||
|
const tab = ref(0)
|
||||||
|
const tabs = ref(['人员台账', '年龄段统计', '通用字段统计'])
|
||||||
|
</script>
|
||||||
136
src/pages-humanResource/personnel/standingbook.vue
Normal file
136
src/pages-humanResource/personnel/standingbook.vue
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<PageLayout :navbarShow="false">
|
||||||
|
<wd-card style="margin: 10px;" id="top1">
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="24"><uni-title title="所属单位" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="24">
|
||||||
|
<SelectDept label="" v-model="orgCode" @change="getList" rowKey="orgCode" :multiple="false">
|
||||||
|
</SelectDept>
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="12"><uni-title title="姓名" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
<wd-col :span="12"><uni-title title="劳动合同号" align="left" type="h5"></uni-title></wd-col>
|
||||||
|
</wd-row>
|
||||||
|
<wd-row>
|
||||||
|
<wd-col :span="12">
|
||||||
|
<uni-easyinput v-model="realname" placeholder="姓名模糊查询" @change="getList" @clear="getList" />
|
||||||
|
</wd-col>
|
||||||
|
<wd-col :span="12">
|
||||||
|
<uni-easyinput v-model="contractNumber" placeholder="劳动合同号模糊查询" @change="getList"
|
||||||
|
@clear="getList" />
|
||||||
|
</wd-col>
|
||||||
|
</wd-row>
|
||||||
|
</wd-card>
|
||||||
|
<wd-table :data="list" :height="tableHeight">
|
||||||
|
<wd-table-col prop="xh" label="序号" align="center" :width="screenWidth / 5"></wd-table-col>
|
||||||
|
<wd-table-col prop="xm" label="姓名" align="center" :width="screenWidth / 5"></wd-table-col>
|
||||||
|
<wd-table-col prop="xb_dictText" label="性别" align="center" :width="screenWidth / 5"></wd-table-col>
|
||||||
|
<wd-table-col prop="nl" label="年龄" align="center" :width="screenWidth /5"></wd-table-col>
|
||||||
|
<wd-table-col prop="" label="操作" align="center" :width="screenWidth / 5">
|
||||||
|
<template #value="{row}">
|
||||||
|
<text style="color: red;" @click="detail(row)">详情</text>
|
||||||
|
</template>
|
||||||
|
</wd-table-col>
|
||||||
|
</wd-table>
|
||||||
|
<wd-pagination custom-style="border: 1px solid #ececec;border-top:none" v-model="pageNo" :total="total"
|
||||||
|
@change="handleChange"></wd-pagination>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
useMessage,
|
||||||
|
useToast
|
||||||
|
} from 'wot-design-uni'
|
||||||
|
import SelectDept from '@/components/SelectDept/SelectDept'
|
||||||
|
import {
|
||||||
|
listApi
|
||||||
|
} from '@/api/humanResource/personnel'
|
||||||
|
const message = useMessage()
|
||||||
|
const toast = useToast()
|
||||||
|
const realname = ref('') //姓名查询
|
||||||
|
const contractNumber = ref('') //劳动合同号查询
|
||||||
|
const orgCode = ref('') //单位查询
|
||||||
|
const list = ref([])
|
||||||
|
let pageNo = 0
|
||||||
|
let pageSize = 10
|
||||||
|
const total = ref(0)
|
||||||
|
const screenHeight = ref(0)
|
||||||
|
const screenWidth = ref(0)
|
||||||
|
const tableHeight = ref(0)
|
||||||
|
const getList = (e) => {
|
||||||
|
if (e != 1) { //为1时是切换页码
|
||||||
|
pageNo = 1
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
xm: '*' + realname.value + '*',
|
||||||
|
ldhth: '*' + contractNumber.value + '*'
|
||||||
|
}
|
||||||
|
if (orgCode.value.length <= 9) {
|
||||||
|
params.orgCode = orgCode.value + '*';
|
||||||
|
} else {
|
||||||
|
params.jcxd_code = orgCode.value + '*';
|
||||||
|
}
|
||||||
|
listApi({
|
||||||
|
...params,
|
||||||
|
pageNo,
|
||||||
|
pageSize
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
list.value = res.result.records.map((item, index) => ({
|
||||||
|
...item, // 保留原有字段
|
||||||
|
xh: index + 1, // 添加序号 xh,从 1 开始
|
||||||
|
}));
|
||||||
|
total.value = res.result.total
|
||||||
|
}
|
||||||
|
// getHeight();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*切换页码*/
|
||||||
|
const handleChange = ({
|
||||||
|
value
|
||||||
|
}) => {
|
||||||
|
pageNo = value
|
||||||
|
getList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateTableHeight = () => {
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
screenWidth.value = systemInfo.screenWidth;
|
||||||
|
screenHeight.value = systemInfo.screenHeight;
|
||||||
|
// 获取页面顶部元素高度(导航栏+日期选择器)
|
||||||
|
const query = uni.createSelectorQuery();
|
||||||
|
query.select('#top1').boundingClientRect(data => {
|
||||||
|
const topHeight = data ? data.height : 0;
|
||||||
|
const navHeight = 88; // 导航栏高度
|
||||||
|
const margin = 20; // 上下边距
|
||||||
|
// 计算表格可用高度
|
||||||
|
tableHeight.value = screenHeight.value - topHeight - navHeight;
|
||||||
|
}).exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
function detail(record) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: './detail?data=' + encodeURIComponent(JSON.stringify(record))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
calculateTableHeight();
|
||||||
|
// 监听屏幕旋转变化
|
||||||
|
uni.onWindowResize(() => {
|
||||||
|
calculateTableHeight();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
@ -9,12 +9,13 @@
|
|||||||
</route>
|
</route>
|
||||||
<template>
|
<template>
|
||||||
<PageLayout navTitle="干部值班">
|
<PageLayout navTitle="干部值班">
|
||||||
<wd-datetime-picker type="year-month" v-model="dataValue" label="年月" @confirm="getList" />
|
<wd-datetime-picker type="year-month" v-model="dataValue" label="年月" @confirm="getList" id="top1" />
|
||||||
<wd-table :data="dataSource">
|
<wd-table :data="dataSource" :height="tableHeight">
|
||||||
<wd-table-col prop="date" label="日期" width="60" align="center"></wd-table-col>
|
<wd-table-col prop="date" label="日期" :width="screenWidth / 7" align="center"></wd-table-col>
|
||||||
<wd-table-col prop="dbld_dictText" label="带班领导" width="73" align="center"></wd-table-col>
|
<wd-table-col prop="dbld_dictText" label="带班领导" :width="screenWidth * 7 / 32" align="center"></wd-table-col>
|
||||||
<wd-table-col prop="zbld_dictText" label="值班领导" width="73" align="center"></wd-table-col>
|
<wd-table-col prop="zbld_dictText" label="值班领导" :width="screenWidth * 7 / 32" align="center"></wd-table-col>
|
||||||
<wd-table-col prop="zbgbrealname" label="值班干部" width="153" align="center"></wd-table-col>
|
<wd-table-col prop="zbgbrealname" label="值班干部" :width="screenWidth * (47 / 112)"
|
||||||
|
align="center"></wd-table-col>
|
||||||
</wd-table>
|
</wd-table>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</template>
|
</template>
|
||||||
@ -23,8 +24,11 @@
|
|||||||
import {
|
import {
|
||||||
getListApi
|
getListApi
|
||||||
} from '@/api/pages/duty'
|
} from '@/api/pages/duty'
|
||||||
|
|
||||||
const dataValue = ref(Date.now())
|
const dataValue = ref(Date.now())
|
||||||
const dataSource = ref([])
|
const dataSource = ref([])
|
||||||
|
const tableHeight = ref(0)
|
||||||
|
const screenWidth = ref(0)
|
||||||
const getList = () => {
|
const getList = () => {
|
||||||
const date = new Date(dataValue.value);
|
const date = new Date(dataValue.value);
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
@ -33,11 +37,10 @@
|
|||||||
year: year,
|
year: year,
|
||||||
month: month
|
month: month
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
// 格式化日期字段
|
|
||||||
dataSource.value = res.result.records.map(item => {
|
dataSource.value = res.result.records.map(item => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
date: formatDate(item.date) // 调用格式化函数
|
date: formatDate(item.date)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -46,12 +49,33 @@
|
|||||||
const formatDate = (dateStr) => {
|
const formatDate = (dateStr) => {
|
||||||
if (!dateStr) return '';
|
if (!dateStr) return '';
|
||||||
const [year, month, day] = dateStr.split('-');
|
const [year, month, day] = dateStr.split('-');
|
||||||
const formattedMonth = parseInt(month, 10); // 去除前导 0
|
const formattedMonth = parseInt(month, 10);
|
||||||
const formattedDay = parseInt(day, 10); // 去除前导 0
|
const formattedDay = parseInt(day, 10);
|
||||||
return `${formattedMonth}.${formattedDay}`;
|
return `${formattedMonth}.${formattedDay}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
onLoad(() => {
|
const calculateTableHeight = () => {
|
||||||
getList()
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
screenWidth.value = systemInfo.screenWidth;
|
||||||
|
const screenHeight = systemInfo.screenHeight;
|
||||||
|
// 获取页面顶部元素高度(导航栏+日期选择器)
|
||||||
|
const query = uni.createSelectorQuery();
|
||||||
|
query.select('#top1').boundingClientRect(data => {
|
||||||
|
const topHeight = data ? data.height : 0;
|
||||||
|
const navHeight = 44; // 导航栏高度
|
||||||
|
const margin = 20; // 上下边距
|
||||||
|
// 计算表格可用高度
|
||||||
|
tableHeight.value = screenHeight - topHeight - navHeight - margin;
|
||||||
|
}).exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
calculateTableHeight();
|
||||||
|
|
||||||
|
// 监听屏幕旋转变化
|
||||||
|
uni.onWindowResize(() => {
|
||||||
|
calculateTableHeight();
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -25,12 +25,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
|
||||||
ref
|
|
||||||
} from 'vue'
|
|
||||||
import {
|
|
||||||
onLoad
|
|
||||||
} from '@dcloudio/uni-app';
|
|
||||||
import {
|
import {
|
||||||
useAppStore
|
useAppStore
|
||||||
} from '@/store'
|
} from '@/store'
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<wd-loading v-if="loading && pageNo === 1" class="loading-tip">加载中...</wd-loading>
|
<wd-loading v-if="loading && pageNo === 1" class="loading-tip">加载中...</wd-loading>
|
||||||
<!-- 列表内容 -->
|
<!-- 列表内容 -->
|
||||||
<view v-for="(item, i) in list" :key="i">
|
<view v-for="(item, i) in list" :key="i">
|
||||||
<wd-card :title="item.title" title-bold border-radius="8" use-footer-slot @click="getList(item.path)">
|
<wd-card :title="item.title" @click="getList(item.path)">
|
||||||
<view class="card-content">
|
<view class="card-content">
|
||||||
<view class="meta-info">
|
<view class="meta-info">
|
||||||
<wd-icon name="time" size="14px" color="#999"></wd-icon>
|
<wd-icon name="time" size="14px" color="#999"></wd-icon>
|
||||||
@ -39,8 +39,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
onLoad,
|
onLoad,
|
||||||
onReachBottom,
|
onReachBottom
|
||||||
onPullDownRefresh
|
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
import {
|
import {
|
||||||
queryDocumentApi,
|
queryDocumentApi,
|
||||||
@ -202,13 +201,6 @@
|
|||||||
getList(1)
|
getList(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
onPullDownRefresh(() => {
|
|
||||||
pageNo = 1
|
|
||||||
list.value = []
|
|
||||||
getList(1)
|
|
||||||
uni.stopPullDownRefresh()
|
|
||||||
})
|
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
type.value = options.title
|
type.value = options.title
|
||||||
getList(1)
|
getList(1)
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
<view class="form-container">
|
<view class="form-container">
|
||||||
<wd-form ref="form" :model="model">
|
<wd-form ref="form" :model="model">
|
||||||
<!-- 血压数据卡片 -->
|
<!-- 血压数据卡片 -->
|
||||||
<view class="card">
|
<view class="card" >
|
||||||
<wd-cell-group title="血压数据">
|
<wd-cell-group title="血压数据" border>
|
||||||
<wd-input type="number" label="高压值(mmHg)" prop="gyz" v-model="model.gyz" label-width="200px"
|
<wd-input type="number" label="高压值(mmHg)" prop="gyz" v-model="model.gyz" label-width="200px"
|
||||||
:rules="[{ required: true, message: '请输入高压值' }]" />
|
:rules="[{ required: true, message: '请输入高压值' }]" />
|
||||||
<wd-input type="number" label="低压值(mmHg)" prop="dyz" v-model="model.dyz" label-width="200px"
|
<wd-input type="number" label="低压值(mmHg)" prop="dyz" v-model="model.dyz" label-width="200px"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 健康指标卡片 -->
|
<!-- 健康指标卡片 -->
|
||||||
<view class="card">
|
<view class="card">
|
||||||
<wd-cell-group title="健康指标">
|
<wd-cell-group title="健康指标" border>
|
||||||
<wd-input type="number" label="心率(次/分)" prop="xl" v-model="model.xl" label-width="200px"
|
<wd-input type="number" label="心率(次/分)" prop="xl" v-model="model.xl" label-width="200px"
|
||||||
:rules="[{ required: true, message: '请输入心率' }]" />
|
:rules="[{ required: true, message: '请输入心率' }]" />
|
||||||
<wd-input type="number" label="血糖值(mmol/L)" prop="xtz" v-model="model.xtz" label-width="200px"
|
<wd-input type="number" label="血糖值(mmol/L)" prop="xtz" v-model="model.xtz" label-width="200px"
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 其他信息卡片 -->
|
<!-- 其他信息卡片 -->
|
||||||
<view class="card">
|
<view class="card">
|
||||||
<wd-cell-group title="其他信息">
|
<wd-cell-group title="其他信息" border>
|
||||||
<wd-input label="当前位置" prop="wzzb" v-model="model.wzzb" label-width="200px" />
|
<wd-input label="当前位置" prop="wzzb" v-model="model.wzzb" label-width="200px" />
|
||||||
<wd-cell title="附件" prop="path" title-width="200px">
|
<wd-cell title="附件" prop="path" title-width="200px">
|
||||||
<wd-upload :accept="accept" v-model:file-list="model.path" :action="uploadUrl"
|
<wd-upload :accept="accept" v-model:file-list="model.path" :action="uploadUrl"
|
||||||
@ -41,7 +41,6 @@
|
|||||||
</wd-cell>
|
</wd-cell>
|
||||||
</wd-cell-group>
|
</wd-cell-group>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 提交按钮 -->
|
<!-- 提交按钮 -->
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<wd-button type="primary" size="large" @click="handleSubmit" block>
|
<wd-button type="primary" size="large" @click="handleSubmit" block>
|
||||||
|
|||||||
@ -30,10 +30,10 @@
|
|||||||
"text": "首页"
|
"text": "首页"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"iconPath": "static/tabbar/tabbar-message-2.png",
|
"iconPath": "static/tabbar/tabbar-produce.png",
|
||||||
"selectedIconPath": "static/tabbar/tabbar-message.png",
|
"selectedIconPath": "static/tabbar/tabbar-produce-2.png",
|
||||||
"pagePath": "pages/message/message",
|
"pagePath": "pages/produce/index",
|
||||||
"text": "消息"
|
"text": "生产"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"iconPath": "static/tabbar/tabbar-workHome-2.png",
|
"iconPath": "static/tabbar/tabbar-workHome-2.png",
|
||||||
@ -130,6 +130,15 @@
|
|||||||
"navigationBarTitleText": "H5在线预览"
|
"navigationBarTitleText": "H5在线预览"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/index",
|
||||||
|
"type": "page",
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "生产数据"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/user/people",
|
"path": "pages/user/people",
|
||||||
"type": "page",
|
"type": "page",
|
||||||
@ -147,6 +156,42 @@
|
|||||||
"navigationBarTitleText": "工作台",
|
"navigationBarTitleText": "工作台",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/ribaoshuju/rbsjLsxq",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/ribaoshuju/trqRbsj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/ribaoshuju/yyRbsj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/aqbjSssj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/gycsSssj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/index",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/nyxhSssj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/trqSssj",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/produce/shishishuju/ysjSssj",
|
||||||
|
"type": "page"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
@ -336,8 +381,52 @@
|
|||||||
"navigationBarTitleText": "请假申请"
|
"navigationBarTitleText": "请假申请"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "absence/detail",
|
||||||
|
"type": "page",
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "请假详情"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "absence/index",
|
"path": "absence/index",
|
||||||
|
"type": "page",
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "请假信息"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "personnel/ageStatistics",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "personnel/detail",
|
||||||
|
"type": "page",
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "人员详情"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "personnel/generalFieldStatistics",
|
||||||
|
"type": "page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "personnel/index",
|
||||||
|
"type": "page",
|
||||||
|
"layout": "default",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "人员信息"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "personnel/standingbook",
|
||||||
"type": "page"
|
"type": "page"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
195
src/pages/produce/index.vue
Normal file
195
src/pages/produce/index.vue
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
<route lang="json5" type="page">
|
||||||
|
{
|
||||||
|
layout: 'default',
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarTitleText: '生产数据',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
<template>
|
||||||
|
<PageLayout :navbarShow="false">
|
||||||
|
<view>
|
||||||
|
<view class="placeholder"></view>
|
||||||
|
<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>
|
||||||
|
</view>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import trqData from './ribaoshuju/trqRbsj';
|
||||||
|
import yyData from './ribaoshuju/yyRbsj';
|
||||||
|
import sssjForm from './shishishuju/index';
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays,
|
||||||
|
getYearProgress
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
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 scrollViewHeight = ref(0); //状态栏高度
|
||||||
|
const timePercent = ref(0);
|
||||||
|
const dateDate = ref('');
|
||||||
|
|
||||||
|
function onClickItem(e) {
|
||||||
|
if (current.value != e.currentIndex) {
|
||||||
|
current.value = e.currentIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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>
|
||||||
354
src/pages/produce/ribaoshuju/rbsjLsxq.vue
Normal file
354
src/pages/produce/ribaoshuju/rbsjLsxq.vue
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
<template>
|
||||||
|
<PageLayout :navbarShow="false">
|
||||||
|
<view class="stats-container">
|
||||||
|
<uni-title v-if="type === 'trq'" :title="name.unit + '天然气---单位(万方)'" color="blue" type="h2"></uni-title>
|
||||||
|
<uni-title v-if="type === 'yy'" :title="name.dw + '原油---单位(吨)'" color="blue" type="h2"></uni-title>
|
||||||
|
</view>
|
||||||
|
<view class="dateSelect">
|
||||||
|
<cxc-szcx-dateRangeSelect :mode="'range'" v-model="dateRange"></cxc-szcx-dateRangeSelect>
|
||||||
|
</view>
|
||||||
|
<cxc-szcx-lineChart v-if="type === 'trq'" :dataList="dataList" x-field="rqDate" y-field="rq" legend-field="unit"
|
||||||
|
:reference-value="0"></cxc-szcx-lineChart>
|
||||||
|
|
||||||
|
<cxc-szcx-lineChart v-if="type === 'yy'" :dataList="dataList" x-field="scrq" y-field="rcwy" legend-field="dw"
|
||||||
|
:reference-value="0"></cxc-szcx-lineChart>
|
||||||
|
<view style="margin: 0 15px">
|
||||||
|
<view class="stats-container">
|
||||||
|
<view class="stats-item">最大值: {{ dataStats.max }}</view>
|
||||||
|
<view class="stats-item">最小值: {{ dataStats.min }}</view>
|
||||||
|
<view class="stats-item">平均值: {{ dataStats.average }}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="type === 'trq'" class="table-container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<view class="tr header">
|
||||||
|
<view class="th1">序号</view>
|
||||||
|
<view class="th">名称</view>
|
||||||
|
<view class="th">日期</view>
|
||||||
|
<view class="th">日气量</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-Y="true" class="scroll-wrapper">
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<view class="tr" v-for="(item, index) in dataList" :key="index" :class="{ even: index % 2 === 0 }">
|
||||||
|
<view class="td1">{{ index + 1 }}</view>
|
||||||
|
<view class="td">{{ item.unit }}</view>
|
||||||
|
<view class="td">{{ item.rqDate }}</view>
|
||||||
|
<view class="td" :class="{ negative: item.rq < 0 }">
|
||||||
|
{{ item.rq }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空数据提示 -->
|
||||||
|
<view v-if="!dataList.length" class="empty">暂无相关数据</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="type === 'yy'" class="table-container">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<view class="tr header">
|
||||||
|
<view class="th1">序号</view>
|
||||||
|
<view class="th">名称</view>
|
||||||
|
<view class="th">日期</view>
|
||||||
|
<view class="th">日油量</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-Y="true" class="scroll-wrapper">
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<view class="tr" v-for="(item, index) in dataList" :key="index" :class="{ even: index % 2 === 0 }">
|
||||||
|
<view class="td1">{{ index + 1 }}</view>
|
||||||
|
<view class="td">{{ item.dw }}</view>
|
||||||
|
<view class="td">{{ item.scrq }}</view>
|
||||||
|
<view class="td" :class="{ negative: item.rcwy < 0 }">
|
||||||
|
{{ item.rcwy }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空数据提示 -->
|
||||||
|
<view v-if="!dataList.length" class="empty">暂无相关数据</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJinriShengchansj,
|
||||||
|
queryJinriYuanyouShengchansj
|
||||||
|
} from '@/api/produce';
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays,
|
||||||
|
getDateAfterMonths
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
const name = ref({});
|
||||||
|
const type = ref('');
|
||||||
|
const dateRange = ref([]);
|
||||||
|
const dataList = ref([]);
|
||||||
|
const endDate = ref('');
|
||||||
|
const startDate = ref('');
|
||||||
|
const dataStats = ref({
|
||||||
|
min: 0,
|
||||||
|
max: 0,
|
||||||
|
avg: 0
|
||||||
|
});
|
||||||
|
const getJinriShengchansj = (tempDateRange) => {
|
||||||
|
// console.log(tempDateRange);
|
||||||
|
// 添加日期有效性检查
|
||||||
|
if (!tempDateRange || tempDateRange.some((date) => !convertToDate(date))) {
|
||||||
|
console.error('收到无效日期范围:', tempDateRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let queryParms = {};
|
||||||
|
dataList.value = [];
|
||||||
|
queryParms.gas = name.value.gas;
|
||||||
|
queryParms.unit = name.value.unit;
|
||||||
|
queryParms.rqDate_begin = formatDate(tempDateRange[0]);
|
||||||
|
queryParms.rqDate_end = formatDate(tempDateRange[1]);
|
||||||
|
queryParms.pageSize = 500;
|
||||||
|
|
||||||
|
// 添加参数有效性检查
|
||||||
|
if (!queryParms.rqDate_begin || !queryParms.rqDate_end) {
|
||||||
|
console.error('参数格式化失败:', queryParms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log(queryParms);
|
||||||
|
queryJinriShengchansj(queryParms).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
// console.log(res);
|
||||||
|
dataList.value = res.result.records;
|
||||||
|
dataStats.value = calculateStats(dataList.value, 'rq');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getJinriYuanyouShengchansj = (tempDateRange) => {
|
||||||
|
console.log(tempDateRange);
|
||||||
|
// 添加日期有效性检查
|
||||||
|
if (!tempDateRange || tempDateRange.some((date) => !convertToDate(date))) {
|
||||||
|
console.error('收到无效日期范围:', tempDateRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let queryParms = {};
|
||||||
|
dataList.value = [];
|
||||||
|
queryParms.dw = name.value.dw;
|
||||||
|
queryParms.scrq_begin = formatDate(tempDateRange[0]);
|
||||||
|
queryParms.scrq_end = formatDate(tempDateRange[1]);
|
||||||
|
queryParms.pageSize = 500;
|
||||||
|
|
||||||
|
// 添加参数有效性检查
|
||||||
|
if (!queryParms.scrq_begin || !queryParms.scrq_end) {
|
||||||
|
console.error('参数格式化失败:', queryParms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(queryParms);
|
||||||
|
queryJinriYuanyouShengchansj(queryParms).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
console.log(res);
|
||||||
|
dataList.value = res.result.records;
|
||||||
|
dataStats.value = calculateStats(dataList.value, 'rcwy').reverse();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function calculateStats(data, field) {
|
||||||
|
// 过滤掉 field 字段值为 null 或 undefined 的数据
|
||||||
|
const validData = data.filter((item) => item[field] !== null && item[field] !== undefined);
|
||||||
|
if (validData.length === 0) {
|
||||||
|
return {
|
||||||
|
max: null,
|
||||||
|
min: null,
|
||||||
|
average: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 初始化最大值、最小值和总和
|
||||||
|
let max = validData[0][field];
|
||||||
|
let min = validData[0][field];
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
|
// 遍历有效数据
|
||||||
|
for (let i = 0; i < validData.length; i++) {
|
||||||
|
const value = validData[i][field];
|
||||||
|
// 更新最大值
|
||||||
|
if (value > max) {
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
// 更新最小值
|
||||||
|
if (value < min) {
|
||||||
|
min = value;
|
||||||
|
}
|
||||||
|
// 累加值到总和
|
||||||
|
sum += value;
|
||||||
|
}
|
||||||
|
// 计算平均值
|
||||||
|
const average = (sum / validData.length).toFixed(4);
|
||||||
|
|
||||||
|
return {
|
||||||
|
max: max,
|
||||||
|
min: min,
|
||||||
|
average: average
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToDate(str) {
|
||||||
|
try {
|
||||||
|
const date = new Date(str);
|
||||||
|
// 判断日期是否有效
|
||||||
|
if (isNaN(date.getTime())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
//TODO handle the exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 修改后(正确)
|
||||||
|
watch(
|
||||||
|
[() => type.value, dateRange], // 监听 type 和 dateRange
|
||||||
|
([newType, newDateRange]) => {
|
||||||
|
if (!newDateRange || !convertToDate(newDateRange[0]) || !convertToDate(newDateRange[1])) {
|
||||||
|
// console.error('无效的日期范围:', newDateRange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log(newType, newDateRange);
|
||||||
|
|
||||||
|
switch (
|
||||||
|
newType // 直接使用 newType
|
||||||
|
) {
|
||||||
|
case 'trq':
|
||||||
|
getJinriShengchansj(newDateRange);
|
||||||
|
break;
|
||||||
|
case 'yy':
|
||||||
|
getJinriYuanyouShengchansj(newDateRange);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn('未知类型:', newType);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
onMounted(() => {
|
||||||
|
// nextTick();
|
||||||
|
// getJinriShengchansj(dateRange.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
name.value = JSON.parse(options.data);
|
||||||
|
type.value = options.type;
|
||||||
|
// console.log(name.value, type.value);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (now.getHours() < 11) {
|
||||||
|
endDate.value = getDateAfterDays(now, -1); //11点之前 头一天的数据
|
||||||
|
startDate.value = getDateAfterMonths(endDate.value, -1); //11点之前 头一天的数据
|
||||||
|
} else {
|
||||||
|
endDate.value = now;
|
||||||
|
startDate.value = getDateAfterMonths(endDate.value, -1); //11点之前 头一天的数据
|
||||||
|
}
|
||||||
|
dateRange.value = [startDate.value, endDate.value];
|
||||||
|
// console.log(1111, dateRange.value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 40vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 35vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
display: flex;
|
||||||
|
min-height: 14px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.th,
|
||||||
|
.td {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 80px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 18px;
|
||||||
|
vertical-align: middle;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.th1,
|
||||||
|
.td1 {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 40px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 14px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.th {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td.negative {
|
||||||
|
color: #ff4444;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
padding: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: #888;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 10px;
|
||||||
|
margin: 15 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateSelect {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 5px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-item {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #00aa00;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-item+.stats-item {
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
742
src/pages/produce/ribaoshuju/trqRbsj.vue
Normal file
742
src/pages/produce/ribaoshuju/trqRbsj.vue
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<!-- 标题行 -->
|
||||||
|
<view class="header-row">
|
||||||
|
<view class="title">天然气产量</view>
|
||||||
|
<view class="more" @click="selectMore">更多>></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="container">
|
||||||
|
<view v-for="(item, index) in shishiArrSelect" :key="index" class="card-item"
|
||||||
|
@click="handleCardClick(item.gas)">
|
||||||
|
<view class="card">
|
||||||
|
<text class="title">{{ item.gas }}</text>
|
||||||
|
<view class="content">
|
||||||
|
<text class="label">气量</text>
|
||||||
|
<text class="value">{{ formatNumber(item.dailyVolume) || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<text class="label">年累计</text>
|
||||||
|
<text class="value">{{ formatNumber(item.yearVolume) || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="progress-bar">
|
||||||
|
<!-- 动态设置宽度和颜色 -->
|
||||||
|
<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>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<wd-popup v-model="popupSelect" position="top" background-color="#fff">
|
||||||
|
<view style="margin-top: 50px">
|
||||||
|
<view class="titlepopup">选择显示更多生产数据</view>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</wd-popup>
|
||||||
|
<!-- 数据弹窗 -->
|
||||||
|
<wd-popup v-model="popup" position="bottom" background-color="#fff">
|
||||||
|
<view class="popup-content">
|
||||||
|
<view class="popup-header">
|
||||||
|
<text class="title">{{ selectedGas }}数据详情 单位(万立方米)</text>
|
||||||
|
<uni-icons type="closeempty" size="24" color="#666" @click="closePopup"></uni-icons>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="table">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<view class="tr header">
|
||||||
|
<view class="th1">序号</view>
|
||||||
|
<view class="th">名称</view>
|
||||||
|
<view class="th">日气量</view>
|
||||||
|
<view class="th">年累计</view>
|
||||||
|
<view class="th1">操作</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-X="true" scroll-Y="true" class="table-container">
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<view class="tr" v-for="(item, index) in filteredData" :key="index"
|
||||||
|
:class="{ even: index % 2 === 0 }">
|
||||||
|
<view class="td1">{{ index + 1 }}</view>
|
||||||
|
<view class="td">{{ item.unit }}</view>
|
||||||
|
<view class="td" :class="{ negative: item.rq < 0 }">
|
||||||
|
{{ formatNumber(item.rq) }}
|
||||||
|
</view>
|
||||||
|
<view class="td" :class="{ negative: item.yearVolume < 0 }">
|
||||||
|
{{ formatNumber(item.yearVolume) }}
|
||||||
|
</view>
|
||||||
|
<view class="td1" style="color: red" @click="goHistory(item)">历史</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空数据提示 -->
|
||||||
|
<view v-if="!filteredData.length" class="empty">暂无相关数据</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJinriShengchansj,
|
||||||
|
queryYearShengchansj,
|
||||||
|
queryJinriTrqShengchansj
|
||||||
|
} from '@/api/produce';
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
|
||||||
|
const shishiArr = ref([]);
|
||||||
|
const shishiArrSelect = ref([]);
|
||||||
|
const shishiArrDisplay = ref(['气井气', '商品量', '站线综合输差']);
|
||||||
|
const dataJinriUnit = ref([]);
|
||||||
|
const selectedGas = ref('');
|
||||||
|
const filteredData = ref([]);
|
||||||
|
const popup = ref(false);
|
||||||
|
const popupSelect = ref(false);
|
||||||
|
const strDate = ref('');
|
||||||
|
|
||||||
|
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;
|
||||||
|
// let queryParms = {};
|
||||||
|
// filteredData.value = [];
|
||||||
|
// queryParms.day = strDate.value;
|
||||||
|
// queryParms.gas = gas;
|
||||||
|
// queryParms.unit = '文23气田,户部寨气田';
|
||||||
|
// console.log(queryParms);
|
||||||
|
// queryJinriTrqShengchansj(queryParms).then((res) => {
|
||||||
|
// if (res.success) {
|
||||||
|
// console.log(res);
|
||||||
|
// filteredData.value = res.result;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// popup.value.open();
|
||||||
|
// };
|
||||||
|
|
||||||
|
function selectMore() {
|
||||||
|
popupSelect.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNo() {
|
||||||
|
shishiArrDisplay.value = [];
|
||||||
|
onselectionchange()
|
||||||
|
popup.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectDefault() {
|
||||||
|
shishiArrDisplay.value = ['气井气', '商品量', '站线综合输差'];
|
||||||
|
onselectionchange()
|
||||||
|
popup.value = false;
|
||||||
|
}
|
||||||
|
const onselectionchange = () => {
|
||||||
|
shishiArrSelect.value = [];
|
||||||
|
shishiArrDisplay.value.forEach((item) => {
|
||||||
|
shishiArrSelect.value.push(shishiArr.value.filter((item1) => item1.gas === item)[0]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCardClick = (gas) => {
|
||||||
|
selectedGas.value = gas;
|
||||||
|
filteredData.value = dataJinriSumUnit.value.filter((item) => item.gas === gas);
|
||||||
|
popup.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const closePopup = () => {
|
||||||
|
popup.value = false;
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
getJinriTrqShengchansj();
|
||||||
|
|
||||||
|
getJinriShengchansj();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 数字格式化
|
||||||
|
const formatNumber = (num) => {
|
||||||
|
let temp = 0;
|
||||||
|
try {
|
||||||
|
temp = parseFloat(num);
|
||||||
|
} catch (error) {
|
||||||
|
//TODO handle the exception
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp.toFixed(4).replace(/\.?0+$/, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 自动计算综合输差
|
||||||
|
function calcZhsc(tempArray) {
|
||||||
|
console.log(tempArray)
|
||||||
|
let totalJinqi = {
|
||||||
|
gas: '总进气',
|
||||||
|
dailyVolume: 0,
|
||||||
|
yearVolume: 0,
|
||||||
|
yearPlan: '100',
|
||||||
|
yearPerCent: 0
|
||||||
|
};
|
||||||
|
let totalChuqi = {
|
||||||
|
gas: '总出气',
|
||||||
|
dailyVolume: 0,
|
||||||
|
yearVolume: 0,
|
||||||
|
yearPlan: '100',
|
||||||
|
yearPerCent: 0
|
||||||
|
};
|
||||||
|
const compositeZx = {
|
||||||
|
gas: '站线综合输差',
|
||||||
|
dailyVolume: 0,
|
||||||
|
yearVolume: 0,
|
||||||
|
yearPlan: '100',
|
||||||
|
yearPerCent: 0
|
||||||
|
}; // 综合输差
|
||||||
|
const compositeJc = {
|
||||||
|
gas: '进出综合输差',
|
||||||
|
dailyVolume: 0,
|
||||||
|
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;
|
||||||
|
compositeZx.yearVolume += parseFloat(item.yearVolume) || 0;
|
||||||
|
}
|
||||||
|
if (item.gas === '气井气' || item.gas === '外部气' || item.gas === '返回气') {
|
||||||
|
totalJinqi.dailyVolume += parseFloat(item.dailyVolume) || 0;
|
||||||
|
totalJinqi.yearVolume += parseFloat(item.yearVolume) || 0;
|
||||||
|
}
|
||||||
|
if (item.gas === '自耗气' || item.gas === '用户气' || item.gas === '返采油厂干气') {
|
||||||
|
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(trqSpl);
|
||||||
|
|
||||||
|
return tempArray;
|
||||||
|
|
||||||
|
// console.log(composite);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getJinriTrqShengchansj = () => {
|
||||||
|
const now = new Date();
|
||||||
|
if (now.getHours() < 11) {
|
||||||
|
strDate.value = formatDate(getDateAfterDays(now, -1)).toString(); //11点之前 头一天的数据
|
||||||
|
} else {
|
||||||
|
strDate.value = formatDate(now).toString();
|
||||||
|
}
|
||||||
|
let queryParms = {};
|
||||||
|
shishiArr.value = [];
|
||||||
|
|
||||||
|
queryParms.day = strDate.value;
|
||||||
|
// // console.log(queryParms);
|
||||||
|
queryJinriTrqShengchansj(queryParms).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
console.log(1, res);
|
||||||
|
let temp = res.result;
|
||||||
|
|
||||||
|
temp.forEach((item) => {
|
||||||
|
if (item.gas === '气井气') {
|
||||||
|
item.yearPlan = 7500;
|
||||||
|
item.yearPerCent = calcPercent(item.yearPlan, item.yearVolume);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(2, temp);
|
||||||
|
console.log(calcZhsc(temp))
|
||||||
|
shishiArr.value = calcZhsc(temp);
|
||||||
|
nextTick();
|
||||||
|
onselectionchange();
|
||||||
|
console.log(3, shishiArr.value);
|
||||||
|
console.log(4, shishiArrSelect.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function goHistory(val) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/views/shengchan/ribaoshuju/rbsjLsxq?data=' + JSON.stringify(val) + '&type=trq'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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)); // 转为数值
|
||||||
|
}
|
||||||
|
|
||||||
|
const getJinriShengchansj = () => {
|
||||||
|
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 = [];
|
||||||
|
dataJinriSumUnit.value = [];
|
||||||
|
queryParms.rqDate = strDate.value;
|
||||||
|
queryParms.pageSize = 100;
|
||||||
|
// console.log(queryParms);
|
||||||
|
queryJinriShengchansj(queryParms).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
console.log(res);
|
||||||
|
dataJinri.value = res.result.records;
|
||||||
|
dataJinriSumUnit.value = sumByUnit(dataJinri.value); //包含gas unit rq cq totalGas
|
||||||
|
console.log(dataJinriSumUnit.value);
|
||||||
|
// // 使用 nextTick 等待 DOM 更新
|
||||||
|
nextTick();
|
||||||
|
getYearShengchansj(); //再获取今年以来的数据
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const getYearShengchansj = () => {
|
||||||
|
const now = new Date();
|
||||||
|
let year = formatDate(now).split('-')[0];
|
||||||
|
let queryParms = {};
|
||||||
|
queryParms.yearStart = year;
|
||||||
|
queryParms.yearEnd = year;
|
||||||
|
|
||||||
|
// // console.log(2, queryParms.value);
|
||||||
|
queryYearShengchansj(queryParms).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
try {
|
||||||
|
// // console.log(res.result);
|
||||||
|
let yearData = res.result[year];
|
||||||
|
// console.log(dataJinriSumUnit.value.length, dataJinriSumUnit.value, yearData.length,
|
||||||
|
// yearData);
|
||||||
|
dataJinriSumUnit.value.forEach((item) => {
|
||||||
|
yearData.forEach((itemYear) => {
|
||||||
|
// // console.log(item, itemYear);
|
||||||
|
if (item.setId === itemYear.setId) {
|
||||||
|
item.yearVolume = itemYear.yearSum || 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
dataJinriSum.value = sumByGas(dataJinriSumUnit.value);
|
||||||
|
// console.log(dataJinriSum.value);
|
||||||
|
shishiArr.value.forEach((item) => {
|
||||||
|
dataJinriSum.value.forEach((itemjinri) => {
|
||||||
|
if (item.gas === itemjinri.gas) {
|
||||||
|
item.dailyVolume = itemjinri.rq.toFixed(4);
|
||||||
|
item.yearVolume = itemjinri.yearVolume.toFixed(4);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function sumByGas(records) {
|
||||||
|
// console.log(records);
|
||||||
|
const summaryMap = {};
|
||||||
|
try {
|
||||||
|
records.forEach((record) => {
|
||||||
|
const gas = record.gas;
|
||||||
|
if (!summaryMap[gas]) {
|
||||||
|
// 初始化该 gas 类型的汇总对象
|
||||||
|
summaryMap[gas] = {
|
||||||
|
gas: gas,
|
||||||
|
rq: 0,
|
||||||
|
sq: 0,
|
||||||
|
totalGas: 0,
|
||||||
|
yearVolume: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 无论是否是第一次遇到该 gas 类型,都进行累加操作
|
||||||
|
summaryMap[gas].rq += record.rq || 0;
|
||||||
|
summaryMap[gas].sq += record.sq || 0;
|
||||||
|
summaryMap[gas].totalGas += record.totalGas || 0;
|
||||||
|
summaryMap[gas].yearVolume += record.yearVolume || 0;
|
||||||
|
});
|
||||||
|
return Object.values(summaryMap);
|
||||||
|
} catch (error) {
|
||||||
|
//TODO handle the exception
|
||||||
|
// console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sumByUnit(records) {
|
||||||
|
console.log(records);
|
||||||
|
const summaryMap = {};
|
||||||
|
try {
|
||||||
|
records.forEach((record) => {
|
||||||
|
const unit = record.unit;
|
||||||
|
const gas = record.gas;
|
||||||
|
// 添加setId计算
|
||||||
|
const setId = record.setId
|
||||||
|
if (gas != "区输差") {
|
||||||
|
if (!summaryMap[setId]) {
|
||||||
|
// 初始化该 gas 类型的汇总对象
|
||||||
|
summaryMap[setId] = {
|
||||||
|
unit: unit,
|
||||||
|
setId: setId,
|
||||||
|
gas: record.gas,
|
||||||
|
rq: 0,
|
||||||
|
sq: 0,
|
||||||
|
totalGas: 0,
|
||||||
|
yearVolume: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 无论是否是第一次遇到该 unit 类型,都进行累加操作
|
||||||
|
summaryMap[setId].rq += record.rq || 0;
|
||||||
|
summaryMap[setId].sq += record.sq || 0;
|
||||||
|
summaryMap[setId].totalGas += record.totalGas || 0;
|
||||||
|
summaryMap[setId].yearVolume += record.yearVolume || 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: 10 10rpx;
|
||||||
|
border-bottom: 1rpx solid #eee;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titlepopup {
|
||||||
|
font-size: 35rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
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 {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding: 20rpx;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
padding: 30rpx;
|
||||||
|
max-height: 40vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 22rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 30rpx;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 240rpx;
|
||||||
|
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(179, 179, 179, 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>
|
||||||
413
src/pages/produce/ribaoshuju/yyRbsj.vue
Normal file
413
src/pages/produce/ribaoshuju/yyRbsj.vue
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
<template>
|
||||||
|
<!-- <view style="margin-left: 20rpx;"> <uni-title :title="strDate + ':生产数据'" type="h1" color="red" /> -->
|
||||||
|
<!-- </view> -->
|
||||||
|
<view class="content">
|
||||||
|
<!-- 标题行 -->
|
||||||
|
<view class="header-row">
|
||||||
|
<view class="title">原油产量</view>
|
||||||
|
<view class="more"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="container">
|
||||||
|
<view v-for="(item, index) in shishiArr" :key="index" class="card-item" @click="handleCardClick(item.gas)">
|
||||||
|
<view class="card">
|
||||||
|
<!-- <text class="title">{{ item.gas }}</text> -->
|
||||||
|
<view class="content">
|
||||||
|
<text class="label">日油量</text>
|
||||||
|
<text class="value">{{ item.rcwy || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<text class="label">月累计</text>
|
||||||
|
<text class="value">{{ item.yl || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<text class="label">年累计</text>
|
||||||
|
<text class="value">{{ item.nl || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="progress-bar">
|
||||||
|
<!-- 动态设置宽度和颜色 -->
|
||||||
|
<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>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 数据弹窗 -->
|
||||||
|
<wd-popup v-model="popup" position="bottom" background-color="#fff">
|
||||||
|
<view class="popup-content">
|
||||||
|
<view class="popup-header">
|
||||||
|
<text class="title">原油数据详情 单位(吨)</text>
|
||||||
|
<wd-icon name="closeempty" size="24" @click="closePopup"></wd-icon>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view scroll-X="true" scroll-Y="true" class="table-container">
|
||||||
|
<view class="table">
|
||||||
|
<!-- 表头 -->
|
||||||
|
<view class="tr header">
|
||||||
|
<view class="th1">序号</view>
|
||||||
|
<view class="th">名称</view>
|
||||||
|
<view class="th">日油量</view>
|
||||||
|
<view class="th">月累计</view>
|
||||||
|
<view class="th">年累计</view>
|
||||||
|
<view class="th1">操作</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 表格内容 -->
|
||||||
|
<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">
|
||||||
|
{{ formatNumber(item.rcwy) }}
|
||||||
|
</view>
|
||||||
|
<view class="td">{{ formatNumber(item.yl) }}</view>
|
||||||
|
<view class="td">
|
||||||
|
{{ formatNumber(item.nl) }}
|
||||||
|
</view>
|
||||||
|
<view class="td1" style="color: red" @click="goHistory(item)">历史</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空数据提示 -->
|
||||||
|
<view v-if="!dataJinri.length" class="empty">暂无相关数据</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</wd-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJinriYuanyouShengchansj
|
||||||
|
} from '@/api/produce';
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
const shishiArr = ref([{
|
||||||
|
gas: '原油产量',
|
||||||
|
rcwy: '',
|
||||||
|
yl: '',
|
||||||
|
nl: '',
|
||||||
|
yearPlan: '1500',
|
||||||
|
yearPerCent: ''
|
||||||
|
}]);
|
||||||
|
|
||||||
|
const dataJinri = ref([]);
|
||||||
|
const dataJinriSum = ref([]);
|
||||||
|
const popup = ref(false);
|
||||||
|
// 点击卡片处理
|
||||||
|
const handleCardClick = () => {
|
||||||
|
popup.value = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const closePopup = () => {
|
||||||
|
popup.value = false
|
||||||
|
};
|
||||||
|
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 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;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 {
|
||||||
|
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
src/pages/produce/shishishuju/aqbjSssj.vue
Normal file
8
src/pages/produce/shishishuju/aqbjSssj.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
8
src/pages/produce/shishishuju/gycsSssj.vue
Normal file
8
src/pages/produce/shishishuju/gycsSssj.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
20
src/pages/produce/shishishuju/index.vue
Normal file
20
src/pages/produce/shishishuju/index.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<trqSssjVue></trqSssjVue>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJinriShengchansj,
|
||||||
|
queryYearShengchansj,
|
||||||
|
queryJinriTrqShengchansj
|
||||||
|
} from '@/api/produce';
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
import trqSssjVue from './trqSssj';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
8
src/pages/produce/shishishuju/nyxhSssj.vue
Normal file
8
src/pages/produce/shishishuju/nyxhSssj.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
290
src/pages/produce/shishishuju/trqSssj.vue
Normal file
290
src/pages/produce/shishishuju/trqSssj.vue
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
<template>
|
||||||
|
<PageLayout :navbarShow="false">
|
||||||
|
<!-- 标题行 -->
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
</PageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJldZcList,
|
||||||
|
queryJldDataByZc
|
||||||
|
} from '@/api/produce'
|
||||||
|
import {
|
||||||
|
formatDate,
|
||||||
|
getDateAfterDays
|
||||||
|
} from '@/utils/dateTime';
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
jlData.value = JSON.parse(res.data.result).JlData;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
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
src/pages/produce/shishishuju/ysjSssj.vue
Normal file
8
src/pages/produce/shishishuju/ysjSssj.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
BIN
src/static/tabbar/tabbar-produce-2.png
Normal file
BIN
src/static/tabbar/tabbar-produce-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/static/tabbar/tabbar-produce.png
Normal file
BIN
src/static/tabbar/tabbar-produce.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
18
src/types/uni-pages.d.ts
vendored
18
src/types/uni-pages.d.ts
vendored
@ -13,8 +13,18 @@ interface NavigateToOptions {
|
|||||||
"/pages/onlinePreview/detail" |
|
"/pages/onlinePreview/detail" |
|
||||||
"/pages/onlinePreview/onlinePreview" |
|
"/pages/onlinePreview/onlinePreview" |
|
||||||
"/pages/onlinePreview/onlinePreviewH5" |
|
"/pages/onlinePreview/onlinePreviewH5" |
|
||||||
|
"/pages/produce/index" |
|
||||||
"/pages/user/people" |
|
"/pages/user/people" |
|
||||||
"/pages/workHome/index" |
|
"/pages/workHome/index" |
|
||||||
|
"/pages/produce/ribaoshuju/rbsjLsxq" |
|
||||||
|
"/pages/produce/ribaoshuju/trqRbsj" |
|
||||||
|
"/pages/produce/ribaoshuju/yyRbsj" |
|
||||||
|
"/pages/produce/shishishuju/aqbjSssj" |
|
||||||
|
"/pages/produce/shishishuju/gycsSssj" |
|
||||||
|
"/pages/produce/shishishuju/index" |
|
||||||
|
"/pages/produce/shishishuju/nyxhSssj" |
|
||||||
|
"/pages/produce/shishishuju/trqSssj" |
|
||||||
|
"/pages/produce/shishishuju/ysjSssj" |
|
||||||
"/pages-home/home/home" |
|
"/pages-home/home/home" |
|
||||||
"/pages-message/chat/chat" |
|
"/pages-message/chat/chat" |
|
||||||
"/pages-message/contacts/contacts" |
|
"/pages-message/contacts/contacts" |
|
||||||
@ -32,7 +42,13 @@ interface NavigateToOptions {
|
|||||||
"/pages-operate/file/index" |
|
"/pages-operate/file/index" |
|
||||||
"/pages-operate/sc/index" |
|
"/pages-operate/sc/index" |
|
||||||
"/pages-humanResource/absence/add" |
|
"/pages-humanResource/absence/add" |
|
||||||
|
"/pages-humanResource/absence/detail" |
|
||||||
"/pages-humanResource/absence/index" |
|
"/pages-humanResource/absence/index" |
|
||||||
|
"/pages-humanResource/personnel/ageStatistics" |
|
||||||
|
"/pages-humanResource/personnel/detail" |
|
||||||
|
"/pages-humanResource/personnel/generalFieldStatistics" |
|
||||||
|
"/pages-humanResource/personnel/index" |
|
||||||
|
"/pages-humanResource/personnel/standingbook" |
|
||||||
"/pages-integrated/duty/index" |
|
"/pages-integrated/duty/index" |
|
||||||
"/pages-politics/health/add" |
|
"/pages-politics/health/add" |
|
||||||
"/pages-process/approvalTabbar" |
|
"/pages-process/approvalTabbar" |
|
||||||
@ -42,7 +58,7 @@ interface NavigateToOptions {
|
|||||||
interface RedirectToOptions extends NavigateToOptions {}
|
interface RedirectToOptions extends NavigateToOptions {}
|
||||||
|
|
||||||
interface SwitchTabOptions {
|
interface SwitchTabOptions {
|
||||||
url: "/pages/index/index" | "/pages/message/message" | "/pages/workHome/index" | "/pages/user/people"
|
url: "/pages/index/index" | "/pages/produce/index" | "/pages/workHome/index" | "/pages/user/people"
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;
|
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;
|
||||||
|
|||||||
@ -0,0 +1,134 @@
|
|||||||
|
<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';
|
||||||
|
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: 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;
|
||||||
|
min-width: 90px;
|
||||||
|
max-width: 120px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-input.active {
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: #f5f7ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
83
src/uni_modules/cxc-szcx-dateRangeSelect/package.json
Normal file
83
src/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
src/uni_modules/cxc-szcx-dateRangeSelect/readme.md
Normal file
168
src/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
src/uni_modules/cxc-szcx-dictSelect/changelog.md
Normal file
0
src/uni_modules/cxc-szcx-dictSelect/changelog.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<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/system';
|
||||||
|
|
||||||
|
// 定义 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) => {
|
||||||
|
const selectedValuesString = newValue.join(',');
|
||||||
|
emits('update:modelValue', selectedValuesString);
|
||||||
|
emits('change', selectedValuesString);
|
||||||
|
}, {
|
||||||
|
deep: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听 props.modelValue 的变化
|
||||||
|
watch(() => props.modelValue, (newValue) => {
|
||||||
|
selectedValuesArray.value = newValue ? newValue.split(',') : [];
|
||||||
|
}, {
|
||||||
|
immediate: true
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadDictItems();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 可以添加组件的样式 */
|
||||||
|
</style>
|
||||||
83
src/uni_modules/cxc-szcx-dictSelect/package.json
Normal file
83
src/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
src/uni_modules/cxc-szcx-dictSelect/readme.md
Normal file
90
src/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
src/uni_modules/cxc-szcx-lineChart/changelog.md
Normal file
0
src/uni_modules/cxc-szcx-lineChart/changelog.md
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<!-- ECharts图表 -->
|
||||||
|
<view class="chart-container">
|
||||||
|
<l-echart ref="chart" @finished="initChart" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { formatDate, getDateAfterDays, getDateAfterMonths } from '@/utils/dateTime';
|
||||||
|
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
|
||||||
|
},
|
||||||
|
legendArrStr:{ //修改指定中文显示 by 闵
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const chart = ref(null);
|
||||||
|
const chartOption = ref({});
|
||||||
|
const chartTitle = ref('');
|
||||||
|
|
||||||
|
//、数据处理
|
||||||
|
const processSeriesData = () => {
|
||||||
|
const legendItems = [...new Set(props.dataList.map((item) => item[props.legendField]?.trim() || '未命名'))];
|
||||||
|
|
||||||
|
let legendArr = []
|
||||||
|
if(props.legendArrStr){
|
||||||
|
legendArr = props.legendArrStr.split(",")
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
return legendItems.map((legend,index) => {
|
||||||
|
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轴数值
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
if(legendArr.length>0){
|
||||||
|
return {
|
||||||
|
name: legendArr[index],
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: true,
|
||||||
|
smooth: true,
|
||||||
|
data: items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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
src/uni_modules/cxc-szcx-lineChart/package.json
Normal file
83
src/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
src/uni_modules/cxc-szcx-lineChart/readme.md
Normal file
179
src/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,可能会有一定的延迟,需要确保在合适的时机初始化图表。
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="returnCodeOrID === 'orgCode'">
|
||||||
|
<uni-data-picker v-model="selectDepartID" ref="depart" :openSearch="true" :ellipsis="true" placeholder="请选择单位"
|
||||||
|
popup-title="请选择单位" :localdata="stationList" @nodeclick="onnodeclick" @popupclosed="onpopupclosed"
|
||||||
|
:map="{'text':'title','value':'orgCode'}" class="no-wrap-picker"></uni-data-picker>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<uni-data-picker v-model="selectDepartID" ref="depart" :openSearch="true" :ellipsis="true" placeholder="请选择单位"
|
||||||
|
popup-title="请选择单位" :localdata="stationList" @nodeclick="onnodeclick" @popupclosed="onpopupclosed"
|
||||||
|
:map="{'text':'title','value':'id'}" class="no-wrap-picker"></uni-data-picker>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
queryJldZcList
|
||||||
|
} from '@/api/produce'
|
||||||
|
import {
|
||||||
|
queryMyDeptTreeListApi
|
||||||
|
} from '@/api/system/department'
|
||||||
|
const props = defineProps({
|
||||||
|
returnCodeOrID: {
|
||||||
|
type: String,
|
||||||
|
default: "orgCode"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let stationList = ref([])
|
||||||
|
let selectDepartID = ref("") //当前选中的单位ID
|
||||||
|
let selectDepartIDS = ref([]) //选中的级联单位ID数组
|
||||||
|
let tempSelectDepartID = ref("") //临时选择的单位ID
|
||||||
|
let depart = ref(null);
|
||||||
|
let departInfo = ref({}) //"单位的全部信息"
|
||||||
|
let $emit = defineEmits(['change']);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
tempSelectDepartID,
|
||||||
|
(newVal, oldVal) => { //通过监听触发change by 闵
|
||||||
|
$emit('change', newVal, departInfo)
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const getDepartList = () => {
|
||||||
|
queryJldZcList({
|
||||||
|
pId: '1267633406031953921'
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
stationList.value = res.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onnodeclick = ((e) => {
|
||||||
|
departInfo.value = e;
|
||||||
|
if (props.returnCodeOrID == "orgCode") {
|
||||||
|
tempSelectDepartID.value = e.orgCode
|
||||||
|
} else {
|
||||||
|
tempSelectDepartID.value = e.value
|
||||||
|
}
|
||||||
|
// if(!depart.value.isOpened){//如果页面已经关闭 就触发change方法 by 闵
|
||||||
|
// $emit('change', selectDepartID.value, departInfo)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
const onchange = ((e) => {
|
||||||
|
selectDepartID.value = e.detail.value[e.detail.value.length - 1].value
|
||||||
|
// $emit('change', e.detail.value[e.detail.value.length - 1].value, {})
|
||||||
|
})
|
||||||
|
|
||||||
|
const onpopupclosed = ((e) => {
|
||||||
|
selectDepartID.value = tempSelectDepartID.value
|
||||||
|
// $emit('change', selectDepartID.value, departInfo)
|
||||||
|
})
|
||||||
|
onLoad((e) => {
|
||||||
|
getDepartList();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
/* 选择器根据实际情况调整 */
|
||||||
|
.no-wrap-picker::v-deep .uni-data-picker-item {
|
||||||
|
white-space: nowrap;
|
||||||
|
/* 强制不换行 */
|
||||||
|
overflow: hidden;
|
||||||
|
/* 超出部分隐藏 */
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
/* 超出部分显示省略号 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
83
src/uni_modules/cxc-szcx-stationJl-select/package.json
Normal file
83
src/uni_modules/cxc-szcx-stationJl-select/package.json
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"id": "cxc-szcx-stationJl-select",
|
||||||
|
"displayName": "cxc-szcx-stationJl-select",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "cxc-szcx-stationJl-select",
|
||||||
|
"keywords": [
|
||||||
|
"cxc-szcx-stationJl-select"
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/uni_modules/cxc-szcx-stationJl-select/readme.md
Normal file
1
src/uni_modules/cxc-szcx-stationJl-select/readme.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# cxc-szcx-stationJl-select
|
||||||
51
src/uni_modules/uni-data-checkbox/changelog.md
Normal file
51
src/uni_modules/uni-data-checkbox/changelog.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
## 1.0.6(2024-10-22)
|
||||||
|
- 新增 当 multiple 为 false 且传递的 value 为 数组时,使用数组第一项用作反显
|
||||||
|
## 1.0.5(2024-03-20)
|
||||||
|
- 修复 单选模式下选中样式不生效的bug
|
||||||
|
## 1.0.4(2024-01-27)
|
||||||
|
- 修复 修复错别字chagne为change
|
||||||
|
## 1.0.3(2022-09-16)
|
||||||
|
- 可以使用 uni-scss 控制主题色
|
||||||
|
## 1.0.2(2022-06-30)
|
||||||
|
- 优化 在 uni-forms 中的依赖注入方式
|
||||||
|
## 1.0.1(2022-02-07)
|
||||||
|
- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
|
||||||
|
## 1.0.0(2021-11-19)
|
||||||
|
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
|
||||||
|
## 0.2.5(2021-08-23)
|
||||||
|
- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
|
||||||
|
## 0.2.4(2021-08-17)
|
||||||
|
- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
|
||||||
|
## 0.2.3(2021-08-11)
|
||||||
|
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
|
||||||
|
## 0.2.2(2021-07-30)
|
||||||
|
- 优化 在uni-forms组件,与label不对齐的问题
|
||||||
|
## 0.2.1(2021-07-27)
|
||||||
|
- 修复 单选默认值为0不能选中的Bug
|
||||||
|
## 0.2.0(2021-07-13)
|
||||||
|
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||||
|
## 0.1.11(2021-07-06)
|
||||||
|
- 优化 删除无用日志
|
||||||
|
## 0.1.10(2021-07-05)
|
||||||
|
- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
|
||||||
|
## 0.1.9(2021-07-05)
|
||||||
|
- 修复 nvue 黑框样式问题
|
||||||
|
## 0.1.8(2021-06-28)
|
||||||
|
- 修复 selectedTextColor 属性不生效的Bug
|
||||||
|
## 0.1.7(2021-06-02)
|
||||||
|
- 新增 map 属性,可以方便映射text/value属性
|
||||||
|
## 0.1.6(2021-05-26)
|
||||||
|
- 修复 不关联服务空间的情况下组件报错的Bug
|
||||||
|
## 0.1.5(2021-05-12)
|
||||||
|
- 新增 组件示例地址
|
||||||
|
## 0.1.4(2021-04-09)
|
||||||
|
- 修复 nvue 下无法选中的问题
|
||||||
|
## 0.1.3(2021-03-22)
|
||||||
|
- 新增 disabled属性
|
||||||
|
## 0.1.2(2021-02-24)
|
||||||
|
- 优化 默认颜色显示
|
||||||
|
## 0.1.1(2021-02-24)
|
||||||
|
- 新增 支持nvue
|
||||||
|
## 0.1.0(2021-02-18)
|
||||||
|
- “暂无数据”显示居中
|
||||||
@ -0,0 +1,316 @@
|
|||||||
|
|
||||||
|
const events = {
|
||||||
|
load: 'load',
|
||||||
|
error: 'error'
|
||||||
|
}
|
||||||
|
const pageMode = {
|
||||||
|
add: 'add',
|
||||||
|
replace: 'replace'
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrs = [
|
||||||
|
'pageCurrent',
|
||||||
|
'pageSize',
|
||||||
|
'collection',
|
||||||
|
'action',
|
||||||
|
'field',
|
||||||
|
'getcount',
|
||||||
|
'orderby',
|
||||||
|
'where'
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
listData: this.getone ? {} : [],
|
||||||
|
paginationInternal: {
|
||||||
|
current: this.pageCurrent,
|
||||||
|
size: this.pageSize,
|
||||||
|
count: 0
|
||||||
|
},
|
||||||
|
errorMessage: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
let db = null;
|
||||||
|
let dbCmd = null;
|
||||||
|
|
||||||
|
if(this.collection){
|
||||||
|
this.db = uniCloud.database();
|
||||||
|
this.dbCmd = this.db.command;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isEnded = false
|
||||||
|
|
||||||
|
this.$watch(() => {
|
||||||
|
let al = []
|
||||||
|
attrs.forEach(key => {
|
||||||
|
al.push(this[key])
|
||||||
|
})
|
||||||
|
return al
|
||||||
|
}, (newValue, oldValue) => {
|
||||||
|
this.paginationInternal.pageSize = this.pageSize
|
||||||
|
|
||||||
|
let needReset = false
|
||||||
|
for (let i = 2; i < newValue.length; i++) {
|
||||||
|
if (newValue[i] != oldValue[i]) {
|
||||||
|
needReset = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needReset) {
|
||||||
|
this.clear()
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
if (newValue[0] != oldValue[0]) {
|
||||||
|
this.paginationInternal.current = this.pageCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
this._execLoadData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this._debugDataList = []
|
||||||
|
if (!window.unidev) {
|
||||||
|
window.unidev = {
|
||||||
|
clientDB: {
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unidev.clientDB.data.push(this._debugDataList)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
let changeName
|
||||||
|
let events = this.$scope.dataset.eventOpts
|
||||||
|
for (let i = 0; i < events.length; i++) {
|
||||||
|
let event = events[i]
|
||||||
|
if (event[0].includes('^load')) {
|
||||||
|
changeName = event[1][0][0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changeName) {
|
||||||
|
let parent = this.$parent
|
||||||
|
let maxDepth = 16
|
||||||
|
this._changeDataFunction = null
|
||||||
|
while (parent && maxDepth > 0) {
|
||||||
|
let fun = parent[changeName]
|
||||||
|
if (fun && typeof fun === 'function') {
|
||||||
|
this._changeDataFunction = fun
|
||||||
|
maxDepth = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
parent = parent.$parent
|
||||||
|
maxDepth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// if (!this.manual) {
|
||||||
|
// this.loadData()
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
// #ifdef H5
|
||||||
|
beforeDestroy() {
|
||||||
|
if (process.env.NODE_ENV === 'development' && window.unidev) {
|
||||||
|
let cd = this._debugDataList
|
||||||
|
let dl = unidev.clientDB.data
|
||||||
|
for (let i = dl.length - 1; i >= 0; i--) {
|
||||||
|
if (dl[i] === cd) {
|
||||||
|
dl.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
methods: {
|
||||||
|
loadData(args1, args2) {
|
||||||
|
let callback = null
|
||||||
|
if (typeof args1 === 'object') {
|
||||||
|
if (args1.clear) {
|
||||||
|
this.clear()
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
if (args1.current !== undefined) {
|
||||||
|
this.paginationInternal.current = args1.current
|
||||||
|
}
|
||||||
|
if (typeof args2 === 'function') {
|
||||||
|
callback = args2
|
||||||
|
}
|
||||||
|
} else if (typeof args1 === 'function') {
|
||||||
|
callback = args1
|
||||||
|
}
|
||||||
|
|
||||||
|
this._execLoadData(callback)
|
||||||
|
},
|
||||||
|
loadMore() {
|
||||||
|
if (this._isEnded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._execLoadData()
|
||||||
|
},
|
||||||
|
refresh() {
|
||||||
|
this.clear()
|
||||||
|
this._execLoadData()
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this._isEnded = false
|
||||||
|
this.listData = []
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
this.paginationInternal.current = 1
|
||||||
|
},
|
||||||
|
remove(id, {
|
||||||
|
action,
|
||||||
|
callback,
|
||||||
|
confirmTitle,
|
||||||
|
confirmContent
|
||||||
|
} = {}) {
|
||||||
|
if (!id || !id.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.showModal({
|
||||||
|
title: confirmTitle || '提示',
|
||||||
|
content: confirmContent || '是否删除该数据',
|
||||||
|
showCancel: true,
|
||||||
|
success: (res) => {
|
||||||
|
if (!res.confirm) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._execRemove(id, action, callback)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_execLoadData(callback) {
|
||||||
|
if (this.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
this.errorMessage = ''
|
||||||
|
|
||||||
|
this._getExec().then((res) => {
|
||||||
|
this.loading = false
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
count
|
||||||
|
} = res.result
|
||||||
|
this._isEnded = data.length < this.pageSize
|
||||||
|
|
||||||
|
callback && callback(data, this._isEnded)
|
||||||
|
this._dispatchEvent(events.load, data)
|
||||||
|
|
||||||
|
if (this.getone) {
|
||||||
|
this.listData = data.length ? data[0] : undefined
|
||||||
|
} else if (this.pageData === pageMode.add) {
|
||||||
|
this.listData.push(...data)
|
||||||
|
if (this.listData.length) {
|
||||||
|
this.paginationInternal.current++
|
||||||
|
}
|
||||||
|
} else if (this.pageData === pageMode.replace) {
|
||||||
|
this.listData = data
|
||||||
|
this.paginationInternal.count = count
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this._debugDataList.length = 0
|
||||||
|
this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData)))
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}).catch((err) => {
|
||||||
|
this.loading = false
|
||||||
|
this.errorMessage = err
|
||||||
|
callback && callback()
|
||||||
|
this.$emit(events.error, err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_getExec() {
|
||||||
|
let exec = this.db
|
||||||
|
if (this.action) {
|
||||||
|
exec = exec.action(this.action)
|
||||||
|
}
|
||||||
|
|
||||||
|
exec = exec.collection(this.collection)
|
||||||
|
|
||||||
|
if (!(!this.where || !Object.keys(this.where).length)) {
|
||||||
|
exec = exec.where(this.where)
|
||||||
|
}
|
||||||
|
if (this.field) {
|
||||||
|
exec = exec.field(this.field)
|
||||||
|
}
|
||||||
|
if (this.orderby) {
|
||||||
|
exec = exec.orderBy(this.orderby)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
current,
|
||||||
|
size
|
||||||
|
} = this.paginationInternal
|
||||||
|
exec = exec.skip(size * (current - 1)).limit(size).get({
|
||||||
|
getCount: this.getcount
|
||||||
|
})
|
||||||
|
|
||||||
|
return exec
|
||||||
|
},
|
||||||
|
_execRemove(id, action, callback) {
|
||||||
|
if (!this.collection || !id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = Array.isArray(id) ? id : [id]
|
||||||
|
if (!ids.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({
|
||||||
|
mask: true
|
||||||
|
})
|
||||||
|
|
||||||
|
let exec = this.db
|
||||||
|
if (action) {
|
||||||
|
exec = exec.action(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
exec.collection(this.collection).where({
|
||||||
|
_id: dbCmd.in(ids)
|
||||||
|
}).remove().then((res) => {
|
||||||
|
callback && callback(res.result)
|
||||||
|
if (this.pageData === pageMode.replace) {
|
||||||
|
this.refresh()
|
||||||
|
} else {
|
||||||
|
this.removeData(ids)
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
uni.showModal({
|
||||||
|
content: err.message,
|
||||||
|
showCancel: false
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
uni.hideLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeData(ids) {
|
||||||
|
let il = ids.slice(0)
|
||||||
|
let dl = this.listData
|
||||||
|
for (let i = dl.length - 1; i >= 0; i--) {
|
||||||
|
let index = il.indexOf(dl[i]._id)
|
||||||
|
if (index >= 0) {
|
||||||
|
dl.splice(i, 1)
|
||||||
|
il.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_dispatchEvent(type, data) {
|
||||||
|
if (this._changeDataFunction) {
|
||||||
|
this._changeDataFunction(data, this._isEnded)
|
||||||
|
} else {
|
||||||
|
this.$emit(type, data, this._isEnded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,853 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
|
||||||
|
<template v-if="!isLocal">
|
||||||
|
<view class="uni-data-loading">
|
||||||
|
<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18"
|
||||||
|
:content-text="contentText"></uni-load-more>
|
||||||
|
<text v-else>{{mixinDatacomErrorMessage}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}"
|
||||||
|
@change="change">
|
||||||
|
<label class="checklist-box"
|
||||||
|
:class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
|
||||||
|
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
|
||||||
|
<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''"
|
||||||
|
:checked="item.selected" />
|
||||||
|
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')"
|
||||||
|
class="checkbox__inner" :style="item.styleIcon">
|
||||||
|
<view class="checkbox__inner-icon"></view>
|
||||||
|
</view>
|
||||||
|
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
|
||||||
|
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||||
|
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
|
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="change">
|
||||||
|
<label class="checklist-box"
|
||||||
|
:class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
|
||||||
|
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
|
||||||
|
<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''"
|
||||||
|
:checked="item.selected" />
|
||||||
|
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
|
||||||
|
:style="item.styleBackgroud">
|
||||||
|
<view class="radio__inner-icon" :style="item.styleIcon"></view>
|
||||||
|
</view>
|
||||||
|
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
|
||||||
|
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||||
|
<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* DataChecklist 数据选择器
|
||||||
|
* @description 通过数据渲染 checkbox 和 radio
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
||||||
|
* @property {String} mode = [default| list | button | tag] 显示模式
|
||||||
|
* @value default 默认横排模式
|
||||||
|
* @value list 列表模式
|
||||||
|
* @value button 按钮模式
|
||||||
|
* @value tag 标签模式
|
||||||
|
* @property {Boolean} multiple = [true|false] 是否多选
|
||||||
|
* @property {Array|String|Number} value 默认值
|
||||||
|
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
|
||||||
|
* @property {Number|String} min 最小选择个数 ,multiple为true时生效
|
||||||
|
* @property {Number|String} max 最大选择个数 ,multiple为true时生效
|
||||||
|
* @property {Boolean} wrap 是否换行显示
|
||||||
|
* @property {String} icon = [left|right] list 列表模式下icon显示位置
|
||||||
|
* @property {Boolean} selectedColor 选中颜色
|
||||||
|
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
|
||||||
|
* @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
|
||||||
|
* @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
|
||||||
|
* @value left 左侧显示
|
||||||
|
* @value right 右侧显示
|
||||||
|
* @event {Function} change 选中发生变化触发
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'uniDataChecklist',
|
||||||
|
mixins: [uniCloud.mixinDatacom || {}],
|
||||||
|
emits: ['input', 'update:modelValue', 'change'],
|
||||||
|
props: {
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
default () {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// TODO vue3
|
||||||
|
modelValue: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
default () {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
localdata: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
wrap: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
selectedColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selectedTextColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
emptyText: {
|
||||||
|
type: String,
|
||||||
|
default: '暂无数据'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {
|
||||||
|
text: 'text',
|
||||||
|
value: 'value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
localdata: {
|
||||||
|
handler(newVal) {
|
||||||
|
this.range = newVal
|
||||||
|
this.dataList = this.getDataList(this.getSelectedValue(newVal))
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
mixinDatacomResData(newVal) {
|
||||||
|
this.range = newVal
|
||||||
|
this.dataList = this.getDataList(this.getSelectedValue(newVal))
|
||||||
|
},
|
||||||
|
value(newVal) {
|
||||||
|
this.dataList = this.getDataList(newVal)
|
||||||
|
// fix by mehaotian is_reset 在 uni-forms 中定义
|
||||||
|
// if(!this.is_reset){
|
||||||
|
// this.is_reset = false
|
||||||
|
// this.formItem && this.formItem.setValue(newVal)
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
modelValue(newVal) {
|
||||||
|
this.dataList = this.getDataList(newVal);
|
||||||
|
// if(!this.is_reset){
|
||||||
|
// this.is_reset = false
|
||||||
|
// this.formItem && this.formItem.setValue(newVal)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dataList: [],
|
||||||
|
range: [],
|
||||||
|
contentText: {
|
||||||
|
contentdown: '查看更多',
|
||||||
|
contentrefresh: '加载中',
|
||||||
|
contentnomore: '没有更多'
|
||||||
|
},
|
||||||
|
isLocal: true,
|
||||||
|
styles: {
|
||||||
|
selectedColor: '#2979ff',
|
||||||
|
selectedTextColor: '#666',
|
||||||
|
},
|
||||||
|
isTop: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dataValue() {
|
||||||
|
if (this.value === '') return this.modelValue
|
||||||
|
if (this.modelValue === '') return this.value
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// this.form = this.getForm('uniForms')
|
||||||
|
// this.formItem = this.getForm('uniFormsItem')
|
||||||
|
// this.formItem && this.formItem.setValue(this.value)
|
||||||
|
|
||||||
|
// if (this.formItem) {
|
||||||
|
// this.isTop = 6
|
||||||
|
// if (this.formItem.name) {
|
||||||
|
// // 如果存在name添加默认值,否则formData 中不存在这个字段不校验
|
||||||
|
// if(!this.is_reset){
|
||||||
|
// this.is_reset = false
|
||||||
|
// this.formItem.setValue(this.dataValue)
|
||||||
|
// }
|
||||||
|
// this.rename = this.formItem.name
|
||||||
|
// this.form.inputChildrens.push(this)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (this.localdata && this.localdata.length !== 0) {
|
||||||
|
this.isLocal = true
|
||||||
|
this.range = this.localdata
|
||||||
|
this.dataList = this.getDataList(this.getSelectedValue(this.range))
|
||||||
|
} else {
|
||||||
|
if (this.collection) {
|
||||||
|
this.isLocal = false
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadData() {
|
||||||
|
this.mixinDatacomGet().then(res => {
|
||||||
|
this.mixinDatacomResData = res.result.data
|
||||||
|
if (this.mixinDatacomResData.length === 0) {
|
||||||
|
this.isLocal = false
|
||||||
|
this.mixinDatacomErrorMessage = this.emptyText
|
||||||
|
} else {
|
||||||
|
this.isLocal = true
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
this.mixinDatacomErrorMessage = err.message
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取父元素实例
|
||||||
|
*/
|
||||||
|
getForm(name = 'uniForms') {
|
||||||
|
let parent = this.$parent;
|
||||||
|
let parentName = parent.$options.name;
|
||||||
|
while (parentName !== name) {
|
||||||
|
parent = parent.$parent;
|
||||||
|
if (!parent) return false
|
||||||
|
parentName = parent.$options.name;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
},
|
||||||
|
change(e) {
|
||||||
|
const values = e.detail.value
|
||||||
|
|
||||||
|
let detail = {
|
||||||
|
value: [],
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.multiple) {
|
||||||
|
this.range.forEach(item => {
|
||||||
|
|
||||||
|
if (values.includes(item[this.map.value] + '')) {
|
||||||
|
detail.value.push(item[this.map.value])
|
||||||
|
detail.data.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const range = this.range.find(item => (item[this.map.value] + '') === values)
|
||||||
|
if (range) {
|
||||||
|
detail = {
|
||||||
|
value: range[this.map.value],
|
||||||
|
data: range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this.formItem && this.formItem.setValue(detail.value)
|
||||||
|
// TODO 兼容 vue2
|
||||||
|
this.$emit('input', detail.value);
|
||||||
|
// // TOTO 兼容 vue3
|
||||||
|
this.$emit('update:modelValue', detail.value);
|
||||||
|
this.$emit('change', {
|
||||||
|
detail
|
||||||
|
})
|
||||||
|
if (this.multiple) {
|
||||||
|
// 如果 v-model 没有绑定 ,则走内部逻辑
|
||||||
|
// if (this.value.length === 0) {
|
||||||
|
this.dataList = this.getDataList(detail.value, true)
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
this.dataList = this.getDataList(detail.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取渲染的新数组
|
||||||
|
* @param {Object} value 选中内容
|
||||||
|
*/
|
||||||
|
getDataList(value) {
|
||||||
|
// 解除引用关系,破坏原引用关系,避免污染源数据
|
||||||
|
let dataList = JSON.parse(JSON.stringify(this.range))
|
||||||
|
let list = []
|
||||||
|
if (this.multiple) {
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
value = []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Array.isArray(value) && value.length) {
|
||||||
|
value = value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataList.forEach((item, index) => {
|
||||||
|
item.disabled = item.disable || item.disabled || false
|
||||||
|
if (this.multiple) {
|
||||||
|
if (value.length > 0) {
|
||||||
|
let have = value.find(val => val === item[this.map.value])
|
||||||
|
item.selected = have !== undefined
|
||||||
|
} else {
|
||||||
|
item.selected = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.selected = value === item[this.map.value]
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push(item)
|
||||||
|
})
|
||||||
|
return this.setRange(list)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 处理最大最小值
|
||||||
|
* @param {Object} list
|
||||||
|
*/
|
||||||
|
setRange(list) {
|
||||||
|
let selectList = list.filter(item => item.selected)
|
||||||
|
let min = Number(this.min) || 0
|
||||||
|
let max = Number(this.max) || ''
|
||||||
|
list.forEach((item, index) => {
|
||||||
|
if (this.multiple) {
|
||||||
|
if (selectList.length <= min) {
|
||||||
|
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
|
||||||
|
if (have !== undefined) {
|
||||||
|
item.disabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectList.length >= max && max !== '') {
|
||||||
|
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
|
||||||
|
if (have === undefined) {
|
||||||
|
item.disabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setStyles(item, index)
|
||||||
|
list[index] = item
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 设置 class
|
||||||
|
* @param {Object} item
|
||||||
|
* @param {Object} index
|
||||||
|
*/
|
||||||
|
setStyles(item, index) {
|
||||||
|
// 设置自定义样式
|
||||||
|
item.styleBackgroud = this.setStyleBackgroud(item)
|
||||||
|
item.styleIcon = this.setStyleIcon(item)
|
||||||
|
item.styleIconText = this.setStyleIconText(item)
|
||||||
|
item.styleRightIcon = this.setStyleRightIcon(item)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取选中值
|
||||||
|
* @param {Object} range
|
||||||
|
*/
|
||||||
|
getSelectedValue(range) {
|
||||||
|
if (!this.multiple) return this.dataValue
|
||||||
|
let selectedArr = []
|
||||||
|
range.forEach((item) => {
|
||||||
|
if (item.selected) {
|
||||||
|
selectedArr.push(item[this.map.value])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return this.dataValue.length > 0 ? this.dataValue : selectedArr
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置背景样式
|
||||||
|
*/
|
||||||
|
setStyleBackgroud(item) {
|
||||||
|
let styles = {}
|
||||||
|
let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
|
||||||
|
if (this.selectedColor) {
|
||||||
|
if (this.mode !== 'list') {
|
||||||
|
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
|
||||||
|
}
|
||||||
|
if (this.mode === 'tag') {
|
||||||
|
styles['background-color'] = item.selected ? selectedColor : '#f5f5f5'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let classles = ''
|
||||||
|
for (let i in styles) {
|
||||||
|
classles += `${i}:${styles[i]};`
|
||||||
|
}
|
||||||
|
return classles
|
||||||
|
},
|
||||||
|
setStyleIcon(item) {
|
||||||
|
let styles = {}
|
||||||
|
let classles = ''
|
||||||
|
if (this.selectedColor) {
|
||||||
|
let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
|
||||||
|
styles['background-color'] = item.selected ? selectedColor : '#fff'
|
||||||
|
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
|
||||||
|
|
||||||
|
if (!item.selected && item.disabled) {
|
||||||
|
styles['background-color'] = '#F2F6FC'
|
||||||
|
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i in styles) {
|
||||||
|
classles += `${i}:${styles[i]};`
|
||||||
|
}
|
||||||
|
return classles
|
||||||
|
},
|
||||||
|
setStyleIconText(item) {
|
||||||
|
let styles = {}
|
||||||
|
let classles = ''
|
||||||
|
if (this.selectedColor) {
|
||||||
|
let selectedColor = this.selectedColor ? this.selectedColor : '#2979ff'
|
||||||
|
if (this.mode === 'tag') {
|
||||||
|
styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : '#fff') : '#666'
|
||||||
|
} else {
|
||||||
|
styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : selectedColor) : '#666'
|
||||||
|
}
|
||||||
|
if (!item.selected && item.disabled) {
|
||||||
|
styles.color = '#999'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i in styles) {
|
||||||
|
classles += `${i}:${styles[i]};`
|
||||||
|
}
|
||||||
|
return classles
|
||||||
|
},
|
||||||
|
setStyleRightIcon(item) {
|
||||||
|
let styles = {}
|
||||||
|
let classles = ''
|
||||||
|
if (this.mode === 'list') {
|
||||||
|
styles['border-color'] = item.selected ? this.styles.selectedColor : '#DCDFE6'
|
||||||
|
}
|
||||||
|
for (let i in styles) {
|
||||||
|
classles += `${i}:${styles[i]};`
|
||||||
|
}
|
||||||
|
|
||||||
|
return classles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$uni-primary: #2979ff !default;
|
||||||
|
$border-color: #DCDFE6;
|
||||||
|
$disable: 0.4;
|
||||||
|
|
||||||
|
@mixin flex {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-loading {
|
||||||
|
@include flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 36px;
|
||||||
|
padding-left: 10px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-checklist {
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
// 多选样式
|
||||||
|
.checklist-group {
|
||||||
|
@include flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&.is-list {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-box {
|
||||||
|
@include flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
margin: 5px 0;
|
||||||
|
margin-right: 25px;
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文字样式
|
||||||
|
.checklist-content {
|
||||||
|
@include flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-left: 5px;
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkobx__list {
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-right-color: #007aff;
|
||||||
|
border-right-style: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-color: #007aff;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
height: 12px;
|
||||||
|
width: 6px;
|
||||||
|
left: -5px;
|
||||||
|
transform-origin: center;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多选样式
|
||||||
|
.checkbox__inner {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
position: relative;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.checkbox__inner-icon {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
top: 2px;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
top: 1px;
|
||||||
|
/* #endif */
|
||||||
|
left: 5px;
|
||||||
|
height: 8px;
|
||||||
|
width: 4px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-right-color: #fff;
|
||||||
|
border-right-style: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: center;
|
||||||
|
transform: rotate(40deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选样式
|
||||||
|
.radio__inner {
|
||||||
|
@include flex;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
border-radius: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.radio__inner-icon {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认样式
|
||||||
|
&.is--default {
|
||||||
|
|
||||||
|
// 禁用
|
||||||
|
&.is-disable {
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
.checkbox__inner {
|
||||||
|
background-color: #F2F6FC;
|
||||||
|
border-color: $border-color;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
background-color: #F2F6FC;
|
||||||
|
border-color: $border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中
|
||||||
|
&.is-checked {
|
||||||
|
.checkbox__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
|
||||||
|
.checkbox__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
|
||||||
|
.radio__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中禁用
|
||||||
|
&.is-disable {
|
||||||
|
.checkbox__inner {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮样式
|
||||||
|
&.is--button {
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px $border-color solid;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
|
||||||
|
// 禁用
|
||||||
|
&.is-disable {
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
border: 1px #eee solid;
|
||||||
|
opacity: $disable;
|
||||||
|
|
||||||
|
.checkbox__inner {
|
||||||
|
background-color: #F2F6FC;
|
||||||
|
border-color: $border-color;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
background-color: #F2F6FC;
|
||||||
|
border-color: $border-color;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
|
||||||
|
.checkbox__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
|
||||||
|
.checkbox__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
|
||||||
|
.radio__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中禁用
|
||||||
|
&.is-disable {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签样式
|
||||||
|
&.is--tag {
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px $border-color solid;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
margin: 0;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用
|
||||||
|
&.is-disable {
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked {
|
||||||
|
background-color: $uni-primary;
|
||||||
|
border-color: $uni-primary;
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列表样式
|
||||||
|
&.is--list {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
padding: 10px 15px;
|
||||||
|
padding-left: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&.is-list-border {
|
||||||
|
border-top: 1px #eee solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用
|
||||||
|
&.is-disable {
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
.checkbox__inner {
|
||||||
|
background-color: #F2F6FC;
|
||||||
|
border-color: $border-color;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked {
|
||||||
|
.checkbox__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
|
||||||
|
.checkbox__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio__inner {
|
||||||
|
border-color: $uni-primary;
|
||||||
|
.radio__inner-icon {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
color: $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-content {
|
||||||
|
.checkobx__list {
|
||||||
|
opacity: 1;
|
||||||
|
border-color: $uni-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中禁用
|
||||||
|
&.is-disable {
|
||||||
|
.checkbox__inner {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checklist-text {
|
||||||
|
opacity: $disable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
87
src/uni_modules/uni-data-checkbox/package.json
Normal file
87
src/uni_modules/uni-data-checkbox/package.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-data-checkbox",
|
||||||
|
"displayName": "uni-data-checkbox 数据选择器",
|
||||||
|
"version": "1.0.6",
|
||||||
|
"description": "通过数据驱动的单选框和复选框",
|
||||||
|
"keywords": [
|
||||||
|
"uni-ui",
|
||||||
|
"checkbox",
|
||||||
|
"单选",
|
||||||
|
"多选",
|
||||||
|
"单选多选"
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^3.1.1"
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": ["uni-load-more","uni-scss"],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y",
|
||||||
|
"app-harmony": "u",
|
||||||
|
"app-uvue": "u"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/uni_modules/uni-data-checkbox/readme.md
Normal file
18
src/uni_modules/uni-data-checkbox/readme.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## DataCheckbox 数据驱动的单选复选框
|
||||||
|
> **组件名:uni-data-checkbox**
|
||||||
|
> 代码块: `uDataCheckbox`
|
||||||
|
|
||||||
|
|
||||||
|
本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
|
||||||
|
|
||||||
|
1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
|
||||||
|
2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
|
||||||
|
3. 本组件合并了单选多选
|
||||||
|
4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
|
||||||
|
|
||||||
|
在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
79
src/uni_modules/uni-data-picker/changelog.md
Normal file
79
src/uni_modules/uni-data-picker/changelog.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
## 2.0.2(2025-04-14)
|
||||||
|
- 修复 在readonly属性为true时选项匹配错误的问题
|
||||||
|
## 2.0.0(2023-12-14)
|
||||||
|
- 新增 支持 uni-app-x
|
||||||
|
## 1.1.2(2023-04-11)
|
||||||
|
- 修复 更改 modelValue 报错的 bug
|
||||||
|
- 修复 v-for 未使用 key 值控制台 warning
|
||||||
|
## 1.1.1(2023-02-21)
|
||||||
|
- 修复代码合并时引发 value 属性为空时不渲染数据的问题
|
||||||
|
## 1.1.0(2023-02-15)
|
||||||
|
- 修复 localdata 不支持动态更新的bug
|
||||||
|
## 1.0.9(2023-02-15)
|
||||||
|
- 修复 localdata 不支持动态更新的bug
|
||||||
|
## 1.0.8(2022-09-16)
|
||||||
|
- 可以使用 uni-scss 控制主题色
|
||||||
|
## 1.0.7(2022-07-06)
|
||||||
|
- 优化 pc端图标位置不正确的问题
|
||||||
|
## 1.0.6(2022-07-05)
|
||||||
|
- 优化 显示样式
|
||||||
|
## 1.0.5(2022-07-04)
|
||||||
|
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
|
||||||
|
## 1.0.4(2022-04-19)
|
||||||
|
- 修复 字节小程序 本地数据无法选择下一级的Bug
|
||||||
|
## 1.0.3(2022-02-25)
|
||||||
|
- 修复 nvue 不支持的 v-show 的 bug
|
||||||
|
## 1.0.2(2022-02-25)
|
||||||
|
- 修复 条件编译 nvue 不支持的 css 样式
|
||||||
|
## 1.0.1(2021-11-23)
|
||||||
|
- 修复 由上个版本引发的map、v-model等属性不生效的bug
|
||||||
|
## 1.0.0(2021-11-19)
|
||||||
|
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
|
||||||
|
## 0.4.9(2021-10-28)
|
||||||
|
- 修复 VUE2 v-model 概率无效的 bug
|
||||||
|
## 0.4.8(2021-10-27)
|
||||||
|
- 修复 v-model 概率无效的 bug
|
||||||
|
## 0.4.7(2021-10-25)
|
||||||
|
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
|
||||||
|
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
|
||||||
|
## 0.4.6(2021-10-19)
|
||||||
|
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
|
||||||
|
## 0.4.5(2021-09-26)
|
||||||
|
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
|
||||||
|
- 修复 readonly 为 true 时报错的 bug
|
||||||
|
## 0.4.4(2021-09-26)
|
||||||
|
- 修复 上一版本造成的 map 属性失效的 bug
|
||||||
|
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
|
||||||
|
## 0.4.3(2021-09-24)
|
||||||
|
- 修复 某些情况下级联未触发的 bug
|
||||||
|
## 0.4.2(2021-09-23)
|
||||||
|
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
|
||||||
|
- 新增 选项内容过长自动添加省略号
|
||||||
|
## 0.4.1(2021-09-15)
|
||||||
|
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
|
||||||
|
## 0.4.0(2021-07-13)
|
||||||
|
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||||
|
## 0.3.5(2021-06-04)
|
||||||
|
- 修复 无法加载云端数据的问题
|
||||||
|
## 0.3.4(2021-05-28)
|
||||||
|
- 修复 v-model 无效问题
|
||||||
|
- 修复 loaddata 为空数据组时加载时间过长问题
|
||||||
|
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
|
||||||
|
## 0.3.3(2021-05-12)
|
||||||
|
- 新增 组件示例地址
|
||||||
|
## 0.3.2(2021-04-22)
|
||||||
|
- 修复 非树形数据有 where 属性查询报错的问题
|
||||||
|
## 0.3.1(2021-04-15)
|
||||||
|
- 修复 本地数据概率无法回显时问题
|
||||||
|
## 0.3.0(2021-04-07)
|
||||||
|
- 新增 支持云端非树形表结构数据
|
||||||
|
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
|
||||||
|
## 0.2.0(2021-03-15)
|
||||||
|
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
|
||||||
|
## 0.1.9(2021-03-09)
|
||||||
|
- 修复 微信小程序某些情况下无法选择的问题
|
||||||
|
## 0.1.8(2021-02-05)
|
||||||
|
- 优化 部分样式在 nvue 上的兼容表现
|
||||||
|
## 0.1.7(2021-02-05)
|
||||||
|
- 调整为 uni_modules 目录规范
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
// #ifdef H5
|
||||||
|
export default {
|
||||||
|
name: 'Keypress',
|
||||||
|
props: {
|
||||||
|
disable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const keyNames = {
|
||||||
|
esc: ['Esc', 'Escape'],
|
||||||
|
tab: 'Tab',
|
||||||
|
enter: 'Enter',
|
||||||
|
space: [' ', 'Spacebar'],
|
||||||
|
up: ['Up', 'ArrowUp'],
|
||||||
|
left: ['Left', 'ArrowLeft'],
|
||||||
|
right: ['Right', 'ArrowRight'],
|
||||||
|
down: ['Down', 'ArrowDown'],
|
||||||
|
delete: ['Backspace', 'Delete', 'Del']
|
||||||
|
}
|
||||||
|
const listener = ($event) => {
|
||||||
|
if (this.disable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const keyName = Object.keys(keyNames).find(key => {
|
||||||
|
const keyName = $event.key
|
||||||
|
const value = keyNames[key]
|
||||||
|
return value === keyName || (Array.isArray(value) && value.includes(keyName))
|
||||||
|
})
|
||||||
|
if (keyName) {
|
||||||
|
// 避免和其他按键事件冲突
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$emit(keyName, {})
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('keyup', listener)
|
||||||
|
this.$once('hook:beforeDestroy', () => {
|
||||||
|
document.removeEventListener('keyup', listener)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
render: () => {}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
@ -0,0 +1,381 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-data-tree">
|
||||||
|
<view class="uni-data-tree-input" @click="handleInput">
|
||||||
|
<slot :data="selectedPaths" :error="error">
|
||||||
|
<view class="input-value" :class="{'input-value-border': border}">
|
||||||
|
<text v-if="error!=null" class="error-text">{{error!.errMsg}}</text>
|
||||||
|
<scroll-view v-if="selectedPaths.length" class="selected-path" scroll-x="true">
|
||||||
|
<view class="selected-list">
|
||||||
|
<template v-for="(item, index) in selectedPaths">
|
||||||
|
<text class="text-color">{{item[mappingTextName]}}</text>
|
||||||
|
<text v-if="index<selectedPaths.length-1" class="input-split-line">{{split}}</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<text v-else-if="error==null&&!loading" class="placeholder">{{placeholder}}</text>
|
||||||
|
<view v-if="!readonly" class="arrow-area">
|
||||||
|
<view class="input-arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
<view v-if="loading && !isOpened" class="selected-loading">
|
||||||
|
<slot name="picker-loading" :loading="loading"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="uni-data-tree-cover" v-show="isOpened" @click="handleClose"></view>
|
||||||
|
<view class="uni-data-tree-dialog" v-show="isOpened">
|
||||||
|
<view class="uni-popper__arrow"></view>
|
||||||
|
<view class="dialog-caption">
|
||||||
|
<view class="dialog-title-view">
|
||||||
|
<text class="dialog-title">{{popupTitle}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="dialog-close" @click="handleClose">
|
||||||
|
<view class="dialog-close-plus" data-id="close"></view>
|
||||||
|
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view ref="pickerView" class="uni-data-pickerview">
|
||||||
|
<view v-if="error!=null" class="error">
|
||||||
|
<text class="error-text">{{error!.errMsg}}</text>
|
||||||
|
</view>
|
||||||
|
<scroll-view v-if="!isCloudDataList" :scroll-x="true">
|
||||||
|
<view class="selected-node-list">
|
||||||
|
<template v-for="(item, index) in selectedNodes">
|
||||||
|
<text class="selected-node-item" :class="{'selected-node-item-active':index==selectedIndex}"
|
||||||
|
@click="onTabSelect(index)">
|
||||||
|
{{item[mappingTextName]}}
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<list-view class="list-view" :scroll-y="true">
|
||||||
|
<list-item class="list-item" v-for="(item, _) in currentDataList" @click="onNodeClick(item)">
|
||||||
|
<text class="item-text" :class="{'item-text-disabled': item['disable']}">{{item[mappingTextName]}}</text>
|
||||||
|
<text class="check" v-if="item[mappingValueName] == selectedNodes[selectedIndex][mappingValueName]"></text>
|
||||||
|
</list-item>
|
||||||
|
</list-view>
|
||||||
|
<view class="loading-cover" v-if="loading">
|
||||||
|
<slot name="pickerview-loading" :loading="loading"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { dataPicker } from "../uni-data-pickerview/uni-data-picker.uts"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataPicker 级联选择
|
||||||
|
* @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||||
|
* @property {String} popup-title 弹出窗口标题
|
||||||
|
* @property {Array} localdata 本地数据,参考
|
||||||
|
* @property {Boolean} border = [true|false] 是否有边框
|
||||||
|
* @property {Boolean} readonly = [true|false] 是否仅读
|
||||||
|
* @property {Boolean} preload = [true|false] 是否预加载数据
|
||||||
|
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
|
||||||
|
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
|
||||||
|
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||||
|
* @value true 启用分布查询,仅查询当前选中节点
|
||||||
|
* @value false 关闭分布查询,一次查询出所有数据
|
||||||
|
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||||
|
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||||
|
* @property {String|DBCollectionString} collection 表名
|
||||||
|
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||||
|
* @property {String} orderby 排序字段及正序倒叙设置
|
||||||
|
* @property {String|JQLString} where 查询条件
|
||||||
|
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
|
||||||
|
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'UniDataPicker',
|
||||||
|
emits: ['popupopened', 'popupclosed', 'nodeclick', 'change', 'input', 'update:modelValue', 'inputclick'],
|
||||||
|
mixins: [dataPicker],
|
||||||
|
props: {
|
||||||
|
popupTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
heightMobile: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
clearIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
split: {
|
||||||
|
type: String,
|
||||||
|
default: '/'
|
||||||
|
},
|
||||||
|
ellipsis: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpened: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isShowClearIcon() : boolean {
|
||||||
|
if (this.readonly) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.clearIcon && this.selectedPaths.length > 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.load()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear() {
|
||||||
|
},
|
||||||
|
load() {
|
||||||
|
if (this.isLocalData) {
|
||||||
|
this.loadLocalData()
|
||||||
|
} else if (this.isCloudDataList || this.isCloudDataTree) {
|
||||||
|
this.loadCloudDataPath()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
this.isOpened = true
|
||||||
|
this.$emit('popupopened')
|
||||||
|
if (!this.hasCloudTreeData) {
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.isOpened = false
|
||||||
|
this.$emit('popupclosed')
|
||||||
|
},
|
||||||
|
handleInput() {
|
||||||
|
if (this.readonly) {
|
||||||
|
this.$emit('inputclick')
|
||||||
|
} else {
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleClose() {
|
||||||
|
this.hide()
|
||||||
|
},
|
||||||
|
onFinish() {
|
||||||
|
this.selectedPaths = this.getChangeNodes()
|
||||||
|
this.$emit('update:modelValue', this.selectedPaths)
|
||||||
|
this.$emit('change', this.selectedPaths)
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url("../uni-data-pickerview/uni-data-pickerview.css");
|
||||||
|
|
||||||
|
.uni-data-tree {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-input {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #DD524D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-value {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding: 5px 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-value-border {
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-path {
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-more {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-list {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-color {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: grey;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-split-line {
|
||||||
|
opacity: .5;
|
||||||
|
margin-left: 1px;
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-area {
|
||||||
|
position: relative;
|
||||||
|
padding: 0 12px;
|
||||||
|
margin-left: auto;
|
||||||
|
justify-content: center;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-arrow {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-left: 2px solid #999;
|
||||||
|
border-bottom: 2px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-cover {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, .4);
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-dialog {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 20%;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 102;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-caption {
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title-view {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
align-self: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-plus {
|
||||||
|
width: 16px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #666;
|
||||||
|
border-radius: 2px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-rotate {
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-pickerview {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clear {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef H5 */
|
||||||
|
@media all and (min-width: 768px) {
|
||||||
|
.uni-data-tree-cover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-dialog {
|
||||||
|
position: absolute;
|
||||||
|
top: 55px;
|
||||||
|
height: auto;
|
||||||
|
min-height: 400px;
|
||||||
|
max-height: 50vh;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-caption {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
@ -0,0 +1,545 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-data-tree">
|
||||||
|
<view class="uni-data-tree-input" @click="handleInput">
|
||||||
|
<slot :options="options" :data="inputSelected" :error="errorMessage">
|
||||||
|
<view class="input-value" :class="{'input-value-border': border}">
|
||||||
|
<text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
|
||||||
|
<view v-else-if="loading && !isOpened" class="selected-area">
|
||||||
|
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||||
|
</view>
|
||||||
|
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
|
||||||
|
<view class="selected-list">
|
||||||
|
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
|
||||||
|
<text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
|
||||||
|
class="input-split-line">{{split}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<text v-else class="selected-area placeholder">{{placeholder}}</text>
|
||||||
|
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" @click.stop="clear">
|
||||||
|
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
|
||||||
|
<view class="input-arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view class="uni-data-tree-cover" v-show="isOpened" @click="handleClose"></view>
|
||||||
|
<view class="uni-data-tree-dialog" v-show="isOpened">
|
||||||
|
<view class="uni-popper__arrow"></view>
|
||||||
|
<view class="dialog-caption">
|
||||||
|
<view class="title-area">
|
||||||
|
<text class="dialog-title">{{popupTitle}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="dialog-close" @click="handleClose">
|
||||||
|
<view class="dialog-close-plus" data-id="close"></view>
|
||||||
|
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
|
||||||
|
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
|
||||||
|
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" :map="map"
|
||||||
|
:ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
|
||||||
|
</data-picker-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
|
||||||
|
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataPicker 级联选择
|
||||||
|
* @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||||
|
* @property {String} popup-title 弹出窗口标题
|
||||||
|
* @property {Array} localdata 本地数据,参考
|
||||||
|
* @property {Boolean} border = [true|false] 是否有边框
|
||||||
|
* @property {Boolean} readonly = [true|false] 是否仅读
|
||||||
|
* @property {Boolean} preload = [true|false] 是否预加载数据
|
||||||
|
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
|
||||||
|
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
|
||||||
|
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||||
|
* @value true 启用分布查询,仅查询当前选中节点
|
||||||
|
* @value false 关闭分布查询,一次查询出所有数据
|
||||||
|
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||||
|
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||||
|
* @property {String|DBCollectionString} collection 表名
|
||||||
|
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||||
|
* @property {String} orderby 排序字段及正序倒叙设置
|
||||||
|
* @property {String|JQLString} where 查询条件
|
||||||
|
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
|
||||||
|
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'UniDataPicker',
|
||||||
|
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue','inputclick'],
|
||||||
|
mixins: [dataPicker],
|
||||||
|
components: {
|
||||||
|
DataPickerView
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
options: {
|
||||||
|
type: [Object, Array],
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popupTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
heightMobile: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
clearIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
split: {
|
||||||
|
type: String,
|
||||||
|
default: '/'
|
||||||
|
},
|
||||||
|
ellipsis: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpened: false,
|
||||||
|
inputSelected: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.load();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
localdata: {
|
||||||
|
handler() {
|
||||||
|
this.load()
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear() {
|
||||||
|
this._dispatchEvent([]);
|
||||||
|
},
|
||||||
|
onPropsChange() {
|
||||||
|
this._treeData = [];
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
|
||||||
|
this.load();
|
||||||
|
},
|
||||||
|
load() {
|
||||||
|
if (this.readonly) {
|
||||||
|
this._processReadonly(this.localdata, this.dataValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回显本地数据
|
||||||
|
if (this.isLocalData) {
|
||||||
|
this.loadData();
|
||||||
|
this.inputSelected = this.selected.slice(0);
|
||||||
|
} else if (this.isCloudDataList || this.isCloudDataTree) { // 回显 Cloud 数据
|
||||||
|
this.loading = true;
|
||||||
|
this.getCloudDataValue().then((res) => {
|
||||||
|
this.loading = false;
|
||||||
|
this.inputSelected = res;
|
||||||
|
}).catch((err) => {
|
||||||
|
this.loading = false;
|
||||||
|
this.errorMessage = err;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
this.isOpened = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.pickerView.updateData({
|
||||||
|
treeData: this._treeData,
|
||||||
|
selected: this.selected,
|
||||||
|
selectedIndex: this.selectedIndex
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
this.$emit('popupopened')
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.isOpened = false
|
||||||
|
this.$emit('popupclosed')
|
||||||
|
},
|
||||||
|
handleInput() {
|
||||||
|
if (this.readonly) {
|
||||||
|
this.$emit('inputclick')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.show()
|
||||||
|
},
|
||||||
|
handleClose(e) {
|
||||||
|
this.hide()
|
||||||
|
},
|
||||||
|
onnodeclick(e) {
|
||||||
|
this.$emit('nodeclick', e)
|
||||||
|
},
|
||||||
|
ondatachange(e) {
|
||||||
|
this._treeData = this.$refs.pickerView._treeData
|
||||||
|
},
|
||||||
|
onchange(e) {
|
||||||
|
this.hide()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.inputSelected = e;
|
||||||
|
})
|
||||||
|
this._dispatchEvent(e)
|
||||||
|
},
|
||||||
|
_processReadonly(dataList, value) {
|
||||||
|
var isTree = dataList.findIndex((item) => {
|
||||||
|
return item.children
|
||||||
|
})
|
||||||
|
if (isTree > -1) {
|
||||||
|
let inputValue
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
inputValue = value[value.length - 1]
|
||||||
|
if (typeof inputValue === 'object' && inputValue.value) {
|
||||||
|
inputValue = inputValue.value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputValue = value
|
||||||
|
}
|
||||||
|
this.inputSelected = this._findNodePath(inputValue, this.localdata)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hasValue) {
|
||||||
|
this.inputSelected = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = []
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
var val = value[i]
|
||||||
|
var item = dataList.find((v) => {
|
||||||
|
return v.value == val
|
||||||
|
})
|
||||||
|
if (item) {
|
||||||
|
result.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.length) {
|
||||||
|
this.inputSelected = result
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_filterForArray(data, valueArray) {
|
||||||
|
var result = []
|
||||||
|
for (let i = 0; i < valueArray.length; i++) {
|
||||||
|
var value = valueArray[i]
|
||||||
|
var found = data.find((item) => {
|
||||||
|
return item.value == value
|
||||||
|
})
|
||||||
|
if (found) {
|
||||||
|
result.push(found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
_dispatchEvent(selected) {
|
||||||
|
let item = {}
|
||||||
|
if (selected.length) {
|
||||||
|
var value = new Array(selected.length)
|
||||||
|
for (var i = 0; i < selected.length; i++) {
|
||||||
|
value[i] = selected[i].value
|
||||||
|
}
|
||||||
|
item = selected[selected.length - 1]
|
||||||
|
} else {
|
||||||
|
item.value = ''
|
||||||
|
}
|
||||||
|
if (this.formItem) {
|
||||||
|
this.formItem.setValue(item.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('input', item.value)
|
||||||
|
this.$emit('update:modelValue', item.value)
|
||||||
|
this.$emit('change', {
|
||||||
|
detail: {
|
||||||
|
value: selected
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.uni-data-tree {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: #DD524D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-value {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
font-size: 14px;
|
||||||
|
/* line-height: 35px; */
|
||||||
|
padding: 0 10px;
|
||||||
|
padding-right: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 35px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-value-border {
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-area {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-more {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
margin-right: auto;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
width: 40px;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-list {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
/* padding: 0 5px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item {
|
||||||
|
flex-direction: row;
|
||||||
|
/* padding: 0 1px; */
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
white-space: nowrap;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-color {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: grey;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-split-line {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-area {
|
||||||
|
position: relative;
|
||||||
|
width: 20px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
justify-content: center;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-arrow {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-left: 1px solid #999;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-cover {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, .4);
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-dialog {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 5%;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 102;
|
||||||
|
overflow: hidden;
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
width: 750rpx;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-caption {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
/* border-bottom: 1px solid #f0f0f0; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-area {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
margin: auto;
|
||||||
|
/* #endif */
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
/* font-weight: bold; */
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-plus {
|
||||||
|
width: 16px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #666;
|
||||||
|
border-radius: 2px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-rotate {
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-view {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clear {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef H5 */
|
||||||
|
@media all and (min-width: 768px) {
|
||||||
|
.uni-data-tree-cover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-data-tree-dialog {
|
||||||
|
position: absolute;
|
||||||
|
top: 55px;
|
||||||
|
height: auto;
|
||||||
|
min-height: 400px;
|
||||||
|
max-height: 50vh;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-caption {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clear {
|
||||||
|
/* margin-right: 5px; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.uni-popper__arrow,
|
||||||
|
.uni-popper__arrow::after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-color: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-popper__arrow {
|
||||||
|
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
|
||||||
|
top: -6px;
|
||||||
|
left: 10%;
|
||||||
|
margin-right: 3px;
|
||||||
|
border-top-width: 0;
|
||||||
|
border-bottom-color: #EBEEF5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-popper__arrow::after {
|
||||||
|
content: " ";
|
||||||
|
top: 1px;
|
||||||
|
margin-left: -6px;
|
||||||
|
border-top-width: 0;
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,622 @@
|
|||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
localdata: {
|
||||||
|
type: [Array, Object],
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
spaceInfo: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collection: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
orderby: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
pageData: {
|
||||||
|
type: String,
|
||||||
|
default: 'add'
|
||||||
|
},
|
||||||
|
pageCurrent: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 500
|
||||||
|
},
|
||||||
|
getcount: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
getone: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
gettree: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
manual: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preload: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
stepSearh: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
selfField: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
parentField: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {
|
||||||
|
text: "text",
|
||||||
|
value: "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
errorMessage: '',
|
||||||
|
loadMore: {
|
||||||
|
contentdown: '',
|
||||||
|
contentrefresh: '',
|
||||||
|
contentnomore: ''
|
||||||
|
},
|
||||||
|
dataList: [],
|
||||||
|
selected: [],
|
||||||
|
selectedIndex: 0,
|
||||||
|
page: {
|
||||||
|
current: this.pageCurrent,
|
||||||
|
size: this.pageSize,
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isLocalData() {
|
||||||
|
return !this.collection.length;
|
||||||
|
},
|
||||||
|
isCloudData() {
|
||||||
|
return this.collection.length > 0;
|
||||||
|
},
|
||||||
|
isCloudDataList() {
|
||||||
|
return (this.isCloudData && (!this.parentField && !this.selfField));
|
||||||
|
},
|
||||||
|
isCloudDataTree() {
|
||||||
|
return (this.isCloudData && this.parentField && this.selfField);
|
||||||
|
},
|
||||||
|
dataValue() {
|
||||||
|
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null ||
|
||||||
|
this.modelValue !== undefined);
|
||||||
|
return isModelValue ? this.modelValue : this.value;
|
||||||
|
},
|
||||||
|
hasValue() {
|
||||||
|
if (typeof this.dataValue === 'number') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return (this.dataValue != null) && (this.dataValue.length > 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$watch(() => {
|
||||||
|
var al = [];
|
||||||
|
['pageCurrent',
|
||||||
|
'pageSize',
|
||||||
|
'spaceInfo',
|
||||||
|
'value',
|
||||||
|
'modelValue',
|
||||||
|
'localdata',
|
||||||
|
'collection',
|
||||||
|
'action',
|
||||||
|
'field',
|
||||||
|
'orderby',
|
||||||
|
'where',
|
||||||
|
'getont',
|
||||||
|
'getcount',
|
||||||
|
'gettree'
|
||||||
|
].forEach(key => {
|
||||||
|
al.push(this[key])
|
||||||
|
});
|
||||||
|
return al
|
||||||
|
}, (newValue, oldValue) => {
|
||||||
|
let needReset = false
|
||||||
|
for (let i = 2; i < newValue.length; i++) {
|
||||||
|
if (newValue[i] != oldValue[i]) {
|
||||||
|
needReset = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newValue[0] != oldValue[0]) {
|
||||||
|
this.page.current = this.pageCurrent
|
||||||
|
}
|
||||||
|
this.page.size = this.pageSize
|
||||||
|
|
||||||
|
this.onPropsChange()
|
||||||
|
})
|
||||||
|
this._treeData = []
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPropsChange() {
|
||||||
|
this._treeData = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 填充 pickview 数据
|
||||||
|
async loadData() {
|
||||||
|
if (this.isLocalData) {
|
||||||
|
this.loadLocalData();
|
||||||
|
} else if (this.isCloudDataList) {
|
||||||
|
this.loadCloudDataList();
|
||||||
|
} else if (this.isCloudDataTree) {
|
||||||
|
this.loadCloudDataTree();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载本地数据
|
||||||
|
async loadLocalData() {
|
||||||
|
this._treeData = [];
|
||||||
|
this._extractTree(this.localdata, this._treeData);
|
||||||
|
|
||||||
|
let inputValue = this.dataValue;
|
||||||
|
if (inputValue === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(inputValue)) {
|
||||||
|
inputValue = inputValue[inputValue.length - 1];
|
||||||
|
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
|
||||||
|
inputValue = inputValue[this.map.value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selected = this._findNodePath(inputValue, this.localdata);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (单列)
|
||||||
|
async loadCloudDataList() {
|
||||||
|
if (this.loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response = await this.getCommand();
|
||||||
|
let responseData = response.result.data;
|
||||||
|
|
||||||
|
this._treeData = responseData;
|
||||||
|
|
||||||
|
this._updateBindData();
|
||||||
|
this._updateSelected();
|
||||||
|
|
||||||
|
this.onDataChange();
|
||||||
|
} catch (e) {
|
||||||
|
this.errorMessage = e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (树形)
|
||||||
|
async loadCloudDataTree() {
|
||||||
|
if (this.loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let commandOptions = {
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
where: this._cloudDataTreeWhere()
|
||||||
|
};
|
||||||
|
if (this.gettree) {
|
||||||
|
commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await this.getCommand(commandOptions);
|
||||||
|
let responseData = response.result.data;
|
||||||
|
|
||||||
|
this._treeData = responseData;
|
||||||
|
this._updateBindData();
|
||||||
|
this._updateSelected();
|
||||||
|
|
||||||
|
this.onDataChange();
|
||||||
|
} catch (e) {
|
||||||
|
this.errorMessage = e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (节点)
|
||||||
|
async loadCloudDataNode(callback) {
|
||||||
|
if (this.loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let commandOptions = {
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
where: this._cloudDataNodeWhere()
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = await this.getCommand(commandOptions);
|
||||||
|
let responseData = response.result.data;
|
||||||
|
|
||||||
|
callback(responseData);
|
||||||
|
} catch (e) {
|
||||||
|
this.errorMessage = e;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 回显 Cloud 数据
|
||||||
|
getCloudDataValue() {
|
||||||
|
if (this.isCloudDataList) {
|
||||||
|
return this.getCloudDataListValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isCloudDataTree) {
|
||||||
|
return this.getCloudDataTreeValue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 回显 Cloud 数据 (单列)
|
||||||
|
getCloudDataListValue() {
|
||||||
|
// 根据 field's as value标识匹配 where 条件
|
||||||
|
let where = [];
|
||||||
|
let whereField = this._getForeignKeyByField();
|
||||||
|
if (whereField) {
|
||||||
|
where.push(`${whereField} == '${this.dataValue}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
where = where.join(' || ');
|
||||||
|
|
||||||
|
if (this.where) {
|
||||||
|
where = `(${this.where}) && (${where})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getCommand({
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
where
|
||||||
|
}).then((res) => {
|
||||||
|
this.selected = res.result.data;
|
||||||
|
return res.result.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 回显 Cloud 数据 (树形)
|
||||||
|
getCloudDataTreeValue() {
|
||||||
|
return this.getCommand({
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
getTreePath: {
|
||||||
|
startWith: `${this.selfField}=='${this.dataValue}'`
|
||||||
|
}
|
||||||
|
}).then((res) => {
|
||||||
|
let treePath = [];
|
||||||
|
this._extractTreePath(res.result.data, treePath);
|
||||||
|
this.selected = treePath;
|
||||||
|
return treePath;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getCommand(options = {}) {
|
||||||
|
/* eslint-disable no-undef */
|
||||||
|
let db = uniCloud.database(this.spaceInfo)
|
||||||
|
|
||||||
|
const action = options.action || this.action
|
||||||
|
if (action) {
|
||||||
|
db = db.action(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
const collection = options.collection || this.collection
|
||||||
|
db = db.collection(collection)
|
||||||
|
|
||||||
|
const where = options.where || this.where
|
||||||
|
if (!(!where || !Object.keys(where).length)) {
|
||||||
|
db = db.where(where)
|
||||||
|
}
|
||||||
|
|
||||||
|
const field = options.field || this.field
|
||||||
|
if (field) {
|
||||||
|
db = db.field(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderby = options.orderby || this.orderby
|
||||||
|
if (orderby) {
|
||||||
|
db = db.orderBy(orderby)
|
||||||
|
}
|
||||||
|
|
||||||
|
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
|
||||||
|
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
|
||||||
|
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
|
||||||
|
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
|
||||||
|
|
||||||
|
const getOptions = {
|
||||||
|
getCount,
|
||||||
|
getTree
|
||||||
|
}
|
||||||
|
if (options.getTreePath) {
|
||||||
|
getOptions.getTreePath = options.getTreePath
|
||||||
|
}
|
||||||
|
|
||||||
|
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
|
||||||
|
|
||||||
|
return db
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataPostField() {
|
||||||
|
let fields = [this.field];
|
||||||
|
if (this.parentField) {
|
||||||
|
fields.push(`${this.parentField} as parent_value`);
|
||||||
|
}
|
||||||
|
return fields.join(',');
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataTreeWhere() {
|
||||||
|
let result = []
|
||||||
|
let selected = this.selected
|
||||||
|
let parentField = this.parentField
|
||||||
|
if (parentField) {
|
||||||
|
result.push(`${parentField} == null || ${parentField} == ""`)
|
||||||
|
}
|
||||||
|
if (selected.length) {
|
||||||
|
for (var i = 0; i < selected.length - 1; i++) {
|
||||||
|
result.push(`${parentField} == '${selected[i].value}'`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let where = []
|
||||||
|
if (this.where) {
|
||||||
|
where.push(`(${this.where})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.length) {
|
||||||
|
where.push(`(${result.join(' || ')})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return where.join(' && ')
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataNodeWhere() {
|
||||||
|
let where = []
|
||||||
|
let selected = this.selected;
|
||||||
|
if (selected.length) {
|
||||||
|
where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
where = where.join(' || ');
|
||||||
|
|
||||||
|
if (this.where) {
|
||||||
|
return `(${this.where}) && (${where})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return where
|
||||||
|
},
|
||||||
|
|
||||||
|
_getWhereByForeignKey() {
|
||||||
|
let result = []
|
||||||
|
let whereField = this._getForeignKeyByField();
|
||||||
|
if (whereField) {
|
||||||
|
result.push(`${whereField} == '${this.dataValue}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.where) {
|
||||||
|
return `(${this.where}) && (${result.join(' || ')})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join(' || ')
|
||||||
|
},
|
||||||
|
|
||||||
|
_getForeignKeyByField() {
|
||||||
|
let fields = this.field.split(',');
|
||||||
|
let whereField = null;
|
||||||
|
for (let i = 0; i < fields.length; i++) {
|
||||||
|
const items = fields[i].split('as');
|
||||||
|
if (items.length < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (items[1].trim() === 'value') {
|
||||||
|
whereField = items[0].trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return whereField;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateBindData(node) {
|
||||||
|
const {
|
||||||
|
dataList,
|
||||||
|
hasNodes
|
||||||
|
} = this._filterData(this._treeData, this.selected)
|
||||||
|
|
||||||
|
let isleaf = this._stepSearh === false && !hasNodes
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
node.isleaf = isleaf
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataList = dataList
|
||||||
|
this.selectedIndex = dataList.length - 1
|
||||||
|
|
||||||
|
if (!isleaf && this.selected.length < dataList.length) {
|
||||||
|
this.selected.push({
|
||||||
|
value: null,
|
||||||
|
text: "请选择"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isleaf,
|
||||||
|
hasNodes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateSelected() {
|
||||||
|
let dl = this.dataList
|
||||||
|
let sl = this.selected
|
||||||
|
let textField = this.map.text
|
||||||
|
let valueField = this.map.value
|
||||||
|
for (let i = 0; i < sl.length; i++) {
|
||||||
|
let value = sl[i].value
|
||||||
|
let dl2 = dl[i]
|
||||||
|
for (let j = 0; j < dl2.length; j++) {
|
||||||
|
let item2 = dl2[j]
|
||||||
|
if (item2[valueField] === value) {
|
||||||
|
sl[i].text = item2[textField]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_filterData(data, paths) {
|
||||||
|
let dataList = []
|
||||||
|
let hasNodes = true
|
||||||
|
|
||||||
|
dataList.push(data.filter((item) => {
|
||||||
|
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
|
||||||
|
}))
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
let value = paths[i].value
|
||||||
|
let nodes = data.filter((item) => {
|
||||||
|
return item.parent_value === value
|
||||||
|
})
|
||||||
|
|
||||||
|
if (nodes.length) {
|
||||||
|
dataList.push(nodes)
|
||||||
|
} else {
|
||||||
|
hasNodes = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dataList,
|
||||||
|
hasNodes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_extractTree(nodes, result, parent_value) {
|
||||||
|
let list = result || []
|
||||||
|
let valueField = this.map.value
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i]
|
||||||
|
|
||||||
|
let child = {}
|
||||||
|
for (let key in node) {
|
||||||
|
if (key !== 'children') {
|
||||||
|
child[key] = node[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
|
||||||
|
child.parent_value = parent_value
|
||||||
|
}
|
||||||
|
result.push(child)
|
||||||
|
|
||||||
|
let children = node.children
|
||||||
|
if (children) {
|
||||||
|
this._extractTree(children, result, node[valueField])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_extractTreePath(nodes, result) {
|
||||||
|
let list = result || []
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i]
|
||||||
|
|
||||||
|
let child = {}
|
||||||
|
for (let key in node) {
|
||||||
|
if (key !== 'children') {
|
||||||
|
child[key] = node[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(child)
|
||||||
|
|
||||||
|
let children = node.children
|
||||||
|
if (children) {
|
||||||
|
this._extractTreePath(children, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_findNodePath(key, nodes, path = []) {
|
||||||
|
let textField = this.map.text
|
||||||
|
let valueField = this.map.value
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i]
|
||||||
|
let children = node.children
|
||||||
|
let text = node[textField]
|
||||||
|
let value = node[valueField]
|
||||||
|
|
||||||
|
path.push({
|
||||||
|
value,
|
||||||
|
text
|
||||||
|
})
|
||||||
|
|
||||||
|
if (value === key) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children) {
|
||||||
|
const p = this._findNodePath(key, children, path)
|
||||||
|
if (p.length) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path.pop()
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,692 @@
|
|||||||
|
export type PaginationType = {
|
||||||
|
current : number,
|
||||||
|
size : number,
|
||||||
|
count : number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoadMoreType = {
|
||||||
|
contentdown : string,
|
||||||
|
contentrefresh : string,
|
||||||
|
contentnomore : string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SelectedItemType = {
|
||||||
|
name : string,
|
||||||
|
value : string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetCommandOptions = {
|
||||||
|
collection ?: UTSJSONObject,
|
||||||
|
field ?: string,
|
||||||
|
orderby ?: string,
|
||||||
|
where ?: any,
|
||||||
|
pageData ?: string,
|
||||||
|
pageCurrent ?: number,
|
||||||
|
pageSize ?: number,
|
||||||
|
getCount ?: boolean,
|
||||||
|
getTree ?: any,
|
||||||
|
getTreePath ?: UTSJSONObject,
|
||||||
|
startwith ?: string,
|
||||||
|
limitlevel ?: number,
|
||||||
|
groupby ?: string,
|
||||||
|
groupField ?: string,
|
||||||
|
distinct ?: boolean,
|
||||||
|
pageIndistinct ?: boolean,
|
||||||
|
foreignKey ?: string,
|
||||||
|
loadtime ?: string,
|
||||||
|
manual ?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultSelectedNode = {
|
||||||
|
text: '请选择',
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dataPicker = defineMixin({
|
||||||
|
props: {
|
||||||
|
localdata: {
|
||||||
|
type: Array as PropType<Array<UTSJSONObject>>,
|
||||||
|
default: [] as Array<UTSJSONObject>
|
||||||
|
},
|
||||||
|
collection: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
orderby: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
pageData: {
|
||||||
|
type: String,
|
||||||
|
default: 'add'
|
||||||
|
},
|
||||||
|
pageCurrent: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
getcount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
gettree: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
gettreepath: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
startwith: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
limitlevel: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
groupby: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
groupField: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
distinct: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
pageIndistinct: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
foreignKey: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
loadtime: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
manual: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
preload: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
stepSearh: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
selfField: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
parentField: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
defaultProps: {
|
||||||
|
type: Object as PropType<UTSJSONObject>,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
error: null as UniCloudError | null,
|
||||||
|
treeData: [] as Array<UTSJSONObject>,
|
||||||
|
selectedIndex: 0,
|
||||||
|
selectedNodes: [] as Array<UTSJSONObject>,
|
||||||
|
selectedPages: [] as Array<UTSJSONObject>[],
|
||||||
|
selectedValue: '',
|
||||||
|
selectedPaths: [] as Array<UTSJSONObject>,
|
||||||
|
pagination: {
|
||||||
|
current: 1,
|
||||||
|
size: 20,
|
||||||
|
count: 0
|
||||||
|
} as PaginationType
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mappingTextName() : string {
|
||||||
|
// TODO
|
||||||
|
return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text'
|
||||||
|
},
|
||||||
|
mappingValueName() : string {
|
||||||
|
// TODO
|
||||||
|
return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value'
|
||||||
|
},
|
||||||
|
currentDataList() : Array<UTSJSONObject> {
|
||||||
|
if (this.selectedIndex > this.selectedPages.length - 1) {
|
||||||
|
return [] as Array<UTSJSONObject>
|
||||||
|
}
|
||||||
|
return this.selectedPages[this.selectedIndex]
|
||||||
|
},
|
||||||
|
isLocalData() : boolean {
|
||||||
|
return this.localdata.length > 0
|
||||||
|
},
|
||||||
|
isCloudData() : boolean {
|
||||||
|
return this._checkIsNotNull(this.collection)
|
||||||
|
},
|
||||||
|
isCloudDataList() : boolean {
|
||||||
|
return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0))
|
||||||
|
},
|
||||||
|
isCloudDataTree() : boolean {
|
||||||
|
return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0)
|
||||||
|
},
|
||||||
|
dataValue() : any {
|
||||||
|
return this.hasModelValue ? this.modelValue : this.value
|
||||||
|
},
|
||||||
|
hasCloudTreeData() : boolean {
|
||||||
|
return this.treeData.length > 0
|
||||||
|
},
|
||||||
|
hasModelValue() : boolean {
|
||||||
|
if (typeof this.modelValue == 'string') {
|
||||||
|
const valueString = this.modelValue as string
|
||||||
|
return (valueString.length > 0)
|
||||||
|
} else if (Array.isArray(this.modelValue)) {
|
||||||
|
const valueArray = this.modelValue as Array<string>
|
||||||
|
return (valueArray.length > 0)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
hasCloudDataValue() : boolean {
|
||||||
|
if (typeof this.dataValue == 'string') {
|
||||||
|
const valueString = this.dataValue as string
|
||||||
|
return (valueString.length > 0)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.pagination.current = this.pageCurrent
|
||||||
|
this.pagination.size = this.pageSize
|
||||||
|
|
||||||
|
this.$watch(
|
||||||
|
() : any => [
|
||||||
|
this.pageCurrent,
|
||||||
|
this.pageSize,
|
||||||
|
this.localdata,
|
||||||
|
this.value,
|
||||||
|
this.collection,
|
||||||
|
this.field,
|
||||||
|
this.getcount,
|
||||||
|
this.orderby,
|
||||||
|
this.where,
|
||||||
|
this.groupby,
|
||||||
|
this.groupField,
|
||||||
|
this.distinct
|
||||||
|
],
|
||||||
|
(newValue : Array<any>, oldValue : Array<any>) => {
|
||||||
|
this.pagination.size = this.pageSize
|
||||||
|
if (newValue[0] !== oldValue[0]) {
|
||||||
|
this.pagination.current = this.pageCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onPropsChange()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPropsChange() {
|
||||||
|
this.selectedIndex = 0
|
||||||
|
this.selectedNodes.length = 0
|
||||||
|
this.selectedPages.length = 0
|
||||||
|
this.selectedPaths.length = 0
|
||||||
|
|
||||||
|
// 加载数据
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onTabSelect(index : number) {
|
||||||
|
this.selectedIndex = index
|
||||||
|
},
|
||||||
|
|
||||||
|
onNodeClick(nodeData : UTSJSONObject) {
|
||||||
|
if (nodeData.getBoolean('disable', false)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLeaf = this._checkIsLeafNode(nodeData)
|
||||||
|
|
||||||
|
this._trimSelectedNodes(nodeData)
|
||||||
|
|
||||||
|
this.$emit('nodeclick', nodeData)
|
||||||
|
|
||||||
|
if (this.isLocalData) {
|
||||||
|
if (isLeaf || !this._checkHasChildren(nodeData)) {
|
||||||
|
this.onFinish()
|
||||||
|
}
|
||||||
|
} else if (this.isCloudDataList) {
|
||||||
|
this.onFinish()
|
||||||
|
} else if (this.isCloudDataTree) {
|
||||||
|
if (isLeaf) {
|
||||||
|
this.onFinish()
|
||||||
|
} else if (!this._checkHasChildren(nodeData)) {
|
||||||
|
// 尝试请求一次,如果没有返回数据标记为叶子节点
|
||||||
|
this.loadCloudDataNode(nodeData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getChangeNodes(): Array<UTSJSONObject> {
|
||||||
|
const nodes: Array<UTSJSONObject> = []
|
||||||
|
this.selectedNodes.forEach((node : UTSJSONObject) => {
|
||||||
|
const newNode: UTSJSONObject = {}
|
||||||
|
newNode[this.mappingTextName] = node.getString(this.mappingTextName)
|
||||||
|
newNode[this.mappingValueName] = node.getString(this.mappingValueName)
|
||||||
|
nodes.push(newNode)
|
||||||
|
})
|
||||||
|
return nodes
|
||||||
|
},
|
||||||
|
|
||||||
|
onFinish() { },
|
||||||
|
|
||||||
|
// 加载数据(自动判定环境)
|
||||||
|
loadData() {
|
||||||
|
if (this.isLocalData) {
|
||||||
|
this.loadLocalData()
|
||||||
|
} else if (this.isCloudDataList) {
|
||||||
|
this.loadCloudDataList()
|
||||||
|
} else if (this.isCloudDataTree) {
|
||||||
|
this.loadCloudDataTree()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载本地数据
|
||||||
|
loadLocalData() {
|
||||||
|
this.treeData = this.localdata
|
||||||
|
if (Array.isArray(this.dataValue)) {
|
||||||
|
const value = this.dataValue as Array<UTSJSONObject>
|
||||||
|
this.selectedPaths = value.slice(0)
|
||||||
|
this._pushSelectedTreeNodes(value, this.localdata)
|
||||||
|
} else {
|
||||||
|
this._pushSelectedNodes(this.localdata)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (单列)
|
||||||
|
loadCloudDataList() {
|
||||||
|
this._loadCloudData(null, (data : Array<UTSJSONObject>) => {
|
||||||
|
this.treeData = data
|
||||||
|
this._pushSelectedNodes(data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (树形)
|
||||||
|
loadCloudDataTree() {
|
||||||
|
let commandOptions = {
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
where: this._cloudDataTreeWhere(),
|
||||||
|
getTree: true
|
||||||
|
} as GetCommandOptions
|
||||||
|
if (this._checkIsNotNull(this.gettree)) {
|
||||||
|
commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'`
|
||||||
|
}
|
||||||
|
this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
|
||||||
|
this.treeData = data
|
||||||
|
if (this.selectedPaths.length > 0) {
|
||||||
|
this._pushSelectedTreeNodes(this.selectedPaths, data)
|
||||||
|
} else {
|
||||||
|
this._pushSelectedNodes(data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 Cloud 数据 (节点)
|
||||||
|
loadCloudDataNode(nodeData : UTSJSONObject) {
|
||||||
|
const commandOptions = {
|
||||||
|
field: this._cloudDataPostField(),
|
||||||
|
where: this._cloudDataNodeWhere()
|
||||||
|
} as GetCommandOptions
|
||||||
|
this._loadCloudData(commandOptions, (data : Array<UTSJSONObject>) => {
|
||||||
|
nodeData['children'] = data
|
||||||
|
if (data.length == 0) {
|
||||||
|
nodeData['isleaf'] = true
|
||||||
|
this.onFinish()
|
||||||
|
} else {
|
||||||
|
this._pushSelectedNodes(data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 回显 Cloud Tree Path
|
||||||
|
loadCloudDataPath() {
|
||||||
|
if (!this.hasCloudDataValue) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const command : GetCommandOptions = {}
|
||||||
|
|
||||||
|
// 单列
|
||||||
|
if (this.isCloudDataList) {
|
||||||
|
// 根据 field's as value标识匹配 where 条件
|
||||||
|
let where : Array<string> = [];
|
||||||
|
let whereField = this._getForeignKeyByField();
|
||||||
|
if (whereField.length > 0) {
|
||||||
|
where.push(`${whereField} == '${this.dataValue as string}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let whereString = where.join(' || ')
|
||||||
|
if (this._checkIsNotNull(this.where)) {
|
||||||
|
whereString = `(${this.where}) && (${whereString})`
|
||||||
|
}
|
||||||
|
|
||||||
|
command.field = this._cloudDataPostField()
|
||||||
|
command.where = whereString
|
||||||
|
}
|
||||||
|
|
||||||
|
// 树形
|
||||||
|
if (this.isCloudDataTree) {
|
||||||
|
command.field = this._cloudDataPostField()
|
||||||
|
command.getTreePath = {
|
||||||
|
startWith: `${this.selfField}=='${this.dataValue as string}'`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._loadCloudData(command, (data : Array<UTSJSONObject>) => {
|
||||||
|
this._extractTreePath(data, this.selectedPaths)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
_loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array<UTSJSONObject>) => void)) {
|
||||||
|
if (this.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
|
||||||
|
this.error = null
|
||||||
|
|
||||||
|
this._getCommand(options).then((response : UniCloudDBGetResult) => {
|
||||||
|
callback?.(response.data)
|
||||||
|
}).catch((err : any | null) => {
|
||||||
|
this.error = err as UniCloudError
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataPostField() : string {
|
||||||
|
let fields = [this.field];
|
||||||
|
if (this.parentField.length > 0) {
|
||||||
|
fields.push(`${this.parentField} as parent_value`)
|
||||||
|
}
|
||||||
|
return fields.join(',')
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataTreeWhere() : string {
|
||||||
|
let result : Array<string> = []
|
||||||
|
let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths
|
||||||
|
let parentField = this.parentField
|
||||||
|
if (parentField.length > 0) {
|
||||||
|
result.push(`${parentField} == null || ${parentField} == ""`)
|
||||||
|
}
|
||||||
|
if (selectedNodes.length > 0) {
|
||||||
|
for (var i = 0; i < selectedNodes.length - 1; i++) {
|
||||||
|
const parentFieldValue = selectedNodes[i].getString('value', '')
|
||||||
|
result.push(`${parentField} == '${parentFieldValue}'`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let where : Array<string> = []
|
||||||
|
if (this._checkIsNotNull(this.where)) {
|
||||||
|
where.push(`(${this.where as string})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.length > 0) {
|
||||||
|
where.push(`(${result.join(' || ')})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return where.join(' && ')
|
||||||
|
},
|
||||||
|
|
||||||
|
_cloudDataNodeWhere() : string {
|
||||||
|
const where : Array<string> = []
|
||||||
|
if (this.selectedNodes.length > 0) {
|
||||||
|
const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '')
|
||||||
|
where.push(`${this.parentField} == '${value}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let whereString = where.join(' || ')
|
||||||
|
if (this._checkIsNotNull(this.where)) {
|
||||||
|
return `(${this.where as string}) && (${whereString})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return whereString
|
||||||
|
},
|
||||||
|
|
||||||
|
_getWhereByForeignKey() : string {
|
||||||
|
let result : Array<string> = []
|
||||||
|
let whereField = this._getForeignKeyByField();
|
||||||
|
if (whereField.length > 0) {
|
||||||
|
result.push(`${whereField} == '${this.dataValue as string}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._checkIsNotNull(this.where)) {
|
||||||
|
return `(${this.where}) && (${result.join(' || ')})`
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join(' || ')
|
||||||
|
},
|
||||||
|
|
||||||
|
_getForeignKeyByField() : string {
|
||||||
|
const fields = this.field.split(',')
|
||||||
|
let whereField = ''
|
||||||
|
for (let i = 0; i < fields.length; i++) {
|
||||||
|
const items = fields[i].split('as')
|
||||||
|
if (items.length < 2) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (items[1].trim() === 'value') {
|
||||||
|
whereField = items[0].trim()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return whereField
|
||||||
|
},
|
||||||
|
|
||||||
|
_getCommand(options ?: GetCommandOptions) : Promise<UniCloudDBGetResult> {
|
||||||
|
let db = uniCloud.databaseForJQL()
|
||||||
|
|
||||||
|
let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array<any>)) : db.collection(this.collection)
|
||||||
|
|
||||||
|
let filter : UniCloudDBFilter | null = null
|
||||||
|
if (this.foreignKey.length > 0) {
|
||||||
|
filter = collection.foreignKey(this.foreignKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
const where : any = options?.where ?? this.where
|
||||||
|
if (typeof where == 'string') {
|
||||||
|
const whereString = where as string
|
||||||
|
if (whereString.length > 0) {
|
||||||
|
filter = (filter != null) ? filter.where(where) : collection.where(where)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filter = (filter != null) ? filter.where(where) : collection.where(where)
|
||||||
|
}
|
||||||
|
|
||||||
|
let query : UniCloudDBQuery | null = null
|
||||||
|
if (this.field.length > 0) {
|
||||||
|
query = (filter != null) ? filter.field(this.field) : collection.field(this.field)
|
||||||
|
}
|
||||||
|
if (this.groupby.length > 0) {
|
||||||
|
if (query != null) {
|
||||||
|
query = query.groupBy(this.groupby)
|
||||||
|
} else if (filter != null) {
|
||||||
|
query = filter.groupBy(this.groupby)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.groupField.length > 0) {
|
||||||
|
if (query != null) {
|
||||||
|
query = query.groupField(this.groupField)
|
||||||
|
} else if (filter != null) {
|
||||||
|
query = filter.groupField(this.groupField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.distinct == true) {
|
||||||
|
if (query != null) {
|
||||||
|
query = query.distinct(this.field)
|
||||||
|
} else if (filter != null) {
|
||||||
|
query = filter.distinct(this.field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.orderby.length > 0) {
|
||||||
|
if (query != null) {
|
||||||
|
query = query.orderBy(this.orderby)
|
||||||
|
} else if (filter != null) {
|
||||||
|
query = filter.orderBy(this.orderby)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const size = this.pagination.size
|
||||||
|
const current = this.pagination.current
|
||||||
|
if (query != null) {
|
||||||
|
query = query.skip(size * (current - 1)).limit(size)
|
||||||
|
} else if (filter != null) {
|
||||||
|
query = filter.skip(size * (current - 1)).limit(size)
|
||||||
|
} else {
|
||||||
|
query = collection.skip(size * (current - 1)).limit(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOptions = {}
|
||||||
|
const treeOptions = {
|
||||||
|
limitLevel: this.limitlevel,
|
||||||
|
startWith: this.startwith
|
||||||
|
}
|
||||||
|
if (this.getcount == true) {
|
||||||
|
getOptions['getCount'] = this.getcount
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTree : any = options?.getTree ?? this.gettree
|
||||||
|
if (typeof getTree == 'string') {
|
||||||
|
const getTreeString = getTree as string
|
||||||
|
if (getTreeString.length > 0) {
|
||||||
|
getOptions['getTree'] = treeOptions
|
||||||
|
}
|
||||||
|
} else if (typeof getTree == 'object') {
|
||||||
|
getOptions['getTree'] = treeOptions
|
||||||
|
} else {
|
||||||
|
getOptions['getTree'] = getTree
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTreePath = options?.getTreePath ?? this.gettreepath
|
||||||
|
if (typeof getTreePath == 'string') {
|
||||||
|
const getTreePathString = getTreePath as string
|
||||||
|
if (getTreePathString.length > 0) {
|
||||||
|
getOptions['getTreePath'] = getTreePath
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getOptions['getTreePath'] = getTreePath
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.get(getOptions)
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkIsNotNull(value : any) : boolean {
|
||||||
|
if (typeof value == 'string') {
|
||||||
|
const valueString = value as string
|
||||||
|
return (valueString.length > 0)
|
||||||
|
} else if (value instanceof UTSJSONObject) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkIsLeafNode(nodeData : UTSJSONObject) : boolean {
|
||||||
|
if (this.selectedIndex >= this.limitlevel) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeData.getBoolean('isleaf', false)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkHasChildren(nodeData : UTSJSONObject) : boolean {
|
||||||
|
const children = nodeData.getArray('children') ?? ([] as Array<any>)
|
||||||
|
return children.length > 0
|
||||||
|
},
|
||||||
|
|
||||||
|
_pushSelectedNodes(nodes : Array<UTSJSONObject>) {
|
||||||
|
this.selectedNodes.push(DefaultSelectedNode)
|
||||||
|
this.selectedPages.push(nodes)
|
||||||
|
this.selectedIndex = this.selectedPages.length - 1
|
||||||
|
},
|
||||||
|
|
||||||
|
_trimSelectedNodes(nodeData : UTSJSONObject) {
|
||||||
|
this.selectedNodes.splice(this.selectedIndex)
|
||||||
|
this.selectedNodes.push(nodeData)
|
||||||
|
|
||||||
|
if (this.selectedPages.length > 0) {
|
||||||
|
this.selectedPages.splice(this.selectedIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = nodeData.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
|
||||||
|
if (children.length > 0) {
|
||||||
|
this.selectedNodes.push(DefaultSelectedNode)
|
||||||
|
this.selectedPages.push(children)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedIndex = this.selectedPages.length - 1
|
||||||
|
},
|
||||||
|
|
||||||
|
_pushSelectedTreeNodes(paths : Array<UTSJSONObject>, nodes : Array<UTSJSONObject>) {
|
||||||
|
let children : Array<UTSJSONObject> = nodes
|
||||||
|
paths.forEach((node : UTSJSONObject) => {
|
||||||
|
const findNode = children.find((item : UTSJSONObject) : boolean => {
|
||||||
|
return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName))
|
||||||
|
})
|
||||||
|
if (findNode != null) {
|
||||||
|
this.selectedPages.push(children)
|
||||||
|
this.selectedNodes.push(node)
|
||||||
|
children = findNode.getArray<UTSJSONObject>('children') ?? ([] as Array<UTSJSONObject>)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.selectedIndex = this.selectedPages.length - 1
|
||||||
|
},
|
||||||
|
|
||||||
|
_extractTreePath(nodes : Array<UTSJSONObject>, result : Array<UTSJSONObject>) {
|
||||||
|
if (nodes.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = nodes[0]
|
||||||
|
result.push(node)
|
||||||
|
|
||||||
|
const children = node.getArray<UTSJSONObject>('children')
|
||||||
|
if (Array.isArray(children) && children!.length > 0) {
|
||||||
|
this._extractTreePath(children, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
.uni-data-pickerview {
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-cover {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(150, 150, 150, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: #DD524D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-node-list {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-node-item {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 8px 10px 8px 10px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-node-item-active {
|
||||||
|
color: #007aff;
|
||||||
|
border-bottom-color: #007aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-view {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text-disabled {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text-overflow {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check {
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 2px solid #007aff;
|
||||||
|
border-left: 0;
|
||||||
|
border-top: 0;
|
||||||
|
height: 12px;
|
||||||
|
width: 6px;
|
||||||
|
transform-origin: center;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-data-pickerview">
|
||||||
|
<view v-if="error!=null" class="error">
|
||||||
|
<text class="error-text">{{error!.errMsg}}</text>
|
||||||
|
</view>
|
||||||
|
<scroll-view v-if="!isCloudDataList" :scroll-x="true">
|
||||||
|
<view class="selected-node-list">
|
||||||
|
<template v-for="(item, index) in selectedNodes">
|
||||||
|
<text class="selected-node-item" :class="{'selected-node-item-active':index==selectedIndex}"
|
||||||
|
@click="onTabSelect(index)">
|
||||||
|
{{item[mappingTextName]}}
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<list-view class="list-view" :scroll-y="true">
|
||||||
|
<list-item class="list-item" v-for="(item, _) in currentDataList" @click="onNodeClick(item)">
|
||||||
|
<text class="item-text" :class="{'item-text-disabled': item['disable']}">{{item[mappingTextName]}}</text>
|
||||||
|
<text class="check" v-if="item[mappingValueName] == selectedNodes[selectedIndex][mappingValueName]"></text>
|
||||||
|
</list-item>
|
||||||
|
</list-view>
|
||||||
|
<view class="loading-cover" v-if="loading">
|
||||||
|
<slot name="pickerview-loading" :loading="loading"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { dataPicker } from "./uni-data-picker.uts"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataPickerview
|
||||||
|
* @description uni-data-pickerview
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||||
|
* @property {Array} localdata 本地数据,参考
|
||||||
|
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||||
|
* @value true 启用分布查询,仅查询当前选中节点
|
||||||
|
* @value false 关闭分布查询,一次查询出所有数据
|
||||||
|
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||||
|
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||||
|
* @property {String|DBCollectionString} collection 表名
|
||||||
|
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||||
|
* @property {String} orderby 排序字段及正序倒叙设置
|
||||||
|
* @property {String|JQLString} where 查询条件
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'UniDataPickerView',
|
||||||
|
emits: ['nodeclick', 'change', 'update:modelValue'],
|
||||||
|
mixins: [dataPicker],
|
||||||
|
props: {
|
||||||
|
ellipsis: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFinish() {
|
||||||
|
this.$emit('change', this.getChangeNodes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url("uni-data-pickerview.css");
|
||||||
|
</style>
|
||||||
@ -0,0 +1,320 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-data-pickerview">
|
||||||
|
<scroll-view v-if="!isCloudDataList" class="selected-area" scroll-x="true">
|
||||||
|
<view class="selected-list">
|
||||||
|
<view class="selected-item" v-for="(item,index) in selected" :key="index" :class="{
|
||||||
|
'selected-item-active':index == selectedIndex
|
||||||
|
}" @click="handleSelect(index)">
|
||||||
|
<text>{{item.text || ''}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="tab-c">
|
||||||
|
<scroll-view class="list" :scroll-y="true">
|
||||||
|
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in dataList[selectedIndex]"
|
||||||
|
:key="j" @click="handleNodeClick(item, selectedIndex, j)">
|
||||||
|
<text class="item-text">{{item[map.text]}}</text>
|
||||||
|
<view class="check"
|
||||||
|
v-if="selected.length > selectedIndex && item[map.value] == selected[selectedIndex].value">
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="loading-cover" v-if="loading">
|
||||||
|
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||||
|
</view>
|
||||||
|
<view class="error-message" v-if="errorMessage">
|
||||||
|
<text class="error-text">{{errorMessage}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import dataPicker from "./uni-data-picker.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataPickerview
|
||||||
|
* @description uni-data-pickerview
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||||
|
* @property {Array} localdata 本地数据,参考
|
||||||
|
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||||
|
* @value true 启用分布查询,仅查询当前选中节点
|
||||||
|
* @value false 关闭分布查询,一次查询出所有数据
|
||||||
|
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||||
|
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||||
|
* @property {String|DBCollectionString} collection 表名
|
||||||
|
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||||
|
* @property {String} orderby 排序字段及正序倒叙设置
|
||||||
|
* @property {String|JQLString} where 查询条件
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'UniDataPickerView',
|
||||||
|
emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
|
||||||
|
mixins: [dataPicker],
|
||||||
|
props: {
|
||||||
|
managedMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
ellipsis: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!this.managedMode) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.loadData();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPropsChange() {
|
||||||
|
this._treeData = [];
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.loadData();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleSelect(index) {
|
||||||
|
this.selectedIndex = index;
|
||||||
|
},
|
||||||
|
handleNodeClick(item, i, j) {
|
||||||
|
if (item.disable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = this.dataList[i][j];
|
||||||
|
const text = node[this.map.text];
|
||||||
|
const value = node[this.map.value];
|
||||||
|
|
||||||
|
if (i < this.selected.length - 1) {
|
||||||
|
this.selected.splice(i, this.selected.length - i)
|
||||||
|
this.selected.push({
|
||||||
|
text,
|
||||||
|
value
|
||||||
|
})
|
||||||
|
} else if (i === this.selected.length - 1) {
|
||||||
|
this.selected.splice(i, 1, {
|
||||||
|
text,
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isleaf) {
|
||||||
|
this.onSelectedChange(node, node.isleaf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
isleaf,
|
||||||
|
hasNodes
|
||||||
|
} = this._updateBindData()
|
||||||
|
|
||||||
|
// 本地数据
|
||||||
|
if (this.isLocalData) {
|
||||||
|
this.onSelectedChange(node, (!hasNodes || isleaf))
|
||||||
|
} else if (this.isCloudDataList) { // Cloud 数据 (单列)
|
||||||
|
this.onSelectedChange(node, true)
|
||||||
|
} else if (this.isCloudDataTree) { // Cloud 数据 (树形)
|
||||||
|
if (isleaf) {
|
||||||
|
this.onSelectedChange(node, node.isleaf)
|
||||||
|
} else if (!hasNodes) { // 请求一次服务器以确定是否为叶子节点
|
||||||
|
this.loadCloudDataNode((data) => {
|
||||||
|
if (!data.length) {
|
||||||
|
node.isleaf = true
|
||||||
|
} else {
|
||||||
|
this._treeData.push(...data)
|
||||||
|
this._updateBindData(node)
|
||||||
|
}
|
||||||
|
this.onSelectedChange(node, node.isleaf)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateData(data) {
|
||||||
|
this._treeData = data.treeData
|
||||||
|
this.selected = data.selected
|
||||||
|
if (!this._treeData.length) {
|
||||||
|
this.loadData()
|
||||||
|
} else {
|
||||||
|
//this.selected = data.selected
|
||||||
|
this._updateBindData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDataChange() {
|
||||||
|
this.$emit('datachange');
|
||||||
|
},
|
||||||
|
onSelectedChange(node, isleaf) {
|
||||||
|
if (isleaf) {
|
||||||
|
this._dispatchEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
this.$emit('nodeclick', node)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_dispatchEvent() {
|
||||||
|
this.$emit('change', this.selected.slice(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$uni-primary: #007aff !default;
|
||||||
|
|
||||||
|
.uni-data-pickerview {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: #DD524D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-cover {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(255, 255, 255, .5);
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-more {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
margin: auto;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
background-color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 15px;
|
||||||
|
opacity: .9;
|
||||||
|
z-index: 102;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
.selected-area {
|
||||||
|
width: 750rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.selected-list {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-bottom: 1px solid #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 12px 0;
|
||||||
|
text-align: center;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
white-space: nowrap;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-text-overflow {
|
||||||
|
width: 168px;
|
||||||
|
/* fix nvue */
|
||||||
|
overflow: hidden;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 6em;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-active {
|
||||||
|
border-bottom: 2px solid $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-text {
|
||||||
|
color: $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-c {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 12px 15px;
|
||||||
|
/* border-bottom: 1px solid #f0f0f0; */
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-disabled {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
/* flex: 1; */
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text-overflow {
|
||||||
|
width: 280px;
|
||||||
|
/* fix nvue */
|
||||||
|
overflow: hidden;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 20em;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.check {
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 2px solid $uni-primary;
|
||||||
|
border-left: 0;
|
||||||
|
border-top: 0;
|
||||||
|
height: 12px;
|
||||||
|
width: 6px;
|
||||||
|
transform-origin: center;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
transition: all 0.3s;
|
||||||
|
/* #endif */
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
93
src/uni_modules/uni-data-picker/package.json
Normal file
93
src/uni_modules/uni-data-picker/package.json
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-data-picker",
|
||||||
|
"displayName": "uni-data-picker 数据驱动的picker选择器",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
|
||||||
|
"keywords": [
|
||||||
|
"uni-ui",
|
||||||
|
"uniui",
|
||||||
|
"picker",
|
||||||
|
"级联",
|
||||||
|
"省市区",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": ""
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [
|
||||||
|
"uni-load-more",
|
||||||
|
"uni-icons",
|
||||||
|
"uni-scss"
|
||||||
|
],
|
||||||
|
"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": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/uni_modules/uni-data-picker/readme.md
Normal file
22
src/uni_modules/uni-data-picker/readme.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
## DataPicker 级联选择
|
||||||
|
> **组件名:uni-data-picker**
|
||||||
|
> 代码块: `uDataPicker`
|
||||||
|
> 关联组件:`uni-data-pickerview`、`uni-load-more`。
|
||||||
|
|
||||||
|
|
||||||
|
`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
|
||||||
|
|
||||||
|
支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||||
|
|
||||||
|
候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
|
||||||
|
|
||||||
|
`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
|
||||||
|
|
||||||
|
`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
|
||||||
|
|
||||||
|
`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
|
||||||
|
|
||||||
|
在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
169
src/uni_modules/uni-datetime-picker/changelog.md
Normal file
169
src/uni_modules/uni-datetime-picker/changelog.md
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
## 2.2.40(2025-04-14)
|
||||||
|
- 修复 绑定字符串值的时,日历面板选中状态未重置到默认值的问题
|
||||||
|
## 2.2.39(2025-04-14)
|
||||||
|
- 修复 在 iOS 微信小程序上type='daterange'时,传入'YYYY-MM-DD'格式不生效的问题
|
||||||
|
|
||||||
|
## 2.2.38(2024-10-15)
|
||||||
|
- 修复 微信小程序中的getSystemInfo警告
|
||||||
|
## 2.2.35(2024-09-21)
|
||||||
|
- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
|
||||||
|
## 2.2.34(2024-04-24)
|
||||||
|
- 新增 日期点击事件,在点击日期时会触发该事件。
|
||||||
|
## 2.2.33(2024-04-15)
|
||||||
|
- 修复 抖音小程序事件传递失效bug
|
||||||
|
## 2.2.32(2024-02-20)
|
||||||
|
- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
|
||||||
|
## 2.2.31(2024-02-20)
|
||||||
|
- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
|
||||||
|
## 2.2.30(2024-01-31)
|
||||||
|
- 修复 隐藏“秒”时,在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
|
||||||
|
## 2.2.29(2024-01-20)
|
||||||
|
- 新增 show事件,弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694)
|
||||||
|
## 2.2.28(2024-01-18)
|
||||||
|
- 去除 noChange事件,当进行日期范围选择时,若只选了一天,则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815)
|
||||||
|
## 2.2.27(2024-01-10)
|
||||||
|
- 优化 增加noChange事件,当进行日期范围选择时,若有空值,则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815)
|
||||||
|
## 2.2.26(2024-01-08)
|
||||||
|
- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834)
|
||||||
|
## 2.2.25(2023-10-18)
|
||||||
|
- 修复 PC端初次修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||||
|
## 2.2.24(2023-06-02)
|
||||||
|
- 修复 部分情况修改时间,开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
|
||||||
|
- 优化 当前月可以选择上月、下月的日期的Bug
|
||||||
|
## 2.2.23(2023-05-02)
|
||||||
|
- 修复 部分情况修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||||
|
- 修复 部分平台及设备第一次点击无法显示弹框的Bug
|
||||||
|
- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979)
|
||||||
|
## 2.2.22(2023-03-30)
|
||||||
|
- 修复 日历 picker 修改年月后,自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937)
|
||||||
|
- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979)
|
||||||
|
## 2.2.21(2023-02-20)
|
||||||
|
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
|
||||||
|
## 2.2.20(2023-02-17)
|
||||||
|
- 优化 值为空依然选中当天问题
|
||||||
|
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
|
||||||
|
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
|
||||||
|
- 优化 字节小程序日期时间范围选择,底部日期换行的Bug
|
||||||
|
## 2.2.19(2023-02-09)
|
||||||
|
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
|
||||||
|
## 2.2.18(2023-02-08)
|
||||||
|
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
|
||||||
|
- 优化 PC端输入日期格式错误时返回当前日期时间
|
||||||
|
- 优化 PC端输入日期时间超出 start、end 限制的Bug
|
||||||
|
- 优化 移动端日期时间范围用法时间展示不完整问题
|
||||||
|
## 2.2.17(2023-02-04)
|
||||||
|
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
|
||||||
|
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
|
||||||
|
## 2.2.16(2023-02-02)
|
||||||
|
- 修复 字节小程序报错的Bug
|
||||||
|
## 2.2.15(2023-02-02)
|
||||||
|
- 修复 某些情况切换月份错误的Bug
|
||||||
|
## 2.2.14(2023-01-30)
|
||||||
|
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
|
||||||
|
## 2.2.13(2023-01-10)
|
||||||
|
- 修复 多次加载组件造成内存占用的Bug
|
||||||
|
## 2.2.12(2022-12-01)
|
||||||
|
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
|
||||||
|
## 2.2.11(2022-09-19)
|
||||||
|
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
|
||||||
|
## 2.2.10(2022-09-19)
|
||||||
|
- 修复 反向选择日期范围,日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
|
||||||
|
## 2.2.9(2022-09-16)
|
||||||
|
- 可以使用 uni-scss 控制主题色
|
||||||
|
## 2.2.8(2022-09-08)
|
||||||
|
- 修复 close事件无效的Bug
|
||||||
|
## 2.2.7(2022-09-05)
|
||||||
|
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
|
||||||
|
## 2.2.6(2022-06-30)
|
||||||
|
- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
|
||||||
|
## 2.2.5(2022-06-24)
|
||||||
|
- 修复 日历顶部年月及底部确认未国际化的Bug
|
||||||
|
## 2.2.4(2022-03-31)
|
||||||
|
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
|
||||||
|
## 2.2.3(2022-03-28)
|
||||||
|
- 修复 Vue3 下动态赋值未响应的Bug
|
||||||
|
## 2.2.2(2021-12-10)
|
||||||
|
- 修复 clear-icon 属性在小程序平台不生效的Bug
|
||||||
|
## 2.2.1(2021-12-10)
|
||||||
|
- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的Bug
|
||||||
|
## 2.2.0(2021-11-19)
|
||||||
|
- 优化 组件UI,并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||||
|
## 2.1.5(2021-11-09)
|
||||||
|
- 新增 提供组件设计资源,组件样式调整
|
||||||
|
## 2.1.4(2021-09-10)
|
||||||
|
- 修复 hide-second 在移动端的Bug
|
||||||
|
- 修复 单选赋默认值时,赋值日期未高亮的Bug
|
||||||
|
- 修复 赋默认值时,移动端未正确显示时间的Bug
|
||||||
|
## 2.1.3(2021-09-09)
|
||||||
|
- 新增 hide-second 属性,支持只使用时分,隐藏秒
|
||||||
|
## 2.1.2(2021-09-03)
|
||||||
|
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
|
||||||
|
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
|
||||||
|
- 优化 调整字号大小,美化日历界面
|
||||||
|
- 修复 因国际化导致的 placeholder 失效的Bug
|
||||||
|
## 2.1.1(2021-08-24)
|
||||||
|
- 新增 支持国际化
|
||||||
|
- 优化 范围选择器在 pc 端过宽的问题
|
||||||
|
## 2.1.0(2021-08-09)
|
||||||
|
- 新增 适配 vue3
|
||||||
|
## 2.0.19(2021-08-09)
|
||||||
|
- 新增 支持作为 uni-forms 子组件相关功能
|
||||||
|
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
|
||||||
|
## 2.0.18(2021-08-05)
|
||||||
|
- 修复 type 属性动态赋值无效的Bug
|
||||||
|
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
|
||||||
|
- 修复 组件未赋值时范围选左、右日历相同的Bug
|
||||||
|
## 2.0.17(2021-08-04)
|
||||||
|
- 修复 范围选未正确显示当前值的Bug
|
||||||
|
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
|
||||||
|
## 2.0.16(2021-07-21)
|
||||||
|
- 新增 return-type 属性支持返回 date 日期对象
|
||||||
|
## 2.0.15(2021-07-14)
|
||||||
|
- 修复 单选日期类型,初始赋值后不在当前日历的Bug
|
||||||
|
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
|
||||||
|
- 优化 移动端移除显示框的清空按钮,无实际用途
|
||||||
|
## 2.0.14(2021-07-14)
|
||||||
|
- 修复 组件赋值为空,界面未更新的Bug
|
||||||
|
- 修复 start 和 end 不能动态赋值的Bug
|
||||||
|
- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的Bug
|
||||||
|
## 2.0.13(2021-07-08)
|
||||||
|
- 修复 范围选择不能动态赋值的Bug
|
||||||
|
## 2.0.12(2021-07-08)
|
||||||
|
- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
|
||||||
|
## 2.0.11(2021-07-08)
|
||||||
|
- 优化 弹出层在超出视窗边缘定位不准确的问题
|
||||||
|
## 2.0.10(2021-07-08)
|
||||||
|
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的Bug
|
||||||
|
- 优化 弹出层在超出视窗边缘被遮盖的问题
|
||||||
|
## 2.0.9(2021-07-07)
|
||||||
|
- 新增 maskClick 事件
|
||||||
|
- 修复 特殊情况日历 rpx 布局错误的Bug,rpx -> px
|
||||||
|
- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
|
||||||
|
## 2.0.8(2021-07-07)
|
||||||
|
- 新增 日期时间显示框支持插槽
|
||||||
|
## 2.0.7(2021-07-01)
|
||||||
|
- 优化 添加 uni-icons 依赖
|
||||||
|
## 2.0.6(2021-05-22)
|
||||||
|
- 修复 图标在小程序上不显示的Bug
|
||||||
|
- 优化 重命名引用组件,避免潜在组件命名冲突
|
||||||
|
## 2.0.5(2021-05-20)
|
||||||
|
- 优化 代码目录扁平化
|
||||||
|
## 2.0.4(2021-05-12)
|
||||||
|
- 新增 组件示例地址
|
||||||
|
## 2.0.3(2021-05-10)
|
||||||
|
- 修复 ios 下不识别 '-' 日期格式的Bug
|
||||||
|
- 优化 pc 下弹出层添加边框和阴影
|
||||||
|
## 2.0.2(2021-05-08)
|
||||||
|
- 修复 在 admin 中获取弹出层定位错误的bug
|
||||||
|
## 2.0.1(2021-05-08)
|
||||||
|
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
|
||||||
|
## 2.0.0(2021-04-30)
|
||||||
|
- 支持日历形式的日期+时间的范围选择
|
||||||
|
> 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
|
||||||
|
## 1.0.6(2021-03-18)
|
||||||
|
- 新增 hide-second 属性,时间支持仅选择时、分
|
||||||
|
- 修复 选择跟显示的日期不一样的Bug
|
||||||
|
- 修复 chang事件触发2次的Bug
|
||||||
|
- 修复 分、秒 end 范围错误的Bug
|
||||||
|
- 优化 更好的 nvue 适配
|
||||||
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-calendar-item__weeks-box" :class="{
|
||||||
|
'uni-calendar-item--disable':weeks.disable,
|
||||||
|
'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
|
||||||
|
'uni-calendar-item--multiple': weeks.multiple,
|
||||||
|
'uni-calendar-item--after-checked-x':weeks.afterMultiple,
|
||||||
|
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
|
||||||
|
<view class="uni-calendar-item__weeks-box-item" :class="{
|
||||||
|
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
|
||||||
|
'uni-calendar-item--checked-range-text': checkHover,
|
||||||
|
'uni-calendar-item--before-checked':weeks.beforeMultiple,
|
||||||
|
'uni-calendar-item--multiple': weeks.multiple,
|
||||||
|
'uni-calendar-item--after-checked':weeks.afterMultiple,
|
||||||
|
'uni-calendar-item--disable':weeks.disable,
|
||||||
|
}">
|
||||||
|
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
|
||||||
|
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
|
||||||
|
</view>
|
||||||
|
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
weeks: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calendar: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
choiceDate(weeks) {
|
||||||
|
this.$emit('change', weeks)
|
||||||
|
},
|
||||||
|
handleMousemove(weeks) {
|
||||||
|
this.$emit('handleMouse', weeks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" >
|
||||||
|
$uni-primary: #007aff !default;
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 1px 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box-text {
|
||||||
|
font-size: 14px;
|
||||||
|
// font-family: Lato-Bold, Lato;
|
||||||
|
font-weight: bold;
|
||||||
|
color: darken($color: $uni-primary, $amount: 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box-item {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box-circle {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #dd524d;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
|
||||||
|
color: #D1D1D1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--today {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 17%;
|
||||||
|
background-color: #dd524d;
|
||||||
|
width:6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--extra {
|
||||||
|
color: #dd524d;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
|
||||||
|
background-color: $uni-primary;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 3px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--checked .uni-calendar-item--checked-text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--multiple {
|
||||||
|
background-color: #F6F7FC;
|
||||||
|
// color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--multiple .uni-calendar-item--before-checked,
|
||||||
|
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
|
||||||
|
background-color: $uni-primary;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 3px solid #F6F7FC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
|
||||||
|
.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--before-checked-x {
|
||||||
|
border-top-left-radius: 50px;
|
||||||
|
border-bottom-left-radius: 50px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #F6F7FC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar-item--after-checked-x {
|
||||||
|
border-top-right-radius: 50px;
|
||||||
|
border-bottom-right-radius: 50px;
|
||||||
|
background-color: #F6F7FC;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,947 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-calendar" @mouseleave="leaveCale">
|
||||||
|
|
||||||
|
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
|
||||||
|
@click="maskClick"></view>
|
||||||
|
|
||||||
|
<view v-if="insert || show" class="uni-calendar__content"
|
||||||
|
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
|
||||||
|
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
|
||||||
|
|
||||||
|
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
|
||||||
|
<view class="uni-calendar__header-btn uni-calendar--left"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
|
||||||
|
<text
|
||||||
|
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
|
||||||
|
</picker>
|
||||||
|
|
||||||
|
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
|
||||||
|
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!insert" class="dialog-close" @click="maskClick">
|
||||||
|
<view class="dialog-close-plus" data-id="close"></view>
|
||||||
|
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__box">
|
||||||
|
|
||||||
|
<view v-if="showMonth" class="uni-calendar__box-bg">
|
||||||
|
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-calendar__weeks-day">
|
||||||
|
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
|
||||||
|
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
|
||||||
|
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
|
||||||
|
:checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
|
||||||
|
</calendar-item>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
|
||||||
|
style="padding: 0 80px;">
|
||||||
|
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
|
||||||
|
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
|
||||||
|
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
|
||||||
|
</time-picker>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
|
||||||
|
<view class="uni-date-changed--time-start">
|
||||||
|
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
|
||||||
|
</view>
|
||||||
|
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
|
||||||
|
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
|
||||||
|
</time-picker>
|
||||||
|
</view>
|
||||||
|
<view style="line-height: 50px;">
|
||||||
|
<uni-icons type="arrowthinright" color="#999"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="uni-date-changed--time-end">
|
||||||
|
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
|
||||||
|
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
|
||||||
|
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
|
||||||
|
</time-picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
|
||||||
|
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Calendar,
|
||||||
|
getDate,
|
||||||
|
getTime
|
||||||
|
} from './util.js';
|
||||||
|
import calendarItem from './calendar-item.vue'
|
||||||
|
import timePicker from './time-picker.vue'
|
||||||
|
|
||||||
|
import {
|
||||||
|
initVueI18n
|
||||||
|
} from '@dcloudio/uni-i18n'
|
||||||
|
import i18nMessages from './i18n/index.js'
|
||||||
|
const {
|
||||||
|
t
|
||||||
|
} = initVueI18n(i18nMessages)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calendar 日历
|
||||||
|
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
|
||||||
|
* @property {String} date 自定义当前时间,默认为今天
|
||||||
|
* @property {String} startDate 日期选择范围-开始日期
|
||||||
|
* @property {String} endDate 日期选择范围-结束日期
|
||||||
|
* @property {Boolean} range 范围选择
|
||||||
|
* @property {Boolean} insert = [true|false] 插入模式,默认为false
|
||||||
|
* @value true 弹窗模式
|
||||||
|
* @value false 插入模式
|
||||||
|
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
|
||||||
|
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||||
|
* @property {Boolean} showMonth 是否选择月份为背景
|
||||||
|
* @property {[String} defaultValue 选择器打开时默认显示的时间
|
||||||
|
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||||
|
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||||
|
* @event {Function} monthSwitch 切换月份时触发
|
||||||
|
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
calendarItem,
|
||||||
|
timePicker
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
virtualHost: false,
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-TOUTIAO
|
||||||
|
virtualHost: true
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
date: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
defTime: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selectableTimes: {
|
||||||
|
type: [Object],
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
startPlaceholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
endPlaceholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasTime: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
insert: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showMonth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
clearDate: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
checkHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
hideSecond: {
|
||||||
|
type: [Boolean],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
pleStatus: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {
|
||||||
|
before: '',
|
||||||
|
after: '',
|
||||||
|
data: [],
|
||||||
|
fulldate: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultValue: {
|
||||||
|
type: [String, Object, Array],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
weeks: [],
|
||||||
|
calendar: {},
|
||||||
|
nowDate: {},
|
||||||
|
aniMaskShow: false,
|
||||||
|
firstEnter: true,
|
||||||
|
time: '',
|
||||||
|
timeRange: {
|
||||||
|
startTime: '',
|
||||||
|
endTime: ''
|
||||||
|
},
|
||||||
|
tempSingleDate: '',
|
||||||
|
tempRange: {
|
||||||
|
before: '',
|
||||||
|
after: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
date: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (!this.range) {
|
||||||
|
this.tempSingleDate = newVal
|
||||||
|
setTimeout(() => {
|
||||||
|
this.init(newVal)
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defTime: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (!this.range) {
|
||||||
|
this.time = newVal
|
||||||
|
} else {
|
||||||
|
this.timeRange.startTime = newVal.start
|
||||||
|
this.timeRange.endTime = newVal.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
startDate(val) {
|
||||||
|
// 字节小程序 watch 早于 created
|
||||||
|
if (!this.cale) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.cale.setStartDate(val)
|
||||||
|
this.cale.setDate(this.nowDate.fullDate)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
},
|
||||||
|
endDate(val) {
|
||||||
|
// 字节小程序 watch 早于 created
|
||||||
|
if (!this.cale) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.cale.setEndDate(val)
|
||||||
|
this.cale.setDate(this.nowDate.fullDate)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
},
|
||||||
|
selected(newVal) {
|
||||||
|
// 字节小程序 watch 早于 created
|
||||||
|
if (!this.cale) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
},
|
||||||
|
pleStatus: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
const {
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
fulldate,
|
||||||
|
which
|
||||||
|
} = newVal
|
||||||
|
this.tempRange.before = before
|
||||||
|
this.tempRange.after = after
|
||||||
|
setTimeout(() => {
|
||||||
|
if (fulldate) {
|
||||||
|
this.cale.setHoverMultiple(fulldate)
|
||||||
|
if (before && after) {
|
||||||
|
this.cale.lastHover = true
|
||||||
|
if (this.rangeWithinMonth(after, before)) return
|
||||||
|
this.setDate(before)
|
||||||
|
} else {
|
||||||
|
this.cale.setMultiple(fulldate)
|
||||||
|
this.setDate(this.nowDate.fullDate)
|
||||||
|
this.calendar.fullDate = ''
|
||||||
|
this.cale.lastHover = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 字节小程序 watch 早于 created
|
||||||
|
if (!this.cale) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cale.setDefaultMultiple(before, after)
|
||||||
|
if (which === 'left' && before) {
|
||||||
|
this.setDate(before)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
} else if (after) {
|
||||||
|
this.setDate(after)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
}
|
||||||
|
this.cale.lastHover = true
|
||||||
|
}
|
||||||
|
}, 16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
timepickerStartTime() {
|
||||||
|
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
|
||||||
|
return activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||||
|
},
|
||||||
|
timepickerEndTime() {
|
||||||
|
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
|
||||||
|
return activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* for i18n
|
||||||
|
*/
|
||||||
|
selectDateText() {
|
||||||
|
return t("uni-datetime-picker.selectDate")
|
||||||
|
},
|
||||||
|
startDateText() {
|
||||||
|
return this.startPlaceholder || t("uni-datetime-picker.startDate")
|
||||||
|
},
|
||||||
|
endDateText() {
|
||||||
|
return this.endPlaceholder || t("uni-datetime-picker.endDate")
|
||||||
|
},
|
||||||
|
okText() {
|
||||||
|
return t("uni-datetime-picker.ok")
|
||||||
|
},
|
||||||
|
yearText() {
|
||||||
|
return t("uni-datetime-picker.year")
|
||||||
|
},
|
||||||
|
monthText() {
|
||||||
|
return t("uni-datetime-picker.month")
|
||||||
|
},
|
||||||
|
MONText() {
|
||||||
|
return t("uni-calender.MON")
|
||||||
|
},
|
||||||
|
TUEText() {
|
||||||
|
return t("uni-calender.TUE")
|
||||||
|
},
|
||||||
|
WEDText() {
|
||||||
|
return t("uni-calender.WED")
|
||||||
|
},
|
||||||
|
THUText() {
|
||||||
|
return t("uni-calender.THU")
|
||||||
|
},
|
||||||
|
FRIText() {
|
||||||
|
return t("uni-calender.FRI")
|
||||||
|
},
|
||||||
|
SATText() {
|
||||||
|
return t("uni-calender.SAT")
|
||||||
|
},
|
||||||
|
SUNText() {
|
||||||
|
return t("uni-calender.SUN")
|
||||||
|
},
|
||||||
|
confirmText() {
|
||||||
|
return t("uni-calender.confirm")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 获取日历方法实例
|
||||||
|
this.cale = new Calendar({
|
||||||
|
selected: this.selected,
|
||||||
|
startDate: this.startDate,
|
||||||
|
endDate: this.endDate,
|
||||||
|
range: this.range,
|
||||||
|
})
|
||||||
|
// 选中某一天
|
||||||
|
this.init(this.date)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
leaveCale() {
|
||||||
|
this.firstEnter = true
|
||||||
|
},
|
||||||
|
handleMouse(weeks) {
|
||||||
|
if (weeks.disable) return
|
||||||
|
if (this.cale.lastHover) return
|
||||||
|
let {
|
||||||
|
before,
|
||||||
|
after
|
||||||
|
} = this.cale.multipleStatus
|
||||||
|
if (!before) return
|
||||||
|
this.calendar = weeks
|
||||||
|
// 设置范围选
|
||||||
|
this.cale.setHoverMultiple(this.calendar.fullDate)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
// hover时,进入一个日历,更新另一个
|
||||||
|
if (this.firstEnter) {
|
||||||
|
this.$emit('firstEnterCale', this.cale.multipleStatus)
|
||||||
|
this.firstEnter = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rangeWithinMonth(A, B) {
|
||||||
|
const [yearA, monthA] = A.split('-')
|
||||||
|
const [yearB, monthB] = B.split('-')
|
||||||
|
return yearA === yearB && monthA === monthB
|
||||||
|
},
|
||||||
|
// 蒙版点击事件
|
||||||
|
maskClick() {
|
||||||
|
this.close()
|
||||||
|
this.$emit('maskClose')
|
||||||
|
},
|
||||||
|
|
||||||
|
clearCalender() {
|
||||||
|
if (this.range) {
|
||||||
|
this.timeRange.startTime = ''
|
||||||
|
this.timeRange.endTime = ''
|
||||||
|
this.tempRange.before = ''
|
||||||
|
this.tempRange.after = ''
|
||||||
|
this.cale.multipleStatus.before = ''
|
||||||
|
this.cale.multipleStatus.after = ''
|
||||||
|
this.cale.multipleStatus.data = []
|
||||||
|
this.cale.lastHover = false
|
||||||
|
} else {
|
||||||
|
this.time = ''
|
||||||
|
this.tempSingleDate = ''
|
||||||
|
}
|
||||||
|
this.calendar.fullDate = ''
|
||||||
|
this.setDate(new Date())
|
||||||
|
},
|
||||||
|
|
||||||
|
bindDateChange(e) {
|
||||||
|
const value = e.detail.value + '-1'
|
||||||
|
this.setDate(value)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 初始化日期显示
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
init(date) {
|
||||||
|
// 字节小程序 watch 早于 created
|
||||||
|
if (!this.cale) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.cale.setDate(date || new Date())
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
this.nowDate = this.cale.getInfo(date)
|
||||||
|
this.calendar = {
|
||||||
|
...this.nowDate
|
||||||
|
}
|
||||||
|
if (!date) {
|
||||||
|
// 优化date为空默认不选中今天
|
||||||
|
this.calendar.fullDate = ''
|
||||||
|
if (this.defaultValue && !this.range) {
|
||||||
|
// 暂时只支持移动端非范围选择
|
||||||
|
const defaultDate = new Date(this.defaultValue)
|
||||||
|
const fullDate = getDate(defaultDate)
|
||||||
|
const year = defaultDate.getFullYear()
|
||||||
|
const month = defaultDate.getMonth() + 1
|
||||||
|
const date = defaultDate.getDate()
|
||||||
|
const day = defaultDate.getDay()
|
||||||
|
this.calendar = {
|
||||||
|
fullDate,
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
date,
|
||||||
|
day
|
||||||
|
},
|
||||||
|
this.tempSingleDate = fullDate
|
||||||
|
this.time = getTime(defaultDate, this.hideSecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 打开日历弹窗
|
||||||
|
*/
|
||||||
|
open() {
|
||||||
|
// 弹窗模式并且清理数据
|
||||||
|
if (this.clearDate && !this.insert) {
|
||||||
|
this.cale.cleanMultipleStatus()
|
||||||
|
this.init(this.date)
|
||||||
|
}
|
||||||
|
this.show = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.aniMaskShow = true
|
||||||
|
}, 50)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 关闭日历弹窗
|
||||||
|
*/
|
||||||
|
close() {
|
||||||
|
this.aniMaskShow = false
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.show = false
|
||||||
|
this.$emit('close')
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 确认按钮
|
||||||
|
*/
|
||||||
|
confirm() {
|
||||||
|
this.setEmit('confirm')
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 变化触发
|
||||||
|
*/
|
||||||
|
change(isSingleChange) {
|
||||||
|
if (!this.insert && !isSingleChange) return
|
||||||
|
this.setEmit('change')
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 选择月份触发
|
||||||
|
*/
|
||||||
|
monthSwitch() {
|
||||||
|
let {
|
||||||
|
year,
|
||||||
|
month
|
||||||
|
} = this.nowDate
|
||||||
|
this.$emit('monthSwitch', {
|
||||||
|
year,
|
||||||
|
month: Number(month)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 派发事件
|
||||||
|
* @param {Object} name
|
||||||
|
*/
|
||||||
|
setEmit(name) {
|
||||||
|
if (!this.range) {
|
||||||
|
if (!this.calendar.fullDate) {
|
||||||
|
this.calendar = this.cale.getInfo(new Date())
|
||||||
|
this.tempSingleDate = this.calendar.fullDate
|
||||||
|
}
|
||||||
|
if (this.hasTime && !this.time) {
|
||||||
|
this.time = getTime(new Date(), this.hideSecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
date,
|
||||||
|
fullDate,
|
||||||
|
extraInfo
|
||||||
|
} = this.calendar
|
||||||
|
this.$emit(name, {
|
||||||
|
range: this.cale.multipleStatus,
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
date,
|
||||||
|
time: this.time,
|
||||||
|
timeRange: this.timeRange,
|
||||||
|
fulldate: fullDate,
|
||||||
|
extraInfo: extraInfo || {}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 选择天触发
|
||||||
|
* @param {Object} weeks
|
||||||
|
*/
|
||||||
|
choiceDate(weeks) {
|
||||||
|
if (weeks.disable) return
|
||||||
|
this.calendar = weeks
|
||||||
|
this.calendar.userChecked = true
|
||||||
|
// 设置多选
|
||||||
|
this.cale.setMultiple(this.calendar.fullDate, true)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
this.tempSingleDate = this.calendar.fullDate
|
||||||
|
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
|
||||||
|
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
|
||||||
|
if (beforeDate > afterDate && afterDate) {
|
||||||
|
this.tempRange.before = this.cale.multipleStatus.after
|
||||||
|
this.tempRange.after = this.cale.multipleStatus.before
|
||||||
|
} else {
|
||||||
|
this.tempRange.before = this.cale.multipleStatus.before
|
||||||
|
this.tempRange.after = this.cale.multipleStatus.after
|
||||||
|
}
|
||||||
|
this.change(true)
|
||||||
|
},
|
||||||
|
changeMonth(type) {
|
||||||
|
let newDate
|
||||||
|
if (type === 'pre') {
|
||||||
|
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
|
||||||
|
} else if (type === 'next') {
|
||||||
|
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDate(newDate)
|
||||||
|
this.monthSwitch()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 设置日期
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
setDate(date) {
|
||||||
|
this.cale.setDate(date)
|
||||||
|
this.weeks = this.cale.weeks
|
||||||
|
this.nowDate = this.cale.getInfo(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$uni-primary: #007aff !default;
|
||||||
|
|
||||||
|
.uni-calendar {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__mask {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
transition-property: opacity;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
opacity: 0;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
z-index: 99;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--mask-show {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--fixed {
|
||||||
|
position: fixed;
|
||||||
|
bottom: calc(var(--window-bottom));
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
transform: translateY(460px);
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
z-index: 99;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--ani-show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__content {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__content-mobile {
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__header {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__header-mobile {
|
||||||
|
padding: 10px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--fixed-top {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top-color: rgba(0, 0, 0, 0.4);
|
||||||
|
border-top-style: solid;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--fixed-width {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__backtoday {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 25rpx;
|
||||||
|
padding: 0 5px;
|
||||||
|
padding-left: 10px;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-top-left-radius: 25px;
|
||||||
|
border-bottom-left-radius: 25px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__header-text {
|
||||||
|
text-align: center;
|
||||||
|
width: 100px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__button-text {
|
||||||
|
text-align: center;
|
||||||
|
width: 100px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $uni-primary;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
letter-spacing: 3px;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__header-btn-box {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__header-btn {
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
border-left-color: #808080;
|
||||||
|
border-left-style: solid;
|
||||||
|
border-left-width: 1px;
|
||||||
|
border-top-color: #555555;
|
||||||
|
border-top-style: solid;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--left {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar--right {
|
||||||
|
transform: rotate(135deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.uni-calendar__weeks {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__weeks-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__weeks-day {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
border-bottom-color: #F5F5F5;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__weeks-day-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #B2B2B2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__box {
|
||||||
|
position: relative;
|
||||||
|
// padding: 0 10px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__box-bg {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-calendar__box-bg-text {
|
||||||
|
font-size: 200px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999;
|
||||||
|
opacity: 0.1;
|
||||||
|
text-align: center;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
line-height: 1;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-date-changed {
|
||||||
|
padding: 0 10px;
|
||||||
|
// line-height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
border-top-color: #DCDCDC;
|
||||||
|
;
|
||||||
|
border-top-style: solid;
|
||||||
|
border-top-width: 1px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-date-btn--ok {
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-date-changed--time-start {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-date-changed--time-end {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-date-changed--time-date {
|
||||||
|
color: #999;
|
||||||
|
line-height: 50px;
|
||||||
|
/* #ifdef MP-TOUTIAO */
|
||||||
|
font-size: 16px;
|
||||||
|
/* #endif */
|
||||||
|
margin-right: 5px;
|
||||||
|
// opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-picker-style {
|
||||||
|
// width: 62px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-10 {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 25px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-plus {
|
||||||
|
width: 16px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #737987;
|
||||||
|
border-radius: 2px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-close-rotate {
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker--btn {
|
||||||
|
border-radius: 100px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.uni-datetime-picker--btn:active {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"uni-datetime-picker.selectDate": "select date",
|
||||||
|
"uni-datetime-picker.selectTime": "select time",
|
||||||
|
"uni-datetime-picker.selectDateTime": "select date and time",
|
||||||
|
"uni-datetime-picker.startDate": "start date",
|
||||||
|
"uni-datetime-picker.endDate": "end date",
|
||||||
|
"uni-datetime-picker.startTime": "start time",
|
||||||
|
"uni-datetime-picker.endTime": "end time",
|
||||||
|
"uni-datetime-picker.ok": "ok",
|
||||||
|
"uni-datetime-picker.clear": "clear",
|
||||||
|
"uni-datetime-picker.cancel": "cancel",
|
||||||
|
"uni-datetime-picker.year": "-",
|
||||||
|
"uni-datetime-picker.month": "",
|
||||||
|
"uni-calender.MON": "MON",
|
||||||
|
"uni-calender.TUE": "TUE",
|
||||||
|
"uni-calender.WED": "WED",
|
||||||
|
"uni-calender.THU": "THU",
|
||||||
|
"uni-calender.FRI": "FRI",
|
||||||
|
"uni-calender.SAT": "SAT",
|
||||||
|
"uni-calender.SUN": "SUN",
|
||||||
|
"uni-calender.confirm": "confirm"
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import en from './en.json'
|
||||||
|
import zhHans from './zh-Hans.json'
|
||||||
|
import zhHant from './zh-Hant.json'
|
||||||
|
export default {
|
||||||
|
en,
|
||||||
|
'zh-Hans': zhHans,
|
||||||
|
'zh-Hant': zhHant
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"uni-datetime-picker.selectDate": "选择日期",
|
||||||
|
"uni-datetime-picker.selectTime": "选择时间",
|
||||||
|
"uni-datetime-picker.selectDateTime": "选择日期时间",
|
||||||
|
"uni-datetime-picker.startDate": "开始日期",
|
||||||
|
"uni-datetime-picker.endDate": "结束日期",
|
||||||
|
"uni-datetime-picker.startTime": "开始时间",
|
||||||
|
"uni-datetime-picker.endTime": "结束时间",
|
||||||
|
"uni-datetime-picker.ok": "确定",
|
||||||
|
"uni-datetime-picker.clear": "清除",
|
||||||
|
"uni-datetime-picker.cancel": "取消",
|
||||||
|
"uni-datetime-picker.year": "年",
|
||||||
|
"uni-datetime-picker.month": "月",
|
||||||
|
"uni-calender.SUN": "日",
|
||||||
|
"uni-calender.MON": "一",
|
||||||
|
"uni-calender.TUE": "二",
|
||||||
|
"uni-calender.WED": "三",
|
||||||
|
"uni-calender.THU": "四",
|
||||||
|
"uni-calender.FRI": "五",
|
||||||
|
"uni-calender.SAT": "六",
|
||||||
|
"uni-calender.confirm": "确认"
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"uni-datetime-picker.selectDate": "選擇日期",
|
||||||
|
"uni-datetime-picker.selectTime": "選擇時間",
|
||||||
|
"uni-datetime-picker.selectDateTime": "選擇日期時間",
|
||||||
|
"uni-datetime-picker.startDate": "開始日期",
|
||||||
|
"uni-datetime-picker.endDate": "結束日期",
|
||||||
|
"uni-datetime-picker.startTime": "開始时间",
|
||||||
|
"uni-datetime-picker.endTime": "結束时间",
|
||||||
|
"uni-datetime-picker.ok": "確定",
|
||||||
|
"uni-datetime-picker.clear": "清除",
|
||||||
|
"uni-datetime-picker.cancel": "取消",
|
||||||
|
"uni-datetime-picker.year": "年",
|
||||||
|
"uni-datetime-picker.month": "月",
|
||||||
|
"uni-calender.SUN": "日",
|
||||||
|
"uni-calender.MON": "一",
|
||||||
|
"uni-calender.TUE": "二",
|
||||||
|
"uni-calender.WED": "三",
|
||||||
|
"uni-calender.THU": "四",
|
||||||
|
"uni-calender.FRI": "五",
|
||||||
|
"uni-calender.SAT": "六",
|
||||||
|
"uni-calender.confirm": "確認"
|
||||||
|
}
|
||||||
@ -0,0 +1,940 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-datetime-picker">
|
||||||
|
<view @click="initTimePicker">
|
||||||
|
<slot>
|
||||||
|
<view class="uni-datetime-picker-timebox-pointer"
|
||||||
|
:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
|
||||||
|
<text class="uni-datetime-picker-text">{{time}}</text>
|
||||||
|
<view v-if="!time" class="uni-datetime-picker-time">
|
||||||
|
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
|
||||||
|
<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
|
||||||
|
:style="fixNvueBug">
|
||||||
|
<view class="uni-title">
|
||||||
|
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="dateShow" class="uni-datetime-picker__container-box">
|
||||||
|
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
|
||||||
|
@change="bindDateChange">
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
</picker-view>
|
||||||
|
<!-- 兼容 nvue 不支持伪类 -->
|
||||||
|
<text class="uni-datetime-picker-sign sign-left">-</text>
|
||||||
|
<text class="uni-datetime-picker-sign sign-right">-</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="timeShow" class="uni-datetime-picker__container-box">
|
||||||
|
<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
|
||||||
|
:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column v-if="!hideSecond">
|
||||||
|
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
|
||||||
|
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||||
|
</view>
|
||||||
|
</picker-view-column>
|
||||||
|
</picker-view>
|
||||||
|
<!-- 兼容 nvue 不支持伪类 -->
|
||||||
|
<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
|
||||||
|
<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-datetime-picker-btn">
|
||||||
|
<view @click="clearTime">
|
||||||
|
<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="uni-datetime-picker-btn-group">
|
||||||
|
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
|
||||||
|
<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
|
||||||
|
</view>
|
||||||
|
<view @click="setTime">
|
||||||
|
<text class="uni-datetime-picker-btn-text">{{okText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
initVueI18n
|
||||||
|
} from '@dcloudio/uni-i18n'
|
||||||
|
import i18nMessages from './i18n/index.js'
|
||||||
|
const {
|
||||||
|
t
|
||||||
|
} = initVueI18n(i18nMessages)
|
||||||
|
import {
|
||||||
|
fixIosDateFormat
|
||||||
|
} from './util'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DatetimePicker 时间选择器
|
||||||
|
* @description 可以同时选择日期和时间的选择器
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
||||||
|
* @property {String} type = [datetime | date | time] 显示模式
|
||||||
|
* @property {Boolean} multiple = [true|false] 是否多选
|
||||||
|
* @property {String|Number} value 默认值
|
||||||
|
* @property {String|Number} start 起始日期或时间
|
||||||
|
* @property {String|Number} end 起始日期或时间
|
||||||
|
* @property {String} return-type = [timestamp | string]
|
||||||
|
* @event {Function} change 选中发生变化触发
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UniDatetimePicker',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
indicatorStyle: `height: 50px;`,
|
||||||
|
visible: false,
|
||||||
|
fixNvueBug: {},
|
||||||
|
dateShow: true,
|
||||||
|
timeShow: true,
|
||||||
|
title: '日期和时间',
|
||||||
|
// 输入框当前时间
|
||||||
|
time: '',
|
||||||
|
// 当前的年月日时分秒
|
||||||
|
year: 1920,
|
||||||
|
month: 0,
|
||||||
|
day: 0,
|
||||||
|
hour: 0,
|
||||||
|
minute: 0,
|
||||||
|
second: 0,
|
||||||
|
// 起始时间
|
||||||
|
startYear: 1920,
|
||||||
|
startMonth: 1,
|
||||||
|
startDay: 1,
|
||||||
|
startHour: 0,
|
||||||
|
startMinute: 0,
|
||||||
|
startSecond: 0,
|
||||||
|
// 结束时间
|
||||||
|
endYear: 2120,
|
||||||
|
endMonth: 12,
|
||||||
|
endDay: 31,
|
||||||
|
endHour: 23,
|
||||||
|
endMinute: 59,
|
||||||
|
endSecond: 59,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
virtualHost: false,
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-TOUTIAO
|
||||||
|
virtualHost: true
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'datetime'
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
returnType: {
|
||||||
|
type: String,
|
||||||
|
default: 'string'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
hideSecond: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// #ifndef VUE3
|
||||||
|
value: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.parseValue(fixIosDateFormat(newVal))
|
||||||
|
this.initTime(false)
|
||||||
|
} else {
|
||||||
|
this.time = ''
|
||||||
|
this.parseValue(Date.now())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE3
|
||||||
|
modelValue: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.parseValue(fixIosDateFormat(newVal))
|
||||||
|
this.initTime(false)
|
||||||
|
} else {
|
||||||
|
this.time = ''
|
||||||
|
this.parseValue(Date.now())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
type: {
|
||||||
|
handler(newValue) {
|
||||||
|
if (newValue === 'date') {
|
||||||
|
this.dateShow = true
|
||||||
|
this.timeShow = false
|
||||||
|
this.title = '日期'
|
||||||
|
} else if (newValue === 'time') {
|
||||||
|
this.dateShow = false
|
||||||
|
this.timeShow = true
|
||||||
|
this.title = '时间'
|
||||||
|
} else {
|
||||||
|
this.dateShow = true
|
||||||
|
this.timeShow = true
|
||||||
|
this.title = '日期和时间'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
handler(newVal) {
|
||||||
|
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
handler(newVal) {
|
||||||
|
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||||
|
months(newVal) {
|
||||||
|
this.checkValue('month', this.month, newVal)
|
||||||
|
},
|
||||||
|
days(newVal) {
|
||||||
|
this.checkValue('day', this.day, newVal)
|
||||||
|
},
|
||||||
|
hours(newVal) {
|
||||||
|
this.checkValue('hour', this.hour, newVal)
|
||||||
|
},
|
||||||
|
minutes(newVal) {
|
||||||
|
this.checkValue('minute', this.minute, newVal)
|
||||||
|
},
|
||||||
|
seconds(newVal) {
|
||||||
|
this.checkValue('second', this.second, newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 当前年、月、日、时、分、秒选择范围
|
||||||
|
years() {
|
||||||
|
return this.getCurrentRange('year')
|
||||||
|
},
|
||||||
|
|
||||||
|
months() {
|
||||||
|
return this.getCurrentRange('month')
|
||||||
|
},
|
||||||
|
|
||||||
|
days() {
|
||||||
|
return this.getCurrentRange('day')
|
||||||
|
},
|
||||||
|
|
||||||
|
hours() {
|
||||||
|
return this.getCurrentRange('hour')
|
||||||
|
},
|
||||||
|
|
||||||
|
minutes() {
|
||||||
|
return this.getCurrentRange('minute')
|
||||||
|
},
|
||||||
|
|
||||||
|
seconds() {
|
||||||
|
return this.getCurrentRange('second')
|
||||||
|
},
|
||||||
|
|
||||||
|
// picker 当前值数组
|
||||||
|
ymd() {
|
||||||
|
return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
|
||||||
|
},
|
||||||
|
hms() {
|
||||||
|
return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当前 date 是 start
|
||||||
|
currentDateIsStart() {
|
||||||
|
return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当前 date 是 end
|
||||||
|
currentDateIsEnd() {
|
||||||
|
return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
|
||||||
|
},
|
||||||
|
|
||||||
|
// 当前年、月、日、时、分、秒的最小值和最大值
|
||||||
|
minYear() {
|
||||||
|
return this.startYear
|
||||||
|
},
|
||||||
|
maxYear() {
|
||||||
|
return this.endYear
|
||||||
|
},
|
||||||
|
minMonth() {
|
||||||
|
if (this.year === this.startYear) {
|
||||||
|
return this.startMonth
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxMonth() {
|
||||||
|
if (this.year === this.endYear) {
|
||||||
|
return this.endMonth
|
||||||
|
} else {
|
||||||
|
return 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minDay() {
|
||||||
|
if (this.year === this.startYear && this.month === this.startMonth) {
|
||||||
|
return this.startDay
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxDay() {
|
||||||
|
if (this.year === this.endYear && this.month === this.endMonth) {
|
||||||
|
return this.endDay
|
||||||
|
} else {
|
||||||
|
return this.daysInMonth(this.year, this.month)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minHour() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsStart) {
|
||||||
|
return this.startHour
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
return this.startHour
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxHour() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsEnd) {
|
||||||
|
return this.endHour
|
||||||
|
} else {
|
||||||
|
return 23
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
return this.endHour
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minMinute() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsStart && this.hour === this.startHour) {
|
||||||
|
return this.startMinute
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
if (this.hour === this.startHour) {
|
||||||
|
return this.startMinute
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxMinute() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsEnd && this.hour === this.endHour) {
|
||||||
|
return this.endMinute
|
||||||
|
} else {
|
||||||
|
return 59
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
if (this.hour === this.endHour) {
|
||||||
|
return this.endMinute
|
||||||
|
} else {
|
||||||
|
return 59
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minSecond() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
|
||||||
|
return this.startSecond
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
if (this.hour === this.startHour && this.minute === this.startMinute) {
|
||||||
|
return this.startSecond
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxSecond() {
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
|
||||||
|
return this.endSecond
|
||||||
|
} else {
|
||||||
|
return 59
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
if (this.hour === this.endHour && this.minute === this.endMinute) {
|
||||||
|
return this.endSecond
|
||||||
|
} else {
|
||||||
|
return 59
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for i18n
|
||||||
|
*/
|
||||||
|
selectTimeText() {
|
||||||
|
return t("uni-datetime-picker.selectTime")
|
||||||
|
},
|
||||||
|
okText() {
|
||||||
|
return t("uni-datetime-picker.ok")
|
||||||
|
},
|
||||||
|
clearText() {
|
||||||
|
return t("uni-datetime-picker.clear")
|
||||||
|
},
|
||||||
|
cancelText() {
|
||||||
|
return t("uni-datetime-picker.cancel")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const res = uni.getSystemInfoSync();
|
||||||
|
this.fixNvueBug = {
|
||||||
|
top: res.windowHeight / 2,
|
||||||
|
left: res.windowWidth / 2
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @param {Object} item
|
||||||
|
* 小于 10 在前面加个 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
lessThanTen(item) {
|
||||||
|
return item < 10 ? '0' + item : item
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析时分秒字符串,例如:00:00:00
|
||||||
|
* @param {String} timeString
|
||||||
|
*/
|
||||||
|
parseTimeType(timeString) {
|
||||||
|
if (timeString) {
|
||||||
|
let timeArr = timeString.split(':')
|
||||||
|
this.hour = Number(timeArr[0])
|
||||||
|
this.minute = Number(timeArr[1])
|
||||||
|
this.second = Number(timeArr[2])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
|
||||||
|
* @param {String | Number} datetime
|
||||||
|
*/
|
||||||
|
initPickerValue(datetime) {
|
||||||
|
let defaultValue = null
|
||||||
|
if (datetime) {
|
||||||
|
defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
|
||||||
|
} else {
|
||||||
|
defaultValue = Date.now()
|
||||||
|
defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
|
||||||
|
}
|
||||||
|
this.parseValue(defaultValue)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始值规则:
|
||||||
|
* - 用户设置初始值 value
|
||||||
|
* - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
|
||||||
|
* - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
|
||||||
|
* - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
|
||||||
|
* - 无起始终止时间,则初始值为 value
|
||||||
|
* - 无初始值 value,则初始值为当前本地时间 Date.now()
|
||||||
|
* @param {Object} value
|
||||||
|
* @param {Object} dateBase
|
||||||
|
*/
|
||||||
|
compareValueWithStartAndEnd(value, start, end) {
|
||||||
|
let winner = null
|
||||||
|
value = this.superTimeStamp(value)
|
||||||
|
start = this.superTimeStamp(start)
|
||||||
|
end = this.superTimeStamp(end)
|
||||||
|
|
||||||
|
if (start && end) {
|
||||||
|
if (value < start) {
|
||||||
|
winner = new Date(start)
|
||||||
|
} else if (value > end) {
|
||||||
|
winner = new Date(end)
|
||||||
|
} else {
|
||||||
|
winner = new Date(value)
|
||||||
|
}
|
||||||
|
} else if (start && !end) {
|
||||||
|
winner = start <= value ? new Date(value) : new Date(start)
|
||||||
|
} else if (!start && end) {
|
||||||
|
winner = value <= end ? new Date(value) : new Date(end)
|
||||||
|
} else {
|
||||||
|
winner = new Date(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return winner
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为可比较的时间戳,接受日期、时分秒、时间戳
|
||||||
|
* @param {Object} value
|
||||||
|
*/
|
||||||
|
superTimeStamp(value) {
|
||||||
|
let dateBase = ''
|
||||||
|
if (this.type === 'time' && value && typeof value === 'string') {
|
||||||
|
const now = new Date()
|
||||||
|
const year = now.getFullYear()
|
||||||
|
const month = now.getMonth() + 1
|
||||||
|
const day = now.getDate()
|
||||||
|
dateBase = year + '/' + month + '/' + day + ' '
|
||||||
|
}
|
||||||
|
if (Number(value)) {
|
||||||
|
value = parseInt(value)
|
||||||
|
dateBase = 0
|
||||||
|
}
|
||||||
|
return this.createTimeStamp(dateBase + value)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析默认值 value,字符串、时间戳
|
||||||
|
* @param {Object} defaultTime
|
||||||
|
*/
|
||||||
|
parseValue(value) {
|
||||||
|
if (!value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.type === 'time' && typeof value === "string") {
|
||||||
|
this.parseTimeType(value)
|
||||||
|
} else {
|
||||||
|
let defaultDate = null
|
||||||
|
defaultDate = new Date(value)
|
||||||
|
if (this.type !== 'time') {
|
||||||
|
this.year = defaultDate.getFullYear()
|
||||||
|
this.month = defaultDate.getMonth() + 1
|
||||||
|
this.day = defaultDate.getDate()
|
||||||
|
}
|
||||||
|
if (this.type !== 'date') {
|
||||||
|
this.hour = defaultDate.getHours()
|
||||||
|
this.minute = defaultDate.getMinutes()
|
||||||
|
this.second = defaultDate.getSeconds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.hideSecond) {
|
||||||
|
this.second = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析可选择时间范围 start、end,年月日字符串、时间戳
|
||||||
|
* @param {Object} defaultTime
|
||||||
|
*/
|
||||||
|
parseDatetimeRange(point, pointType) {
|
||||||
|
// 时间为空,则重置为初始值
|
||||||
|
if (!point) {
|
||||||
|
if (pointType === 'start') {
|
||||||
|
this.startYear = 1920
|
||||||
|
this.startMonth = 1
|
||||||
|
this.startDay = 1
|
||||||
|
this.startHour = 0
|
||||||
|
this.startMinute = 0
|
||||||
|
this.startSecond = 0
|
||||||
|
}
|
||||||
|
if (pointType === 'end') {
|
||||||
|
this.endYear = 2120
|
||||||
|
this.endMonth = 12
|
||||||
|
this.endDay = 31
|
||||||
|
this.endHour = 23
|
||||||
|
this.endMinute = 59
|
||||||
|
this.endSecond = 59
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.type === 'time') {
|
||||||
|
const pointArr = point.split(':')
|
||||||
|
this[pointType + 'Hour'] = Number(pointArr[0])
|
||||||
|
this[pointType + 'Minute'] = Number(pointArr[1])
|
||||||
|
this[pointType + 'Second'] = Number(pointArr[2])
|
||||||
|
} else {
|
||||||
|
if (!point) {
|
||||||
|
pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Number(point)) {
|
||||||
|
point = parseInt(point)
|
||||||
|
}
|
||||||
|
// datetime 的 end 没有时分秒, 则不限制
|
||||||
|
const hasTime = /[0-9]:[0-9]/
|
||||||
|
if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
|
||||||
|
point)) {
|
||||||
|
point = point + ' 23:59:59'
|
||||||
|
}
|
||||||
|
const pointDate = new Date(point)
|
||||||
|
this[pointType + 'Year'] = pointDate.getFullYear()
|
||||||
|
this[pointType + 'Month'] = pointDate.getMonth() + 1
|
||||||
|
this[pointType + 'Day'] = pointDate.getDate()
|
||||||
|
if (this.type === 'datetime') {
|
||||||
|
this[pointType + 'Hour'] = pointDate.getHours()
|
||||||
|
this[pointType + 'Minute'] = pointDate.getMinutes()
|
||||||
|
this[pointType + 'Second'] = pointDate.getSeconds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取 年、月、日、时、分、秒 当前可选范围
|
||||||
|
getCurrentRange(value) {
|
||||||
|
const range = []
|
||||||
|
for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
|
||||||
|
range.push(i)
|
||||||
|
}
|
||||||
|
return range
|
||||||
|
},
|
||||||
|
|
||||||
|
// 字符串首字母大写
|
||||||
|
capitalize(str) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||||
|
checkValue(name, value, values) {
|
||||||
|
if (values.indexOf(value) === -1) {
|
||||||
|
this[name] = values[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 每个月的实际天数
|
||||||
|
daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
|
||||||
|
return new Date(year, month, 0).getDate();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成时间戳
|
||||||
|
* @param {Object} time
|
||||||
|
*/
|
||||||
|
createTimeStamp(time) {
|
||||||
|
if (!time) return
|
||||||
|
if (typeof time === "number") {
|
||||||
|
return time
|
||||||
|
} else {
|
||||||
|
time = time.replace(/-/g, '/')
|
||||||
|
if (this.type === 'date') {
|
||||||
|
time = time + ' ' + '00:00:00'
|
||||||
|
}
|
||||||
|
return Date.parse(time)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成日期或时间的字符串
|
||||||
|
*/
|
||||||
|
createDomSting() {
|
||||||
|
const yymmdd = this.year +
|
||||||
|
'-' +
|
||||||
|
this.lessThanTen(this.month) +
|
||||||
|
'-' +
|
||||||
|
this.lessThanTen(this.day)
|
||||||
|
|
||||||
|
let hhmmss = this.lessThanTen(this.hour) +
|
||||||
|
':' +
|
||||||
|
this.lessThanTen(this.minute)
|
||||||
|
|
||||||
|
if (!this.hideSecond) {
|
||||||
|
hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type === 'date') {
|
||||||
|
return yymmdd
|
||||||
|
} else if (this.type === 'time') {
|
||||||
|
return hhmmss
|
||||||
|
} else {
|
||||||
|
return yymmdd + ' ' + hhmmss
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化返回值,并抛出 change 事件
|
||||||
|
*/
|
||||||
|
initTime(emit = true) {
|
||||||
|
this.time = this.createDomSting()
|
||||||
|
if (!emit) return
|
||||||
|
if (this.returnType === 'timestamp' && this.type !== 'time') {
|
||||||
|
this.$emit('change', this.createTimeStamp(this.time))
|
||||||
|
this.$emit('input', this.createTimeStamp(this.time))
|
||||||
|
this.$emit('update:modelValue', this.createTimeStamp(this.time))
|
||||||
|
} else {
|
||||||
|
this.$emit('change', this.time)
|
||||||
|
this.$emit('input', this.time)
|
||||||
|
this.$emit('update:modelValue', this.time)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户选择日期或时间更新 data
|
||||||
|
* @param {Object} e
|
||||||
|
*/
|
||||||
|
bindDateChange(e) {
|
||||||
|
const val = e.detail.value
|
||||||
|
this.year = this.years[val[0]]
|
||||||
|
this.month = this.months[val[1]]
|
||||||
|
this.day = this.days[val[2]]
|
||||||
|
},
|
||||||
|
bindTimeChange(e) {
|
||||||
|
const val = e.detail.value
|
||||||
|
this.hour = this.hours[val[0]]
|
||||||
|
this.minute = this.minutes[val[1]]
|
||||||
|
this.second = this.seconds[val[2]]
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化弹出层
|
||||||
|
*/
|
||||||
|
initTimePicker() {
|
||||||
|
if (this.disabled) return
|
||||||
|
const value = fixIosDateFormat(this.time)
|
||||||
|
this.initPickerValue(value)
|
||||||
|
this.visible = !this.visible
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发或关闭弹框
|
||||||
|
*/
|
||||||
|
tiggerTimePicker(e) {
|
||||||
|
this.visible = !this.visible
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户点击“清空”按钮,清空当前值
|
||||||
|
*/
|
||||||
|
clearTime() {
|
||||||
|
this.time = ''
|
||||||
|
this.$emit('change', this.time)
|
||||||
|
this.$emit('input', this.time)
|
||||||
|
this.$emit('update:modelValue', this.time)
|
||||||
|
this.tiggerTimePicker()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户点击“确定”按钮
|
||||||
|
*/
|
||||||
|
setTime() {
|
||||||
|
this.initTime()
|
||||||
|
this.tiggerTimePicker()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$uni-primary: #007aff !default;
|
||||||
|
|
||||||
|
.uni-datetime-picker {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
/* width: 100%; */
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-view {
|
||||||
|
height: 130px;
|
||||||
|
width: 270px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-item {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-btn {
|
||||||
|
margin-top: 60px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-btn-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $uni-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-btn-group {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-cancel {
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-mask {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0px;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
z-index: 998;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-popup {
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 30px;
|
||||||
|
width: 270px;
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
height: 500px;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
width: 330px;
|
||||||
|
/* #endif */
|
||||||
|
background-color: #fff;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-nvue-height {
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
height: 330px;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-time {
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-column {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-timebox {
|
||||||
|
|
||||||
|
border: 1px solid #E5E5E5;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 7px 10px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-timebox-pointer {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.uni-datetime-picker-disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 50px
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker-sign {
|
||||||
|
position: absolute;
|
||||||
|
top: 53px;
|
||||||
|
/* 减掉 10px 的元素高度,兼容nvue */
|
||||||
|
color: #999;
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
font-size: 16px;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-left {
|
||||||
|
left: 86px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-right {
|
||||||
|
right: 86px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-center {
|
||||||
|
left: 135px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-datetime-picker__container-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-hide-second {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,421 @@
|
|||||||
|
class Calendar {
|
||||||
|
constructor({
|
||||||
|
selected,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
range,
|
||||||
|
} = {}) {
|
||||||
|
// 当前日期
|
||||||
|
this.date = this.getDateObj(new Date()) // 当前初入日期
|
||||||
|
// 打点信息
|
||||||
|
this.selected = selected || [];
|
||||||
|
// 起始时间
|
||||||
|
this.startDate = startDate
|
||||||
|
// 终止时间
|
||||||
|
this.endDate = endDate
|
||||||
|
// 是否范围选择
|
||||||
|
this.range = range
|
||||||
|
// 多选状态
|
||||||
|
this.cleanMultipleStatus()
|
||||||
|
// 每周日期
|
||||||
|
this.weeks = {}
|
||||||
|
this.lastHover = false
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置日期
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
setDate(date) {
|
||||||
|
const selectDate = this.getDateObj(date)
|
||||||
|
this.getWeeks(selectDate.fullDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理多选状态
|
||||||
|
*/
|
||||||
|
cleanMultipleStatus() {
|
||||||
|
this.multipleStatus = {
|
||||||
|
before: '',
|
||||||
|
after: '',
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setStartDate(startDate) {
|
||||||
|
this.startDate = startDate
|
||||||
|
}
|
||||||
|
|
||||||
|
setEndDate(endDate) {
|
||||||
|
this.endDate = endDate
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreMonthObj(date) {
|
||||||
|
date = fixIosDateFormat(date)
|
||||||
|
date = new Date(date)
|
||||||
|
|
||||||
|
const oldMonth = date.getMonth()
|
||||||
|
date.setMonth(oldMonth - 1)
|
||||||
|
const newMonth = date.getMonth()
|
||||||
|
if (oldMonth !== 0 && newMonth - oldMonth === 0) {
|
||||||
|
date.setMonth(newMonth - 1)
|
||||||
|
}
|
||||||
|
return this.getDateObj(date)
|
||||||
|
}
|
||||||
|
getNextMonthObj(date) {
|
||||||
|
date = fixIosDateFormat(date)
|
||||||
|
date = new Date(date)
|
||||||
|
|
||||||
|
const oldMonth = date.getMonth()
|
||||||
|
date.setMonth(oldMonth + 1)
|
||||||
|
const newMonth = date.getMonth()
|
||||||
|
if (newMonth - oldMonth > 1) {
|
||||||
|
date.setMonth(newMonth - 1)
|
||||||
|
}
|
||||||
|
return this.getDateObj(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定格式Date对象
|
||||||
|
*/
|
||||||
|
getDateObj(date) {
|
||||||
|
date = fixIosDateFormat(date)
|
||||||
|
date = new Date(date)
|
||||||
|
|
||||||
|
return {
|
||||||
|
fullDate: getDate(date),
|
||||||
|
year: date.getFullYear(),
|
||||||
|
month: addZero(date.getMonth() + 1),
|
||||||
|
date: addZero(date.getDate()),
|
||||||
|
day: date.getDay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取上一个月日期集合
|
||||||
|
*/
|
||||||
|
getPreMonthDays(amount, dateObj) {
|
||||||
|
const result = []
|
||||||
|
for (let i = amount - 1; i >= 0; i--) {
|
||||||
|
const month = dateObj.month - 1
|
||||||
|
result.push({
|
||||||
|
date: new Date(dateObj.year, month, -i).getDate(),
|
||||||
|
month,
|
||||||
|
disable: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取本月日期集合
|
||||||
|
*/
|
||||||
|
getCurrentMonthDays(amount, dateObj) {
|
||||||
|
const result = []
|
||||||
|
const fullDate = this.date.fullDate
|
||||||
|
for (let i = 1; i <= amount; i++) {
|
||||||
|
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
|
||||||
|
const isToday = fullDate === currentDate
|
||||||
|
// 获取打点信息
|
||||||
|
const info = this.selected && this.selected.find((item) => {
|
||||||
|
if (this.dateEqual(currentDate, item.date)) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 日期禁用
|
||||||
|
let disableBefore = true
|
||||||
|
let disableAfter = true
|
||||||
|
if (this.startDate) {
|
||||||
|
disableBefore = dateCompare(this.startDate, currentDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.endDate) {
|
||||||
|
disableAfter = dateCompare(currentDate, this.endDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
let multiples = this.multipleStatus.data
|
||||||
|
let multiplesStatus = -1
|
||||||
|
if (this.range && multiples) {
|
||||||
|
multiplesStatus = multiples.findIndex((item) => {
|
||||||
|
return this.dateEqual(item, currentDate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const checked = multiplesStatus !== -1
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
fullDate: currentDate,
|
||||||
|
year: dateObj.year,
|
||||||
|
date: i,
|
||||||
|
multiple: this.range ? checked : false,
|
||||||
|
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||||
|
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||||
|
month: dateObj.month,
|
||||||
|
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
|
||||||
|
currentDate, this.endDate)),
|
||||||
|
isToday,
|
||||||
|
userChecked: false,
|
||||||
|
extraInfo: info
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取下一个月日期集合
|
||||||
|
*/
|
||||||
|
_getNextMonthDays(amount, dateObj) {
|
||||||
|
const result = []
|
||||||
|
const month = dateObj.month + 1
|
||||||
|
for (let i = 1; i <= amount; i++) {
|
||||||
|
result.push({
|
||||||
|
date: i,
|
||||||
|
month,
|
||||||
|
disable: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前日期详情
|
||||||
|
* @param {Object} date
|
||||||
|
*/
|
||||||
|
getInfo(date) {
|
||||||
|
if (!date) {
|
||||||
|
date = new Date()
|
||||||
|
}
|
||||||
|
const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
|
||||||
|
return res ? res : this.getDateObj(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较时间是否相等
|
||||||
|
*/
|
||||||
|
dateEqual(before, after) {
|
||||||
|
before = new Date(fixIosDateFormat(before))
|
||||||
|
after = new Date(fixIosDateFormat(after))
|
||||||
|
return before.valueOf() === after.valueOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较真实起始日期
|
||||||
|
*/
|
||||||
|
|
||||||
|
isLogicBefore(currentDate, before, after) {
|
||||||
|
let logicBefore = before
|
||||||
|
if (before && after) {
|
||||||
|
logicBefore = dateCompare(before, after) ? before : after
|
||||||
|
}
|
||||||
|
return this.dateEqual(logicBefore, currentDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
isLogicAfter(currentDate, before, after) {
|
||||||
|
let logicAfter = after
|
||||||
|
if (before && after) {
|
||||||
|
logicAfter = dateCompare(before, after) ? after : before
|
||||||
|
}
|
||||||
|
return this.dateEqual(logicAfter, currentDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日期范围内所有日期
|
||||||
|
* @param {Object} begin
|
||||||
|
* @param {Object} end
|
||||||
|
*/
|
||||||
|
geDateAll(begin, end) {
|
||||||
|
var arr = []
|
||||||
|
var ab = begin.split('-')
|
||||||
|
var ae = end.split('-')
|
||||||
|
var db = new Date()
|
||||||
|
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||||||
|
var de = new Date()
|
||||||
|
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||||||
|
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||||
|
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||||
|
for (var k = unixDb; k <= unixDe;) {
|
||||||
|
k = k + 24 * 60 * 60 * 1000
|
||||||
|
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取多选状态
|
||||||
|
*/
|
||||||
|
setMultiple(fullDate) {
|
||||||
|
if (!this.range) return
|
||||||
|
|
||||||
|
let {
|
||||||
|
before,
|
||||||
|
after
|
||||||
|
} = this.multipleStatus
|
||||||
|
if (before && after) {
|
||||||
|
if (!this.lastHover) {
|
||||||
|
this.lastHover = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.multipleStatus.before = fullDate
|
||||||
|
this.multipleStatus.after = ''
|
||||||
|
this.multipleStatus.data = []
|
||||||
|
this.multipleStatus.fulldate = ''
|
||||||
|
this.lastHover = false
|
||||||
|
} else {
|
||||||
|
if (!before) {
|
||||||
|
this.multipleStatus.before = fullDate
|
||||||
|
this.multipleStatus.after = undefined;
|
||||||
|
this.lastHover = false
|
||||||
|
} else {
|
||||||
|
this.multipleStatus.after = fullDate
|
||||||
|
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||||
|
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
|
||||||
|
.after);
|
||||||
|
} else {
|
||||||
|
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
|
||||||
|
.before);
|
||||||
|
}
|
||||||
|
this.lastHover = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getWeeks(fullDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鼠标 hover 更新多选状态
|
||||||
|
*/
|
||||||
|
setHoverMultiple(fullDate) {
|
||||||
|
//抖音小程序点击会触发hover事件,需要避免一下
|
||||||
|
// #ifndef MP-TOUTIAO
|
||||||
|
if (!this.range || this.lastHover) return
|
||||||
|
const {
|
||||||
|
before
|
||||||
|
} = this.multipleStatus
|
||||||
|
|
||||||
|
if (!before) {
|
||||||
|
this.multipleStatus.before = fullDate
|
||||||
|
} else {
|
||||||
|
this.multipleStatus.after = fullDate
|
||||||
|
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||||
|
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||||||
|
} else {
|
||||||
|
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getWeeks(fullDate)
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新默认值多选状态
|
||||||
|
*/
|
||||||
|
setDefaultMultiple(before, after) {
|
||||||
|
this.multipleStatus.before = before
|
||||||
|
this.multipleStatus.after = after
|
||||||
|
if (before && after) {
|
||||||
|
if (dateCompare(before, after)) {
|
||||||
|
this.multipleStatus.data = this.geDateAll(before, after);
|
||||||
|
this.getWeeks(after)
|
||||||
|
} else {
|
||||||
|
this.multipleStatus.data = this.geDateAll(after, before);
|
||||||
|
this.getWeeks(before)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取每周数据
|
||||||
|
* @param {Object} dateData
|
||||||
|
*/
|
||||||
|
getWeeks(dateData) {
|
||||||
|
const {
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
} = this.getDateObj(dateData)
|
||||||
|
|
||||||
|
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
|
||||||
|
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
|
||||||
|
|
||||||
|
const currentMonthDayAmount = new Date(year, month, 0).getDate()
|
||||||
|
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
|
||||||
|
|
||||||
|
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
|
||||||
|
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
|
||||||
|
|
||||||
|
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
|
||||||
|
|
||||||
|
const weeks = new Array(6)
|
||||||
|
for (let i = 0; i < calendarDays.length; i++) {
|
||||||
|
const index = Math.floor(i / 7)
|
||||||
|
if (!weeks[index]) {
|
||||||
|
weeks[index] = new Array(7)
|
||||||
|
}
|
||||||
|
weeks[index][i % 7] = calendarDays[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.calendar = calendarDays
|
||||||
|
this.weeks = weeks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDateTime(date, hideSecond) {
|
||||||
|
return `${getDate(date)} ${getTime(date, hideSecond)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDate(date) {
|
||||||
|
date = fixIosDateFormat(date)
|
||||||
|
date = new Date(date)
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
return `${year}-${addZero(month)}-${addZero(day)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTime(date, hideSecond) {
|
||||||
|
date = fixIosDateFormat(date)
|
||||||
|
date = new Date(date)
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function addZero(num) {
|
||||||
|
if (num < 10) {
|
||||||
|
num = `0${num}`
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultSecond(hideSecond) {
|
||||||
|
return hideSecond ? '00:00' : '00:00:00'
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateCompare(startDate, endDate) {
|
||||||
|
startDate = new Date(fixIosDateFormat(startDate))
|
||||||
|
endDate = new Date(fixIosDateFormat(endDate))
|
||||||
|
return startDate <= endDate
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDate(date) {
|
||||||
|
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||||||
|
return date.match(dateReg)
|
||||||
|
}
|
||||||
|
//ios低版本15及以下,无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
|
||||||
|
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
|
||||||
|
|
||||||
|
function fixIosDateFormat(value) {
|
||||||
|
if (typeof value === 'string' && dateTimeReg.test(value)) {
|
||||||
|
value = value.replace(/-/g, '/')
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Calendar,
|
||||||
|
getDateTime,
|
||||||
|
getDate,
|
||||||
|
getTime,
|
||||||
|
addZero,
|
||||||
|
getDefaultSecond,
|
||||||
|
dateCompare,
|
||||||
|
checkDate,
|
||||||
|
fixIosDateFormat
|
||||||
|
}
|
||||||
90
src/uni_modules/uni-datetime-picker/package.json
Normal file
90
src/uni_modules/uni-datetime-picker/package.json
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-datetime-picker",
|
||||||
|
"displayName": "uni-datetime-picker 日期选择器",
|
||||||
|
"version": "2.2.40",
|
||||||
|
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
|
||||||
|
"keywords": [
|
||||||
|
"uni-datetime-picker",
|
||||||
|
"uni-ui",
|
||||||
|
"uniui",
|
||||||
|
"日期时间选择器",
|
||||||
|
"日期时间"
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": ""
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [
|
||||||
|
"uni-scss",
|
||||||
|
"uni-icons"
|
||||||
|
],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "n",
|
||||||
|
"app-harmony": "u",
|
||||||
|
"app-uvue": "u"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/uni_modules/uni-datetime-picker/readme.md
Normal file
21
src/uni_modules/uni-datetime-picker/readme.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
|
||||||
|
> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
|
||||||
|
|
||||||
|
## DatetimePicker 时间选择器
|
||||||
|
|
||||||
|
> **组件名:uni-datetime-picker**
|
||||||
|
> 代码块: `uDatetimePicker`
|
||||||
|
|
||||||
|
|
||||||
|
该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
|
||||||
|
|
||||||
|
若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
|
||||||
|
|
||||||
|
**_点击 picker 默认值规则:_**
|
||||||
|
|
||||||
|
- 若设置初始值 value, 会显示在 picker 显示框中
|
||||||
|
- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
115
src/uni_modules/uni-easyinput/changelog.md
Normal file
115
src/uni_modules/uni-easyinput/changelog.md
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
## 1.1.19(2024-07-18)
|
||||||
|
- 修复 初始值传入 null 导致input报错的bug
|
||||||
|
## 1.1.18(2024-04-11)
|
||||||
|
- 修复 easyinput组件双向绑定问题
|
||||||
|
## 1.1.17(2024-03-28)
|
||||||
|
- 修复 在头条小程序下丢失事件绑定的问题
|
||||||
|
## 1.1.16(2024-03-20)
|
||||||
|
- 修复 在密码输入情况下 清除和小眼睛覆盖bug 在edge浏览器下显示双眼睛bug
|
||||||
|
## 1.1.15(2024-02-21)
|
||||||
|
- 新增 左侧插槽:left
|
||||||
|
## 1.1.14(2024-02-19)
|
||||||
|
- 修复 onBlur的emit传值错误
|
||||||
|
## 1.1.12(2024-01-29)
|
||||||
|
- 补充 adjust-position文档属性补充
|
||||||
|
## 1.1.11(2024-01-29)
|
||||||
|
- 补充 adjust-position属性传递值:(Boolean)当键盘弹起时,是否自动上推页面
|
||||||
|
## 1.1.10(2024-01-22)
|
||||||
|
- 去除 移除无用的log输出
|
||||||
|
## 1.1.9(2023-04-11)
|
||||||
|
- 修复 vue3 下 keyboardheightchange 事件报错的bug
|
||||||
|
## 1.1.8(2023-03-29)
|
||||||
|
- 优化 trim 属性默认值
|
||||||
|
## 1.1.7(2023-03-29)
|
||||||
|
- 新增 cursor-spacing 属性
|
||||||
|
## 1.1.6(2023-01-28)
|
||||||
|
- 新增 keyboardheightchange 事件,可监听键盘高度变化
|
||||||
|
## 1.1.5(2022-11-29)
|
||||||
|
- 优化 主题样式
|
||||||
|
## 1.1.4(2022-10-27)
|
||||||
|
- 修复 props 中背景颜色无默认值的bug
|
||||||
|
## 1.1.0(2022-06-30)
|
||||||
|
|
||||||
|
- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
|
||||||
|
- 新增 clear 事件,点击右侧叉号图标触发
|
||||||
|
- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
|
||||||
|
- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
|
||||||
|
|
||||||
|
## 1.0.5(2022-06-07)
|
||||||
|
|
||||||
|
- 优化 clearable 显示策略
|
||||||
|
|
||||||
|
## 1.0.4(2022-06-07)
|
||||||
|
|
||||||
|
- 优化 clearable 显示策略
|
||||||
|
|
||||||
|
## 1.0.3(2022-05-20)
|
||||||
|
|
||||||
|
- 修复 关闭图标某些情况下无法取消的 bug
|
||||||
|
|
||||||
|
## 1.0.2(2022-04-12)
|
||||||
|
|
||||||
|
- 修复 默认值不生效的 bug
|
||||||
|
|
||||||
|
## 1.0.1(2022-04-02)
|
||||||
|
|
||||||
|
- 修复 value 不能为 0 的 bug
|
||||||
|
|
||||||
|
## 1.0.0(2021-11-19)
|
||||||
|
|
||||||
|
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
|
||||||
|
|
||||||
|
## 0.1.4(2021-08-20)
|
||||||
|
|
||||||
|
- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
|
||||||
|
|
||||||
|
## 0.1.3(2021-08-11)
|
||||||
|
|
||||||
|
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
|
||||||
|
|
||||||
|
## 0.1.2(2021-07-30)
|
||||||
|
|
||||||
|
- 优化 vue3 下事件警告的问题
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- 优化 errorMessage 属性支持 Boolean 类型
|
||||||
|
|
||||||
|
## 0.1.0(2021-07-13)
|
||||||
|
|
||||||
|
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||||
|
|
||||||
|
## 0.0.16(2021-06-29)
|
||||||
|
|
||||||
|
- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
|
||||||
|
|
||||||
|
## 0.0.15(2021-06-21)
|
||||||
|
|
||||||
|
- 修复 passwordIcon 属性拼写错误的 bug
|
||||||
|
|
||||||
|
## 0.0.14(2021-06-18)
|
||||||
|
|
||||||
|
- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标
|
||||||
|
- 修复 confirmType 属性不生效的问题
|
||||||
|
|
||||||
|
## 0.0.13(2021-06-04)
|
||||||
|
|
||||||
|
- 修复 disabled 状态可清出内容的 bug
|
||||||
|
|
||||||
|
## 0.0.12(2021-05-12)
|
||||||
|
|
||||||
|
- 新增 组件示例地址
|
||||||
|
|
||||||
|
## 0.0.11(2021-05-07)
|
||||||
|
|
||||||
|
- 修复 input-border 属性不生效的问题
|
||||||
|
|
||||||
|
## 0.0.10(2021-04-30)
|
||||||
|
|
||||||
|
- 修复 ios 遮挡文字、显示一半的问题
|
||||||
|
|
||||||
|
## 0.0.9(2021-02-05)
|
||||||
|
|
||||||
|
- 调整为 uni_modules 目录规范
|
||||||
|
- 优化 兼容 nvue 页面
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @desc 函数防抖
|
||||||
|
* @param func 目标函数
|
||||||
|
* @param wait 延迟执行毫秒数
|
||||||
|
* @param immediate true - 立即执行, false - 延迟执行
|
||||||
|
*/
|
||||||
|
export const debounce = function(func, wait = 1000, immediate = true) {
|
||||||
|
let timer;
|
||||||
|
return function() {
|
||||||
|
let context = this,
|
||||||
|
args = arguments;
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
if (immediate) {
|
||||||
|
let callNow = !timer;
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
timer = null;
|
||||||
|
}, wait);
|
||||||
|
if (callNow) func.apply(context, args);
|
||||||
|
} else {
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
func.apply(context, args);
|
||||||
|
}, wait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @desc 函数节流
|
||||||
|
* @param func 函数
|
||||||
|
* @param wait 延迟执行毫秒数
|
||||||
|
* @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
|
||||||
|
*/
|
||||||
|
export const throttle = (func, wait = 1000, type = 1) => {
|
||||||
|
let previous = 0;
|
||||||
|
let timeout;
|
||||||
|
return function() {
|
||||||
|
let context = this;
|
||||||
|
let args = arguments;
|
||||||
|
if (type === 1) {
|
||||||
|
let now = Date.now();
|
||||||
|
|
||||||
|
if (now - previous > wait) {
|
||||||
|
func.apply(context, args);
|
||||||
|
previous = now;
|
||||||
|
}
|
||||||
|
} else if (type === 2) {
|
||||||
|
if (!timeout) {
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
timeout = null;
|
||||||
|
func.apply(context, args)
|
||||||
|
}, wait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,676 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
|
||||||
|
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
|
||||||
|
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')" size="22"></uni-icons>
|
||||||
|
<slot name="left">
|
||||||
|
</slot>
|
||||||
|
<!-- #ifdef MP-ALIPAY -->
|
||||||
|
<textarea :enableNative="enableNative" v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
|
||||||
|
<input :enableNative="enableNative" v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-ALIPAY -->
|
||||||
|
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{ 'input-padding': inputBorder }" :name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange"></textarea>
|
||||||
|
<input v-else :type="type === 'password' ? 'text' : type" class="uni-easyinput__content-input" :style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder" :placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" :cursor-spacing="cursorSpacing" :adjust-position="adjustPosition" @focus="_Focus" @blur="_Blur" @input="onInput" @confirm="onConfirm" @keyboardheightchange="onkeyboardheightchange" />
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<template v-if="type === 'password' && passwordIcon">
|
||||||
|
<!-- 开启密码时显示小眼睛 -->
|
||||||
|
<uni-icons v-if="isVal" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" :type="showPassword ? 'eye-slash-filled' : 'eye-filled'" :size="22" :color="focusShow ? primaryColor : '#c0c4cc'" @click="onEyes"></uni-icons>
|
||||||
|
</template>
|
||||||
|
<template v-if="suffixIcon">
|
||||||
|
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')" size="22"></uni-icons>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon" :class="{ 'is-textarea-icon': type === 'textarea' }" type="clear" :size="clearSize" :color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'" @click="onClear"></uni-icons>
|
||||||
|
</template>
|
||||||
|
<slot name="right"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* Easyinput 输入框
|
||||||
|
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=3455
|
||||||
|
* @property {String} value 输入内容
|
||||||
|
* @property {String } type 输入框的类型(默认text) password/text/textarea/..
|
||||||
|
* @value text 文本输入键盘
|
||||||
|
* @value textarea 多行文本输入键盘
|
||||||
|
* @value password 密码输入键盘
|
||||||
|
* @value number 数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
|
||||||
|
* @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
|
||||||
|
* @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
|
||||||
|
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
|
||||||
|
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true)
|
||||||
|
* @property {String } placeholder 输入框的提示文字
|
||||||
|
* @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
|
||||||
|
* @property {Boolean} focus 是否自动获得焦点(默认false)
|
||||||
|
* @property {Boolean} disabled 是否禁用(默认false)
|
||||||
|
* @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
|
||||||
|
* @property {String } confirmType 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
|
||||||
|
* @property {Number } clearSize 清除图标的大小,单位px(默认15)
|
||||||
|
* @property {String} prefixIcon 输入框头部图标
|
||||||
|
* @property {String} suffixIcon 输入框尾部图标
|
||||||
|
* @property {String} primaryColor 设置主题色(默认#2979ff)
|
||||||
|
* @property {Boolean} trim 是否自动去除两端的空格
|
||||||
|
* @property {Boolean} cursorSpacing 指定光标与键盘的距离,单位 px
|
||||||
|
* @property {Boolean} ajust-position 当键盘弹起时,是否上推内容,默认值:true
|
||||||
|
* @value both 去除两端空格
|
||||||
|
* @value left 去除左侧空格
|
||||||
|
* @value right 去除右侧空格
|
||||||
|
* @value start 去除左侧空格
|
||||||
|
* @value end 去除右侧空格
|
||||||
|
* @value all 去除全部空格
|
||||||
|
* @value none 不去除空格
|
||||||
|
* @property {Boolean} inputBorder 是否显示input输入框的边框(默认true)
|
||||||
|
* @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
|
||||||
|
* @property {Object} styles 自定义颜色
|
||||||
|
* @event {Function} input 输入框内容发生变化时触发
|
||||||
|
* @event {Function} focus 输入框获得焦点时触发
|
||||||
|
* @event {Function} blur 输入框失去焦点时触发
|
||||||
|
* @event {Function} confirm 点击完成按钮时触发
|
||||||
|
* @event {Function} iconClick 点击图标时触发
|
||||||
|
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
|
||||||
|
*/
|
||||||
|
function obj2strClass(obj) {
|
||||||
|
let classess = '';
|
||||||
|
for (let key in obj) {
|
||||||
|
const val = obj[key];
|
||||||
|
if (val) {
|
||||||
|
classess += `${key} `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classess;
|
||||||
|
}
|
||||||
|
|
||||||
|
function obj2strStyle(obj) {
|
||||||
|
let style = '';
|
||||||
|
for (let key in obj) {
|
||||||
|
const val = obj[key];
|
||||||
|
style += `${key}:${val};`;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
name: 'uni-easyinput',
|
||||||
|
emits: [
|
||||||
|
'click',
|
||||||
|
'iconClick',
|
||||||
|
'update:modelValue',
|
||||||
|
'input',
|
||||||
|
'focus',
|
||||||
|
'blur',
|
||||||
|
'confirm',
|
||||||
|
'clear',
|
||||||
|
'eyes',
|
||||||
|
'change',
|
||||||
|
'keyboardheightchange'
|
||||||
|
],
|
||||||
|
model: {
|
||||||
|
prop: 'modelValue',
|
||||||
|
event: 'update:modelValue'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
virtualHost: false,
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-TOUTIAO
|
||||||
|
virtualHost: true
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
form: {
|
||||||
|
from: 'uniForm',
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
formItem: {
|
||||||
|
from: 'uniFormItem',
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
value: [Number, String],
|
||||||
|
modelValue: [Number, String],
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ' '
|
||||||
|
},
|
||||||
|
placeholderStyle: String,
|
||||||
|
focus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 140
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String,
|
||||||
|
default: 'done'
|
||||||
|
},
|
||||||
|
clearSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
inputBorder: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
prefixIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
suffixIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
trim: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
cursorSpacing: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
passwordIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
adjustPosition: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
primaryColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {
|
||||||
|
color: '#333',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
disableColor: '#F7F6F6',
|
||||||
|
borderColor: '#e5e5e5'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorMessage: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
enableNative: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
focused: false,
|
||||||
|
val: '',
|
||||||
|
showMsg: '',
|
||||||
|
border: false,
|
||||||
|
isFirstBorder: false,
|
||||||
|
showClearIcon: false,
|
||||||
|
showPassword: false,
|
||||||
|
focusShow: false,
|
||||||
|
localMsg: '',
|
||||||
|
isEnter: false // 用于判断当前是否是使用回车操作
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 输入框内是否有值
|
||||||
|
isVal() {
|
||||||
|
const val = this.val;
|
||||||
|
// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
|
||||||
|
if (val || val === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
msg() {
|
||||||
|
// console.log('computed', this.form, this.formItem);
|
||||||
|
// if (this.form) {
|
||||||
|
// return this.errorMessage || this.formItem.errMsg;
|
||||||
|
// }
|
||||||
|
// TODO 处理头条 formItem 中 errMsg 不更新的问题
|
||||||
|
return this.localMsg || this.errorMessage;
|
||||||
|
},
|
||||||
|
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
|
||||||
|
inputMaxlength() {
|
||||||
|
return Number(this.maxlength);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理外层样式的style
|
||||||
|
boxStyle() {
|
||||||
|
return `color:${
|
||||||
|
this.inputBorder && this.msg ? '#e43d33' : this.styles.color
|
||||||
|
};`;
|
||||||
|
},
|
||||||
|
// input 内容的类和样式处理
|
||||||
|
inputContentClass() {
|
||||||
|
return obj2strClass({
|
||||||
|
'is-input-border': this.inputBorder,
|
||||||
|
'is-input-error-border': this.inputBorder && this.msg,
|
||||||
|
'is-textarea': this.type === 'textarea',
|
||||||
|
'is-disabled': this.disabled,
|
||||||
|
'is-focused': this.focusShow
|
||||||
|
});
|
||||||
|
},
|
||||||
|
inputContentStyle() {
|
||||||
|
const focusColor = this.focusShow ?
|
||||||
|
this.primaryColor :
|
||||||
|
this.styles.borderColor;
|
||||||
|
const borderColor =
|
||||||
|
this.inputBorder && this.msg ? '#dd524d' : focusColor;
|
||||||
|
return obj2strStyle({
|
||||||
|
'border-color': borderColor || '#e5e5e5',
|
||||||
|
'background-color': this.disabled ?
|
||||||
|
this.styles.disableColor : this.styles.backgroundColor
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// input右侧样式
|
||||||
|
inputStyle() {
|
||||||
|
const paddingRight =
|
||||||
|
this.type === 'password' || this.clearable || this.prefixIcon ?
|
||||||
|
'' :
|
||||||
|
'10px';
|
||||||
|
return obj2strStyle({
|
||||||
|
'padding-right': paddingRight,
|
||||||
|
'padding-left': this.prefixIcon ? '' : '10px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newVal) {
|
||||||
|
// fix by mehaotian 解决 值为null的情况下,input报错的bug
|
||||||
|
if (newVal === null) {
|
||||||
|
this.val = '';
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.val = newVal;
|
||||||
|
},
|
||||||
|
modelValue(newVal) {
|
||||||
|
if (newVal === null) {
|
||||||
|
this.val = '';
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.val = newVal;
|
||||||
|
},
|
||||||
|
focus(newVal) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focused = this.focus;
|
||||||
|
this.focusShow = this.focus;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
|
||||||
|
if (this.form && this.formItem) {
|
||||||
|
this.$watch('formItem.errMsg', newVal => {
|
||||||
|
this.localMsg = newVal;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focused = this.focus;
|
||||||
|
this.focusShow = this.focus;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 初始化变量值
|
||||||
|
*/
|
||||||
|
init() {
|
||||||
|
if (this.value || this.value === 0) {
|
||||||
|
this.val = this.value;
|
||||||
|
} else if (
|
||||||
|
this.modelValue ||
|
||||||
|
this.modelValue === 0 ||
|
||||||
|
this.modelValue === ''
|
||||||
|
) {
|
||||||
|
this.val = this.modelValue;
|
||||||
|
} else {
|
||||||
|
// fix by ht 如果初始值为null,则input报错,待框架修复
|
||||||
|
this.val = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击图标时触发
|
||||||
|
* @param {Object} type
|
||||||
|
*/
|
||||||
|
onClickIcon(type) {
|
||||||
|
this.$emit('iconClick', type);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示隐藏内容,密码框时生效
|
||||||
|
*/
|
||||||
|
onEyes() {
|
||||||
|
this.showPassword = !this.showPassword;
|
||||||
|
this.$emit('eyes', this.showPassword);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入时触发
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
onInput(event) {
|
||||||
|
let value = event.detail.value;
|
||||||
|
// 判断是否去除空格
|
||||||
|
if (this.trim) {
|
||||||
|
if (typeof this.trim === 'boolean' && this.trim) {
|
||||||
|
value = this.trimStr(value);
|
||||||
|
}
|
||||||
|
if (typeof this.trim === 'string') {
|
||||||
|
value = this.trimStr(value, this.trim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.errMsg) this.errMsg = '';
|
||||||
|
this.val = value;
|
||||||
|
// TODO 兼容 vue2
|
||||||
|
this.$emit('input', value);
|
||||||
|
// TODO 兼容 vue3
|
||||||
|
this.$emit('update:modelValue', value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部调用方法
|
||||||
|
* 获取焦点时触发
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
onFocus() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.focused = true;
|
||||||
|
});
|
||||||
|
this.$emit('focus', null);
|
||||||
|
},
|
||||||
|
|
||||||
|
_Focus(event) {
|
||||||
|
this.focusShow = true;
|
||||||
|
this.$emit('focus', event);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部调用方法
|
||||||
|
* 失去焦点时触发
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
onBlur() {
|
||||||
|
this.focused = false;
|
||||||
|
this.$emit('blur', null);
|
||||||
|
},
|
||||||
|
_Blur(event) {
|
||||||
|
let value = event.detail.value;
|
||||||
|
this.focusShow = false;
|
||||||
|
this.$emit('blur', event);
|
||||||
|
// 根据类型返回值,在event中获取的值理论上讲都是string
|
||||||
|
if (this.isEnter === false) {
|
||||||
|
this.$emit('change', this.val);
|
||||||
|
}
|
||||||
|
// 失去焦点时参与表单校验
|
||||||
|
if (this.form && this.formItem) {
|
||||||
|
const { validateTrigger } = this.form;
|
||||||
|
if (validateTrigger === 'blur') {
|
||||||
|
this.formItem.onFieldChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按下键盘的发送键
|
||||||
|
* @param {Object} e
|
||||||
|
*/
|
||||||
|
onConfirm(e) {
|
||||||
|
this.$emit('confirm', this.val);
|
||||||
|
this.isEnter = true;
|
||||||
|
this.$emit('change', this.val);
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.isEnter = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理内容
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
onClear(event) {
|
||||||
|
this.val = '';
|
||||||
|
// TODO 兼容 vue2
|
||||||
|
this.$emit('input', '');
|
||||||
|
// TODO 兼容 vue2
|
||||||
|
// TODO 兼容 vue3
|
||||||
|
this.$emit('update:modelValue', '');
|
||||||
|
// 点击叉号触发
|
||||||
|
this.$emit('clear');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 键盘高度发生变化的时候触发此事件
|
||||||
|
* 兼容性:微信小程序2.7.0+、App 3.1.0+
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
onkeyboardheightchange(event) {
|
||||||
|
this.$emit('keyboardheightchange', event);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除空格
|
||||||
|
*/
|
||||||
|
trimStr(str, pos = 'both') {
|
||||||
|
if (pos === 'both') {
|
||||||
|
return str.trim();
|
||||||
|
} else if (pos === 'left') {
|
||||||
|
return str.trimLeft();
|
||||||
|
} else if (pos === 'right') {
|
||||||
|
return str.trimRight();
|
||||||
|
} else if (pos === 'start') {
|
||||||
|
return str.trimStart();
|
||||||
|
} else if (pos === 'end') {
|
||||||
|
return str.trimEnd();
|
||||||
|
} else if (pos === 'all') {
|
||||||
|
return str.replace(/\s+/g, '');
|
||||||
|
} else if (pos === 'none') {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$uni-error: #e43d33;
|
||||||
|
$uni-border-1: #dcdfe6 !default;
|
||||||
|
|
||||||
|
.uni-easyinput {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 100%;
|
||||||
|
/* #endif */
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
color: #333;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput__content {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// min-height: 36px;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
// 处理border动画刚开始显示黑色的问题
|
||||||
|
border-color: #fff;
|
||||||
|
transition-property: border-color;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput__content-input {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: auto;
|
||||||
|
/* #endif */
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 35px;
|
||||||
|
// min-height: 36px;
|
||||||
|
|
||||||
|
/*ifdef H5*/
|
||||||
|
& ::-ms-reveal {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& ::-ms-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& ::-o-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*endif*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput__placeholder-class {
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
// font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-textarea {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-textarea-icon {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput__content-textarea {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 6px;
|
||||||
|
margin-left: 0;
|
||||||
|
height: 80px;
|
||||||
|
min-height: 80px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
min-height: 80px;
|
||||||
|
width: auto;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-padding {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-clear-icon {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示边框
|
||||||
|
.is-input-border {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid $uni-border-1;
|
||||||
|
border-radius: 4px;
|
||||||
|
/* #ifdef MP-ALIPAY */
|
||||||
|
overflow: hidden;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-error-message {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -17px;
|
||||||
|
left: 0;
|
||||||
|
line-height: 12px;
|
||||||
|
color: $uni-error;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-error-msg--boeder {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-input-error-border {
|
||||||
|
border-color: $uni-error;
|
||||||
|
|
||||||
|
.uni-easyinput__placeholder-class {
|
||||||
|
color: mix(#fff, $uni-error, 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput--border {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 10px 15px;
|
||||||
|
// padding-bottom: 0;
|
||||||
|
border-top: 1px #eee solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-easyinput-error {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-first-border {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
border: none;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
border-width: 0;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-disabled {
|
||||||
|
background-color: #f7f6f6;
|
||||||
|
color: #d5d5d5;
|
||||||
|
|
||||||
|
.uni-easyinput__placeholder-class {
|
||||||
|
color: #d5d5d5;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
88
src/uni_modules/uni-easyinput/package.json
Normal file
88
src/uni_modules/uni-easyinput/package.json
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-easyinput",
|
||||||
|
"displayName": "uni-easyinput 增强输入框",
|
||||||
|
"version": "1.1.19",
|
||||||
|
"description": "Easyinput 组件是对原生input组件的增强",
|
||||||
|
"keywords": [
|
||||||
|
"uni-ui",
|
||||||
|
"uniui",
|
||||||
|
"input",
|
||||||
|
"uni-easyinput",
|
||||||
|
"输入框"
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": ""
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [
|
||||||
|
"uni-scss",
|
||||||
|
"uni-icons"
|
||||||
|
],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/uni_modules/uni-easyinput/readme.md
Normal file
11
src/uni_modules/uni-easyinput/readme.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
### Easyinput 增强输入框
|
||||||
|
> **组件名:uni-easyinput**
|
||||||
|
> 代码块: `uEasyinput`
|
||||||
|
|
||||||
|
|
||||||
|
easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
25
src/uni_modules/uni-load-more/changelog.md
Normal file
25
src/uni_modules/uni-load-more/changelog.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
## 1.3.6(2024-10-15)
|
||||||
|
- 修复 微信小程序中的getSystemInfo警告
|
||||||
|
## 1.3.5(2024-10-12)
|
||||||
|
- 修复 微信小程序中的getSystemInfo警告
|
||||||
|
## 1.3.4(2024-10-12)
|
||||||
|
- 修复 微信小程序中的getSystemInfo警告
|
||||||
|
## 1.3.3(2022-01-20)
|
||||||
|
- 新增 showText属性 ,是否显示文本
|
||||||
|
## 1.3.2(2022-01-19)
|
||||||
|
- 修复 nvue 平台下不显示文本的bug
|
||||||
|
## 1.3.1(2022-01-19)
|
||||||
|
- 修复 微信小程序平台样式选择器报警告的问题
|
||||||
|
## 1.3.0(2021-11-19)
|
||||||
|
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
|
||||||
|
## 1.2.1(2021-08-24)
|
||||||
|
- 新增 支持国际化
|
||||||
|
## 1.2.0(2021-07-30)
|
||||||
|
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||||
|
## 1.1.8(2021-05-12)
|
||||||
|
- 新增 组件示例地址
|
||||||
|
## 1.1.7(2021-03-30)
|
||||||
|
- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug
|
||||||
|
## 1.1.6(2021-02-05)
|
||||||
|
- 调整为uni_modules目录规范
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"uni-load-more.contentdown": "Pull up to show more",
|
||||||
|
"uni-load-more.contentrefresh": "loading...",
|
||||||
|
"uni-load-more.contentnomore": "No more data"
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import en from './en.json'
|
||||||
|
import zhHans from './zh-Hans.json'
|
||||||
|
import zhHant from './zh-Hant.json'
|
||||||
|
export default {
|
||||||
|
en,
|
||||||
|
'zh-Hans': zhHans,
|
||||||
|
'zh-Hant': zhHant
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"uni-load-more.contentdown": "上拉显示更多",
|
||||||
|
"uni-load-more.contentrefresh": "正在加载...",
|
||||||
|
"uni-load-more.contentnomore": "没有更多数据了"
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"uni-load-more.contentdown": "上拉顯示更多",
|
||||||
|
"uni-load-more.contentrefresh": "正在加載...",
|
||||||
|
"uni-load-more.contentnomore": "沒有更多數據了"
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
84
src/uni_modules/uni-load-more/package.json
Normal file
84
src/uni_modules/uni-load-more/package.json
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-load-more",
|
||||||
|
"displayName": "uni-load-more 加载更多",
|
||||||
|
"version": "1.3.6",
|
||||||
|
"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
|
||||||
|
"keywords": [
|
||||||
|
"uni-ui",
|
||||||
|
"uniui",
|
||||||
|
"加载更多",
|
||||||
|
"load-more"
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": ""
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": ["uni-scss"],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/uni_modules/uni-load-more/readme.md
Normal file
14
src/uni_modules/uni-load-more/readme.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
### LoadMore 加载更多
|
||||||
|
> **组件名:uni-load-more**
|
||||||
|
> 代码块: `uLoadMore`
|
||||||
|
|
||||||
|
|
||||||
|
用于列表中,做滚动加载使用,展示 loading 的各种状态。
|
||||||
|
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
|
|
||||||
|
|
||||||
15
src/uni_modules/uni-segmented-control/changelog.md
Normal file
15
src/uni_modules/uni-segmented-control/changelog.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## 1.2.3(2024-04-02)
|
||||||
|
- 修复 修复在微信小程序下inactiveColor失效bug
|
||||||
|
## 1.2.2(2024-03-28)
|
||||||
|
- 修复 在vue2下:style动态绑定导致编译失败的bug
|
||||||
|
## 1.2.1(2024-03-20)
|
||||||
|
- 新增 inActiveColor属性,可供配置未激活时的颜色
|
||||||
|
## 1.2.0(2021-11-19)
|
||||||
|
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
|
||||||
|
## 1.1.0(2021-07-30)
|
||||||
|
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||||
|
## 1.0.5(2021-05-12)
|
||||||
|
- 新增 项目示例地址
|
||||||
|
## 1.0.4(2021-02-05)
|
||||||
|
- 调整为uni_modules目录规范
|
||||||
@ -0,0 +1,146 @@
|
|||||||
|
<template>
|
||||||
|
<view :class="[styleType === 'text'?'segmented-control--text' : 'segmented-control--button' ]"
|
||||||
|
:style="{ borderColor: styleType === 'text' ? '' : activeColor }" class="segmented-control">
|
||||||
|
<view v-for="(item, index) in values" :class="[styleType === 'text' ? '' : 'segmented-control__item--button',
|
||||||
|
index === 0 && styleType === 'button' ? 'segmented-control__item--button--first' : '',
|
||||||
|
index === values.length - 1 && styleType === 'button' ? 'segmented-control__item--button--last':'']" :key="index"
|
||||||
|
:style="{backgroundColor: index === currentIndex && styleType === 'button' ? activeColor : styleType === 'button' ?inActiveColor:'transparent', borderColor: index === currentIndex && styleType === 'text' || styleType === 'button' ? activeColor : inActiveColor}"
|
||||||
|
class="segmented-control__item" @click="_onClick(index)">
|
||||||
|
<view>
|
||||||
|
<text
|
||||||
|
:style="{color:index === currentIndex? styleType === 'text'? activeColor: '#fff': styleType === 'text'? '#000': activeColor}"
|
||||||
|
class="segmented-control__text"
|
||||||
|
:class="styleType === 'text' && index === currentIndex ? 'segmented-control__item--text': ''">{{ item }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* SegmentedControl 分段器
|
||||||
|
* @description 用作不同视图的显示
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=54
|
||||||
|
* @property {Number} current 当前选中的tab索引值,从0计数
|
||||||
|
* @property {String} styleType = [button|text] 分段器样式类型
|
||||||
|
* @value button 按钮类型
|
||||||
|
* @value text 文字类型
|
||||||
|
* @property {String} activeColor 选中的标签背景色与边框颜色
|
||||||
|
* @property {String} inActiveColor 未选中的标签背景色与边框颜色
|
||||||
|
* @property {Array} values 选项数组
|
||||||
|
* @event {Function} clickItem 组件触发点击事件时触发,e={currentIndex}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UniSegmentedControl',
|
||||||
|
emits: ['clickItem'],
|
||||||
|
props: {
|
||||||
|
current: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979FF'
|
||||||
|
},
|
||||||
|
inActiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
styleType: {
|
||||||
|
type: String,
|
||||||
|
default: 'button'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentIndex: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
current(val) {
|
||||||
|
if (val !== this.currentIndex) {
|
||||||
|
this.currentIndex = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
created() {
|
||||||
|
this.currentIndex = this.current
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
_onClick(index) {
|
||||||
|
if (this.currentIndex !== index) {
|
||||||
|
this.currentIndex = index
|
||||||
|
this.$emit('clickItem', {
|
||||||
|
currentIndex: index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.segmented-control {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
height: 36px;
|
||||||
|
overflow: hidden;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
cursor: pointer;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__item {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__item--button {
|
||||||
|
border-style: solid;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__item--button--first {
|
||||||
|
border-left-width: 1px;
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__item--button--last {
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__item--text {
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control__text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
85
src/uni_modules/uni-segmented-control/package.json
Normal file
85
src/uni_modules/uni-segmented-control/package.json
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"id": "uni-segmented-control",
|
||||||
|
"displayName": "uni-segmented-control 分段器",
|
||||||
|
"version": "1.2.3",
|
||||||
|
"description": "分段器由至少 2 个分段控件组成,用作不同视图的显示",
|
||||||
|
"keywords": [
|
||||||
|
"uni-ui",
|
||||||
|
"uniui",
|
||||||
|
"分段器",
|
||||||
|
"segement",
|
||||||
|
"顶部选择"
|
||||||
|
],
|
||||||
|
"repository": "https://github.com/dcloudio/uni-ui",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": ""
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"example": "../../temps/example_temps"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": ["uni-scss"],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "y",
|
||||||
|
"Edge": "y",
|
||||||
|
"Firefox": "y",
|
||||||
|
"Safari": "y"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/uni_modules/uni-segmented-control/readme.md
Normal file
13
src/uni_modules/uni-segmented-control/readme.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## SegmentedControl 分段器
|
||||||
|
> **组件名:uni-segmented-control**
|
||||||
|
> 代码块: `uSegmentedControl`
|
||||||
|
|
||||||
|
|
||||||
|
用作不同视图的显示
|
||||||
|
|
||||||
|
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control)
|
||||||
|
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||||
|
|
||||||
|
|
||||||
10
src/uni_modules/uni-title/changelog.md
Normal file
10
src/uni_modules/uni-title/changelog.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
## 1.1.1(2022-05-19)
|
||||||
|
- 修改组件描述
|
||||||
|
## 1.1.0(2021-11-19)
|
||||||
|
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||||
|
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-title](https://uniapp.dcloud.io/component/uniui/uni-title)
|
||||||
|
## 1.0.2(2021-05-12)
|
||||||
|
- 新增 示例地址
|
||||||
|
- 修复 示例项目缺少组件的Bug
|
||||||
|
## 1.0.1(2021-02-05)
|
||||||
|
- 调整为uni_modules目录规范
|
||||||
171
src/uni_modules/uni-title/components/uni-title/uni-title.vue
Normal file
171
src/uni_modules/uni-title/components/uni-title/uni-title.vue
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-title__box" :style="{'align-items':textAlign}">
|
||||||
|
<text class="uni-title__base" :class="['uni-'+type]" :style="{'color':color}">{{title}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* Title 标题
|
||||||
|
* @description 标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=1066
|
||||||
|
* @property {String} type = [h1|h2|h3|h4|h5] 标题类型
|
||||||
|
* @value h1 一级标题
|
||||||
|
* @value h2 二级标题
|
||||||
|
* @value h3 三级标题
|
||||||
|
* @value h4 四级标题
|
||||||
|
* @value h5 五级标题
|
||||||
|
* @property {String} title 标题内容
|
||||||
|
* @property {String} align = [left|center|right] 对齐方式
|
||||||
|
* @value left 做对齐
|
||||||
|
* @value center 居中对齐
|
||||||
|
* @value right 右对齐
|
||||||
|
* @property {String} color 字体颜色
|
||||||
|
* @property {Boolean} stat = [true|false] 是否开启统计功能呢,如不填写type值,默认为开启,填写 type 属性,默认为关闭
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name:"UniTitle",
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#333333'
|
||||||
|
},
|
||||||
|
stat: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
textAlign() {
|
||||||
|
let align = 'center';
|
||||||
|
switch (this.align) {
|
||||||
|
case 'left':
|
||||||
|
align = 'flex-start'
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
align = 'center'
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
align = 'flex-end'
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return align
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
title(newVal) {
|
||||||
|
if (this.isOpenStat()) {
|
||||||
|
// 上报数据
|
||||||
|
if (uni.report) {
|
||||||
|
uni.report('title', this.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.isOpenStat()) {
|
||||||
|
// 上报数据
|
||||||
|
if (uni.report) {
|
||||||
|
uni.report('title', this.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isOpenStat() {
|
||||||
|
if (this.stat === '') {
|
||||||
|
this.isStat = false
|
||||||
|
}
|
||||||
|
let stat_type = (typeof(this.stat) === 'boolean' && this.stat) || (typeof(this.stat) === 'string' && this.stat !==
|
||||||
|
'')
|
||||||
|
if (this.type === "") {
|
||||||
|
this.isStat = true
|
||||||
|
if (this.stat.toString() === 'false') {
|
||||||
|
this.isStat = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type !== '') {
|
||||||
|
this.isStat = true
|
||||||
|
if (stat_type) {
|
||||||
|
this.isStat = true
|
||||||
|
} else {
|
||||||
|
this.isStat = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.isStat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* .uni-title {
|
||||||
|
|
||||||
|
} */
|
||||||
|
.uni-title__box {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-title__base {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
/* font-weight: 400; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
/* font-weight: 300; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
/* font-weight: 200; */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user