生产模块
This commit is contained in:
parent
d510a9a734
commit
2ee9a1b0d6
@ -33,10 +33,10 @@ export default defineUniPages({
|
||||
text: '首页',
|
||||
},
|
||||
{
|
||||
iconPath: 'static/tabbar/tabbar-message-2.png',
|
||||
selectedIconPath: 'static/tabbar/tabbar-message.png',
|
||||
pagePath: 'pages/message/message',
|
||||
text: '消息',
|
||||
"iconPath": "static/tabbar/tabbar-produce.png",
|
||||
"selectedIconPath": "static/tabbar/tabbar-produce-2.png",
|
||||
"pagePath": "pages/produce/index",
|
||||
"text": "生产"
|
||||
},
|
||||
{
|
||||
iconPath: 'static/tabbar/tabbar-workHome-2.png',
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
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',
|
||||
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/
|
||||
// ts对 HTTP 方法名称的大小写敏感。在 TypeScript 的类型定义中,HTTP 方法通常被定义为全大写的字符串字面量类型,如 "POST",而非"post"。
|
||||
interface LoginParams {
|
||||
username: string;
|
||||
password: string;
|
||||
captcha?: string; //非必填字段
|
||||
username : string;
|
||||
password : string;
|
||||
captcha ?: string; //非必填字段
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12,13 +12,13 @@ interface LoginParams {
|
||||
* @returns 登录请求的 Promise
|
||||
*/
|
||||
export function loginApi(config : LoginParams) {
|
||||
// 如果传了 captcha,走本地登录(/sys/login),否则走单点登录(/sys/sinopecLogin)
|
||||
const url = config.captcha ? '/sys/login' : '/sys/sinopecLogin';
|
||||
return http({
|
||||
url,
|
||||
method: 'POST',
|
||||
data: config,
|
||||
});
|
||||
// 如果传了 captcha,走本地登录(/sys/login),否则走单点登录(/sys/sinopecLogin)
|
||||
const url = config.captcha ? '/sys/login' : '/sys/sinopecLogin';
|
||||
return http({
|
||||
url,
|
||||
method: 'POST',
|
||||
data: config,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +48,7 @@ export function jurisdictionApi(id : string) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getUserPermissionApi(config) { // 获取权限
|
||||
export function getUserPermissionApi(config : object) { // 获取权限
|
||||
return http({
|
||||
url: '/sys/permission/getUserPermissionByToken',
|
||||
method: 'GET',
|
||||
@ -59,7 +59,7 @@ export function getUserPermissionApi(config) { // 获取权限
|
||||
/**
|
||||
* 获取首页轮播图
|
||||
*/
|
||||
export function queryCarouselApi(config) {
|
||||
export function queryCarouselApi(config : object) {
|
||||
return http({
|
||||
url: '/CxcDaping/cxcDaping/list',
|
||||
method: 'GET',
|
||||
@ -70,7 +70,7 @@ export function queryCarouselApi(config) {
|
||||
/**
|
||||
* 获取分类字典
|
||||
*/
|
||||
export function getCategoryItemsApi(pid) { // 分类字典专用
|
||||
export function getCategoryItemsApi(pid : string) {
|
||||
return http({
|
||||
url: '/sys/category/findtree',
|
||||
method: 'GET',
|
||||
@ -78,4 +78,11 @@ export function getCategoryItemsApi(pid) { // 分类字典专用
|
||||
pid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getDictItemsApi(dictCode : string) { // 字典标签专用
|
||||
return http({
|
||||
url: `/sys/dict/getDictItems/${dictCode}`,
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
@ -155,7 +155,7 @@
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if(loading.value) return
|
||||
if (loading.value) return
|
||||
form.value.validate().then(({
|
||||
valid,
|
||||
errors
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</wd-row>
|
||||
<wd-row>
|
||||
<wd-col :span="24">
|
||||
<SelectDept label="" v-model="orgCode" @change="Search" rowKey="orgCode" :multiple="false">
|
||||
<SelectDept label="" v-model="orgCode" @change="queryLeave" rowKey="orgCode" :multiple="false">
|
||||
</SelectDept>
|
||||
</wd-col>
|
||||
</wd-row>
|
||||
@ -27,10 +27,10 @@
|
||||
</wd-row>
|
||||
<wd-row>
|
||||
<wd-col :span="12">
|
||||
<uni-easyinput v-model="realname" placeholder="姓名模糊查询" @change="Search" @clear="Search" />
|
||||
<uni-easyinput v-model="realname" placeholder="姓名模糊查询" @change="queryLeave" @clear="queryLeave" />
|
||||
</wd-col>
|
||||
<wd-col :span="12">
|
||||
<uni-easyinput v-model="contractNumber" placeholder="劳动合同号查询" @change="Search" @clear="Search" />
|
||||
<uni-easyinput v-model="contractNumber" placeholder="劳动合同号查询" @change="queryLeave" @clear="queryLeave" />
|
||||
</wd-col>
|
||||
</wd-row>
|
||||
<wd-row>
|
||||
@ -70,10 +70,10 @@
|
||||
const list = ref([]) //请假信息列表
|
||||
const realname = ref('') //姓名查询
|
||||
const contractNumber = ref('') //劳动合同号查询
|
||||
const orgCode = ref('') //单位查询
|
||||
const type = ref('') //图表点击事件 请假类别
|
||||
const range = ref([]) //日期查询
|
||||
const timeout = ref(null)
|
||||
const orgCode = ref('')
|
||||
let pageNo = 1
|
||||
let pageSize = 10
|
||||
let loading = false
|
||||
@ -147,15 +147,6 @@
|
||||
}, 300);
|
||||
};
|
||||
|
||||
function Search() {
|
||||
if (timeout.value) {
|
||||
clearTimeout(timeout.value);
|
||||
}
|
||||
timeout.value = setTimeout(() => {
|
||||
queryLeave()
|
||||
}, 300); // 300ms 防抖时间
|
||||
}
|
||||
|
||||
function reset() {
|
||||
orgCode.value = ''
|
||||
range.value = []
|
||||
|
||||
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>
|
||||
<template>
|
||||
<PageLayout navTitle="干部值班">
|
||||
<wd-datetime-picker type="year-month" v-model="dataValue" label="年月" @confirm="getList" />
|
||||
<wd-table :data="dataSource">
|
||||
<wd-table-col prop="date" label="日期" width="60" align="center"></wd-table-col>
|
||||
<wd-table-col prop="dbld_dictText" label="带班领导" width="73" align="center"></wd-table-col>
|
||||
<wd-table-col prop="zbld_dictText" label="值班领导" width="73" align="center"></wd-table-col>
|
||||
<wd-table-col prop="zbgbrealname" label="值班干部" width="153" align="center"></wd-table-col>
|
||||
<wd-datetime-picker type="year-month" v-model="dataValue" label="年月" @confirm="getList" id="top1" />
|
||||
<wd-table :data="dataSource" :height="tableHeight">
|
||||
<wd-table-col prop="date" label="日期" :width="screenWidth / 7" 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="screenWidth * 7 / 32" align="center"></wd-table-col>
|
||||
<wd-table-col prop="zbgbrealname" label="值班干部" :width="screenWidth * (47 / 112)"
|
||||
align="center"></wd-table-col>
|
||||
</wd-table>
|
||||
</PageLayout>
|
||||
</template>
|
||||
@ -23,8 +24,11 @@
|
||||
import {
|
||||
getListApi
|
||||
} from '@/api/pages/duty'
|
||||
|
||||
const dataValue = ref(Date.now())
|
||||
const dataSource = ref([])
|
||||
const tableHeight = ref(0)
|
||||
const screenWidth = ref(0)
|
||||
const getList = () => {
|
||||
const date = new Date(dataValue.value);
|
||||
const year = date.getFullYear();
|
||||
@ -33,11 +37,10 @@
|
||||
year: year,
|
||||
month: month
|
||||
}).then(res => {
|
||||
// 格式化日期字段
|
||||
dataSource.value = res.result.records.map(item => {
|
||||
return {
|
||||
...item,
|
||||
date: formatDate(item.date) // 调用格式化函数
|
||||
date: formatDate(item.date)
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -46,12 +49,33 @@
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
const [year, month, day] = dateStr.split('-');
|
||||
const formattedMonth = parseInt(month, 10); // 去除前导 0
|
||||
const formattedDay = parseInt(day, 10); // 去除前导 0
|
||||
const formattedMonth = parseInt(month, 10);
|
||||
const formattedDay = parseInt(day, 10);
|
||||
return `${formattedMonth}.${formattedDay}`;
|
||||
};
|
||||
|
||||
onLoad(() => {
|
||||
getList()
|
||||
const calculateTableHeight = () => {
|
||||
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>
|
||||
@ -30,10 +30,10 @@
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"iconPath": "static/tabbar/tabbar-message-2.png",
|
||||
"selectedIconPath": "static/tabbar/tabbar-message.png",
|
||||
"pagePath": "pages/message/message",
|
||||
"text": "消息"
|
||||
"iconPath": "static/tabbar/tabbar-produce.png",
|
||||
"selectedIconPath": "static/tabbar/tabbar-produce-2.png",
|
||||
"pagePath": "pages/produce/index",
|
||||
"text": "生产"
|
||||
},
|
||||
{
|
||||
"iconPath": "static/tabbar/tabbar-workHome-2.png",
|
||||
@ -130,6 +130,15 @@
|
||||
"navigationBarTitleText": "H5在线预览"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/produce/index",
|
||||
"type": "page",
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTitleText": "生产数据"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/user/people",
|
||||
"type": "page",
|
||||
@ -147,6 +156,42 @@
|
||||
"navigationBarTitleText": "工作台",
|
||||
"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": [
|
||||
@ -353,6 +398,36 @@
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
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 |
17
src/types/uni-pages.d.ts
vendored
17
src/types/uni-pages.d.ts
vendored
@ -13,8 +13,18 @@ interface NavigateToOptions {
|
||||
"/pages/onlinePreview/detail" |
|
||||
"/pages/onlinePreview/onlinePreview" |
|
||||
"/pages/onlinePreview/onlinePreviewH5" |
|
||||
"/pages/produce/index" |
|
||||
"/pages/user/people" |
|
||||
"/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-message/chat/chat" |
|
||||
"/pages-message/contacts/contacts" |
|
||||
@ -34,6 +44,11 @@ interface NavigateToOptions {
|
||||
"/pages-humanResource/absence/add" |
|
||||
"/pages-humanResource/absence/detail" |
|
||||
"/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-politics/health/add" |
|
||||
"/pages-process/approvalTabbar" |
|
||||
@ -42,7 +57,7 @@ interface NavigateToOptions {
|
||||
interface RedirectToOptions extends NavigateToOptions {}
|
||||
|
||||
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;
|
||||
|
||||
@ -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
|
||||
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
|
||||
|
||||
|
||||
145
src/uni_modules/wu-calendar/changelog.md
Normal file
145
src/uni_modules/wu-calendar/changelog.md
Normal file
@ -0,0 +1,145 @@
|
||||
## 1.5.6(2024-11-25)
|
||||
1. 修复上版本日历高度错误的bug
|
||||
2. 新增clearSelect方法用于清除日历选择
|
||||
3. 新增todayDefaultStyle属性用于控制是否显示今日默认样式
|
||||
## 1.5.5(2024-11-14)
|
||||
1. 通过减少view数量优化日历性能
|
||||
2. 修复nvue错误日历样式以及滑动时无法切换日历的bug
|
||||
3. 修复nvue警告
|
||||
## 1.5.4(2024-10-12)
|
||||
修复忘记删除方法,导致运行错误
|
||||
## 1.5.3(2024-10-12)
|
||||
更新nvue下可能会造成日历重叠的bug
|
||||
## 1.5.2(2024-06-14)
|
||||
修复错误style语法
|
||||
## 1.5.1(2024-06-11)
|
||||
修复弹窗确认与取消设置颜色不生效
|
||||
## 1.5.0(2024-06-03)
|
||||
1. 修复monthSwitch事件初始化时被触发的问题
|
||||
2. monthSwitch事件新增fullDate属性(用来方便直接获取字符串形式的完整日期)
|
||||
3. 日历新增confirmFullDate属性,用来指定在弹窗模式下的日期点击确认按钮时是否需要选择完整日期
|
||||
## 1.4.9(2024-05-08)
|
||||
更新域名
|
||||
## 1.4.8(2024-04-22)
|
||||
修复日历内外高度不一致的问题
|
||||
## 1.4.7(2024-04-16)
|
||||
增加 operationPosition 属性 用来控制弹窗日历取消和确认按钮的显示位置
|
||||
## 1.4.6(2024-04-16)
|
||||
新增属性 actBadgeColor, 当通过 `selected` 属性设置某个日期 `badgeColor`后,如果该日期被选择且主题色与 `badgeColor` 一致时,徽标会显示本颜色
|
||||
## 1.4.5(2024-04-15)
|
||||
1. 新增reset方法来重置日历数据
|
||||
2. 新增插槽-operation 用来自定义弹窗日历确认和取消按钮
|
||||
3. selected 属性新增 badgeColor 用来指定 badge 颜色
|
||||
4. close 事件改为弹窗日历点击mask关闭时触发,新增cancel事件,弹窗日历点击取消时触发。
|
||||
## 1.4.4(2024-01-19)
|
||||
修复vue2初始化时使用同一引用类型造成的bug
|
||||
## 1.4.3(2024-01-17)
|
||||
优化切换折叠状态时的记录方式
|
||||
## 1.4.2(2024-01-12)
|
||||
优化 monthShowCurrentMonth 属性, 如果仅显示当月直接不展示该元素。
|
||||
## 1.4.1(2024-01-12)
|
||||
优化 monthShowCurrentMonth 属性, 如果仅显示当月直接不展示该元素。
|
||||
## 1.4.0(2024-01-11)
|
||||
修复type="week"时找不到
|
||||
## 1.3.9(2024-01-10)
|
||||
优化: 将日历日期宽度固定改为跟随父级来决定宽度,避免出现父元素宽度变化带来的对不齐
|
||||
## 1.3.8(2024-01-04)
|
||||
1. 增加节日
|
||||
2. 日历增加自定义高度
|
||||
3. vue页面日历折叠时增加动效
|
||||
4. 增加头部插槽
|
||||
5. 仅显示当月时自动扩大间距,不会再出现下面一排空白的尴尬情况了
|
||||
## 1.3.7(2023-12-19)
|
||||
修复回到今日时没有正确记录折叠日期
|
||||
修复selected变化时无法正常更新打点信息
|
||||
## 1.3.6(2023-12-13)
|
||||
修复单选模式下选中时展示的错误的weeks
|
||||
## 1.3.5(2023-12-13)
|
||||
修复动态修改date以及其他会触发更新init的函数, swiper不对及只会更新一个下一个数据的bug
|
||||
## 1.3.4(2023-12-08)
|
||||
修复selectd没有启用深度监听,导致直接添加数组带来的异常
|
||||
## 1.3.3(2023-11-23)
|
||||
1. 修复weeks错误类型提示
|
||||
2. 修复calendarChange返回month类型不对
|
||||
## 1.3.2(2023-11-22)
|
||||
修复将今日日期打点禁用后造成的bug
|
||||
## 1.3.1(2023-11-21)
|
||||
1. 修复wu-icon依赖缺失
|
||||
2. 新增rangeHaveDisableTruncation属性, 用来指定范围选择遇到打点禁用日期是否进行截断
|
||||
## 1.3.0(2023-11-19)
|
||||
1. 日历新增类型(周、月日历)
|
||||
2. 日历新增折叠功能
|
||||
3. 日历新增以周几开始的属性(周日、周一)
|
||||
## 1.2.9(2023-11-08)
|
||||
1. 修复mode变化时,不会正确重置的问题
|
||||
2. 优化月份大文字显示方式
|
||||
## 1.2.8(2023-10-22)
|
||||
新增maskClick用来控制是否点击遮罩层关闭
|
||||
新增disabledChoice用来控制是否禁止点击日历
|
||||
## 1.2.7(2023-09-22)
|
||||
修复传date值情况下不会默认选中的bug
|
||||
## 1.2.6(2023-09-22)
|
||||
修改useToday描述
|
||||
## 1.2.5(2023-09-22)
|
||||
新增useToday属性用来指定是否使用今天作为默认时间
|
||||
## 1.2.4(2023-09-21)
|
||||
修复插入模式下顶部会显示弹窗关闭的内容
|
||||
## 1.2.3(2023-09-20)
|
||||
修复恢复默认数据错误的bug
|
||||
## 1.2.2(2023-09-19)
|
||||
新增rangeSameDay属性用来指定选日期范围选择时起始日期是否可以为同一天
|
||||
## 1.2.1(2023-09-18)
|
||||
1.修复wu-calendar回到今日错误
|
||||
2.优化wu-calendar picker日期与当前日历日期同步
|
||||
3.wu-calendar新增mode属性,用来控制单日期、多日期、日期选择范围模式
|
||||
4.优化wu-calendar date属性来更好的指定多日期、范围日期的默认值
|
||||
## 1.2.0(2023-09-17)
|
||||
修复date变化时未成功重置
|
||||
## 1.1.9(2023-09-17)
|
||||
1. 新增mode属性用来指定日期选择模式
|
||||
2. 增加多选
|
||||
3. 增加范围选择模式、多选模式默认值
|
||||
## 1.1.8(2023-09-12)
|
||||
修复回到今日错误
|
||||
新增日历picker日期与日历同步
|
||||
## 1.1.7(2023-09-11)
|
||||
自定义事件声明
|
||||
## 1.1.6(2023-09-09)
|
||||
增加 `rangeEndRepick` 属性,用来指定选择完成后点击选择范围内的日期是否可以重选结束日期
|
||||
## 1.1.5(2023-09-09)
|
||||
修复每月仅显示当月数据时上方星期错乱的问题
|
||||
## 1.1.4(2023-09-05)
|
||||
1. 优化动态计算算法
|
||||
2. 优化弹窗模式打开缓慢的问题
|
||||
3. 优化Color方法
|
||||
## 1.1.3(2023-09-03)
|
||||
新增插件预览图片
|
||||
## 1.1.2(2023-09-02)
|
||||
1. 新增monthShowCurrentMonth 用来设置是否每月仅展示当月数据
|
||||
2. 修复动态加载时下一月数据更新错误问题
|
||||
3. 修复confirm和change事件选中的列表中有被禁止的日期的问题
|
||||
## 1.1.1(2023-08-31)
|
||||
修复在插入模式中无法滑动的bug
|
||||
## 1.1.0(2023-08-29)
|
||||
修复回到今日bug(来自群里464与A毛毛大佬的测试)
|
||||
## 1.0.9(2023-08-29)
|
||||
修复依赖缺失
|
||||
## 1.0.8(2023-08-22)
|
||||
修复v2初始化时使用不存在的属性导致不可使用的bug(来自wu-ui群内攸宁大佬的反馈)
|
||||
## 1.0.7(2023-08-21)
|
||||
阻止默认滑动事件执行
|
||||
## 1.0.6(2023-08-21)
|
||||
修复支付宝高度消失的问题
|
||||
## 1.0.5(2023-08-21)
|
||||
修改说明
|
||||
## 1.0.4(2023-08-20)
|
||||
去除误加打印
|
||||
## 1.0.3(2023-08-20)
|
||||
1. 修复初始化时下个月份日期计算不对的问题
|
||||
2. 增加打点禁用、设置打点徽标位置
|
||||
## 1.0.2(2023-08-20)
|
||||
更新展示截图
|
||||
## 1.0.1(2023-08-20)
|
||||
修改展示截图及说明
|
||||
## 1.0.0(2023-08-20)
|
||||
动态滑动计算的日历插件,还可以设置滑动切换模式、自定义主题颜色、自定义文案、农历显示等功能,可以让您纵享丝滑的使用日历。
|
||||
14
src/uni_modules/wu-calendar/components/i18n/en.json
Normal file
14
src/uni_modules/wu-calendar/components/i18n/en.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"wu-calender.ok": "ok",
|
||||
"wu-calender.cancel": "cancel",
|
||||
"wu-calender.year": "year",
|
||||
"wu-calender.month": "month",
|
||||
"wu-calender.today": "today",
|
||||
"wu-calender.MON": "MON",
|
||||
"wu-calender.TUE": "TUE",
|
||||
"wu-calender.WED": "WED",
|
||||
"wu-calender.THU": "THU",
|
||||
"wu-calender.FRI": "FRI",
|
||||
"wu-calender.SAT": "SAT",
|
||||
"wu-calender.SUN": "SUN"
|
||||
}
|
||||
8
src/uni_modules/wu-calendar/components/i18n/index.js
Normal file
8
src/uni_modules/wu-calendar/components/i18n/index.js
Normal file
@ -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
|
||||
}
|
||||
14
src/uni_modules/wu-calendar/components/i18n/zh-Hans.json
Normal file
14
src/uni_modules/wu-calendar/components/i18n/zh-Hans.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"wu-calender.ok": "确定",
|
||||
"wu-calender.cancel": "取消",
|
||||
"wu-calender.year": "年",
|
||||
"wu-calender.month": "月",
|
||||
"wu-calender.today": "今日",
|
||||
"wu-calender.SUN": "日",
|
||||
"wu-calender.MON": "一",
|
||||
"wu-calender.TUE": "二",
|
||||
"wu-calender.WED": "三",
|
||||
"wu-calender.THU": "四",
|
||||
"wu-calender.FRI": "五",
|
||||
"wu-calender.SAT": "六"
|
||||
}
|
||||
14
src/uni_modules/wu-calendar/components/i18n/zh-Hant.json
Normal file
14
src/uni_modules/wu-calendar/components/i18n/zh-Hant.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"wu-calender.ok": "確定",
|
||||
"wu-calender.cancel": "取消",
|
||||
"wu-calender.year": "年",
|
||||
"wu-calender.month": "月",
|
||||
"wu-calender.today": "今日",
|
||||
"wu-calender.SUN": "日",
|
||||
"wu-calender.MON": "一",
|
||||
"wu-calender.TUE": "二",
|
||||
"wu-calender.WED": "三",
|
||||
"wu-calender.THU": "四",
|
||||
"wu-calender.FRI": "五",
|
||||
"wu-calender.SAT": "六"
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
export default {
|
||||
props: {
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 折叠状态
|
||||
FoldStatus: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
month: {
|
||||
type: [Number, String],
|
||||
default: null
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
startText: {
|
||||
type: String,
|
||||
default: '开始'
|
||||
},
|
||||
endText: {
|
||||
type: String,
|
||||
default: '结束'
|
||||
},
|
||||
weeks: {
|
||||
type: [Object, Array],
|
||||
default: ()=> {
|
||||
return []
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
default: 64
|
||||
},
|
||||
monthShowCurrentMonth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
actBadgeColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
// 默认边距
|
||||
defaultMargin: {
|
||||
type: Number,
|
||||
default: 8
|
||||
},
|
||||
// 是否显示今日默认样式(默认为true)
|
||||
todayDefaultStyle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<view class="wu-calendar-block">
|
||||
<view v-if="showMonth && FoldShowMonth" class="wu-calendar__box-bg">
|
||||
<text class="wu-calendar__box-bg-text">{{month}}</text>
|
||||
</view>
|
||||
<!-- 月或周日历 -->
|
||||
<view class="wu-calendar__weeks" v-for="(item, index) in weeks" :key="index">
|
||||
<template v-for="(weeks, weeksIndex) in item">
|
||||
<wu-calendar-item :key="weeksIndex" v-if="!monthShowCurrentMonth || !weeks.empty" class="wu-calendar-item--hook" :weekItemStyle="weekItemStyle" :weeks="weeks" :calendar="calendar"
|
||||
:selected="selected" :lunar="lunar" @change="choiceDate" :color="color" :actBadgeColor="actBadgeColor"
|
||||
:startText="startText" :endText="endText" :itemHeight="itemHeight - defaultMargin" :todayDefaultStyle="todayDefaultStyle"></wu-calendar-item>
|
||||
<view v-else class="wu-calendar__weeks-item" :style="[weekItemStyle]"></view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/wu-ui-tools/libs/mixin/mpMixin.js';
|
||||
import mixin from '@/uni_modules/wu-ui-tools/libs/mixin/mixin.js';
|
||||
import props from './props.js';
|
||||
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from '../i18n/index.js'
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(i18nMessages)
|
||||
|
||||
export default {
|
||||
emits: ['change'],
|
||||
mixins: [mpMixin, mixin, props],
|
||||
data() {
|
||||
return {
|
||||
FoldShowMonth: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.FoldShowMonth = this.FoldStatus == 'open';
|
||||
},
|
||||
computed: {
|
||||
weekItemStyle() {
|
||||
let weeksLength = Object.keys(this.weeks).length;
|
||||
let calendarHeight = this.FoldStatus === 'open' ? this.itemHeight * 6 : this.itemHeight;
|
||||
let margin = weeksLength && this.weeks[weeksLength - 1][0].empty ? this.itemHeight / (weeksLength - 1) + this.defaultMargin : this.defaultMargin
|
||||
return {
|
||||
marginTop: margin / 2 + 'px',
|
||||
marginBottom: margin / 2 + 'px',
|
||||
height: this.itemHeight - this.defaultMargin + 'px'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
FoldStatus(newVal) {
|
||||
this.$nextTick(()=>{
|
||||
this.FoldShowMonth = this.FoldStatus == 'open';
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$wu-text-color-grey: #999;
|
||||
|
||||
.wu-calendar-block {
|
||||
.wu-calendar__weeks {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.wu-calendar__weeks-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wu-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;
|
||||
}
|
||||
|
||||
.wu-calendar__box-bg-text {
|
||||
font-size: 100rpx;
|
||||
transform: scale(4);
|
||||
font-weight: bold;
|
||||
color: $wu-text-color-grey;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,55 @@
|
||||
export default {
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
startText: {
|
||||
type: String,
|
||||
default: '开始'
|
||||
},
|
||||
endText: {
|
||||
type: String,
|
||||
default: '结束'
|
||||
},
|
||||
weeks: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
default: 64
|
||||
},
|
||||
actBadgeColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
weekItemStyle: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
// 是否显示今日默认样式(默认为true)
|
||||
todayDefaultStyle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<view ref="$weeksBox" class="wu-calendar-item__weeks-box" :style="[calendarItemStyle, weekItemStyle, {
|
||||
borderTopLeftRadius: weeks.beforeRange ? '12rpx' : '',
|
||||
borderBottomLeftRadius: weeks.beforeRange ? '12rpx' : '',
|
||||
borderTopRightRadius: weeks.afterRange ? '12rpx' : '',
|
||||
borderBottomRightRadius: weeks.afterRange ? '12rpx' : '',
|
||||
}]" @click="choiceDate(weeks)">
|
||||
<view class="wu-calendar-item__weeks-box-item" :style="[actMultipleStyle, {width: itemWidth, height: itemHeight + 'px'}]">
|
||||
<!-- 自定义打点上方信息 -->
|
||||
<text v-if="weeks.extraInfo && weeks.extraInfo.topInfo" class="wu-calendar-item__weeks-lunar-text" :style="[{color: weeks.extraInfo.topInfoColor || '#e43d33'}, calendarItemStyle, actMultipleStyle]">{{weeks.extraInfo.topInfo}}</text>
|
||||
<!-- 徽标 -->
|
||||
<text v-if="selected && weeks.extraInfo && weeks.extraInfo.badge" class="wu-calendar-item__weeks-box-circle" :style="[badgeStyle]"></text>
|
||||
<!-- 日期文字 -->
|
||||
<text class="wu-calendar-item__weeks-box-text" :style="[calendarItemStyle, actMultipleStyle]">{{weeks.date}}</text>
|
||||
<!-- 今日的文字 -->
|
||||
<text v-if="!lunar && !weeks.extraInfo && weeks.isDay && !weeks.beforeRange && !weeks.afterRange" class="wu-calendar-item__weeks-lunar-text" :style="[calendarItemStyle, actMultipleStyle]">{{todayText}}</text>
|
||||
<!-- 农历文字 -->
|
||||
<text v-if="lunar && !weeks.extraInfo && !weeks.beforeRange && !weeks.afterRange" class="wu-calendar-item__weeks-lunar-text" :style="[calendarItemStyle, actMultipleStyle]">{{dayText}}</text>
|
||||
<!-- 选中的文字展示 -->
|
||||
<text v-if="!weeks.extraInfo && (weeks.beforeRange || weeks.afterRange)" class="wu-calendar-item__weeks-lunar-text" :style="[calendarItemStyle, actMultipleStyle]">{{multipleText}}</text>
|
||||
<!-- 自定义打点下方信息 -->
|
||||
<text v-if="weeks.extraInfo && weeks.extraInfo.info" class="wu-calendar-item__weeks-lunar-text" :style="[{color: weeks.extraInfo.infoColor || '#e43d33'}, calendarItemStyle, actMultipleStyle]">{{weeks.extraInfo.info}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/wu-ui-tools/libs/mixin/mpMixin.js';
|
||||
import mixin from '@/uni_modules/wu-ui-tools/libs/mixin/mixin.js';
|
||||
import props from './props.js';
|
||||
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from '../i18n/index.js'
|
||||
import { nextTick } from 'vue';
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(i18nMessages)
|
||||
|
||||
export default {
|
||||
emits: ['change'],
|
||||
mixins: [mpMixin, mixin, props],
|
||||
computed: {
|
||||
todayText() {
|
||||
return t("wu-calender.today")
|
||||
},
|
||||
// 每项日历样式
|
||||
calendarItemStyle() {
|
||||
let style = {};
|
||||
let color = this.$w.Color.gradient(this.color, this.$w.Color.isLight(this.color) ? '#000' : '#fff', 100)[6]
|
||||
// 有顺序别乱动
|
||||
// 选中的日期范围内的样式
|
||||
if (this.weeks.rangeMultiple) {
|
||||
style = {
|
||||
backgroundColor: this.$w.Color.gradient(this.color, '#fff', 100)[80],
|
||||
color
|
||||
}
|
||||
};
|
||||
// 今天的日期样式
|
||||
if (this.weeks.isDay && this.todayDefaultStyle) {
|
||||
style.color = color;
|
||||
}
|
||||
// 禁用的日期样式
|
||||
if(this.weeks.disable) {
|
||||
style = {
|
||||
backgroundColor: 'rgba(249, 249, 249, 0.3)',
|
||||
color: '#c0c0c0'
|
||||
}
|
||||
}
|
||||
return style;
|
||||
},
|
||||
// 选中的日期样式
|
||||
actMultipleStyle() {
|
||||
if ((this.weeks.beforeRange || this.weeks.afterRange || this.weeks.multiples || (this.calendar.fullDate === this.weeks
|
||||
.fullDate && this.weeks.mode === 'single')) && !this.weeks.disable) {
|
||||
// #ifdef APP-NVUE
|
||||
if(this.itemWidth == '100%') return {};
|
||||
return {
|
||||
backgroundColor: this.color,
|
||||
color: '#fff',
|
||||
borderRadius: '12rpx'
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
return {
|
||||
backgroundColor: this.color,
|
||||
color: '#fff',
|
||||
borderRadius: '12rpx'
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
// 徽标样式
|
||||
badgeStyle() {
|
||||
let style = {
|
||||
backgroundColor: this.weeks.disable ? '#c0c0c0' : '#e43d33',
|
||||
width: '16rpx',
|
||||
height: '16rpx'
|
||||
};
|
||||
if(this.weeks.extraInfo) {
|
||||
if(this.weeks.extraInfo.badgeColor) {
|
||||
// 如果当前是选中日期的徽标且徽标颜色与主题色一致 为了保证 徽标颜色可以被看见 再选中时将其设置为 #fff
|
||||
if ((this.weeks.beforeRange || this.weeks.afterRange || this.weeks.multiples || (this.calendar.fullDate === this.weeks
|
||||
.fullDate && this.weeks.mode === 'single')) && !this.weeks.disable && this.$w.Color.convertFormat(this.weeks.extraInfo.badgeColor) == this.$w.Color.convertFormat(this.color)) {
|
||||
style.backgroundColor = this.actBadgeColor;
|
||||
} else {
|
||||
style.backgroundColor = this.weeks.extraInfo.badgeColor
|
||||
}
|
||||
}
|
||||
if(this.weeks.extraInfo.badgeSize) {
|
||||
style.width = this.weeks.extraInfo.badgeSize
|
||||
style.height = this.weeks.extraInfo.badgeSize
|
||||
}
|
||||
|
||||
if(!this.weeks.extraInfo.badgePosition) {
|
||||
style.right = '10rpx';
|
||||
style.top = '10rpx';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'top-left'){
|
||||
style.top = '10rpx';
|
||||
style.left = '10rpx';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'top-center'){
|
||||
style.top = '10rpx';
|
||||
style.left = 'center';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'top-right'){
|
||||
style.top = '10rpx';
|
||||
style.right = '10rpx';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'bottom-left'){
|
||||
style.bottom = '10rpx';
|
||||
style.left = '10rpx';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'bottom-center'){
|
||||
style.bottom = '10rpx';
|
||||
style.left = 'center';
|
||||
} else if(this.weeks.extraInfo.badgePosition == 'bottom-right'){
|
||||
style.bottom = '10rpx';
|
||||
style.right = '10rpx';
|
||||
}
|
||||
}
|
||||
|
||||
return style
|
||||
},
|
||||
// 日期文字
|
||||
dayText() {
|
||||
let text = '';
|
||||
if (this.weeks.isDay) {
|
||||
text = this.todayText
|
||||
} else if(this.weeks.lunar.festival) {
|
||||
text = this.weeks.lunar.festival
|
||||
} else if(this.weeks.lunar.isTerm) {
|
||||
text = this.weeks.lunar.Term
|
||||
} else if (this.weeks.lunar.IDayCn === '初一') {
|
||||
text = this.weeks.lunar.IMonthCn
|
||||
} else {
|
||||
text = this.weeks.lunar.IDayCn
|
||||
}
|
||||
return text
|
||||
},
|
||||
// 选中的文字
|
||||
multipleText() {
|
||||
let text = '';
|
||||
if (this.weeks.afterRange) {
|
||||
text = this.endText
|
||||
} else if (this.weeks.beforeRange) {
|
||||
text = this.startText
|
||||
}
|
||||
return text;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemWidth: '100%'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// #ifdef APP-NVUE
|
||||
setTimeout(()=>{
|
||||
const dom = uni.requireNativePlugin('dom');
|
||||
dom.getComponentRect(this.$refs.$weeksBox, res=> {
|
||||
this.itemWidth = res.size.width + 'px';
|
||||
})
|
||||
}, 10)
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/uni_modules/wu-ui-tools/theme.scss';
|
||||
$wu-font-size-base: 28rpx;
|
||||
$wu-text-color: #333;
|
||||
$wu-font-size-sm: 24rpx;
|
||||
$wu-color-error: #e43d33;
|
||||
$wu-opacity-disabled: 0.3;
|
||||
$wu-text-color-disable: #c0c0c0;
|
||||
|
||||
.wu-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 0.5px;
|
||||
}
|
||||
|
||||
.wu-calendar-item__weeks-box-text {
|
||||
font-size: $wu-font-size-base;
|
||||
color: $wu-text-color;
|
||||
}
|
||||
|
||||
.wu-calendar-item__weeks-lunar-text {
|
||||
font-size: $wu-font-size-sm;
|
||||
color: $wu-text-color;
|
||||
}
|
||||
|
||||
.wu-calendar-item__weeks-box-item {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wu-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
border-radius: 16rpx;
|
||||
background-color: $wu-color-error;
|
||||
}
|
||||
|
||||
.wu-calendar-item--disable {
|
||||
background-color: rgba(249, 249, 249, $wu-opacity-disabled);
|
||||
color: $wu-text-color-disable;
|
||||
}
|
||||
|
||||
.wu-calendar-item--extra {
|
||||
color: $wu-color-error;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.wu-calendar-item--checked {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
664
src/uni_modules/wu-calendar/components/wu-calendar/calendar.js
Normal file
664
src/uni_modules/wu-calendar/components/wu-calendar/calendar.js
Normal file
@ -0,0 +1,664 @@
|
||||
/**
|
||||
* @1900-2100区间内的公历、农历互转
|
||||
* @charset UTF-8
|
||||
* @github https://github.com/jjonline/calendar.js
|
||||
* @Author Jea杨(JJonline@JJonline.Cn)
|
||||
* @Time 2014-7-21
|
||||
* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
|
||||
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
|
||||
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
|
||||
* @Version 1.0.3
|
||||
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
|
||||
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
|
||||
*/
|
||||
/* eslint-disable */
|
||||
var calendar = {
|
||||
|
||||
/**
|
||||
* 农历1900-2100的润大小信息表
|
||||
* @Array Of Property
|
||||
* @return Hex
|
||||
*/
|
||||
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0,
|
||||
0x055d2, // 1900-1909
|
||||
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
|
||||
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
|
||||
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
|
||||
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
|
||||
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
|
||||
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
|
||||
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
|
||||
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
|
||||
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
|
||||
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
|
||||
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
|
||||
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
|
||||
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
|
||||
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
|
||||
/** Add By JJonline@JJonline.Cn**/
|
||||
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
|
||||
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
|
||||
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
|
||||
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
|
||||
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
|
||||
0x0d520
|
||||
], // 2100
|
||||
|
||||
/**
|
||||
* 公历每个月份的天数普通表
|
||||
* @Array Of Property
|
||||
* @return Number
|
||||
*/
|
||||
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||
|
||||
/**
|
||||
* 天干地支之天干速查表
|
||||
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表
|
||||
* @Array Of Property
|
||||
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149',
|
||||
'\u620c', '\u4ea5'
|
||||
],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表<=>生肖
|
||||
* @Array Of Property
|
||||
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21',
|
||||
'\u72d7', '\u732a'
|
||||
],
|
||||
|
||||
/**
|
||||
* 24节气速查表
|
||||
* @Array Of Property
|
||||
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
|
||||
* @return Cn string
|
||||
*/
|
||||
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206',
|
||||
'\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3',
|
||||
'\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206',
|
||||
'\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'
|
||||
],
|
||||
|
||||
/**
|
||||
* 1900-2100各年的24节气日期速查表
|
||||
* @Array Of Property
|
||||
* @return 0x string For splice
|
||||
*/
|
||||
sTermInfo: [
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
|
||||
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
|
||||
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
|
||||
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
|
||||
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
|
||||
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
|
||||
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
|
||||
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
|
||||
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
|
||||
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'
|
||||
],
|
||||
|
||||
festivals: {
|
||||
'1-1': '元旦',
|
||||
'2-14': '情人节',
|
||||
'3-8': '妇女节',
|
||||
'3-12': '植树节',
|
||||
'4-1': '愚人节',
|
||||
'5-1': '劳动节',
|
||||
'5-4': '青年节',
|
||||
'5-12': '护士节',
|
||||
'6-1': '儿童节',
|
||||
'8-1': '建军节',
|
||||
'9-10': '教师节',
|
||||
'10-1': '国庆',
|
||||
'11-1': '万圣节',
|
||||
'12-24': '圣诞节',
|
||||
'正月初一': '春节',
|
||||
'二月初二': '龙抬头',
|
||||
'五月初五': '端午节',
|
||||
'七月初七': '七夕节',
|
||||
'七月十五': '中元节',
|
||||
'八月十五': '中秋节',
|
||||
'九月初九': '重阳节',
|
||||
'腊月初八': '腊八节',
|
||||
'腊月廿三': '小年',
|
||||
'腊月三十': '除夕',
|
||||
},
|
||||
|
||||
/**
|
||||
* 数字转中文速查表
|
||||
* @Array Of Property
|
||||
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d',
|
||||
'\u5341'
|
||||
],
|
||||
|
||||
/**
|
||||
* 日期转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['初','十','廿','卅']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
|
||||
|
||||
/**
|
||||
* 月份转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341',
|
||||
'\u51ac', '\u814a'
|
||||
],
|
||||
|
||||
/**
|
||||
* 返回农历y年一整年的总天数
|
||||
* @param lunar Year
|
||||
* @return Number
|
||||
* @eg:var count = calendar.lYearDays(1987) ;//count=387
|
||||
*/
|
||||
lYearDays: function(y) {
|
||||
var i;
|
||||
var sum = 348
|
||||
for (i = 0x8000; i > 0x8; i >>= 1) {
|
||||
sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0
|
||||
}
|
||||
return (sum + this.leapDays(y))
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0-12)
|
||||
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
|
||||
*/
|
||||
leapMonth: function(y) { // 闰字编码 \u95f0
|
||||
return (this.lunarInfo[y - 1900] & 0xf)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月的天数 若该年没有闰月则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0、29、30)
|
||||
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
|
||||
*/
|
||||
leapDays: function(y) {
|
||||
if (this.leapMonth(y)) {
|
||||
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
|
||||
}
|
||||
return (0)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
|
||||
* @param lunar Year
|
||||
* @return Number (-1、29、30)
|
||||
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
|
||||
*/
|
||||
monthDays: function(y, m) {
|
||||
if (m > 12 || m < 1) {
|
||||
return -1
|
||||
} // 月份参数从1至12,参数错误返回-1
|
||||
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回公历(!)y年m月的天数
|
||||
* @param solar Year
|
||||
* @return Number (-1、28、29、30、31)
|
||||
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
|
||||
*/
|
||||
solarDays: function(y, m) {
|
||||
if (m > 12 || m < 1) {
|
||||
return -1
|
||||
} // 若参数错误 返回-1
|
||||
var ms = m - 1
|
||||
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
|
||||
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
|
||||
} else {
|
||||
return (this.solarMonth[ms])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 农历年份转换为干支纪年
|
||||
* @param lYear 农历年的年份数
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhiYear: function(lYear) {
|
||||
var ganKey = (lYear - 3) % 10
|
||||
var zhiKey = (lYear - 3) % 12
|
||||
if (ganKey == 0) ganKey = 10 // 如果余数为0则为最后一个天干
|
||||
if (zhiKey == 0) zhiKey = 12 // 如果余数为0则为最后一个地支
|
||||
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
|
||||
},
|
||||
|
||||
/**
|
||||
* 公历月、日判断所属星座
|
||||
* @param cMonth [description]
|
||||
* @param cDay [description]
|
||||
* @return Cn string
|
||||
*/
|
||||
toAstro: function(cMonth, cDay) {
|
||||
var s =
|
||||
'\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
|
||||
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
|
||||
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7' // 座
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入offset偏移量返回干支
|
||||
* @param offset 相对甲子的偏移量
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhi: function(offset) {
|
||||
return this.Gan[offset % 10] + this.Zhi[offset % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入公历(!)y年获得该年第n个节气的公历日期
|
||||
* @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
|
||||
* @return day Number
|
||||
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
|
||||
*/
|
||||
getTerm: function(y, n) {
|
||||
if (y < 1900 || y > 2100) {
|
||||
return -1
|
||||
}
|
||||
if (n < 1 || n > 24) {
|
||||
return -1
|
||||
}
|
||||
var _table = this.sTermInfo[y - 1900]
|
||||
var _info = [
|
||||
parseInt('0x' + _table.substr(0, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(5, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(10, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(15, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(20, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(25, 5)).toString()
|
||||
]
|
||||
var _calday = [
|
||||
_info[0].substr(0, 1),
|
||||
_info[0].substr(1, 2),
|
||||
_info[0].substr(3, 1),
|
||||
_info[0].substr(4, 2),
|
||||
|
||||
_info[1].substr(0, 1),
|
||||
_info[1].substr(1, 2),
|
||||
_info[1].substr(3, 1),
|
||||
_info[1].substr(4, 2),
|
||||
|
||||
_info[2].substr(0, 1),
|
||||
_info[2].substr(1, 2),
|
||||
_info[2].substr(3, 1),
|
||||
_info[2].substr(4, 2),
|
||||
|
||||
_info[3].substr(0, 1),
|
||||
_info[3].substr(1, 2),
|
||||
_info[3].substr(3, 1),
|
||||
_info[3].substr(4, 2),
|
||||
|
||||
_info[4].substr(0, 1),
|
||||
_info[4].substr(1, 2),
|
||||
_info[4].substr(3, 1),
|
||||
_info[4].substr(4, 2),
|
||||
|
||||
_info[5].substr(0, 1),
|
||||
_info[5].substr(1, 2),
|
||||
_info[5].substr(3, 1),
|
||||
_info[5].substr(4, 2)
|
||||
]
|
||||
return parseInt(_calday[n - 1])
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历数字月份返回汉语通俗表示法
|
||||
* @param lunar month
|
||||
* @return Cn string
|
||||
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
|
||||
*/
|
||||
toChinaMonth: function(m) { // 月 => \u6708
|
||||
if (m > 12 || m < 1) {
|
||||
return -1
|
||||
} // 若参数错误 返回-1
|
||||
var s = this.nStr3[m - 1]
|
||||
s += '\u6708' // 加上月字
|
||||
return s
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历日期数字返回汉字表示法
|
||||
* @param lunar day
|
||||
* @return Cn string
|
||||
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
|
||||
*/
|
||||
toChinaDay: function(d) { // 日 => \u65e5
|
||||
var s
|
||||
switch (d) {
|
||||
case 10:
|
||||
s = '\u521d\u5341';
|
||||
break
|
||||
case 20:
|
||||
s = '\u4e8c\u5341';
|
||||
break
|
||||
break
|
||||
case 30:
|
||||
s = '\u4e09\u5341';
|
||||
break
|
||||
break
|
||||
default:
|
||||
s = this.nStr2[Math.floor(d / 10)]
|
||||
s += this.nStr1[d % 10]
|
||||
}
|
||||
return (s)
|
||||
},
|
||||
|
||||
/**
|
||||
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
|
||||
* @param y year
|
||||
* @return Cn string
|
||||
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
|
||||
*/
|
||||
getAnimal: function(y) {
|
||||
return this.Animals[(y - 4) % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y solar year
|
||||
* @param m solar month
|
||||
* @param d solar day
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.solar2lunar(1987,11,01));
|
||||
*/
|
||||
solar2lunar: function(y, m, d) { // 参数区间1900.1.31~2100.12.31
|
||||
// 年份限定、上限
|
||||
if (y < 1900 || y > 2100) {
|
||||
return -1 // undefined转换为数字变为NaN
|
||||
}
|
||||
// 公历传参最下限
|
||||
if (y == 1900 && m == 1 && d < 31) {
|
||||
return -1
|
||||
}
|
||||
// 未传参 获得当天
|
||||
if (!y) {
|
||||
var objDate = new Date()
|
||||
} else {
|
||||
var objDate = new Date(y, parseInt(m) - 1, d)
|
||||
}
|
||||
var i;
|
||||
var leap = 0;
|
||||
var temp = 0
|
||||
// 修正ymd参数
|
||||
var y = objDate.getFullYear()
|
||||
var m = objDate.getMonth() + 1
|
||||
var d = objDate.getDate()
|
||||
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0,
|
||||
31)) / 86400000
|
||||
for (i = 1900; i < 2101 && offset > 0; i++) {
|
||||
temp = this.lYearDays(i)
|
||||
offset -= temp
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp;
|
||||
i--
|
||||
}
|
||||
|
||||
// 是否今天
|
||||
var isTodayObj = new Date()
|
||||
var isToday = false
|
||||
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
|
||||
isToday = true
|
||||
}
|
||||
// 星期几
|
||||
var nWeek = objDate.getDay()
|
||||
var cWeek = this.nStr1[nWeek]
|
||||
// 数字表示周几顺应天朝周一开始的惯例
|
||||
if (nWeek == 0) {
|
||||
nWeek = 7
|
||||
}
|
||||
// 农历年
|
||||
var year = i
|
||||
var leap = this.leapMonth(i) // 闰哪个月
|
||||
var isLeap = false
|
||||
|
||||
// 效验闰月
|
||||
for (i = 1; i < 13 && offset > 0; i++) {
|
||||
// 闰月
|
||||
if (leap > 0 && i == (leap + 1) && isLeap == false) {
|
||||
--i
|
||||
isLeap = true;
|
||||
temp = this.leapDays(year) // 计算农历闰月天数
|
||||
} else {
|
||||
temp = this.monthDays(year, i) // 计算农历普通月天数
|
||||
}
|
||||
// 解除闰月
|
||||
if (isLeap == true && i == (leap + 1)) {
|
||||
isLeap = false
|
||||
}
|
||||
offset -= temp
|
||||
}
|
||||
// 闰月导致数组下标重叠取反
|
||||
if (offset == 0 && leap > 0 && i == leap + 1) {
|
||||
if (isLeap) {
|
||||
isLeap = false
|
||||
} else {
|
||||
isLeap = true;
|
||||
--i
|
||||
}
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp;
|
||||
--i
|
||||
}
|
||||
// 农历月
|
||||
var month = i
|
||||
// 农历日
|
||||
var day = offset + 1
|
||||
// 天干地支处理
|
||||
var sm = m - 1
|
||||
var gzY = this.toGanZhiYear(year)
|
||||
|
||||
// 当月的两个节气
|
||||
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
|
||||
var firstNode = this.getTerm(y, (m * 2 - 1)) // 返回当月「节」为几日开始
|
||||
var secondNode = this.getTerm(y, (m * 2)) // 返回当月「节」为几日开始
|
||||
|
||||
// 依据12节气修正干支月
|
||||
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
|
||||
if (d >= firstNode) {
|
||||
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
|
||||
}
|
||||
|
||||
// 传入的日期的节气与否
|
||||
var isTerm = false
|
||||
var Term = null
|
||||
if (firstNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 2]
|
||||
}
|
||||
if (secondNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 1]
|
||||
}
|
||||
|
||||
// 计算农历日期
|
||||
const IMonthCn = (isLeap ? '\u95f0' : '') + this.toChinaMonth(month)
|
||||
// 农历日期的汉字表述法
|
||||
let IDayCn = this.toChinaDay(day)
|
||||
|
||||
// 节日
|
||||
let festival = '';
|
||||
// 农历的月日汉字表述
|
||||
let lMDcn = IMonthCn + IDayCn;
|
||||
// 月份日期
|
||||
let MD = m + '-' + d;
|
||||
if (this.festivals.hasOwnProperty(lMDcn)) {
|
||||
festival = this.festivals[lMDcn]
|
||||
} else if(this.festivals.hasOwnProperty(MD)) {
|
||||
festival = this.festivals[MD]
|
||||
}
|
||||
|
||||
// 日柱 当月一日与 1900/1/1 相差天数
|
||||
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
|
||||
var gzD = this.toGanZhi(dayCyclical + d - 1)
|
||||
// 该日期所属的星座
|
||||
var astro = this.toAstro(m, d)
|
||||
|
||||
return {
|
||||
'lYear': year,
|
||||
'lMonth': month,
|
||||
'lDay': day,
|
||||
'Animal': this.getAnimal(year),
|
||||
'IMonthCn': IMonthCn,
|
||||
'IDayCn': IDayCn,
|
||||
'cYear': y,
|
||||
'cMonth': m,
|
||||
'cDay': d,
|
||||
'gzYear': gzY,
|
||||
'gzMonth': gzM,
|
||||
'gzDay': gzD,
|
||||
'isToday': isToday,
|
||||
'isLeap': isLeap,
|
||||
'nWeek': nWeek,
|
||||
'ncWeek': '\u661f\u671f' + cWeek,
|
||||
'isTerm': isTerm,
|
||||
'Term': Term,
|
||||
'astro': astro,
|
||||
'festival': festival
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y lunar year
|
||||
* @param m lunar month
|
||||
* @param d lunar day
|
||||
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.lunar2solar(1987,9,10));
|
||||
*/
|
||||
lunar2solar: function(y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
|
||||
var isLeapMonth = !!isLeapMonth
|
||||
var leapOffset = 0
|
||||
var leapMonth = this.leapMonth(y)
|
||||
var leapDay = this.leapDays(y)
|
||||
if (isLeapMonth && (leapMonth != m)) {
|
||||
return -1
|
||||
} // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
|
||||
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) {
|
||||
return -1
|
||||
} // 超出了最大极限值
|
||||
var day = this.monthDays(y, m)
|
||||
var _day = day
|
||||
// bugFix 2016-9-25
|
||||
// if month is leap, _day use leapDays method
|
||||
if (isLeapMonth) {
|
||||
_day = this.leapDays(y, m)
|
||||
}
|
||||
if (y < 1900 || y > 2100 || d > _day) {
|
||||
return -1
|
||||
} // 参数合法性效验
|
||||
|
||||
// 计算农历的时间差
|
||||
var offset = 0
|
||||
for (var i = 1900; i < y; i++) {
|
||||
offset += this.lYearDays(i)
|
||||
}
|
||||
var leap = 0;
|
||||
var isAdd = false
|
||||
for (var i = 1; i < m; i++) {
|
||||
leap = this.leapMonth(y)
|
||||
if (!isAdd) { // 处理闰月
|
||||
if (leap <= i && leap > 0) {
|
||||
offset += this.leapDays(y);
|
||||
isAdd = true
|
||||
}
|
||||
}
|
||||
offset += this.monthDays(y, i)
|
||||
}
|
||||
// 转换闰月农历 需补充该年闰月的前一个月的时差
|
||||
if (isLeapMonth) {
|
||||
offset += day
|
||||
}
|
||||
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
|
||||
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
|
||||
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
|
||||
var cY = calObj.getUTCFullYear()
|
||||
var cM = calObj.getUTCMonth() + 1
|
||||
var cD = calObj.getUTCDate()
|
||||
|
||||
return this.solar2lunar(cY, cM, cD)
|
||||
}
|
||||
}
|
||||
|
||||
export default calendar
|
||||
166
src/uni_modules/wu-calendar/components/wu-calendar/props.js
Normal file
166
src/uni_modules/wu-calendar/components/wu-calendar/props.js
Normal file
@ -0,0 +1,166 @@
|
||||
export default {
|
||||
props: {
|
||||
// 自定义当前时间
|
||||
date: {
|
||||
type: [String, Array],
|
||||
default: ''
|
||||
},
|
||||
// 日历类型(默认为month)
|
||||
type: {
|
||||
type: String,
|
||||
default: 'month',
|
||||
validator(value) {
|
||||
return ['month', 'week'].includes(value)
|
||||
}
|
||||
},
|
||||
// 日期选择模式
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'single'
|
||||
},
|
||||
// 是否使用默认日期(今天,默认为true)
|
||||
useToday: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示今日默认样式(默认为true)
|
||||
todayDefaultStyle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否使用折叠功能
|
||||
fold: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
},
|
||||
// 主题色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#3c9cff'
|
||||
},
|
||||
// 日历中每一项日期的高度(默认70),单位px
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
default: 70
|
||||
},
|
||||
// 取消文字的颜色
|
||||
cancelColor: {
|
||||
type: String,
|
||||
default: '#333'
|
||||
},
|
||||
// 确定文字的颜色
|
||||
confirmColor: {
|
||||
type: String,
|
||||
default: '#333'
|
||||
},
|
||||
// mode=range时,第一个日期底部的提示文字
|
||||
startText: {
|
||||
type: String,
|
||||
default: '开始'
|
||||
},
|
||||
// mode=range时,最后一个日期底部的提示文字
|
||||
endText: {
|
||||
type: String,
|
||||
default: '结束'
|
||||
},
|
||||
// 日历以周几开始
|
||||
startWeek: {
|
||||
type: String,
|
||||
default: 'sun',
|
||||
validator(value) {
|
||||
return ['sun', 'mon'].includes(value)
|
||||
}
|
||||
},
|
||||
// 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否显示农历
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 日期选择范围-开始日期
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 日期选择范围-结束日期
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 允许日期选择范围内重选结束日期
|
||||
rangeEndRepick: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 允许日期选择范围起始日期为同一天
|
||||
rangeSameDay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 允许日期选择范围内遇到打点禁用日期进行截断
|
||||
rangeHaveDisableTruncation: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 每月仅显示当月日期
|
||||
monthShowCurrentMonth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 插入模式,可选值,ture:插入模式;false:弹窗模式; 默认为插入模式
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 滑动切换模式,可选值 horizontal: 横向 vertical:纵向 none: 不使用滑动切换
|
||||
slideSwitchMode: {
|
||||
type: String,
|
||||
default: 'horizontal'
|
||||
},
|
||||
// 是否显示月份为背景
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹窗模式是否清空上次选择内容
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否点击遮罩层关闭
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否禁止点击日历
|
||||
disabledChoice: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 弹窗日历取消和确认按钮的显示位置
|
||||
operationPosition: {
|
||||
type: String,
|
||||
default: 'top',
|
||||
validator(value) {
|
||||
return ['top', 'bottom'].includes(value)
|
||||
}
|
||||
},
|
||||
// 弹窗日历点击确认时是否需要选择完整日期
|
||||
confirmFullDate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 当通过 `selected` 属性设置某个日期 `badgeColor`后,如果该日期被选择且主题色与 `badgeColor` 一致时,徽标会显示本颜色
|
||||
actBadgeColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
...uni.$w?.props?.calendar
|
||||
}
|
||||
}
|
||||
552
src/uni_modules/wu-calendar/components/wu-calendar/util.js
Normal file
552
src/uni_modules/wu-calendar/components/wu-calendar/util.js
Normal file
@ -0,0 +1,552 @@
|
||||
import calendar from './calendar.js';
|
||||
import CALENDAR from './calendar.js'
|
||||
|
||||
class Calendar {
|
||||
constructor({
|
||||
date,
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
mode,
|
||||
monthShowCurrentMonth,
|
||||
rangeEndRepick,
|
||||
rangeSameDay,
|
||||
rangeHaveDisableTruncation,
|
||||
type,
|
||||
foldStatus,
|
||||
startWeek
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDate(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
// 日历以周几开始
|
||||
this.startWeek = startWeek
|
||||
// 日期选择类型
|
||||
this.mode = mode
|
||||
// 日历类型
|
||||
this.type = type
|
||||
// 折叠状态
|
||||
this.foldStatus = foldStatus
|
||||
// 允许范围内重选结束日期
|
||||
this.rangeEndRepick = rangeEndRepick
|
||||
// 允许日期选择范围起始日期为同一天
|
||||
this.rangeSameDay = rangeSameDay
|
||||
// 日期选择范围内遇到打点禁用日期是否截断
|
||||
this.rangeHaveDisableTruncation = rangeHaveDisableTruncation
|
||||
// 每月是否仅显示当月的数据
|
||||
this.monthShowCurrentMonth = monthShowCurrentMonth
|
||||
// 清理多选状态
|
||||
this.cleanRange()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
// 多个日期
|
||||
this.multiple = [];
|
||||
}
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.selectDate = this.getDate(date)
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除范围
|
||||
*/
|
||||
cleanRange() {
|
||||
this.rangeStatus = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除多选
|
||||
*/
|
||||
cleanMultiple() {
|
||||
this.multiple = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置开始日期
|
||||
*/
|
||||
resetSatrtDate(startDate) {
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置结束日期
|
||||
*/
|
||||
resetEndDate(endDate) {
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置是否每月仅显示当月数据
|
||||
* @param {Boolean} show 是否仅显示当月数据
|
||||
*/
|
||||
resetMonthShowCurrentMonth(show) {
|
||||
this.monthShowCurrentMonth = show
|
||||
}
|
||||
|
||||
// 重置允许范围内重选结束日期
|
||||
resetRangeEndRepick(val) {
|
||||
this.rangeEndRepick = val
|
||||
}
|
||||
|
||||
// 重置允许日期范围选择起始日期为同一天
|
||||
resetRangeSameDay(val) {
|
||||
this.rangeSameDay = val
|
||||
}
|
||||
|
||||
// 重置范围内遇到打点禁用日期是否截断
|
||||
resetRangeHaveDisableTruncation(val) {
|
||||
this.rangeHaveDisableTruncation = val
|
||||
}
|
||||
|
||||
// 重置日期选择模式
|
||||
resetMode(val) {
|
||||
this.mode = val
|
||||
}
|
||||
|
||||
// 重置折叠状态
|
||||
resetFoldStatus(val) {
|
||||
this.foldStatus = val
|
||||
}
|
||||
|
||||
// 重置日历以周几开始
|
||||
resetStartWeek(val) {
|
||||
this.startWeek = val
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建本月某一天的信息
|
||||
*/
|
||||
_createCurrentDay(nowDate, full, date) {
|
||||
// 是否今天
|
||||
let isDay = this.date.fullDate === nowDate
|
||||
// 获取打点信息
|
||||
let info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(nowDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
disableBefore = this.dateCompare(this.startDate, nowDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
disableAfter = this.dateCompare(nowDate, this.endDate)
|
||||
}
|
||||
|
||||
// 范围选择模式
|
||||
let ranges = this.rangeStatus.data
|
||||
let checked = false
|
||||
if (this.mode == 'range') {
|
||||
checked = ranges.findIndex((item) => this.dateEqual(item, nowDate)) !== -1 ? true : false;
|
||||
}
|
||||
|
||||
// 多日期选择模式
|
||||
let multiples = this.multiple
|
||||
let multiplesChecked = false
|
||||
if (this.mode == 'multiple') {
|
||||
multiplesChecked = multiples.findIndex(item => this.dateEqual(item, nowDate)) !== -1;
|
||||
}
|
||||
|
||||
let data = {
|
||||
fullDate: nowDate,
|
||||
year: full.year,
|
||||
date,
|
||||
type: this.type,
|
||||
mode: this.mode,
|
||||
multiples: this.mode == 'multiple' ? multiplesChecked : false,
|
||||
rangeMultiple: this.mode == 'range' ? checked : false,
|
||||
beforeRange: this.dateEqual(this.rangeStatus.before, nowDate),
|
||||
afterRange: this.dateEqual(this.rangeStatus.after, nowDate),
|
||||
month: full.month,
|
||||
lunar: this.getlunar(full.year, full.month, date),
|
||||
disable: !(disableBefore && disableAfter),
|
||||
isDay
|
||||
}
|
||||
|
||||
|
||||
if (info) {
|
||||
data.extraInfo = info;
|
||||
data.disable = info.disable || false;
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任意时间
|
||||
*/
|
||||
getDate(date, AddDayCount = 0, str = 'day') {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31 && AddDayCount > 0) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
const preMonth = dd.getMonth()
|
||||
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
|
||||
const nextMonth = dd.getMonth()
|
||||
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if (AddDayCount < 0 && preMonth !== 0 && nextMonth - preMonth > AddDayCount) {
|
||||
dd.setMonth(nextMonth + (nextMonth - preMonth + AddDayCount))
|
||||
}
|
||||
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if (AddDayCount > 0 && nextMonth - preMonth > AddDayCount) {
|
||||
dd.setMonth(nextMonth - (nextMonth - preMonth - AddDayCount))
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'week':
|
||||
dd.setDate(dd.getDate() + (AddDayCount * 7))
|
||||
break;
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上月剩余天数
|
||||
*/
|
||||
_getLastMonthDays(firstDay, full) {
|
||||
let dateArr = []
|
||||
for (let i = firstDay; i > 0; i--) {
|
||||
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
|
||||
dateArr.push({
|
||||
date: beforeDate,
|
||||
month: full.month - 1,
|
||||
year: full.year,
|
||||
lunar: this.getlunar(full.year, full.month - 1, beforeDate),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取本月天数
|
||||
*/
|
||||
_currentMonthDays(dateData, full) {
|
||||
let dateArr = []
|
||||
let fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= dateData; i++) {
|
||||
let nowDate = full.year + '-' + (full.month < 10 ?
|
||||
full.month : full.month) + '-' + (i < 10 ?
|
||||
'0' + i : i)
|
||||
dateArr.push(this._createCurrentDay(nowDate, full, i))
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取下月天数
|
||||
*/
|
||||
_getNextMonthDays(surplus, full) {
|
||||
let dateArr = []
|
||||
for (let i = 1; i < surplus + 1; i++) {
|
||||
dateArr.push({
|
||||
date: i,
|
||||
month: Number(full.month) + 1,
|
||||
lunar: this.getlunar(full.year, Number(full.month) + 1, i),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取任意日期的一周
|
||||
*/
|
||||
_getWeekDays(dateData) {
|
||||
let dateArr = [];
|
||||
let oneDayTime = 1000 * 60 * 60 * 24
|
||||
let today = new Date(dateData);
|
||||
// 获取这个日期是星期几
|
||||
let todayDay;
|
||||
let startDate;
|
||||
// 如果日历以周一开始
|
||||
if(this.startWeek == 'mon') {
|
||||
todayDay = today.getDay() || 7;
|
||||
startDate = new Date(today.getTime() - oneDayTime * (todayDay - 1));
|
||||
} else {
|
||||
todayDay = today.getDay();
|
||||
startDate = new Date(today.getTime() - oneDayTime * todayDay);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
let temp = new Date(startDate.getTime() + i * oneDayTime)
|
||||
let newDate = this.getDate(`${temp.getFullYear()}-${temp.getMonth() + 1}-${temp.getDate()}`)
|
||||
dateArr.push(this._createCurrentDay(newDate.fullDate, newDate, Number(newDate.date)))
|
||||
}
|
||||
|
||||
return dateArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
|
||||
return dateInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before = '', after = '') {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (before.getTime() - after.getTime() === 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @param {Object} begin
|
||||
* @param {Object} end
|
||||
*/
|
||||
getDateAll(begin, end) {
|
||||
// 找出所有打点中已禁用的部分 不让其被添加在日期选择范围内
|
||||
let disableList = this.selected.filter(item => item.date && item.disable).map(item => item.date)
|
||||
|
||||
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 wuxDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||
var wuxDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = wuxDb; k <= wuxDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
let fullDate = this.getDate(new Date(parseInt(k))).fullDate
|
||||
// 如果要在选择范围内截断日期
|
||||
if(this.rangeHaveDisableTruncation) {
|
||||
// 如果不在打点禁止列表中
|
||||
if (disableList.includes(fullDate)) return arr;
|
||||
arr.push(fullDate)
|
||||
} else {
|
||||
if (!disableList.includes(fullDate)) arr.push(fullDate);
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
/**
|
||||
* 计算阴历日期显示
|
||||
*/
|
||||
getlunar(year, month, date) {
|
||||
return CALENDAR.solar2lunar(year, month, date)
|
||||
}
|
||||
/**
|
||||
* 设置打点
|
||||
*/
|
||||
setSelectInfo(data, value) {
|
||||
this.selected = value
|
||||
this._getWeek(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置范围
|
||||
*/
|
||||
setRange(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.rangeStatus;
|
||||
|
||||
// 非范围选择不再执行
|
||||
if (this.mode != 'range') return
|
||||
|
||||
// 判断目前的日期 是否 比before日期小或者等于before日期 如果为true就要重置
|
||||
let reset = this.dateCompare(fullDate, before);
|
||||
// 如果日期选择范围允许为同一天 且 目前是需要重置的
|
||||
if (this.rangeSameDay && before && reset) {
|
||||
// 判断是否需要相等 如果 不相等 则 重置 如果相等 则不重置
|
||||
reset = !this.dateEqual(fullDate, before);
|
||||
}
|
||||
|
||||
if ((before && after || reset) && (!this.rangeEndRepick || (this.rangeEndRepick && this.rangeStatus.data
|
||||
.indexOf(fullDate) == -1))) {
|
||||
this.rangeStatus.before = fullDate;
|
||||
this.rangeStatus.after = '';
|
||||
this.rangeStatus.data = [];
|
||||
} else {
|
||||
if (!before) {
|
||||
this.rangeStatus.before = fullDate
|
||||
} else {
|
||||
if (this.dateCompare(this.rangeStatus.before, fullDate)) {
|
||||
this.rangeStatus.data = this.getDateAll(this.rangeStatus.before, fullDate);
|
||||
} else {
|
||||
this.rangeStatus.data = this.getDateAll(fullDate, this.rangeStatus.before);
|
||||
}
|
||||
this.rangeStatus.after = this.rangeStatus.data[this.rangeStatus.data.length - 1]
|
||||
}
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置多选
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
// 非多选不再执行
|
||||
if (this.mode != 'multiple') return
|
||||
// 检查是否已经多选
|
||||
let index = this.multiple.findIndex((item) => {
|
||||
if (this.dateEqual(fullDate, item)) {
|
||||
return item
|
||||
}
|
||||
});
|
||||
if (index === -1) {
|
||||
this.multiple.push(fullDate)
|
||||
this.setDate(fullDate)
|
||||
} else {
|
||||
this.multiple = this.multiple.filter((item, i) => i != index)
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
_getWeek(dateData, useWeeks = true) {
|
||||
const {
|
||||
year,
|
||||
month
|
||||
} = this.getDate(dateData)
|
||||
|
||||
let weeks = {}
|
||||
// 日历数据
|
||||
let canlender = [];
|
||||
|
||||
if (this.foldStatus === 'open') {
|
||||
// 默认以周末开始
|
||||
let firstDay = new Date(year, month - 1, 1).getDay();
|
||||
// 如果以周一开始
|
||||
if(this.startWeek === 'mon') {
|
||||
firstDay = firstDay === 0 ? 6 : firstDay - 1;
|
||||
}
|
||||
let currentDay = new Date(year, month, 0).getDate()
|
||||
// 日期数据
|
||||
let dates = {
|
||||
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
|
||||
currentMonthDys: this._currentMonthDays(currentDay, this.getDate(dateData)), // 本月天数
|
||||
weeks: []
|
||||
}
|
||||
// 下月开始几天
|
||||
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
|
||||
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
|
||||
|
||||
// 如果仅显示当月
|
||||
if (this.monthShowCurrentMonth) {
|
||||
// 日历数据
|
||||
canlender = canlender.concat(
|
||||
dates.lastMonthDays.map(item => item = {
|
||||
empty: true,
|
||||
lunar: {},
|
||||
}),
|
||||
dates.currentMonthDys,
|
||||
dates.nextMonthDays.map(item => item = {
|
||||
empty: true,
|
||||
lunar: {},
|
||||
}),
|
||||
);
|
||||
|
||||
} else {
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
}
|
||||
|
||||
} else {
|
||||
canlender = this._getWeekDays(dateData)
|
||||
}
|
||||
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 === 0) {
|
||||
weeks[parseInt(i / 7)] = new Array(7)
|
||||
}
|
||||
weeks[parseInt(i / 7)][i % 7] = canlender[i] || {};
|
||||
}
|
||||
|
||||
if (useWeeks) {
|
||||
this.canlender = canlender
|
||||
this.weeks = weeks
|
||||
}
|
||||
|
||||
return weeks
|
||||
}
|
||||
|
||||
|
||||
//静态方法
|
||||
// static init(date) {
|
||||
// if (!this.instance) {
|
||||
// this.instance = new Calendar(date);
|
||||
// }
|
||||
// return this.instance;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
export default Calendar
|
||||
1069
src/uni_modules/wu-calendar/components/wu-calendar/wu-calendar.vue
Normal file
1069
src/uni_modules/wu-calendar/components/wu-calendar/wu-calendar.vue
Normal file
File diff suppressed because it is too large
Load Diff
91
src/uni_modules/wu-calendar/package.json
Normal file
91
src/uni_modules/wu-calendar/package.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"id": "wu-calendar",
|
||||
"displayName": "wu-calendar 最全日历,动态滑动切换、多滑动模式、多日历类型、多日期选择模式等,全端兼容,无论平台,一致体验。",
|
||||
"version": "1.5.6",
|
||||
"description": "唯一支持动态滑动计算的日历插件,多滑动切换模式(纵、横、不滑动)、多日历类型(周、月)、多日期选择模式(单选、多选、范围)、日历周几(周日、周一)、自定义主题、农历显示等,可以让您纵享丝滑的使用日历",
|
||||
"keywords": [
|
||||
"wu-calendar",
|
||||
"日历",
|
||||
"多日历类型",
|
||||
"动态滑动计算",
|
||||
"wu-ui"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.5.5"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"wu-ui-tools",
|
||||
"wu-icon",
|
||||
"wu-safe-bottom"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y",
|
||||
"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",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/uni_modules/wu-calendar/readme.md
Normal file
16
src/uni_modules/wu-calendar/readme.md
Normal file
@ -0,0 +1,16 @@
|
||||
## wu-calendar 最全日历
|
||||
|
||||
> **组件名:wu-calendar**
|
||||
|
||||
目前插件市场上唯一可以动态滑动计算的日历插件,多滑动切换模式(纵、横向滑动,不滑动)、多日历类型(周、月日历)、多日历选择模式(日期单选、多选、范围选择)、多日历起始周几设置(周日、周一)、自定义主题颜色(副色自动生成)、自定义文案、农历显示等功能,可以让您纵享丝滑的使用日历。
|
||||
|
||||
## [查看文档](https://wuui.cn/zh-CN/components/calendar.html)
|
||||
|
||||
## [更多组件, 请查看 `wu-ui` 组件库](https://ext.dcloud.net.cn/plugin?name=wu--ui)
|
||||
(请勿下载插件zip)
|
||||
|
||||
<a href="https://ext.dcloud.net.cn/plugin?name=wu--ui">
|
||||
<img src="https://wuui.cn/intr.png">
|
||||
</a>
|
||||
|
||||
**如使用过程中有任何问题,或者您对wu-ui有一些好的建议。<br>欢迎加入 [wu-ui 交流群](https://wuui.cn/zh-CN/components/qqFeedBack.html)**
|
||||
10
src/uni_modules/wu-icon/changelog.md
Normal file
10
src/uni_modules/wu-icon/changelog.md
Normal file
@ -0,0 +1,10 @@
|
||||
## 1.0.4(2024-05-08)
|
||||
更新域名
|
||||
## 1.0.3(2023-08-08)
|
||||
修复链接引入错误
|
||||
## 1.0.2(2023-08-07)
|
||||
修复引入错误
|
||||
## 1.0.1(2023-08-07)
|
||||
支持自定义(包括nvue)文字与图片图标
|
||||
## 1.0.0(2023-08-03)
|
||||
基于字体的图标集,包含了大多数常见场景的图标,支持自定义,支持自定义图片图标等。可自定义颜色、大小。
|
||||
159
src/uni_modules/wu-icon/components/wu-icon/icons.js
Normal file
159
src/uni_modules/wu-icon/components/wu-icon/icons.js
Normal file
@ -0,0 +1,159 @@
|
||||
export default {
|
||||
'wuicon-level': 'e68f',
|
||||
'wuicon-download': 'e670',
|
||||
'wuicon-search': 'e632',
|
||||
'wuicon-reload': 'e627',
|
||||
'wuicon-scan': 'e631',
|
||||
'wuicon-calendar': 'e65c',
|
||||
'wuicon-bag': 'e647',
|
||||
'wuicon-checkbox-mark': 'e659',
|
||||
'wuicon-attach': 'e640',
|
||||
'wuicon-wifi-off': 'e6cc',
|
||||
|
||||
'wuicon-woman': 'e626',
|
||||
'wuicon-man': 'e675',
|
||||
'wuicon-chat': 'e656',
|
||||
'wuicon-chat-fill': 'e63f',
|
||||
'wuicon-red-packet': 'e6c3',
|
||||
'wuicon-folder': 'e694',
|
||||
'wuicon-order': 'e695',
|
||||
'wuicon-arrow-up-fill': 'e636',
|
||||
'wuicon-arrow-down-fill': 'e638',
|
||||
'wuicon-backspace': 'e64d',
|
||||
'wuicon-photo': 'e60d',
|
||||
'wuicon-photo-fill': 'e6b4',
|
||||
'wuicon-lock': 'e69d',
|
||||
'wuicon-lock-fill': 'e6a6',
|
||||
'wuicon-lock-open': 'e68d',
|
||||
'wuicon-lock-opened-fill': 'e6a1',
|
||||
'wuicon-home': 'e67b',
|
||||
'wuicon-home-fill': 'e68e',
|
||||
'wuicon-star': 'e618',
|
||||
'wuicon-star-fill': 'e61e',
|
||||
'wuicon-share': 'e629',
|
||||
'wuicon-share-fill': 'e6bb',
|
||||
'wuicon-share-square': 'e6c4',
|
||||
'wuicon-volume': 'e605',
|
||||
'wuicon-volume-fill': 'e624',
|
||||
'wuicon-volume-off': 'e6bd',
|
||||
'wuicon-volume-off-fill': 'e6c8',
|
||||
'wuicon-trash': 'e623',
|
||||
'wuicon-trash-fill': 'e6ce',
|
||||
'wuicon-shopping-cart': 'e6cb',
|
||||
'wuicon-shopping-cart-fill': 'e630',
|
||||
'wuicon-question-circle': 'e622',
|
||||
'wuicon-question-circle-fill': 'e6bc',
|
||||
'wuicon-plus': 'e625',
|
||||
'wuicon-plus-circle': 'e603',
|
||||
'wuicon-plus-circle-fill': 'e611',
|
||||
'wuicon-tags': 'e621',
|
||||
'wuicon-tags-fill': 'e613',
|
||||
'wuicon-pause': 'e61c',
|
||||
'wuicon-pause-circle': 'e696',
|
||||
'wuicon-pause-circle-fill': 'e60c',
|
||||
'wuicon-play-circle': 'e6af',
|
||||
'wuicon-play-circle-fill': 'e62a',
|
||||
'wuicon-map': 'e665',
|
||||
'wuicon-map-fill': 'e6a8',
|
||||
'wuicon-phone': 'e6ba',
|
||||
'wuicon-phone-fill': 'e6ac',
|
||||
'wuicon-list': 'e690',
|
||||
'wuicon-list-dot': 'e6a9',
|
||||
'wuicon-info-circle': 'e69f',
|
||||
'wuicon-info-circle-fill': 'e6a7',
|
||||
'wuicon-minus': 'e614',
|
||||
'wuicon-minus-circle': 'e6a5',
|
||||
'wuicon-mic': 'e66d',
|
||||
'wuicon-mic-off': 'e691',
|
||||
'wuicon-grid': 'e68c',
|
||||
'wuicon-grid-fill': 'e698',
|
||||
'wuicon-eye': 'e664',
|
||||
'wuicon-eye-fill': 'e697',
|
||||
'wuicon-eye-off': 'e69c',
|
||||
'wuicon-eye-off-outline': 'e688',
|
||||
'wuicon-file-text': 'e687',
|
||||
'wuicon-file-text-fill': 'e67f',
|
||||
'wuicon-edit-pen': 'e65d',
|
||||
'wuicon-edit-pen-fill': 'e679',
|
||||
'wuicon-email': 'e673',
|
||||
'wuicon-email-fill': 'e683',
|
||||
'wuicon-checkmark': 'e64a',
|
||||
'wuicon-checkmark-circle': 'e643',
|
||||
'wuicon-checkmark-circle-fill': 'e668',
|
||||
'wuicon-clock': 'e66c',
|
||||
'wuicon-clock-fill': 'e64b',
|
||||
'wuicon-close': 'e65a',
|
||||
'wuicon-close-circle': 'e64e',
|
||||
'wuicon-close-circle-fill': 'e666',
|
||||
'wuicon-car': 'e64f',
|
||||
'wuicon-car-fill': 'e648',
|
||||
'wuicon-bell': 'e651',
|
||||
'wuicon-bell-fill': 'e604',
|
||||
'wuicon-play-left': 'e6bf',
|
||||
'wuicon-play-right': 'e6b3',
|
||||
'wuicon-play-left-fill': 'e6ae',
|
||||
'wuicon-play-right-fill': 'e6ad',
|
||||
'wuicon-skip-back-left': 'e6c5',
|
||||
'wuicon-skip-forward-right': 'e61f',
|
||||
'wuicon-setting': 'e602',
|
||||
'wuicon-setting-fill': 'e6d0',
|
||||
'wuicon-more-dot-fill': 'e66f',
|
||||
'wuicon-more-circle': 'e69e',
|
||||
'wuicon-more-circle-fill': 'e684',
|
||||
'wuicon-arrow-upward': 'e641',
|
||||
'wuicon-arrow-downward': 'e634',
|
||||
'wuicon-arrow-leftward': 'e63b',
|
||||
'wuicon-arrow-rightward': 'e644',
|
||||
'wuicon-arrow-up': 'e633',
|
||||
'wuicon-arrow-down': 'e63e',
|
||||
'wuicon-arrow-left': 'e646',
|
||||
'wuicon-arrow-right': 'e63c',
|
||||
'wuicon-thumb-up': 'e612',
|
||||
'wuicon-thumb-up-fill': 'e62c',
|
||||
'wuicon-thumb-down': 'e60a',
|
||||
'wuicon-thumb-down-fill': 'e628',
|
||||
'wuicon-coupon': 'e65f',
|
||||
'wuicon-coupon-fill': 'e64c',
|
||||
'wuicon-kefu-ermai': 'e660',
|
||||
'wuicon-server-fill': 'e610',
|
||||
'wuicon-server-man': 'e601',
|
||||
'wuicon-warning': 'e6c1',
|
||||
'wuicon-warning-fill': 'e6c7',
|
||||
'wuicon-camera': 'e642',
|
||||
'wuicon-camera-fill': 'e650',
|
||||
'wuicon-pushpin': 'e6d1',
|
||||
'wuicon-pushpin-fill': 'e6b6',
|
||||
'wuicon-heart': 'e6a2',
|
||||
'wuicon-heart-fill': 'e68b',
|
||||
'wuicon-account': 'e63a',
|
||||
'wuicon-account-fill': 'e653',
|
||||
'wuicon-integral': 'e693',
|
||||
'wuicon-integral-fill': 'e6b1',
|
||||
'wuicon-gift': 'e680',
|
||||
'wuicon-gift-fill': 'e6b0',
|
||||
|
||||
|
||||
'wuicon-empty-data': 'e671',
|
||||
'wuicon-empty-address': 'e68a',
|
||||
'wuicon-empty-favor': 'e662',
|
||||
'wuicon-empty-car': 'e656',
|
||||
'wuicon-empty-order': 'e66b',
|
||||
'wuicon-empty-list': 'e671',
|
||||
'wuicon-empty-search': 'e677',
|
||||
'wuicon-empty-permission': 'e67c',
|
||||
'wuicon-empty-news': 'e67d',
|
||||
'wuicon-empty-history': 'e684',
|
||||
'wuicon-empty-coupon': 'e69b',
|
||||
'wuicon-empty-page': 'e60e',
|
||||
|
||||
'wuicon-apple-fill': 'e635',
|
||||
'wuicon-zhifubao-circle-fill': 'e617',
|
||||
'wuicon-weixin-circle-fill': 'e6cd',
|
||||
'wuicon-weixin-fill': 'e620',
|
||||
'wuicon-qq-fill': 'e608',
|
||||
'wuicon-qq-circle-fill': 'e6b9',
|
||||
'wuicon-moments': 'e6a0',
|
||||
'wuicon-moments-circel-fill': 'e6c2',
|
||||
'wuicon-twitter': 'e607',
|
||||
'wuicon-twitter-circle-fill': 'e6cf',
|
||||
}
|
||||
90
src/uni_modules/wu-icon/components/wu-icon/props.js
Normal file
90
src/uni_modules/wu-icon/components/wu-icon/props.js
Normal file
@ -0,0 +1,90 @@
|
||||
export default {
|
||||
props: {
|
||||
// 图标类名
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 图标颜色,可接受主题色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#606266'
|
||||
},
|
||||
// 字体大小,单位px
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '16px'
|
||||
},
|
||||
// 是否显示粗体
|
||||
bold: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
|
||||
index: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
// 触摸图标时的类名
|
||||
hoverClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 自定义扩展前缀,方便用户扩展自己的图标库
|
||||
customPrefix: {
|
||||
type: String,
|
||||
default: 'wuicon'
|
||||
},
|
||||
// 图标右边或者下面的文字
|
||||
label: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// label的位置,只能右边或者下边
|
||||
labelPos: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
},
|
||||
// label的大小
|
||||
labelSize: {
|
||||
type: [String, Number],
|
||||
default: '15px'
|
||||
},
|
||||
// label的颜色
|
||||
labelColor: {
|
||||
type: String,
|
||||
default: '#606266'
|
||||
},
|
||||
// label与图标的距离
|
||||
space: {
|
||||
type: [String, Number],
|
||||
default: '3px'
|
||||
},
|
||||
// 图片的mode
|
||||
imgMode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 用于显示图片小图标时,图片的宽度
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 用于显示图片小图标时,图片的高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 用于解决某些情况下,让图标垂直居中的用途
|
||||
top: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 是否阻止事件传播
|
||||
stop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
...uni.$w?.props?.icon
|
||||
}
|
||||
}
|
||||
225
src/uni_modules/wu-icon/components/wu-icon/wu-icon.vue
Normal file
225
src/uni_modules/wu-icon/components/wu-icon/wu-icon.vue
Normal file
@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<view class="wu-icon" @tap="clickHandler" :class="['wu-icon--' + labelPos]">
|
||||
<!-- 这里进行空字符串判断,如果仅仅是v-if="label",可能会出现传递0的时候,结果也无法显示 -->
|
||||
<text v-if="label !== '' && (labelPos == 'left' || labelPos == 'top')" class="wu-icon__label" :style="labelStyle">{{ label }}</text>
|
||||
<image class="wu-icon__img" v-if="isImg" :src="name" :mode="imgMode"
|
||||
:style="[imgStyle, $w.addStyle(customStyle)]"></image>
|
||||
<text v-else class="wu-icon__icon" :class="uClasses" :style="[iconStyle, $w.addStyle(customStyle)]"
|
||||
:hover-class="hoverClass">{{icon}}</text>
|
||||
<!-- 这里进行空字符串判断,如果仅仅是v-if="label",可能会出现传递0的时候,结果也无法显示 -->
|
||||
<text v-if="label !== '' && (labelPos == 'right' || labelPos == 'bottom')" class="wu-icon__label" :style="labelStyle">{{ label }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/wu-ui-tools/libs/mixin/mpMixin.js'
|
||||
import mixin from '@/uni_modules/wu-ui-tools/libs/mixin/mixin.js'
|
||||
// #ifdef APP-NVUE
|
||||
// nvue通过weex的dom模块引入字体,相关文档地址如下:
|
||||
// https://weex.apache.org/zh/docs/modules/dom.html#addrule
|
||||
import iconUrl from './wuicons.ttf';
|
||||
const domModule = weex.requireModule('dom');
|
||||
domModule.addRule('fontFace', {
|
||||
'fontFamily': "wuicon-iconfont",
|
||||
'src': "url('" + iconUrl + "')"
|
||||
})
|
||||
// #endif
|
||||
// 引入图标名称,已经对应的unicode
|
||||
import icons from './icons';
|
||||
import props from './props.js';
|
||||
/**
|
||||
* icon 图标
|
||||
* @description 基于字体的图标集,包含了大多数常见场景的图标。
|
||||
* @tutorial https://wuui.cn/zh-CN/components/icon.html
|
||||
* @property {String} name 图标名称,若带有 `/` 或遵循 `base64` 图片格式,会被认为是图片图标,则文字图标相关属性会失效。
|
||||
* @property {String} color 图标颜色,可接受主题色 (默认 color: #606266 )
|
||||
* @property {String | Number} size 图标字体大小,单位px/rpx (默认 '16px' )
|
||||
* @property {Boolean} bold 是否显示粗体 (默认 false )
|
||||
* @property {String | Number} index 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
|
||||
* @property {String} hoverClass 图标按下去的样式类,用法同uni的view组件的hoverClass参数,详情见官网
|
||||
* @property {String} customPrefix 自定义扩展前缀,方便用户扩展自己的图标库 (默认 'wuicon' )
|
||||
* @property {String | Number} label 图标右侧的label文字
|
||||
* @property {String} labelPos label相对于图标的位置(默认 'right' )
|
||||
* @value top 上方
|
||||
* @value bottom 下方
|
||||
* @value left 左侧
|
||||
* @value right 右侧
|
||||
* @property {String | Number} labelSize label字体大小,单位px (默认 '15px' )
|
||||
* @property {String} labelColor 图标右侧的label文字颜色 ( 默认 color['wu-content-color'] )
|
||||
* @property {String | Number} space label与图标的距离,单位px (默认 '3px' )
|
||||
* @property {String} imgMode image组件的mode,详见:[image](https://uniapp.dcloud.net.cn/component/image.html#image)
|
||||
* @property {String | Number} width 显示图片小图标时的宽度
|
||||
* @property {String | Number} height 显示图片小图标时的高度
|
||||
* @property {String | Number} top 图标在垂直方向上的定位 用于解决某些情况下,让图标垂直居中的用途 (默认 0 )
|
||||
* @property {Boolean} stop 是否阻止事件传播 (默认 false )
|
||||
* @property {Object} customStyle icon的样式,对象形式
|
||||
* @event {Function} click 点击图标时触发
|
||||
* @event {Function} touchstart 事件触摸时触发
|
||||
* @example <wu-icon name="photo" color="#2979ff" size="28"></wu-icon>
|
||||
*/
|
||||
export default {
|
||||
name: 'wu-icon',
|
||||
emits: ['click'],
|
||||
mixins: [mpMixin, mixin, props],
|
||||
data() {
|
||||
return {
|
||||
colorType: [
|
||||
'primary',
|
||||
'success',
|
||||
'info',
|
||||
'error',
|
||||
'warning'
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uClasses() {
|
||||
let classes = []
|
||||
classes.push(this.customPrefix)
|
||||
classes.push(this.customPrefix + '-' + this.name)
|
||||
// 主题色,通过类配置
|
||||
if (this.color && this.colorType.includes(this.color)) classes.push('wu-icon__icon--' + this.color)
|
||||
// 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
|
||||
// 故需将其拆成一个字符串的形式,通过空格隔开各个类名
|
||||
//#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
|
||||
classes = classes.join(' ')
|
||||
//#endif
|
||||
return classes
|
||||
},
|
||||
iconStyle() {
|
||||
let style = {}
|
||||
style = {
|
||||
fontSize: this.$w.addUnit(this.size),
|
||||
lineHeight: this.$w.addUnit(this.size),
|
||||
fontWeight: this.bold ? 'bold' : 'normal',
|
||||
// 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
|
||||
top: this.$w.addUnit(this.top)
|
||||
}
|
||||
// 非主题色值时,才当作颜色值
|
||||
if (this.color && !this.colorType.includes(this.color)) style.color = this.color
|
||||
return style
|
||||
},
|
||||
// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
|
||||
isImg() {
|
||||
const isBase64 = this.name.indexOf('data:') > -1 && this.name.indexOf('base64') > -1;
|
||||
return this.name.indexOf('/') !== -1 || isBase64;
|
||||
},
|
||||
imgStyle() {
|
||||
let style = {}
|
||||
// 如果设置width和height属性,则优先使用,否则使用size属性
|
||||
style.width = this.width ? this.$w.addUnit(this.width) : this.$w.addUnit(this.size)
|
||||
style.height = this.height ? this.$w.addUnit(this.height) : this.$w.addUnit(this.size)
|
||||
return style
|
||||
},
|
||||
// 通过图标名,查找对应的图标
|
||||
icon() {
|
||||
// 如果内置的图标中找不到对应的图标,就直接返回name值,因为用户可能传入的是unicode代码
|
||||
const code = icons['wuicon-' + this.name];
|
||||
if (['wuicon'].indexOf(this.customPrefix) > -1) {
|
||||
return code ? unescape(`%u${code}`) : this.name;
|
||||
} else {
|
||||
// #ifndef APP-NVUE
|
||||
return ''
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
return unescape(`%u${this.name}`)
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
// label样式
|
||||
labelStyle() {
|
||||
let style = {
|
||||
color: this.labelColor,
|
||||
fontSize: this.$w.addUnit(this.labelSize),
|
||||
marginLeft: this.labelPos == 'right' ? this.$w.addUnit(this.space) : 0,
|
||||
marginTop: this.labelPos == 'bottom' ? this.$w.addUnit(this.space) : 0,
|
||||
marginRight: this.labelPos == 'left' ? this.$w.addUnit(this.space) : 0,
|
||||
marginBottom: this.labelPos == 'top' ? this.$w.addUnit(this.space) : 0
|
||||
};
|
||||
return style
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickHandler(e) {
|
||||
this.$emit('click', this.index)
|
||||
// 是否阻止事件冒泡
|
||||
this.stop && this.preventEvent(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/uni_modules/wu-ui-tools/libs/css/components.scss';
|
||||
@import '@/uni_modules/wu-ui-tools/libs/css/color.scss';
|
||||
// 变量定义
|
||||
$wu-icon-primary: $wu-primary !default;
|
||||
$wu-icon-success: $wu-success !default;
|
||||
$wu-icon-info: $wu-info !default;
|
||||
$wu-icon-warning: $wu-warning !default;
|
||||
$wu-icon-error: $wu-error !default;
|
||||
$wu-icon-label-line-height: 1 !default;
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
// 非nvue下加载字体
|
||||
@font-face {
|
||||
font-family: 'wuicon-iconfont';
|
||||
src: url('./wuicons.ttf') format('truetype');
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.wu-icon {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
|
||||
&--left, &--right {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&--top, &--bottom {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-family: wuicon-iconfont;
|
||||
position: relative;
|
||||
@include flex;
|
||||
align-items: center;
|
||||
|
||||
&--primary {
|
||||
color: $wu-icon-primary;
|
||||
}
|
||||
|
||||
&--success {
|
||||
color: $wu-icon-success;
|
||||
}
|
||||
|
||||
&--error {
|
||||
color: $wu-icon-error;
|
||||
}
|
||||
|
||||
&--warning {
|
||||
color: $wu-icon-warning;
|
||||
}
|
||||
|
||||
&--info {
|
||||
color: $wu-icon-info;
|
||||
}
|
||||
}
|
||||
|
||||
&__img {
|
||||
/* #ifndef APP-NVUE */
|
||||
height: auto;
|
||||
will-change: transform;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
&__label {
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: $wu-icon-label-line-height;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
src/uni_modules/wu-icon/components/wu-icon/wuicons.ttf
Normal file
BIN
src/uni_modules/wu-icon/components/wu-icon/wuicons.ttf
Normal file
Binary file not shown.
87
src/uni_modules/wu-icon/package.json
Normal file
87
src/uni_modules/wu-icon/package.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "wu-icon",
|
||||
"displayName": "wu-icon 图标 全面兼容小程序、nvue、vue2、vue3等多端",
|
||||
"version": "1.0.4",
|
||||
"description": "基于字体的图标集,包含了大多数常见场景的图标,支持自定义,支持自定义图片图标等。可自定义颜色、大小。",
|
||||
"keywords": [
|
||||
"wu-ui",
|
||||
"图标",
|
||||
"wu-icon",
|
||||
"文字图标"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.4.15"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"wu-ui-tools"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/uni_modules/wu-icon/readme.md
Normal file
10
src/uni_modules/wu-icon/readme.md
Normal file
@ -0,0 +1,10 @@
|
||||
## wu-icon 图标库
|
||||
|
||||
> **组件名:wu-icon**
|
||||
|
||||
基于字体的图标集,包含了大多数常见场景的图标,支持自定义(包括nvue)文字与图片图标等。
|
||||
|
||||
## <a href="https://wuui.cn/zh-CN/components/icon" target="_blank">查看文档</a>
|
||||
|
||||
## [更多插件,请关注wu-ui组件库](https://ext.dcloud.net.cn/plugin?name=wuui) <small>(请不要 下载插件ZIP)</small>
|
||||
**如使用过程中有任何问题,或者您对wu-ui有一些好的建议。<br>欢迎加入 [wu-ui 交流群](https://wuui.cn/zh-CN/components/qqFeedBack.html)**
|
||||
6
src/uni_modules/wu-safe-bottom/changelog.md
Normal file
6
src/uni_modules/wu-safe-bottom/changelog.md
Normal file
@ -0,0 +1,6 @@
|
||||
## 1.0.2(2024-05-08)
|
||||
更新域名
|
||||
## 1.0.1(2023-09-11)
|
||||
优化底部安全距离计算方法
|
||||
## 1.0.0(2023-09-01)
|
||||
主要是针对IPhone X等一些底部带指示条的机型,指示条的操作区域与页面底部存在重合,容易导致用户误操作,因此我们需要针对这些机型进行底部安全区适配。
|
||||
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
props: {
|
||||
...uni.$w?.props?.safeBottom
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<view
|
||||
class="wu-safe-bottom"
|
||||
:style="[style]"
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/wu-ui-tools/libs/mixin/mpMixin.js';
|
||||
import mixin from '@/uni_modules/wu-ui-tools/libs/mixin/mixin.js';
|
||||
import props from './props.js';
|
||||
/**
|
||||
* SafeBottom 底部安全区
|
||||
* @description 这个适配,主要是针对IPhone X等一些底部带指示条的机型,指示条的操作区域与页面底部存在重合,容易导致用户误操作,因此我们需要针对这些机型进行底部安全区适配。
|
||||
* @tutorial https://wuui.cn/zh-CN/components/safeAreaInset.html
|
||||
* @property {type} prop_name
|
||||
* @property {Object} customStyle 定义需要用到的外部样式
|
||||
*
|
||||
* @event {Function()}
|
||||
* @example <wu-status-bar></wu-status-bar>
|
||||
*/
|
||||
export default {
|
||||
name: "wu-safe-bottom",
|
||||
mixins: [mpMixin, mixin, props],
|
||||
data() {
|
||||
return {
|
||||
safeAreaBottomHeight: 0,
|
||||
isNvue: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
const {
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowTop,
|
||||
safeArea,
|
||||
screenHeight,
|
||||
safeAreaInsets
|
||||
} = this.$w.sys();
|
||||
const style = {};
|
||||
// #ifdef MP-WEIXIN
|
||||
style.height = this.$w.addUnit(screenHeight - safeArea.bottom, 'px');
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
style.height = this.$w.addUnit(safeAreaInsets.bottom, 'px');
|
||||
// #endif
|
||||
return this.$w.deepMerge(style, this.$w.addStyle(this.customStyle));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wu-safe-bottom {
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
88
src/uni_modules/wu-safe-bottom/package.json
Normal file
88
src/uni_modules/wu-safe-bottom/package.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"id": "wu-safe-bottom",
|
||||
"displayName": "wu-safe-bottom底部安全区 全端兼容 无论平台 一致体验",
|
||||
"version": "1.0.2",
|
||||
"description": "针对一些底部带指示条的机型,操作区域与页面底部重合,容易误操作,因此本插件对这些机型进行底部安全区适配",
|
||||
"keywords": [
|
||||
"wu-ui",
|
||||
"wuui",
|
||||
"wu-safe-bottom",
|
||||
"safe-bottom",
|
||||
"底部安全区"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.4.15"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"wu-ui-tools"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user