zhangyu #2

Merged
zhangyv merged 4 commits from zhangyu into main 2 years ago

@ -11,4 +11,22 @@ export default {
}); });
}, },
resourcesList(data) {
return request({
url: "/admin/system/resourcesList",
method: "POST",
data,
});
},
getDistrict(data) {
return request({
url: "/admin/store/getDistrict",
method: "POST",
data,
});
},
}; };

@ -28,6 +28,14 @@ export default {
}); });
}, },
createItem(data) {
return request({
url: "/admin/classify/createItem",
method: "POST",
data,
});
},
}, },
freightRules(data) { freightRules(data) {
@ -38,4 +46,23 @@ export default {
}); });
}, },
goodsItem(data) {
return request({
url: "/admin/goods/goodsItem",
method: "POST",
data,
});
},
goodsEdit(data) {
return request({
url: "/admin/goods/goodsEdit",
method: "POST",
data,
});
},
}; };

@ -11,6 +11,40 @@ export default {
data, data,
}); });
}, },
orderProfit(data) {
return request({
url: "/admin/dataCount/orderProfit",
method: "POST",
data,
});
},
orderGood(data) {
return request({
url: "/admin/dataCount/orderGood",
method: "POST",
data,
});
},
},
getStoreSetting(data) {
return request({
url: "/admin/store/getStoreSetting",
method: "POST",
data,
})
},
setStoreSetting(data) {
return request({
url: "/admin/store/setStoreSetting",
method: "POST",
data,
})
} }
}; };

@ -51,6 +51,49 @@ export default {
}); });
}, },
after_sale: {
index(data) {
return request({
url: "/admin/after_sale/index",
method: "POST",
data,
});
},
update(data) {
return request({
url: "/admin/after_sale/update",
method: "POST",
data,
});
},
show(data) {
return request({
url: "/admin/after_sale/show",
method: "POST",
data,
});
},
express(data) {
return request({
url: "/client/common/express",
method: "POST",
data,
});
},
enums(data) {
return request({
url: "/client/after_sale/enums",
method: "POST",
data,
});
},
}
}; };

@ -0,0 +1,41 @@
import {
request
} from "@/utils/request";
export default {
list(data) {
return request({
url: "/admin/shop/List",
method: "POST",
data,
})
},
edit(data) {
return request({
url: "/admin/shop/edit",
method: "POST",
data,
})
},
editStatus(data) {
return request({
url: "/admin/shop/editStatus",
method: "POST",
data,
})
},
synchronousGoods(data) {
return request({
url: "/admin/shop/synchronousGoods",
method: "POST",
data,
})
},
};

@ -0,0 +1,43 @@
import {
request
} from "@/utils/request";
export default {
userList(data) {
return request({
url: "/admin/user/userList",
method: "GET",
data,
})
},
userItem(data) {
return request({
url: "/admin/user/userItem",
method: "GET",
data,
})
},
getLog(data) {
return request({
url: "/admin/user/getLog",
method: "GET",
data,
})
},
changeInformation(data) {
return request({
url: "/admin/user/changeInformation",
method: "GET",
data,
})
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

@ -1,22 +1,49 @@
<template> <template>
<view class="myTable"> <view class="myTable" :style="{ height: props.height }">
<wd-toast /> <wd-toast />
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading> <kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<scroll-view scroll-y="true" class="scroll-Y" @scrolltolower="lower"> <scroll-view scroll-y="true" class="scroll-Y" :style="{ height: props.height }" @scrolltolower="lower">
<slot :list="list"></slot> <slot :list="list"></slot>
<view v-if="list.length == 0"> <view v-show="firstLoading" v-if="list.length == 0">
<wd-status-tip image="search" tip="当前查询无结果" /> <wd-status-tip image="search" tip="暂无数据 ~" />
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue';
import kevyloading from "@/components/kevy-loading/kevy-loading"; import kevyloading from "@/components/kevy-loading/kevy-loading";
import { useToast } from '@/uni_modules/wot-design-uni' import { useToast } from '@/uni_modules/wot-design-uni';
const toast = useToast() const toast = useToast()
/**
* @typedef {Object} ApiObjResponse
* @property {Object} data - 响应数据对象
* @property {Array} data.rows - 数据行
* @property {number} data.pageSize - 每页条目数
* @property {number} data.total - 总条目数
*/
/**
* @typedef {Object} Props
* @property {Function} apiObj - 用于获取数据的 API 函数
* @property {Object} params - API 调用的附加参数
* @property {String} height - 组件的高度
*/
/**
* @typedef {Object} Query
* @property {number} page - 当前页数
* @property {number} pageSize - 每页条目数
*/
/**
* 主要组件逻辑
*
* @param {Props} props - 组件属性
*/
const props = defineProps({ const props = defineProps({
apiObj: { apiObj: {
type: Function, type: Function,
@ -25,76 +52,104 @@ const props = defineProps({
params: { params: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
height: {
type: String,
default: "100vh"
} }
}) });
/** @type {Query} */
const query = ref({ const query = ref({
page: 1, page: 1,
pageSize: 20 pageSize: 20
}) });
/** @type {Ref<boolean>} */
const loading = ref(false);
/** @type {Ref<boolean>} */
const firstLoading = ref(false);
const loading = ref(false)
const total = ref(0) const total = ref(0)
const list = ref([]) const list = ref([])
/**
* 获取数据的函数
*
* @returns {Promise<void>} - 异步函数
*/
const getData = async () => { const getData = async () => {
console.log(getData); loading.value = true;
loading.value = true
const res = await props.apiObj({ const res = await props.apiObj({
...query.value, ...query.value,
...props.params ...props.params
}) });
if (res.data.rows.length) { if (res.data.rows.length) {
query.value.pageSize = res.data.pageSize query.value.pageSize = res.data.pageSize;
total.value = res.data.total total.value = res.data.total;
list.value = [...list.value, ...res.data.rows] list.value = [...list.value, ...res.data.rows];
} else { } else {
toast.success('全部加载完了') toast.success('全部加载完了');
} }
loading.value = false loading.value = false;
} firstLoading.value = true;
};
getData() getData();
/**
* 更新数据的函数
*
* @param {Object} upParams - 更新参数
* @returns {Promise<void>} - 异步函数
*/
const upData = async (upParams = {}) => { const upData = async (upParams = {}) => {
loading.value = true loading.value = true;
query.value.page = 1 query.value.page = 1;
query.value.pageSize = 20 query.value.pageSize = 20;
const res = await props.apiObj({ const res = await props.apiObj({
...query.value, ...query.value,
...props.params, ...props.params,
...upParams ...upParams
})
console.log({
...query.value,
...props.params,
...upParams
}); });
query.value.pageSize = res.data.pageSize query.value.pageSize = res.data.pageSize;
total.value = res.data.total total.value = res.data.total;
list.value = res.data.rows list.value = res.data.rows;
loading.value = false loading.value = false;
} };
/**
* 下拉刷新时触发的函数
*
* @param {Event} e - 下拉事件对象
*/
const lower = e => { const lower = e => {
query.value.page++ query.value.page++;
getData() getData();
} };
/**
* 暴露组件的函数
*/
defineExpose({ defineExpose({
upData upData
}) });
</script> </script>
<style lang="scss"> <style lang="scss">
.myTable {
display: flex;
overflow: hidden;
}
.scroll-Y { .scroll-Y {
height: calc(100vh - 120px); height: 100%;
} }
</style> </style>

@ -12,9 +12,22 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue';
import kevyloading from "@/components/kevy-loading/kevy-loading"; import kevyloading from "@/components/kevy-loading/kevy-loading";
/**
* @typedef {Object} Props
* @property {Function} apiObj - The API function to fetch data.
* @property {Object} params - Additional parameters for the API call.
*/
/**
* @typedef {Object} Query
* @property {number} page - The current page.
* @property {number} pageSize - The page size.
*/
/** @type {Props} */
const props = defineProps({ const props = defineProps({
apiObj: { apiObj: {
type: Function, type: Function,
@ -24,59 +37,84 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}) default: () => ({})
} }
}) });
/** @type {Query} */
const query = ref({ const query = ref({
page: 1, page: 1,
pageSize: 20 pageSize: 20
}) });
/** @type {Ref<boolean>} */
const loading = ref(false);
/** @type {Ref<number>} */
const total = ref(0);
const loading = ref(false) /** @type {Ref<Array>} */
const total = ref(0) const list = ref([]);
const list = ref([])
/**
* Function to fetch data from the API.
*
* @returns {Promise<void>} - Asynchronous function.
*/
const getData = async () => { const getData = async () => {
loading.value = true loading.value = true;
const res = await props.apiObj({ const res = await props.apiObj({
...query.value, ...query.value,
...props.params ...props.params
}) });
query.value.pageSize = res.data.pageSize query.value.pageSize = res.data.pageSize;
total.value = res.data.total total.value = res.data.total;
list.value = res.data.rows list.value = res.data.rows;
loading.value = false loading.value = false;
} };
getData() // Initial data fetch
getData();
/**
* Function to update data with optional parameters.
*
* @param {Object} upParams - Optional parameters for the update.
* @returns {Promise<void>} - Asynchronous function.
*/
const upData = async (upParams = {}) => { const upData = async (upParams = {}) => {
loading.value = true loading.value = true;
query.value.page = 1 query.value.page = 1;
query.value.pageSize = 20 query.value.pageSize = 20;
const res = await props.apiObj({ const res = await props.apiObj({
...query.value, ...query.value,
...props.params, ...props.params,
...upParams ...upParams
}) });
query.value.pageSize = res.data.pageSize query.value.pageSize = res.data.pageSize;
total.value = res.data.total total.value = res.data.total;
list.value = res.data.rows list.value = res.data.rows;
loading.value = false loading.value = false;
} };
/**
* Function to handle change events, updating the page and fetching data.
*
* @param {Object} event - The event object containing the new value.
*/
function handleChange({ value }) { function handleChange({ value }) {
query.value.page = value query.value.page = value;
getData() getData();
} }
/**
* Expose the `upData` function to the parent component.
*/
defineExpose({ defineExpose({
upData upData
}) });
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>

@ -0,0 +1,189 @@
<template>
<view class="" style="z-index: 999;">
<wd-popup v-model="show" closable position="left" custom-style="width: 86vw;" @close="handleClose">
<div class="pop myUpload">
<div class="bg-white overflow-hidden h-full" style="background-clip: content-box;">
<view class="bg-gray-100 p-4 flex">
<view class="mr-4">
<wd-button @tap="chooseFile"></wd-button>
</view>
<view>
<wd-button @tap="chooseFile"></wd-button>
</view>
</view>
<div v-if="LArr.length" class="shadow-lg ">
<div class="text px-2 mt-3 font-bold">已选择 ({{ LArr.length }} )</div>
<div class="bg-gray images flex gap-2 overflow-x-auto p-4 pt-2 ">
<view @click="onClickCheck({ url: img })" class=" border-gray-100 border-solid flex rounded-[14px] relative"
v-for="img of LArr">
<wd-img mode="aspectFill" radius="10" :width="100" :height="100" :src="img" />
<view class="absolute bg-white opacity-80 inset-0 flex items-center justify-center border-spacing-1">取消选择
</view>
</view>
</div>
</div>
<div v-else class="shadow-lg ">
<div class="text p-3 font-bold">可选择 ({{ LArr.length }} )</div>
</div>
<view class="overflow-hidden rounded-t-3xl">
<myList ref="myListRef" :apiObj="system.resourcesList" :params="{ ...params, classify_id }">
<template #default="{ list }">
<view class="grid grid-cols-2 gap-4 p-4 overflow-hidden rounded-t-3xl">
<view
class="relative flex flex-col items-center justify-center bg-gray-100 p-4 rounded-md overflow-hidden"
v-for="item of list" v-show="item.type === 1">
<div class="list-item-img" @click="onClickCheck(item)" v-if="item.type === 1"
:style="{ backgroundImage: 'url(' + item.url + ')' }"></div>
<div class="list-item-img" @dblclick="onClickDir(item)" v-if="item.type === 3"
:style="{ backgroundImage: 'url(' + folderPng + ')' }"></div>
<div class="list-item-name">{{ item.name }}</div>
<view @click="onClickCheck(item)"
class="absolute bg-white opacity-80 inset-2 flex items-center justify-center border-spacing-1"
v-if="LArr.includes(item.url)">取消选择</view>
</view>
</view>
</template>
</myList>
</view>
</div>
</div>
</wd-popup>
</view>
</template>
<script setup>
import { ref } from 'vue'
import system from '@/api/modules/system.js'
import myList from "/components/myList/index.vue"
import folderPng from '@/assets/images/folder.png'
import { uploadImage } from '@/utils/request';
const myListRef = ref(null)
const formData = ref({
parent_id: 0,
type: "image",
})
const chooseFile = async () => {
uni.chooseImage({
count: 1, // 9
sizeType: ['original', 'compressed'], //
sourceType: ['album'], //
success: async (res) => {
try {
if (!res.tempFilePaths || !res.tempFilePaths.length) {
throw new Error('未选择文件或文件路径无效。');
}
const filePath = res.tempFilePaths[0];
const result = await uploadImage({ filePath, formData: formData.value, name: "image" })
console.log('成功上传图片:', result);
myListRef.value.upData()
//
} catch (error) {
console.error('选择文件或上传图片时出错:', error.message);
//
}
}
});
}
const emit = defineEmits(['update:modelValue']);
const props = defineProps({
modelValue: {
type: String,
default: ""
},
size: {
type: Number,
default: 1
},
})
const LArr = ref([])
const onClickCheck = (row) => {
const index = LArr.value.findIndex(item => item === row.url)
if (index > -1) {
LArr.value.splice(index, 1)
} else {
if (props.size > LArr.value.length) {
LArr.value.unshift(row.url)
} else {
uni.showToast({
title: `已选择 ${LArr.value.length}`,
icon: 'none'
})
console.log(`已选择 ${LArr.value.length}`);
}
}
}
const show = ref(true)
// if (Array.isArray(props.modelValue)) {
// } else {
// }
// defineExpose({
// upData
// })
</script>
<style lang="scss">
.list-item-img {
width: 100%;
height: 80px;
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
}
.list-item-name {
text-align: center;
padding: 5px 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
width: 100%;
}
.pop {
// position: fixed;
background: rgba(0, 0, 0, 0.256);
background-clip: border-box;
z-index: 9;
overflow: hidden;
inset: 0px;
}
</style>

@ -0,0 +1,216 @@
<template>
<view>
<view v-if="props.modelValue && props.modelValue.length" @click="open(true)" class="flex gap-2 overflow-x-auto">
<view class=" border-gray-100 border-solid flex rounded-[14px] relative"
v-for="img of (Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue])" :key="img">
<wd-img mode="aspectFill" radius="10" :width="100" :height="100" :src="img" />
</view>
</view>
<view v-else @click="open(true)" class="flex gap-2 overflow-x-auto">
<view style="width: 100px;height: 100px;"
class=" border-gray-100 border-solid flex rounded-[14px] relative flex-col items-center justify-center">
<wd-icon name="image" size="28px"></wd-icon>
<view class="mt-2 font-bold text-[12px]">请选择</view>
</view>
</view>
<wd-popup :z-index="998" v-model="show" closable position="left" custom-style="width: 86vw;" @close="close(false)">
<view class="pop myUpload">
<view class="bg-white overflow-hidden h-full" style="background-clip: content-box;">
<view class="bg-gray-100 p-4 flex">
<view class="mr-4">
<wd-button type="warning" @tap="chooseFile"></wd-button>
</view>
<view>
<wd-button @tap="ok"></wd-button>
</view>
</view>
<view v-if="LArr.length" class="shadow-lg ">
<view class="text px-2 mt-3 font-bold">已选择 ({{ LArr.length }} )</view>
<view class="bg-gray images flex gap-2 overflow-x-auto p-4 pt-2 ">
<view @click="onClickCheck({ url: img })" class=" border-gray-100 border-solid flex rounded-[14px] relative"
v-for="img of LArr" :key="img">
<wd-img mode="aspectFill" radius="10" :width="100" :height="100" :src="img" />
<view class="absolute bg-white opacity-80 inset-0 flex items-center justify-center border-spacing-1">取消选择
</view>
</view>
</view>
</view>
<view v-else class="shadow-lg ">
<view class="text p-3 font-bold">可选择 ({{ size }} )</view>
</view>
<view class="overflow-hidden rounded-t-3xl">
<myList ref="myListRef" :apiObj="system.resourcesList">
<template #default="{ list }">
<view class="grid grid-cols-2 gap-4 p-4 overflow-hidden rounded-t-3xl">
<view
class="relative flex flex-col items-center justify-center bg-gray-100 p-4 rounded-md overflow-hidden"
v-for="item of list" :key="item.id" v-show="item.type === 1">
<view class="list-item-img" @click="onClickCheck(item)" v-if="item.type === 1"
:style="{ backgroundImage: 'url(' + item.url + ')' }"></view>
<view class="list-item-img" @dblclick="onClickDir(item)" v-if="item.type === 3"
:style="{ backgroundImage: 'url(' + folderPng + ')' }"></view>
<view class="list-item-name">{{ item.name }}</view>
<view @click="onClickCheck(item)"
class="absolute bg-white opacity-80 inset-2 flex items-center justify-center border-spacing-1"
v-if="LArr.includes(item.url)">取消选择</view>
</view>
</view>
</template>
</myList>
</view>
</view>
</view>
</wd-popup>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import system from '@/api/modules/system.js'
import myList from "/components/myList/index.vue"
import folderPng from '@/assets/images/folder.png'
import { uploadImage } from '@/utils/request';
const myListRef = ref(null)
const formData = ref({
parent_id: 0,
type: "image",
})
const chooseFile = async () => {
uni.chooseImage({
count: 1, // 9
sizeType: ['original', 'compressed'], //
sourceType: ['album'], //
success: async (res) => {
try {
if (!res.tempFilePaths || !res.tempFilePaths.length) {
throw new Error('未选择文件或文件路径无效。');
}
const filePath = res.tempFilePaths[0];
const result = await uploadImage({ filePath, formData: formData.value, name: "image" })
console.log('成功上传图片:', result);
myListRef.value.upData()
//
} catch (error) {
console.error('选择文件或上传图片时出错:', error.message);
//
}
}
});
}
const emit = defineEmits(['update:modelValue']);
const props = defineProps({
modelValue: {
type: String,
default: ""
},
size: {
type: Number,
default: 1
},
})
const LArr = ref([])
const show = ref(false)
const open = (O) => {
show.value = O
if (O && myListRef.value?.upData) {
myListRef.value.upData()
}
if (props.modelValue) {
if (Array.isArray(props.modelValue)) {
LArr.value = JSON.parse(JSON.stringify(props.modelValue))
} else {
LArr.value = [props.modelValue]
}
}
}
open(false)
const close = () => {
// LArr.value = []
}
const ok = () => {
if (props.size == 1) {
emit("update:modelValue", LArr.value.pop())
} else {
emit("update:modelValue", LArr.value)
}
show.value = false
}
const onClickCheck = (row) => {
const index = LArr.value.findIndex(item => item === row.url)
if (index > -1) {
LArr.value.splice(index, 1)
} else {
if (props.size > LArr.value.length) {
LArr.value.unshift(row.url)
} else {
uni.showToast({
title: `已选择 ${LArr.value.length}`,
icon: 'none'
})
console.log(`已选择 ${LArr.value.length}`);
}
}
}
</script>
<style lang="scss">
.list-item-img {
width: 100%;
height: 80px;
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
}
.list-item-name {
text-align: center;
padding: 5px 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
width: 100%;
}
.pop {
// position: fixed;
background: rgba(0, 0, 0, 0.256);
background-clip: border-box;
overflow: hidden;
inset: 0px;
}
</style>

@ -0,0 +1,56 @@
## 1.0.32022-02-25
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.22022-02-25
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.12021-11-23
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.02021-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.92021-10-28
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.82021-10-27
- 修复 v-model 概率无效的 bug
## 0.4.72021-10-25
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.62021-10-19
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.52021-09-26
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.42021-09-26
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.32021-09-24
- 修复 某些情况下级联未触发的 bug
## 0.4.22021-09-23
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.12021-09-15
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.02021-07-13
- 组件兼容 vue3如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.52021-06-04
- 修复 无法加载云端数据的问题
## 0.3.42021-05-28
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.32021-05-12
- 新增 组件示例地址
## 0.3.22021-04-22
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.12021-04-15
- 修复 本地数据概率无法回显时问题
## 0.3.02021-04-07
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.02021-03-15
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.92021-03-09
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.82021-02-05
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.72021-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,598 @@
<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>{{ 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="#e1e1e1" size="14"></uni-icons> -->
<!-- <i class="iconfont icon-reeor-fill"></i> -->
</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-if="isOpened"
@click="handleClose"
></view>
<view class="uni-data-tree-dialog" v-if="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",
],
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.form = this.getForm("uniForms");
this.formItem = this.getForm("uniFormsItem");
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name;
this.form.inputChildrens.push(this);
}
}
this.$nextTick(() => {
this.load();
});
},
methods: {
clear() {
this.inputSelected.splice(0);
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.parentField && !this.selfField && this.hasValue) {
this.getNodeData(() => {
this.inputSelected = this.selected.slice(0);
});
} else if (this.hasValue) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0);
});
}
},
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;
},
show() {
this.isOpened = true;
this.$nextTick(() => {
this.$refs.pickerView.updateData({
treeData: this._treeData,
selected: this.selected,
selectedIndex: this.selectedIndex,
});
});
this.$emit("popupopened");
},
hide() {
this.isOpened = false;
this.$emit("popupclosed");
},
handleInput() {
if (this.readonly) {
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.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 {
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: 38px;
padding: 0 5px;
overflow: hidden;
/* #ifdef APP-NVUE */
height: 40px;
/* #endif */
}
.input-value-border {
border: 1px solid #e5e5e5;
border-radius: 5px;
}
.selected-area {
/* #ifndef MP-ALIPAY */
flex: 1;
/* #endif */
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 */
}
.placeholder {
color: grey;
}
.input-split-line {
opacity: 0.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, 0.4);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
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;
/* #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;
}
/* #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>

@ -0,0 +1,563 @@
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: 20
},
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
},
postField() {
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
return fields.join(',');
},
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 = []
},
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
},
getNodeData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: this._pathWhere()
}).then((res) => {
this.loading = false
this.selected = res.result.data
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
getTreePath(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
getTreePath: {
startWith: `${this.selfField}=='${this.dataValue}'`
}
}).then((res) => {
this.loading = false
let treePath = []
this._extractTreePath(res.result.data, treePath)
this.selected = treePath
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
loadData() {
if (this.isLocaldata) {
this._processLocalData()
return
}
if (this.dataValue != null) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
this._updateSelected()
})
return
}
if (this.stepSearh) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
})
} else {
this._loadAllData((data) => {
this._treeData = []
this._extractTree(data, this._treeData, null)
this._updateBindData()
})
}
},
_loadAllData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
gettree: true,
startwith: `${this.selfField}=='${this.dataValue}'`
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_loadNodeData(callback, pw) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: pw || this._postWhere(),
pageSize: 500
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_pathWhere() {
let result = []
let where_field = this._getParentNameByField();
if (where_field) {
result.push(`${where_field} == '${this.dataValue}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_postWhere() {
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(' && ')
},
_nodeWhere() {
let result = []
let selected = this.selected
if (selected.length) {
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_getParentNameByField() {
const fields = this.field.split(',');
let where_field = 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') {
where_field = items[0].trim();
break;
}
}
return where_field
},
_isTreeView() {
return (this.parentField && this.selfField)
},
_updateSelected() {
var dl = this.dataList
var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2[valueField] === value) {
sl[i].text = item2[textField]
break
}
}
}
},
_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
}
},
_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++) {
var value = paths[i].value
var 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 []
},
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var 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)
}
}
}

@ -0,0 +1,364 @@
<template>
<view class="uni-data-pickerview">
<scroll-view
class="selected-area"
scroll-x="true"
scroll-y="false"
:show-scrollbar="false"
>
<view class="selected-list">
<template v-for="(item, index) in selected">
<view
class="selected-item"
:class="{
'selected-item-active': index == selectedIndex,
'selected-item-text-overflow': ellipsis,
}"
:key="index"
v-if="item.text"
@click="handleSelect(index)"
>
<text class="">{{ item.text }}</text>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList">
<scroll-view
class="list"
:key="i"
v-if="i == selectedIndex"
:scroll-y="true"
>
<view
class="item"
:class="{ 'is-disabled': !!item.disable }"
v-for="(item, j) in child"
:key="j"
@click="handleNodeClick(item, i, j)"
>
<text class="item-text item-text-overflow">{{
item[map.text]
}}</text>
<view
class="check"
v-if="selected.length > i && item[map.value] == selected[i].value"
></view>
</view>
</scroll-view>
</template>
<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,
},
},
data() {
return {};
},
created() {
if (this.managedMode) {
return;
}
this.$nextTick(() => {
this.load();
});
},
methods: {
onPropsChange() {
this._treeData = [];
this.selectedIndex = 0;
this.load();
},
load() {
if (this.isLocaldata) {
this.loadData();
} else if (this.dataValue.length) {
this.getTreePath((res) => {
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._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true);
return;
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true);
return;
}
if (!isleaf && !hasNodes) {
this._loadNodeData((data) => {
if (!data.length) {
node.isleaf = true;
} else {
this._treeData.push(...data);
this._updateBindData(node);
}
this.onSelectedChange(node, node.isleaf);
}, this._nodeWhere());
return;
}
this.onSelectedChange(node, false);
},
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>
.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, 0.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: 0.9;
z-index: 102;
}
/* #ifdef APP-NVUE */
.selected-area {
width: 750rpx;
}
/* #endif */
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10rpx;
margin-right: 10rpx;
padding: 12rpx 0;
text-align: center;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.selected-item-text-overflow {
width: 168px;
line-height: 50rpx;
/* 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 #007aff;
}
.selected-item-text {
color: #007aff;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
}
.item {
padding: 12px 15px;
line-height: 50rpx;
/* border-bottom: 1px solid #f0f0f0; */
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
text-align: left;
}
.is-disabled {
opacity: 0.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 #007aff;
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>

@ -0,0 +1,92 @@
{
"id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "1.0.3",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
"uniui",
"picker",
"级联",
"省市区",
""
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-load-more",
"uni-icons",
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"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"
}
}
}
}
}

@ -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

@ -5,6 +5,12 @@
"versionName" : "1.0.0", "versionName" : "1.0.0",
"versionCode" : "100", "versionCode" : "100",
"transformPx" : false, "transformPx" : false,
"h5" : {
"router" : {
"base" : "/mobile-admin/",
"mode" : "hash"
}
},
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus" : {
"usingComponents" : true, "usingComponents" : true,

@ -64,6 +64,114 @@
"gestureBack": "YES" "gestureBack": "YES"
} }
} }
},
{
"path": "afterSale/index",
"style": {
"navigationBarTitleText": "订单售后",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "afterSale/details",
"style": {
"navigationBarTitleText": "订单售后",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "setup/index",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "cat/index",
"style": {
"navigationBarTitleText": "分类管理",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "cat/edit",
"style": {
"navigationBarTitleText": "分类编辑",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "shop/list",
"style": {
"navigationBarTitleText": "门店列表",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "shop/edit",
"style": {
"navigationBarTitleText": "门店编辑",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "user/list",
"style": {
"navigationBarTitleText": "用户列表",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "user/edit",
"style": {
"navigationBarTitleText": "用户信息",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
} }
] ]
} }

@ -1,10 +1,5 @@
<template> <template>
<view class="content"> <view class="content">
<wd-button>主要按钮</wd-button>
<wd-button type="success">成功按钮</wd-button>
<wd-button type="info">信息按钮</wd-button>
<wd-button type="warning">警告按钮</wd-button>
<wd-button type="error">危险按钮</wd-button>
</view> </view>
</template> </template>
@ -15,13 +10,12 @@ const token = uni.getStorageSync("token");
if (token) { if (token) {
const user_info = uni.getStorageSync("user_info"); const user_info = uni.getStorageSync("user_info");
if (user_info.type == 1) { if (user_info.type == 1) {
utils.toUrl("/store/index/index") utils.toUrl("/store/index/index", "redirectTo")
} }
} else { } else {
utils.toUrl("/pages/login/index") utils.toUrl("/pages/login/index", "redirectTo")
} }
</script> </script>
<style> <style>

@ -27,6 +27,16 @@ const model = ref({
const loading = ref(false) const loading = ref(false)
const form = ref(null) const form = ref(null)
// if (token) {
// const user_info = uni.getStorageSync("user_info");
// if (user_info.type == 1) {
// utils.toUrl("/store/index/index")
// }
// } else {
// utils.toUrl("/pages/login/index")
// }
function handleSubmit() { function handleSubmit() {
loading.value = true loading.value = true
form.value form.value
@ -47,17 +57,27 @@ function handleSubmit() {
title: "登录成功", title: "登录成功",
}); });
console.log(res.data.user_info);
if (res.data.user_info.type == 1) { if (res.data.user_info.type == 1) {
utils.toUrl("/store/index/index") utils.toUrl("/store/index/index", "redirectTo")
} else {
uni.showToast({
title: '登录平台开发中 ···',
icon: 'none'
})
} }
loading.value = false
} else {
uni.showToast({
title: res.message,
icon: 'none'
})
loading.value = false
} }
loading.value = false loading.value = false
}) })
} else {
loading.value = false
} }
}) })
.catch((error) => { .catch((error) => {

@ -0,0 +1,159 @@
<template>
<div class="floor">
<div v-if="saleDetails.after_sale && saleDetails.after_sale != '' && saleDetails.after_sale">
<div class="list">
<div class="name">申请类型</div>
<div class="text">{{ ['', '退货退款', '换货'][saleDetails.after_sale.apply_type] }}</div>
</div>
<div class="list">
<div class="name">申请原因</div>
<div class="text"
v-if="afterSaleEnumsList && saleDetails && saleDetails.after_sale && saleDetails.after_sale.apply_type && saleDetails.after_sale.apply_reason && afterSaleEnumsList[saleDetails.after_sale.apply_type] && afterSaleEnumsList[saleDetails.after_sale.apply_type][saleDetails.after_sale.apply_reason]">
{{ afterSaleEnumsList[saleDetails.after_sale.apply_type][saleDetails.after_sale.apply_reason].label }}
</div>
<div v-else>
--
</div>
</div>
<div class="list" v-if="saleDetails.after_sale.apply_files != ''">
<div class="name">图片描述</div>
<image style="width: 100px; height: 100px;margin-right: 15px;"
v-for="(img, i) in saleDetails.after_sale.apply_files" :key="i" :src="img" :zoom-rate="1.2"
:preview-src-list="saleDetails.after_sale.apply_files" fit="cover">
</image>
</div>
<div class="list" v-if="saleDetails.after_sale.apply_type == 1">
<div class="name">退款金额</div>
<div class="text">{{ saleDetails.after_sale.refund_amount }}</div>
</div>
<div v-if="saleDetails.after_sale.apply_type == 2">
<div class="list">
<div class="name">换货类型</div>
<div class="text">
<div v-for="item in saleDetails.after_sale.goods_json.goods_sku_json" :key="item.attr_group_id">
{{ item.group_name }}{{ item.name }}</div>
</div>
</div>
<div class="list">
<div class="name">换货数量</div>
<div class="text">
{{ saleDetails.after_sale.goods_json.num }}
</div>
</div>
<div class="list" v-if="saleDetails.after_sale.address_json">
<div class="name">买家地址</div>
<div class="text">
<div>收货人{{ saleDetails.after_sale.address_json.name }}</div>
<div>收货电话{{ saleDetails.after_sale.address_json.mobile }}</div>
<div>收货地址{{ saleDetails.after_sale.address_json.address }}</div>
</div>
</div>
<div class="list" v-if="saleDetails.after_sale.apply_type == 2 && saleDetails.after_sale.shop_express_json">
<div class="name">快递公司</div>
<div class="text">
{{ express_company }}
</div>
</div>
<div class="list" v-if="saleDetails.after_sale.apply_type == 2 && saleDetails.after_sale.shop_express_json">
<div class="name">快递单号</div>
<div class="text">
{{ saleDetails.after_sale.shop_express_json.express_number }}
</div>
</div>
</div>
<div class="list">
<div class="name">售后状态</div>
<div class="text">{{ saleDetails.after_sale.status_text }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import order from '@/api/store/order.js';
const saleDetails = ref({})
//
const express_company = ref()
const express = async () => {
try {
const res = await order.after_sale.express()
if (res.code !== 0) throw new Error(res.message)
res.data.forEach((item) => {
if (item.value == saleDetails.value.after_sale.shop_express_json.express_company) {
express_company.value = item.label;
}
})
} catch (error) {
console.dir(error)
}
}
onLoad(({ id }) => {
const getSaleDetail = async ({ id }) => {
try {
const res = await order.after_sale.show({ id })
console.log(res)
if (res.code !== 0) throw new Error(res.message)
saleDetails.value = res.data;
express();
} catch (error) {
console.dir(error)
}
}
getSaleDetail({ id });
})
const afterSaleEnumsList = ref([])
const afterSaleEnums = async () => {
try {
const res = await order.after_sale.enums()
if (res.code !== 0) throw new Error(res.message)
afterSaleEnumsList.value = res.data.reasonMap
} catch (error) {
console.dir(error)
}
}
afterSaleEnums();
</script>
<style scoped lang="scss">
.floor {
background: #fff;
padding: 30px 50px;
height: 100%;
.list {
display: flex;
justify-content: flex-start;
padding-bottom: 15px;
font-size: 14px;
line-height: 36px;
.name {
padding-right: 20px;
color: #888;
}
text {
margin-right: 20px;
}
img {
width: 300px;
}
}
}
</style>

@ -0,0 +1,569 @@
<template>
<view class="content">
<wd-message-box></wd-message-box>
<wd-message-box selector="wd-message-box-slot" use-slot>
<view>
<wd-form :model="shipmentsModel">
<wd-cell-group border>
<view class="mb-4">
<wd-radio-group v-model="shipmentsModel.send_type" shape="button" @change="change">
<wd-radio :value="1">快递发货</wd-radio>
<wd-radio :value="2">无需物流</wd-radio>
</wd-radio-group>
</view>
<view class="mb-4 overflow-hidden bg-white border-gray-100 border-solid border-[8px] p-3 rounded"
v-if="shipmentsModel.send_type == 1">
<view class="mb-2">
<wd-radio-group shape="button" v-model="shipmentsModel.delivery_company">
<view class="flex overflow-auto">
<wd-radio v-for="item of expressList" :value="item.value">{{ item.label }}</wd-radio>
</view>
</wd-radio-group>
</view>
<wd-input label-width="100px" clearable v-model="shipmentsModel.delivery_no" placeholder="快递单号">
</wd-input>
</view>
</wd-cell-group>
</wd-form>
</view>
</wd-message-box>
<view class=" bg-white sticky top-0 z-50">
<div class="flex items-center">
<view class="flex-1">
<wd-search @search="search" @clear="search({ value: '' })" v-model="params.keywords" hide-cancel>
<template #prefix>
<wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType">
<view class="search-type">
<text>{{ searchType }}</text>
<wd-icon custom-class="icon-arrow" name="fill-arrow-down"></wd-icon>
</view>
</wd-popover>
</template>
</wd-search>
</view>
<div class="mr-2">
<wd-button @click="utils.toUrl('/store/order/index')" size="small">普通订单</wd-button>
</div>
</div>
<wd-tabs @change="(e) => {
params.status = e.index;
search({ value: params.keywords })
}" v-model="params.status">
<wd-tab v-for="item in status" :key="item" :title="`${item.content}`"></wd-tab>
</wd-tabs>
</view>
<view class="goodsBox p-2">
<myList ref="myListRef" :apiObj="order.after_sale.index" :params="{ ...params, status: params.status - 1 }">
<template #default="{ list }">
<view>
<view v-for="item of list" class="goods">
<wd-card type="rectangle">
<template #title>
<view class="title">
<view>
<span class="mr-2" v-if="item.shop">{{ item.shop.name }}</span>
<span class="mr-2" v-else></span>
<span class="font-bold">({{ ["待审核", "审核通过", "审核不通过", "买家发货", "商家发货", "已完成"][item.status] }})</span>
</view>
<view @click="utils.copy(item.order.order_no, '已复制单号')" class="title-tip">
<span style="font-size: 24rpx;margin-left: 8px;">单号{{ item.order.order_no }}</span>
</view>
</view>
</template>
<view v-for="subItem of [item.order_detail]" style="height: 60px;" class="content mb-4">
<image :src="subItem.goods_pic" width="40" height="40" alt="joy"
style="border-radius: 4px; margin-right: 12px;width: 60px;height: 60px;min-width: 60px;" />
<view>
<view class="line2" style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ subItem.goods_name }}</view>
<!-- <view class="font-bold" style="color: rgb(255, 0, 0); font-size: 16px;">{{ subItem.price }}
</view> -->
<view class="font-bold" style="font-size: 22rpx;">小计: {{ subItem.price }} <text
style="color: rgb(255, 0, 0); font-size: 24rpx;">({{
subItem.num }}) </text></view>
<div class="goods_sky" style="font-size: 22rpx;">
<span v-for="(sku, _index) of subItem.goods_sku_json" :key="_index">
{{ sku.group_name }}{{ sku.name }}</span>
</div>
</view>
</view>
<view class="bg-gray-50 p-2">
<view class="text-[12px]" v-if="item.user">
<view class="mb-1">
用户{{ item.user.nickname }}
<text class="font-bold">
( 会员ID{{ item.user.id }} )
</text>
<view class="bg-gray-100 my-2 p-2 relative">
<view>收货人{{ item.order.receiver_name }} &nbsp; 电话{{ item.order.receiver_phone }}</view>
<view v-if="item.order.delivery_address">
收货地址{{ item.order.delivery_address }} {{
item.order.delivery_address_detail }}
</view>
<view
@click="utils.copy(`收货人:${item.order.receiver_name} 电话:${item.order.receiver_phone} 收货地址:${item.order.delivery_address}`, '已复制快递信息')"
class="absolute right-2 top-2">
<wd-icon name="file-copy" size="14px"></wd-icon>
</view>
</view>
</view>
<view class="flex items-center" v-if='[0, 1, 2][item.delivery_type]'>
配送方式:
<wd-tag v-if="item.apply_type == 1" class="ml-2" type="success">
退货退款
</wd-tag>
<wd-tag v-if="item.apply_type == 2" class="ml-2" type="success">
换货
</wd-tag>
</view>
</view>
</view>
<template #footer>
<!-- <view class="bg-gray-50 p-2 mb-2.5 flex justify-between" style="font-size: 22rpx;">
<view>
售后状态:
</view>
</view> -->
<view class="flex justify-between items-center">
<!-- <view class="font-bold">实付: {{ item.pay_price }} </view> -->
<view></view>
<view class="flex-1 flex justify-end">
<!-- <view v-if="item.apply_cancel === 1" class="mr-2">
<wd-button type="error" @click="orderApproval(item)" size="small">退款</wd-button>
</view>
<view class="mr-2">
<wd-button @click="printing(item)" size="small">小票打印</wd-button>
</view>
<view class="mr-2">
<wd-button @click="orderNotes(item)" size="small">备注</wd-button>
</view>
<view v-if="item.status == 1" class="">
<wd-button @click="shipments(item)" size="small">发货</wd-button>
</view> -->
<view style="margin-right: 16rpx;">
<wd-button @click="utils.toUrl('/store/afterSale/details?id=' + item.id)"
size="small">退款详情</wd-button>
</view>
<template v-if="item.status == 0">
<view style="margin-right: 16rpx;">
<wd-button @click="orderApproval(item)" size="small">退款审批</wd-button>
</view>
</template>
<template v-if="item.status == 3 && item.apply_type == 2">
<view style="margin-right: 16rpx;">
<wd-button @click="shipments(item)" size="small">待发货</wd-button>
</view>
</template>
<template v-if="item.status == 3 && item.apply_type == 1">
<view style="margin-right: 16rpx;">
<wd-button @click="showActions(item)" size="small">确认收货</wd-button>
</view>
</template>
</view>
</view>
</template>
</wd-card>
</view>
</view>
</template>
</myList>
</view>
<wd-toast />
<wd-action-sheet v-model="show" :actions="actions" @select="select" />
</view>
</template>
<script setup>
import utils from '@/utils/utils.js';
import order from '@/api/store/order.js';
import myList from "/components/myList/index.vue";
import { useMessage } from '@/uni_modules/wot-design-uni';
import { useToast } from '@/uni_modules/wot-design-uni';
import { ref } from 'vue';
const message = useMessage('wd-message-box-slot');
const message1 = useMessage();
const toast = useToast();
const show = ref(false)
let afterType = 1
const actions = ref([
{
name: '线上退款',
subname: '(退回原支付账户)'
},
{
name: '线下退款'
},
])
/**
* 处理订单备注操作
* @param {Object} row - 行数据
*/
const orderNotes = (row, text) => {
message1
.prompt({
title: text,
inputValue: row.refund_amount
})
.then((resp) => {
order.after_sale.update({
id: row.id,
status: 5,
refund_amount: resp.value,
refund_type: afterType,
shop_description: 1,
}).then(res => {
if (res.code == 0) {
toast.success('操作成功');
row.status = 5;
} else {
toast.error('操作失败');
}
});
})
.catch((error) => {
console.log(error);
});
};
let afterRow = {}
function showActions(row) {
afterRow = row
show.value = true
}
function select({ item, index }) {
console.log(item);
if (item.name == '线上退款') {
afterType = 1
orderNotes(afterRow, '线上退款')
}
if (item.name == '线下退款') {
afterType = 2
orderNotes(afterRow, '线下退款')
}
}
const classify_id = ref(0);
const params = ref({
keywords: "",
status: "",
type: 'order_no'
});
const myListRef = ref(null);
const search = ({ value }) => {
myListRef.value.upData({
keywords: value,
classify_id: classify_id.value,
status: params.value.status - 1
});
};
const searchType = ref('订单编号');
const popover = ref(false);
const status = ref([
{ content: '全部' },
{ content: '审核中' },
{ content: '审核通过' },
{ content: '审核不通过' },
{ content: '买家已发货' },
{ content: '商家已发货' },
{ content: '已完成' },
]);
const menu = ref([
{ content: '订单编号' },
{ content: '商品名称' },
{ content: '手机号' },
{ content: '会员昵称' },
{ content: '收货人' },
]);
/**
* 切换搜索类型
* @param {Object} item - 切换的项
*/
function changeSearchType({ item, index }) {
searchType.value = item.content;
if (item.content == '订单编号') {
params.value.type = "order_no";
}
if (item.content == '商品名称') {
params.value.type = "goods_name";
}
if (item.content == '手机号') {
params.value.type = "receiver_phone";
}
if (item.content == '会员昵称') {
params.value.type = "nickname";
}
if (item.content == '收货人') {
params.value.type = "receiver_name";
}
}
/**
* 更改状态
* @param {Object} row - 行数据
*/
const changeS = (row) => {
//
// goods.goodsEditAttribute({
// id: item.id,
// value: [1, 0][item.status],
// type: "status"
// }).then(res => {
// if (res.code == 0) {
// toast.success('')
// item.status = [1, 0][item.status]
// } else {
// showNotify({ type: 'error', message: '' })
// }
// })
};
const expressList = ref([]);
/**
* 获取物流公司列表
*/
const getExpressList = () => {
order.GetExpressList().then(res => {
expressList.value = Object.entries(res.data).reduce((express, item) => {
express.push({ label: item[1], value: item[0] });
return express;
}, []);
});
};
//
getExpressList();
const shipmentsModel = ref({
send_type: 2,
delivery_company: ""
});
/**
* 处理发货操作
* @param {Object} row - 行数据
*/
const shipments = (row) => {
message
.confirm({
title: '订单发货',
})
.then((resp) => {
if (shipmentsModel.value.send_type == 2) {
order.orderSend({
id: row.id,
send_type: "2"
});
row.status = 2;
toast.success('操作成功');
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
};
}, 300);
}
if (shipmentsModel.value.send_type == 1) {
if (shipmentsModel.value.delivery_company && shipmentsModel.value.delivery_no) {
order.orderSend({
id: row.id,
status: "4",
express_company: shipmentsModel.value.delivery_company,
express_number: shipmentsModel.value.delivery_no,
});
row.status = 4;
row.success('操作成功');
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
};
}, 300);
} else {
toast.error('发货失败,请完善选择填写');
shipments(row);
}
}
})
.catch((error) => {
console.log(error);
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
};
}, 300);
});
};
/**
* 处理打印小票操作
* @param {Object} row - 行数据
*/
const printing = (row) => {
message1
.confirm({
title: '确认收货',
})
.then((resp) => {
order.printOrder({
id: row.id,
send_type: "2"
}).then(res => {
if (res.code == 0) {
toast.success('操作成功');
} else {
toast.error('操作失败');
}
});
})
.catch((error) => {
console.log(error);
});
};
/**
* 处理退款审批操作
* @param {Object} row - 行数据
*/
const orderApproval = (row) => {
message1
.confirm({
title: '退款审批',
confirmButtonText: "同意",
cancelButtonText: "拒绝",
})
.then((resp) => {
order.after_sale.update({
id: row.id,
shop_description: "同意",
status: 1
}).then(res => {
if (res.code == 0) {
toast.success('操作成功');
row.status = 1;
} else {
toast.error('操作失败');
}
});
})
.catch((error) => {
if (error.action == 'cancel') {
order.after_sale.update({
id: row.id,
shop_description: "拒绝",
status: 0
}).then(res => {
if (res.code == 0) {
toast.success('操作成功');
row.status = 2;
} else {
toast.error('操作失败');
}
});
}
});
};
</script>
<style lang="scss" scoped>
.search-type {
position: relative;
height: 30px;
line-height: 30px;
padding: 0 8px 0 16px;
font-size: 24rpx;
color: rgba(0, 0, 0, .45);
}
.search-type::after {
position: absolute;
content: '';
width: 1px;
right: 0;
top: 5px;
bottom: 5px;
background: rgba(0, 0, 0, 0.25);
}
.search-type {
:deep(.icon-arrow) {
display: inline-block;
font-size: 20px;
vertical-align: middle;
}
}
.goodsBox {
.content,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.content {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
}
</style>

@ -0,0 +1,88 @@
<template>
<view class="charts-box bg-white content p-2">
<view v-if="parent.id" class="p-4 mb-2 bg-slate-50">
上级分类 ({{ parent.name }})
</view>
<wd-form ref="form" :model="baseForm">
<wd-cell-group class="flex py-2 w-full" title="分类图片">
<view class="ml-3">
<myUpload v-model="baseForm.pic_url" :size="1"></myUpload>
</view>
</wd-cell-group>
<wd-form-item label-width="76px" label="分类名称" prop="address">
<wd-input v-model="baseForm.name" placeholder="请输入分类名称" clearable />
</wd-form-item>
<wd-form-item label-width="80px" label="分类排序" prop="address">
<view class="ml-3 flex">
<wd-input-number v-model="baseForm.sort" />
</view>
</wd-form-item>
<wd-form-item label-width="80px" label="状态" prop="address">
<view class="ml-3 flex">
<wd-switch v-model="baseForm.status" :active-value="1" :inactive-value="0" />
</view>
</wd-form-item>
<view class="footer m-4">
<wd-button @click="saveCat" type="primary" size="large" block>保存</wd-button>
</view>
</wd-form>
</view>
</template>
<script setup>
import { ref } from 'vue'
import goods from '@/api/store/goods.js'
import myUpload from "@/components/myUpload/index.vue"
import {
onLoad,
} from "@dcloudio/uni-app";
const parent = ref({})
const model = ref({})
const baseForm = ref({})
onLoad(async (e) => {
if (e.parent) {
parent.value = JSON.parse(e.parent)
}
if (e.edit) {
baseForm.value = JSON.parse(e.edit)
}
})
const saveCat = () => {
goods.classify.createItem({
parent_id: parent.value.id || baseForm.value.id || 0,
...baseForm.value
}).then(res => {
if (res.code == 0) {
uni.showToast({
title: '操作成功!',
icon: 'success'
})
uni.navigateBack()
}
})
}
</script>
<style scoped>
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
width: 100%;
height: 300px;
}
</style>

@ -0,0 +1,130 @@
<template>
<view class="charts-box bg-white content">
<view v-show="classifyList.length" class="flex overflow-auto flex-wrap">
<div class="grid grid-cols-3 gap-4 p-4 w-full">
<wd-button @click="utils.toUrl('/store/cat/edit?edit=' + JSON.stringify({}))" style="width: 100%;"
class="bg-[#f0f0f0] w-full flex-1" :round="false">
新增
</wd-button>
<wd-button @click="showActions(cat)" style="width: 100%;" v-for="cat of classifyList"
class="bg-[#f0f0f0] w-full flex-1" type="info" :round="false">
{{ cat.name }}
</wd-button>
</div>
</view>
<wd-action-sheet v-model="show" :actions="actions" @close="close" @select="select" />
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
</view>
</template>
<script setup>
import { ref } from 'vue'
import utils from '@/utils/utils.js'
import goods from '@/api/store/goods.js'
import kevyloading from "@/components/kevy-loading/kevy-loading";
/** @type {Ref<boolean>} */
const loading = ref(false);
import {
onShow,
} from "@dcloudio/uni-app";
const model = ref({})
const baseForm = ref({})
const show = ref(false)
const actions = ref([
{
name: '编辑分类'
},
{
name: '新增子项'
}
])
const opt = ref("编辑分类")
function showActions(row) {
show.value = true
model.value = row
console.log(row);
}
function close() {
show.value = false
}
function select({ item, index }) {
opt.value = item.name
if (opt.value == '编辑分类') {
// message.alert({
// title: ""
// })
baseForm.value = model.value
utils.toUrl('/store/cat/edit?edit=' + JSON.stringify(baseForm.value))
}
if (opt.value == '新增子项') {
console.log(model.value);
if (model.value.parentIds.length == 3) {
return uni.showToast({
title: '三级分类不可新增子级',
icon: 'none'
})
} else {
baseForm.value = model.value
utils.toUrl('/store/cat/edit?edit=' + JSON.stringify({}) + "&parent=" + JSON.stringify(baseForm.value))
}
// baseForm.value = model.value
// utils.toUrl('/store/cat/edit?edit=' + JSON.stringify(baseForm.value))
}
}
const classifyList = ref([])
const getClassify = () => {
loading.value = true
function flattenCategories(categories, parentIds = []) {
let flatCategories = [];
for (const category of categories) {
const categoryWithParents = {
...category,
parentIds: [...parentIds, category.id],
};
flatCategories.push(categoryWithParents);
if (category.children && category.children.length > 0) {
flatCategories = flatCategories.concat(flattenCategories(category.children, [...parentIds, category.id]));
}
}
return flatCategories;
}
goods.classify.list().then(res => {
classifyList.value = flattenCategories(res.data)
loading.value = false
})
}
onShow(() => {
getClassify()
})
</script>
<style scoped>
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
width: 100%;
height: 300px;
}
</style>

@ -0,0 +1,78 @@
<template>
<view class="charts-box">
<qiun-data-charts type="bar" :opts="opts" :chartData="barData" />
</view>
</template>
<script>
export default {
props: {
barData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chartData: {},
// config-ucharts.js ['bar'] opts opts
opts: {
color: ["#8eabfb", "#8eabfb", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"],
padding: [15, 30, 0, 5],
enableScroll: false,
legend: {},
xAxis: {
boundaryGap: "justify",
disableGrid: false,
min: 0,
axisLine: false,
max: 70
},
yAxis: {},
extra: {
bar: {
linearType: "custom",
barBorderCircle: true,
type: "group",
width: 30,
meterBorde: 1,
meterFillColor: "#FFFFFF",
activeBgColor: "#000000",
activeBgOpacity: 0.08,
categoryGap: 2
}
}
}
};
},
created() {
// this.getServerData();
},
methods: {
getServerData() {
//
setTimeout(() => {
//
let res = {
categories: ["2018", "2019", "2020", "2021", "2022", "2023"],
series: [
{
name: "目标值",
data: [35, 36, 31, 33, 13, 34]
},
]
};
this.chartData = JSON.parse(JSON.stringify(res));
}, 100);
},
}
};
</script>
<style scoped>
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
width: 100%;
height: 300px;
}
</style>

@ -0,0 +1,26 @@
<template>
<view class="myTabbar">
<wd-tabbar custom-class="mb-3" fixed safeAreaInsetBottom placeholder v-model="tab" shape="round">
<wd-tabbar-item @click="utils.toUrl('/store/index/index')" name="home" title="首页" icon="home"></wd-tabbar-item>
<!-- <wd-tabbar-item name="cart" title="分类" icon="cart"></wd-tabbar-item> -->
<wd-tabbar-item name="user" @click="utils.toUrl('/store/user/list')" title="用户管理" icon="user"></wd-tabbar-item>
<wd-tabbar-item @click="utils.toUrl('/store/shop/list')" name="shop" title="门店管理" icon="detection"></wd-tabbar-item>
<!-- <wd-tabbar-item name="user" title="我的" icon="user"></wd-tabbar-item> -->
</wd-tabbar>
</view>
</template>
<script setup>
import utils from '@/utils/utils.js';
const props = defineProps({
tab: {
type: String,
default: "home"
}
})
const tab = props.tab
</script>
<style lang="scss"></style>

@ -1,7 +1,9 @@
<template> <template>
<view class="skuEdit"> <view class="skuEdit">
<wd-table rowHeight="100" :data="Pdata.use_sku == 0
<wd-table :data="skuLibrary" :stripe="false"> ? skuDefault
: skuLibrary
" :stripe="false">
<wd-table-col prop="name" label="SKU"> <wd-table-col prop="name" label="SKU">
<template #value="scope"> <template #value="scope">
@ -45,9 +47,20 @@
</view> </view>
</template> </template>
</wd-table-col> </wd-table-col>
<wd-table-col prop="major" label="产品图">
<template #value="scope">
<view class="overflow-hidden w-full h-full flex items-center justify-center">
<view class="px-2 pb-1 bg-white flex items-center justify-center mt-4 overflow-hidden">
<myUpload v-model="scope.row.pic_url"></myUpload>
</view>
</view>
</template>
</wd-table-col>
</wd-table> </wd-table>
<view class="bg-gray-100 rounded mb-2"> <view v-show="Pdata.use_sku == 1" class="bg-gray-100 rounded mb-2">
<div class="p-2 bg-white w-full"> <div class="p-2 bg-white w-full">
<div class="name mb-2 text-xs">规格设置</div> <div class="name mb-2 text-xs">规格设置</div>
<view class="flex bg-white px-3 py-1 rounded w-full"> <view class="flex bg-white px-3 py-1 rounded w-full">
@ -58,7 +71,6 @@
</view> </view>
</div> </div>
<div class="p-2 bg-white"> <div class="p-2 bg-white">
<div style="display: flex; flex-flow: column; align-items: flex-start;"> <div style="display: flex; flex-flow: column; align-items: flex-start;">
<div class="name mb-2 text-xs">规格组</div> <div class="name mb-2 text-xs">规格组</div>
@ -89,17 +101,26 @@
</view> </view>
<wd-toast />
</view> </view>
</template> </template>
<script> <script>
import myUpload from "@/components/myUpload/index.vue"
import { useToast } from '@/uni_modules/wot-design-uni' import { useToast } from '@/uni_modules/wot-design-uni'
const toast = useToast() const toast = useToast()
export default { export default {
name: "skuEdit", name: "skuEdit",
props: {
Pdata: {
type: Object,
default: () => ({})
},
},
components: {
myUpload
},
data() { data() {
return { return {
// sku // sku
@ -128,7 +149,16 @@ export default {
// sku // sku
} }
}, },
created() {
this.skuDefault = this.Pdata.skuDefault.length ? this.Pdata.skuDefault : this.skuDefault
this.skuLibrary = this.Pdata.skuLibrary
this.skuGroup = this.Pdata.skuGroup
},
methods: { methods: {
successImage($event, index) {
console.log($event, index);
},
/** /**
* 处理规格数据 * 处理规格数据
*/ */
@ -217,6 +247,15 @@ export default {
}, },
// //
addSkuGroup() { addSkuGroup() {
if (!this.addGroupData.name) {
uni.showToast({
title: '请填写规格组名称',
icon: 'none'
})
return
}
// //
console.log("添加了一个规格组"); console.log("添加了一个规格组");
this.skuGroup.push(this.addGroupData); this.skuGroup.push(this.addGroupData);
@ -280,7 +319,14 @@ export default {
if (!this.addGouppItemData[index]) { if (!this.addGouppItemData[index]) {
toast.error('请填写规格名称!') if (!this.addGroupData.name) {
uni.showToast({
title: '请填写规格名称',
icon: 'none'
})
return
}
return return
} }

@ -0,0 +1,56 @@
## 1.0.32022-02-25
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.22022-02-25
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.12021-11-23
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.02021-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.92021-10-28
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.82021-10-27
- 修复 v-model 概率无效的 bug
## 0.4.72021-10-25
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.62021-10-19
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.52021-09-26
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.42021-09-26
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.32021-09-24
- 修复 某些情况下级联未触发的 bug
## 0.4.22021-09-23
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.12021-09-15
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.02021-07-13
- 组件兼容 vue3如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.52021-06-04
- 修复 无法加载云端数据的问题
## 0.3.42021-05-28
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.32021-05-12
- 新增 组件示例地址
## 0.3.22021-04-22
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.12021-04-15
- 修复 本地数据概率无法回显时问题
## 0.3.02021-04-07
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.02021-03-15
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.92021-03-09
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.82021-02-05
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.72021-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,598 @@
<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>{{ 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="#e1e1e1" size="14"></uni-icons> -->
<!-- <i class="iconfont icon-reeor-fill"></i> -->
</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-if="isOpened"
@click="handleClose"
></view>
<view class="uni-data-tree-dialog" v-if="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",
],
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.form = this.getForm("uniForms");
this.formItem = this.getForm("uniFormsItem");
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name;
this.form.inputChildrens.push(this);
}
}
this.$nextTick(() => {
this.load();
});
},
methods: {
clear() {
this.inputSelected.splice(0);
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.parentField && !this.selfField && this.hasValue) {
this.getNodeData(() => {
this.inputSelected = this.selected.slice(0);
});
} else if (this.hasValue) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0);
});
}
},
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;
},
show() {
this.isOpened = true;
this.$nextTick(() => {
this.$refs.pickerView.updateData({
treeData: this._treeData,
selected: this.selected,
selectedIndex: this.selectedIndex,
});
});
this.$emit("popupopened");
},
hide() {
this.isOpened = false;
this.$emit("popupclosed");
},
handleInput() {
if (this.readonly) {
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.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 {
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: 38px;
padding: 0 5px;
overflow: hidden;
/* #ifdef APP-NVUE */
height: 40px;
/* #endif */
}
.input-value-border {
border: 1px solid #e5e5e5;
border-radius: 5px;
}
.selected-area {
/* #ifndef MP-ALIPAY */
flex: 1;
/* #endif */
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 */
}
.placeholder {
color: grey;
}
.input-split-line {
opacity: 0.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, 0.4);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
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;
/* #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;
}
/* #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>

@ -0,0 +1,563 @@
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: 20
},
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
},
postField() {
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
return fields.join(',');
},
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 = []
},
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
},
getNodeData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: this._pathWhere()
}).then((res) => {
this.loading = false
this.selected = res.result.data
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
getTreePath(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
getTreePath: {
startWith: `${this.selfField}=='${this.dataValue}'`
}
}).then((res) => {
this.loading = false
let treePath = []
this._extractTreePath(res.result.data, treePath)
this.selected = treePath
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
loadData() {
if (this.isLocaldata) {
this._processLocalData()
return
}
if (this.dataValue != null) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
this._updateSelected()
})
return
}
if (this.stepSearh) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
})
} else {
this._loadAllData((data) => {
this._treeData = []
this._extractTree(data, this._treeData, null)
this._updateBindData()
})
}
},
_loadAllData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
gettree: true,
startwith: `${this.selfField}=='${this.dataValue}'`
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_loadNodeData(callback, pw) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: pw || this._postWhere(),
pageSize: 500
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_pathWhere() {
let result = []
let where_field = this._getParentNameByField();
if (where_field) {
result.push(`${where_field} == '${this.dataValue}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_postWhere() {
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(' && ')
},
_nodeWhere() {
let result = []
let selected = this.selected
if (selected.length) {
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_getParentNameByField() {
const fields = this.field.split(',');
let where_field = 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') {
where_field = items[0].trim();
break;
}
}
return where_field
},
_isTreeView() {
return (this.parentField && this.selfField)
},
_updateSelected() {
var dl = this.dataList
var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2[valueField] === value) {
sl[i].text = item2[textField]
break
}
}
}
},
_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
}
},
_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++) {
var value = paths[i].value
var 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 []
},
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var 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)
}
}
}

@ -0,0 +1,364 @@
<template>
<view class="uni-data-pickerview">
<scroll-view
class="selected-area"
scroll-x="true"
scroll-y="false"
:show-scrollbar="false"
>
<view class="selected-list">
<template v-for="(item, index) in selected">
<view
class="selected-item"
:class="{
'selected-item-active': index == selectedIndex,
'selected-item-text-overflow': ellipsis,
}"
:key="index"
v-if="item.text"
@click="handleSelect(index)"
>
<text class="">{{ item.text }}</text>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList">
<scroll-view
class="list"
:key="i"
v-if="i == selectedIndex"
:scroll-y="true"
>
<view
class="item"
:class="{ 'is-disabled': !!item.disable }"
v-for="(item, j) in child"
:key="j"
@click="handleNodeClick(item, i, j)"
>
<text class="item-text item-text-overflow">{{
item[map.text]
}}</text>
<view
class="check"
v-if="selected.length > i && item[map.value] == selected[i].value"
></view>
</view>
</scroll-view>
</template>
<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,
},
},
data() {
return {};
},
created() {
if (this.managedMode) {
return;
}
this.$nextTick(() => {
this.load();
});
},
methods: {
onPropsChange() {
this._treeData = [];
this.selectedIndex = 0;
this.load();
},
load() {
if (this.isLocaldata) {
this.loadData();
} else if (this.dataValue.length) {
this.getTreePath((res) => {
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._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true);
return;
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true);
return;
}
if (!isleaf && !hasNodes) {
this._loadNodeData((data) => {
if (!data.length) {
node.isleaf = true;
} else {
this._treeData.push(...data);
this._updateBindData(node);
}
this.onSelectedChange(node, node.isleaf);
}, this._nodeWhere());
return;
}
this.onSelectedChange(node, false);
},
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>
.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, 0.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: 0.9;
z-index: 102;
}
/* #ifdef APP-NVUE */
.selected-area {
width: 750rpx;
}
/* #endif */
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10rpx;
margin-right: 10rpx;
padding: 12rpx 0;
text-align: center;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.selected-item-text-overflow {
width: 168px;
line-height: 50rpx;
/* 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 #007aff;
}
.selected-item-text {
color: #007aff;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
}
.item {
padding: 12px 15px;
line-height: 50rpx;
/* border-bottom: 1px solid #f0f0f0; */
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
text-align: left;
}
.is-disabled {
opacity: 0.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 #007aff;
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>

@ -0,0 +1,92 @@
{
"id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "1.0.3",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
"uniui",
"picker",
"级联",
"省市区",
""
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-load-more",
"uni-icons",
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"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"
}
}
}
}
}

@ -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

@ -1,36 +1,57 @@
<template> <template>
<view class="content p-2 bg-gray-100"> <view v-if="load" class="content p-2 bg-gray-100">
<wd-toast />
<wd-form ref="form" :model="model"> <wd-form ref="form" :model="model">
<wd-cell-group border> <wd-cell-group border>
<div class="rounded-md overflow-hidden">
<div class="bg-gray-100 "> <div class="bg-gray-100 ">
<div class="bg-gray-100 rounded mb-2"> <div class="bg-gray-100 rounded mb-2">
<div class="bg-white flex flex-col pt-3 pl-3"> <div class="bg-white flex flex-col pt-3 pl-3">
<div class="name mb-2 text-xs">缩略图</div> <div class="name mb-2 text-xs">缩略图</div>
<wd-upload :limit="1" :file-list="fileList" :action="action" :formData="formData" :header="header" <myUpload v-model="model.pic_url"></myUpload>
@success="successImage" name="image" :before-remove="beforeRemove"></wd-upload>
</div> </div>
</div> </div>
</div> </div>
<!-- <div class="bg-gray-100"> <div class="bg-gray-100">
<div class="bg-gray-100 rounded mb-2"> <div class="bg-gray-100 rounded mb-2">
<div class="bg-white flex flex-col pt-3 pl-3"> <div class="bg-white flex flex-col pt-3 pl-3">
<div class="name mb-2 text-xs">商品主图</div> <div class="name mb-2 text-xs">商品主图</div>
<wd-upload :file-list="fileList" :action="action" :formData="formData" :header="header" <myUpload v-model="model.pic_list" :size="4"></myUpload>
@change="handleChange" name="image"></wd-upload>
</div> </div>
</div> </div>
</div> --> </div>
</div>
<view class="h-2 bg-gray-100"></view> <view class="h-2 bg-gray-100"></view>
<view class=" p-3 rounded mb-2"> <view class=" p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品名称</div> <div class="name mb-2 text-xs">商品名称</div>
<view class="bg-white px-3 py-1 rounded"> <view class="bg-white px-3 py-1 rounded">
<wd-textarea v-model="model.value" auto-height /> <wd-textarea v-model="model.name" auto-height />
</view>
</view>
<view class="h-2 bg-gray-100"></view>
<view class=" p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品分类</div>
<view class="bg-white px-3 py-1 rounded">
<wd-checkbox-group v-model="model.classify_list">
<view class="flex overflow-auto flex-wrap">
<div class="grid grid-cols-3">
<wd-checkbox style="width: 100%;" shape="button" v-for="cat of classifyList"
:modelValue="JSON.stringify(cat.parentIds)">
{{ cat.name }}
</wd-checkbox>
</div>
</view>
</wd-checkbox-group>
</view> </view>
</view> </view>
@ -40,8 +61,7 @@
<div class="p-2 bg-white"> <div class="p-2 bg-white">
<div class="name mb-2 text-xs">服务内容</div> <div class="name mb-2 text-xs">服务内容</div>
<view class="bg-white px-3 py-1 rounded"> <view class="bg-white px-3 py-1 rounded">
<wd-input type="text" v-model="value" placeholder="例子: 正品保障,极速发货,7天退换货。多个请使用英文逗号“,”分隔" <wd-input type="text" v-model="model.server_project" placeholder="例子: 正品保障,极速发货,7天退换货。多个请使用英文逗号“,”分隔" />
@change="handleChange" />
</view> </view>
</div> </div>
</view> </view>
@ -51,11 +71,12 @@
<view class=" p-3 rounded mb-2"> <view class=" p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品重量</div> <div class="name mb-2 text-xs">商品重量</div>
<view class="bg-white px-3 py-2 rounded flex items-center mb-4"> <view class="bg-white px-3 py-2 rounded flex items-center mb-4">
<wd-input-number v-model="value" @change="handleChange" /> <wd-input-number v-model="model.weight" />
<view class="text-xs from-neutral-300 ml-4">千克</view> <view class="text-xs from-neutral-300 ml-4">千克</view>
</view> </view>
<wd-picker class="w-full" :columns="freightRules" label="运费模板" v-model="model.freight_id" /> <wd-picker v-if="freightRules.length" class="w-full" :columns="freightRules" label="运费模板"
v-model="model.freight_id" />
</view> </view>
@ -63,65 +84,133 @@
<view class="p-3 rounded mb-2"> <view class="p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品状态</div> <div class="name mb-2 text-xs">商品状态</div>
<view class="bg-white px-3 py-2 rounded flex items-center mb-4"> <view class="bg-white px-3 py-2 rounded flex items-center">
<wd-switch v-model="model.status" /> <wd-switch v-model="model.status" :active-value="1" :inactive-value="0" />
</view> </view>
</view> </view>
<view class="h-2 bg-gray-100"></view> <view class="h-2 bg-gray-100"></view>
<skuEdit></skuEdit> <view class="p-3 rounded mb-2">
<div class="name mb-2 text-xs">规格</div>
<view class="bg-white px-3 py-2 rounded flex items-center">
<wd-radio-group shape="button" v-model="model.use_sku">
<wd-radio :value="0">单规格</wd-radio>
<wd-radio :value="1">多规格</wd-radio>
</wd-radio-group>
</view>
</view>
<view class="h-2 bg-gray-100"></view>
<skuEdit ref="skuEditRef" :skuGroup="skuGroup"
:Pdata="{ skuDefault, skuLibrary, skuGroup, use_sku: model.use_sku }">
</skuEdit>
</wd-cell-group> </wd-cell-group>
<view class="footer mt-4"> <view class="footer mt-4">
<wd-button type="primary" size="large" block>保存</wd-button> <wd-button @click="saveGoods" type="primary" size="large" block>保存</wd-button>
</view> </view>
</wd-form> </wd-form>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue';
import system from '@/api/modules/system.js' import { useToast, useMessage } from '@/uni_modules/wot-design-uni';
import goods from '@/api/store/goods.js' import goods from '@/api/store/goods.js';
import { useToast, useMessage } from '@/uni_modules/wot-design-uni' import system from '@/api/modules/system.js';
import skuEdit from "./components/skuEdit.vue" import skuEdit from "./components/skuEdit.vue";
import myUpload from "@/components/myUpload/index.vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
const fileList = ref([]) /**
* @typedef {import('@/api/store/goods').GoodsItem} GoodsItem
*/
const beforeRemove = ({ file, resolve, index }) => { /**
fileList.value.splice(index, 1) * @typedef {import('@/api/store/goods').FreightRule} FreightRule
resolve(true) */
}
const action = 'https://saasdemo.byin.vip/admin/system/uploadImage' /**
const token = uni.getStorageSync("token"); * @typedef {Object} Sku
const header = { * @property {string} price - 商品价格
Authorization: `Bearer ${token}` * @property {string} stock - 商品库存
} * @property {string} original_price - 商品原价
const formData = { */
parent_id: 0,
type: "image",
}
function successImage(e) { /**
fileList.value.push({ * @typedef {Object} Model
url: e.file.url * @property {number} id - 商品ID
}) * @property {Array<string>} classify_list - 商品分类组
} * @property {string} name - 商品名称
* @property {string} keywords - 商品关键词
* @property {number} sort - 商品排序
* @property {number} status - 商品状态
* @property {number} freight_id - 运费规则ID
* @property {number} weight - 商品重量
* @property {string} pic_url - 商品缩略图
* @property {Array<string>} pic_list - 商品图组
* @property {string} video - 商品视频
* @property {string} detail - 图文详情
* @property {number} use_sku - 是否使用规格
* @property {Array<Sku>} sku_list - 规格信息
* @property {number} is_discount - 是否有折扣
* @property {number} discount - 折扣比例小数
* @property {number} dist_price - 分销价格
* @property {number} limit - 限购
* @property {number} is_check - 自定义核销佣金
* @property {number} check_type - 佣金类型
* @property {number} check_price - 佣金
*/
/**
* @typedef {Object} FileItem
* @property {string} pic_url - 图片URL
*/
/**
* @typedef {Object} SkuGroup
* @property {Array<Sku>} skuDefault - 默认规格
* @property {Array<Sku>} skuLibrary - 规格库
* @property {Array<Sku>} skuGroup - 规格组
*/
/**
* @typedef {Object} SkuEditRef
* @property {SkuGroup} skuGroup - 规格组
* @property {number} skuDefault - 默认规格
* @property {number} skuLibrary - 规格库
*/
/** @type {Ref<Array<FileItem>>} */
const fileList = ref([]);
/**
* @param {Object} param0
* @param {FileItem} param0.file - 要删除的文件
* @param {Function} param0.resolve - 删除文件的回调函数
* @param {number} param0.index - 文件索引
* @returns {void}
*/
const beforeRemove = ({ file, resolve, index }) => {
fileList.value.splice(index, 1);
resolve(true);
};
/** @type {Ref<Model>} */
const model = ref({ const model = ref({
classify_list: [], // classify_list: [], //
name: "", // name: "", //
keywords: "", // keywords: "", //
sort: 1000, sort: 1000,
status: 0, // status: 0, //
freight_id: 0, // freight_id: 99999999, //
weight: 0, // weight: 0, //
pic_url: "", // pic_url: "", //
pic_list: [], // pic_list: [], //
video: "", // video: "", //
detail: "", // detail: "默认", //
use_sku: 0, // 使 use_sku: 0, // 使
sku_list: [], // sku_list: [], //
is_discount: 0, // is_discount: 0, //
@ -131,37 +220,210 @@ const model = ref({
is_check: 0, // is_check: 0, //
check_type: 0, // check_type: 0, //
check_price: 0, // check_price: 0, //
}) });
const form = ref() /** @type {Ref<boolean>} */
const load = ref(false);
function handleSubmit1() { /** @type {Ref<SkuGroup>} */
form.value const skuGroup = ref([]);
.validate() /** @type {Ref<Array<GoodsItem>>} */
.then(({ valid, errors }) => { const skuDefault = ref([]);
if (valid) { /** @type {Ref<Array<GoodsItem>>} */
showSuccess({ const skuLibrary = ref([]);
msg: '校验通过'
}) /** @type {Ref<SkuEditRef>} */
} const skuEditRef = ref(null);
})
.catch((error) => { /** @type {Ref<Array<FreightRule>>} */
console.log(error, 'error') const freightRules = ref([{
}) label: "默认",
} value: "99999999"
}]);
const freightRules = ref([]) onLoad(async (e) => {
model.value.id = e.id;
/**
* 获取运费规则
* @returns {void}
*/
const GetfreightRules = () => { const GetfreightRules = () => {
goods.freightRules().then(res => { goods.freightRules().then(res => {
freightRules.value = res.data.rows.map(item => { freightRules.value = [
...freightRules.value,
...res.data.rows.map(item => {
return { return {
label: item.name, label: item.name,
value: item.id value: item.id
} };
})
}) })
];
});
};
GetfreightRules();
if (e.id > 0) {
const res = await goods.goodsItem({
id: e.id
});
model.value = res.data;
model.value.pic_list = res.data.pic_list.map(({ pic_url }) => pic_url);
if (!model.value.freight_id) {
model.value.freight_id = 99999999;
}
model.value.classify_list = model.value.classify_list.map(item => JSON.stringify(item));
if (res.data.use_sku == 0) {
skuDefault.value = res.data.goods_sku;
} else {
skuLibrary.value = res.data.goods_sku;
}
skuGroup.value = res.data.sku_group ? res.data.sku_group : [];
load.value = true;
} else {
load.value = true;
}
});
/**
* 保存商品信息
* @returns {Promise<void>}
*/
const saveGoods = async () => {
//
if (model.value.classify_list.length === 0) {
return uni.showToast({
title: '请选择商品分类!',
icon: 'none'
});
}
//
if (model.value.name.trim() === "") {
return uni.showToast({
title: '请输入商品名称!',
icon: 'none'
});
}
//
if (model.value.weight < 0) {
return uni.showToast({
title: '请输入合法的商品重量!',
icon: 'none'
});
}
//
if (String(model.value.pic_url).trim() === "") {
return uni.showToast({
title: '请上传商品缩略图!',
icon: 'none'
});
}
//
if (model.value.pic_list.length === 0) {
return uni.showToast({
title: '请上传商品图片组!',
icon: 'none'
});
}
model.value.sku_group = [];
model.value.sku_list = [];
model.value.dist_price = Number.parseInt(model.value.dist_price);
if (model.value.use_sku == 1) {
model.value.sku_group = skuEditRef.value.skuGroup;
model.value.sku_list = skuEditRef.value.skuLibrary;
} else {
model.value.sku_list = skuEditRef.value.skuDefault;
}
if (!model.value.sku_list.length) {
uni.showToast({
title: '规格不完整,请调整!',
icon: 'none'
});
} }
GetfreightRules()
if (!model.value.sku_list.every(item => Boolean(item.price !== "" && item.stock !== "" && item.original_price !== ""))) {
uni.showToast({
title: '规格不完整,请调整!',
icon: 'none'
});
return;
}
let freight_id = model.value.freight_id;
if (freight_id = 99999999) {
freight_id = 0;
}
const pic_list = model.value.pic_list.map(item => ({
pic_url: item
}));
const classify_list = model.value.classify_list.map(item => JSON.parse(item));
const res = await goods.goodsEdit({ ...model.value, pic_list, freight_id, classify_list });
if (res.code == 0) {
uni.showToast({
title: '商品信息保存成功!',
icon: 'success'
});
uni.navigateBack();
}
};
/** @type {Ref<Array<Object>>} */
const classifyList = ref([]);
/**
* 获取商品分类
* @returns {void}
*/
const getClassify = () => {
/**
* 递归展平商品分类
* @param {Array<GoodsItem>} categories - 商品分类数组
* @param {Array<number>} [parentIds=[]] - 父级分类ID数组
* @returns {Array<Object>} - 展平后的商品分类数组
*/
function flattenCategories(categories, parentIds = []) {
let flatCategories = [];
for (const category of categories) {
const categoryWithParents = {
...category,
parentIds: [...parentIds, category.id],
};
flatCategories.push(categoryWithParents);
if (category.children && category.children.length > 0) {
flatCategories = flatCategories.concat(flattenCategories(category.children, [...parentIds, category.id]));
}
}
return flatCategories;
}
goods.classify.list().then(res => {
classifyList.value = flattenCategories(res.data);
});
};
getClassify();
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>

@ -19,7 +19,7 @@
</view> </view>
<div class="goodsBox p-2"> <div class="goodsBox p-2">
<myList ref="myListRef" :apiObj="goods.list" :params="{ ...params, classify_id }"> <myList height="78vh" ref="myListRef" :apiObj="goods.list" :params="{ ...params, classify_id }">
<template #default="{ list }"> <template #default="{ list }">
<div> <div>
<div v-for="item of list" class="goods"> <div v-for="item of list" class="goods">
@ -48,7 +48,7 @@
style="margin-right: 8px;">下架</wd-button> style="margin-right: 8px;">下架</wd-button>
<wd-button @click="changeS(item)" v-if="item.status !== 1" size="small" <wd-button @click="changeS(item)" v-if="item.status !== 1" size="small"
style="margin-right: 8px;">上架</wd-button> style="margin-right: 8px;">上架</wd-button>
<wd-button @click="utils.toUrl('/store/goods/edit')" size="small">编辑</wd-button> <wd-button @click="utils.toUrl('/store/goods/edit?id=' + item.id)" size="small">编辑</wd-button>
</view> </view>
</template> </template>
</wd-card> </wd-card>
@ -56,7 +56,14 @@
</div> </div>
</template> </template>
</myList> </myList>
<view class="flex mt-2 fixed left-2 right-2 bottom-3 px-10">
<wd-button @click="utils.toUrl('/store/cat/index')" class="flex-3">分类</wd-button>
<wd-button @click="utils.toUrl('/store/goods/edit?id=' + 0)" class="flex-1 ml-4">发布商品</wd-button>
</view>
</div> </div>
<wd-toast /> <wd-toast />
</view> </view>
</template> </template>
@ -64,9 +71,15 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { useToast } from '@/uni_modules/wot-design-uni' import { useToast } from '@/uni_modules/wot-design-uni'
import goods from '@/api/store/goods.js'
import myList from "/components/myList/index.vue" import myList from "/components/myList/index.vue"
import goods from '@/api/store/goods.js'
import utils from '@/utils/utils.js' import utils from '@/utils/utils.js'
import {
onLoad,
onShow
} from "@dcloudio/uni-app";
const toast = useToast() const toast = useToast()
const classify_id = ref(0) const classify_id = ref(0)
@ -147,6 +160,10 @@ const getClassify = () => {
}) })
} }
getClassify() getClassify()
onShow(() => {
search({ value: '' })
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

@ -1,78 +1,268 @@
<template> <template>
<view class="content pt-[44px]"> <view class="content pt-[44px]">
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<view class="w-full"> <view class="w-full">
<wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城首页'"> <wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城首页'">
<template #right> <template #right>
<wd-icon name="setting" size="22px"></wd-icon> <wd-icon @click="utils.toUrl('/store/setup/index')" name="setting" size="22px"></wd-icon>
</template> </template>
</wd-navbar> </wd-navbar>
</view> </view>
<view class="order mb-2"> <view bg-color="#f7f8fa" class="w-full grid grid-cols-3 gap-3 px-3 my-4">
<wd-grid bg-color="#f7f8fa" v-show="oneLine.ok"> <view @click="utils.toUrl('/store/cat/index')" class="text-white rounded-3xl p-4 pb-0 shadow-lg overflow-hidden"
<wd-grid-item icon="round" :text="`用户 (${oneLine.user_count})`" /> style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<wd-grid-item icon="round" :text="`商品 (${oneLine.goods_count})`" /> <view class="font-bold">分类管理</view>
<wd-grid-item icon="round" :text="`售罄 (${oneLine.empty_stock_count})`" /> <view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<wd-grid-item icon="round" :text="`订单 (${oneLine.order_count})`" />
</wd-grid> <view class="flex justify-end">
<div class="rotate-[-28deg] translate-y-3 translate-x-5">
<wd-icon name="chat opacity-80" size="42px"></wd-icon>
</div>
</view>
</view> </view>
<view style="transition: 1s;" class="flex-1 w-full h-full bg-white pt-4 rounded-tr-3xl rounded-tl-3xl shadow-lg oh"> <view @click="utils.toUrl('/store/goods/index')" class="text-white rounded-3xl p-4 pb-0 shadow-lg overflow-hidden"
<view class="w-full grid grid-cols-2 gap-3 px-3">
<view @click="utils.toUrl('/store/goods/index')" class="text-white rounded-3xl p-4 pb-3 shadow-lg overflow-hidden"
style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);"> style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<view class="font-bold">商品管理</view> <view class="font-bold">商品管理</view>
<view class="h-0.5 w-5 mt-0.5 bg-white"></view> <view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<view class="flex justify-end"> <view class="flex justify-end">
<div class="rotate-[-28deg] translate-y-5 translate-x-5"> <div class="rotate-[-28deg] translate-y-3 translate-x-5">
<wd-icon name="goods opacity-80" size="46px"></wd-icon> <wd-icon name="goods opacity-80" size="42px"></wd-icon>
</div> </div>
</view> </view>
</view> </view>
<view @click="utils.toUrl('/store/order/index')" class="text-white rounded-3xl p-4 pb-3 shadow-lg overflow-hidden" <view @click="utils.toUrl('/store/order/index')" class="text-white rounded-3xl p-4 pb-0 shadow-lg overflow-hidden"
style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);"> style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<view class="font-bold">订单中心</view> <view class="font-bold">订单管理</view>
<view class="h-0.5 w-5 mt-0.5 bg-white"></view> <view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<view class="flex justify-end"> <view class="flex justify-end">
<div class="rotate-[-20deg] translate-y-5 translate-x-5"> <div class="rotate-[-28deg] translate-y-3 translate-x-5">
<wd-icon name="gift opacity-80" size="46px"></wd-icon> <wd-icon name="gift opacity-80" size="42px"></wd-icon>
</div> </div>
</view> </view>
</view> </view>
<!-- <view class="bg-dark shadow-md rounded-md p-4">
<wd-icon name="goods" size="22px"></wd-icon>
<view class="mt-2 text-end font-bold">订单中心</view>
</view>
<view class="bg-dark shadow-md rounded-md p-4">
<wd-icon name="goods" size="22px"></wd-icon> <!-- <view @click="utils.toUrl('/store/order/index')" class="text-white rounded-3xl p-4 pb-0 shadow-lg overflow-hidden"
<view class="mt-2 text-end font-bold">订单中心</view> style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<view class="font-bold">订单管理</view>
<view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<view class="flex justify-end">
<div class="rotate-[-28deg] translate-y-3 translate-x-5">
<wd-icon name="gift opacity-80" size="42px"></wd-icon>
</div>
</view>
</view> --> </view> -->
</view>
<view style="transition: 1s;" class="w-full h-full bg-white pt-4 rounded-tr-3xl rounded-tl-3xl shadow-lg oh">
<view class="order mb-2">
<wd-grid v-show="oneLine.ok">
<wd-grid-item icon="round" :text="`用户 (${oneLine.user_count})`" />
<wd-grid-item icon="round" :text="`商品 (${oneLine.goods_count})`" />
<wd-grid-item icon="round" :text="`售罄 (${oneLine.empty_stock_count})`" />
<wd-grid-item icon="round" :text="`订单 (${oneLine.order_count})`" />
</wd-grid>
</view> </view>
</view> </view>
<view class="flex-1 bg-white p-2 pb-4">
<!-- <div class="name mb-2">订单数据</div> -->
<view class=" p-2 rounded-md">
<div class="rounded-md overflow-hidden">
<wd-tabs @change="getOrderProfit">
<wd-tab :title="`今天`" :name="1"></wd-tab>
<wd-tab :title="`本周`" :name="2"></wd-tab>
<wd-tab :title="`本月`" :name="3"></wd-tab>
<wd-tab :title="`本年`" :name="4"></wd-tab>
</wd-tabs>
</div>
<div class="grid grid-cols-2 gap-2 my-4">
<div class="item rounded-1xl bg-slate-50 p-2 flex justify-between" style="font-size: 24rpx;"
v-for="(item, index) of orderProfit.categories">
{{ item }}
<text>{{ orderProfit.series[0].data[index] }}</text>
</div>
</div>
<bar :barData="orderProfit"></bar>
</view>
</view>
<view class="flex-1 bg-white p-2 pb-4 ">
<view class=" p-2 rounded-md">
<div class="rounded-md overflow-hidden">
<wd-tabs @change="getOrderGood">
<wd-tab :title="`今天`" :name="1"></wd-tab>
<wd-tab :title="`本周`" :name="2"></wd-tab>
<wd-tab :title="`本月`" :name="3"></wd-tab>
<wd-tab :title="`本年`" :name="4"></wd-tab>
</wd-tabs>
</div>
<div class="grid grid-cols-2 gap-2 my-4">
<div class="item rounded-1xl bg-slate-50 p-2 flex justify-between" style="font-size: 24rpx;"
v-for="(item, index) of orderGood.categories">
{{ item }}
<text>{{ orderGood.series[0].data[index] }}</text>
</div>
</div>
<bar :barData="orderGood"></bar>
</view>
</view>
<view class="bg-white h-[80px]"></view>
<view class="fixed left-2 right-2 bottom-4 z-50">
<myTabbar></myTabbar>
</view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue';
import utils from '@/utils/utils.js' import utils from '@/utils/utils.js';
import index from '@/api/store/index.js' import index from '@/api/store/index.js';
import myTabbar from "../components/myTabbar/index.vue";
import bar from "../components/bar/bar.vue";
import kevyloading from "@/components/kevy-loading/kevy-loading";
/**
* @type {Ref<boolean>}
* 控制页面加载状态的 Ref
*/
const loading = ref(false);
/**
* 从本地存储中获取用户信息
*/
const user_info = uni.getStorageSync("user_info"); const user_info = uni.getStorageSync("user_info");
const oneLine = ref({}) /**
* @type {Ref<Object>}
* 存储一行数据的 Ref
*/
const oneLine = ref({});
/**
* 获取一行数据的函数
*/
const getOneLine = () => { const getOneLine = () => {
index.dataCount.oneLine().then(res => { index.dataCount.oneLine().then(res => {
oneLine.value = res.data oneLine.value = res.data;
oneLine.value.ok = true oneLine.value.ok = true;
}) });
};
//
getOneLine();
/**
* @type {Ref<Object>}
* 存储订单利润数据的 Ref
*/
const orderProfit = ref({});
/**
* 获取订单利润数据的函数
* @param {Object} e - 包含索引的对象
*/
const getOrderProfit = (e) => {
loading.value = true;
index.dataCount.orderProfit({
date: e.index + 1
}).then(res => {
if (res.code === 0) {
const statusData = res.data.reduce((obj, cur) => {
obj[cur.status] = cur;
return obj;
}, {});
const arr = [
{ name: "未付款订单", data: statusData[0]?.count || 0 },
{ name: "待发货订单", data: statusData[1]?.count || 0 },
{ name: "已发货订单", data: statusData[2]?.count || 0 },
{ name: "已完成订单", data: statusData[3]?.count || 0 },
{ name: "已取消订单", data: statusData[4]?.count || 0 }
];
orderProfit.value.categories = arr.map(item => item.name);
orderProfit.value.series = [
{ name: "订单数据", data: arr.map(item => item.data) }
];
loading.value = false;
console.log(orderProfit.value);
} }
getOneLine() });
};
//
getOrderProfit({ index: 0 });
/**
* @type {Ref<Object>}
* 存储订单商品数据的 Ref
*/
const orderGood = ref({});
/**
* 获取订单商品数据的函数
* @param {Object} e - 包含索引的对象
*/
const getOrderGood = (e) => {
loading.value = true;
index.dataCount.orderGood({
date: e.index + 1
}).then(res => {
if (res.code === 0) {
const payTypeData = res.data.reduce((obj, cur) => {
obj[cur.pay_type] = cur;
return obj;
}, {});
const totalPrice = (
(Number(payTypeData[1]?.pay_price) || 0) +
(Number(payTypeData[2]?.pay_price) || 0) +
(Number(payTypeData[3]?.pay_price) || 0)
);
const arr = [
{ name: "总成交金额", data: totalPrice || 0 },
{ name: "支付宝支付", data: payTypeData[1]?.pay_price || 0 },
{ name: "微信支付", data: payTypeData[2]?.pay_price || 0 },
{ name: "余额支付", data: payTypeData[3]?.pay_price || 0 },
];
orderGood.value.categories = arr.map(item => item.name);
orderGood.value.series = [
{ name: "交易数据", data: arr.map(item => item.data) }
];
loading.value = false;
console.log(orderGood.value);
}
});
};
//
getOrderGood({ index: 0 });
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

@ -34,6 +34,8 @@
</wd-message-box> </wd-message-box>
<view class=" bg-white sticky top-0 z-50"> <view class=" bg-white sticky top-0 z-50">
<div class="flex items-center">
<view class="flex-1">
<wd-search @search="search" @clear="search({ value: '' })" v-model="params.keywords" hide-cancel> <wd-search @search="search" @clear="search({ value: '' })" v-model="params.keywords" hide-cancel>
<template #prefix> <template #prefix>
<wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType"> <wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType">
@ -44,9 +46,13 @@
</wd-popover> </wd-popover>
</template> </template>
</wd-search> </wd-search>
<!-- <wd-drop-menu> </view>
<wd-drop-menu-item v-model="shipmentsModel.delivery_company" :options="expressList" />
</wd-drop-menu> --> <div class="mr-2">
<wd-button @click="utils.toUrl('/store/afterSale/index')" size="small">售后订单</wd-button>
</div>
</div>
<wd-tabs @change="(e) => { <wd-tabs @change="(e) => {
params.status = e.index; params.status = e.index;
search({ value: params.keywords }) search({ value: params.keywords })
@ -67,11 +73,10 @@
<view> <view>
<span class="mr-2" v-if="item.shop">{{ item.shop.name }}</span> <span class="mr-2" v-if="item.shop">{{ item.shop.name }}</span>
<span class="mr-2" v-else></span> <span class="mr-2" v-else></span>
<span class="font-bold">({{ status[item.status + 1].content }})</span> <span class="font-bold">({{ status[item.status + 1].content }})</span>
</view> </view>
<view class="title-tip"> <view @click="utils.copy(item.order_no, '已复制单号')" class="title-tip">
<span style="font-size: 24rpx;margin-left: 8px;">单号{{ item.order_no }}</span> <span style="font-size: 24rpx;margin-left: 8px;">单号{{ item.order_no }}</span>
</view> </view>
</view> </view>
@ -84,13 +89,16 @@
<view class="line2" style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ subItem.goods_name }}</view> <view class="line2" style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ subItem.goods_name }}</view>
<!-- <view class="font-bold" style="color: rgb(255, 0, 0); font-size: 16px;">{{ subItem.price }} <!-- <view class="font-bold" style="color: rgb(255, 0, 0); font-size: 16px;">{{ subItem.price }}
</view> --> </view> -->
<view class="font-bold">小计: {{ subItem.price }} <text <view class="font-bold" style="font-size: 22rpx;">小计: {{ subItem.price }} <text
style="color: rgb(255, 0, 0); font-size: 24rpx;">({{ style="color: rgb(255, 0, 0); font-size: 24rpx;">({{
subItem.num }}) </text></view> subItem.num }}) </text></view>
<div class="goods_sky" style="font-size: 22rpx;">
<span v-for="(sku, _index) of subItem.goods_sku_json" :key="_index">
{{ sku.group_name }}{{ sku.name }}</span>
</div>
</view> </view>
</view> </view>
<view class="bg-gray-50 p-2"> <view class="bg-gray-50 p-2">
<view class="text-[12px]" v-if="item.user"> <view class="text-[12px]" v-if="item.user">
<view class="mb-1"> <view class="mb-1">
@ -99,9 +107,17 @@
( 会员ID{{ item.user.id }} ) ( 会员ID{{ item.user.id }} )
</text> </text>
<view class="bg-gray-100 my-2 p-2"> <view class="bg-gray-100 my-2 p-2 relative">
<view>收货人{{ item.receiver_name }} &nbsp; 电话{{ item.receiver_phone }}</view> <view>收货人{{ item.receiver_name }} &nbsp; 电话{{ item.receiver_phone }}</view>
<view>收货地址{{ item.delivery_address }} {{ item.delivery_address_detail }}</view> <view v-if="item.delivery_address">{{ item.delivery_address }} {{
item.delivery_address_detail }}</view>
<view
@click="utils.copy(`收货人:${item.receiver_name} 电话:${item.receiver_phone} 收货地址:${item.delivery_address}`, '已复制快递信息')"
class="absolute right-2 top-2">
<wd-icon name="file-copy" size="14px"></wd-icon>
</view>
</view> </view>
</view> </view>
@ -160,135 +176,127 @@
</template> </template>
<script setup> <script setup>
import order from '@/api/store/order.js' import utils from '@/utils/utils.js';
import myList from "/components/myList/index.vue" import order from '@/api/store/order.js';
import { useMessage } from '@/uni_modules/wot-design-uni' import myList from "/components/myList/index.vue";
import { useToast } from '@/uni_modules/wot-design-uni' import { useMessage } from '@/uni_modules/wot-design-uni';
import { ref } from 'vue' import { useToast } from '@/uni_modules/wot-design-uni';
const message = useMessage('wd-message-box-slot') import { ref } from 'vue';
const message1 = useMessage()
const toast = useToast() const message = useMessage('wd-message-box-slot');
const message1 = useMessage();
const toast = useToast();
const classify_id = ref(0) const classify_id = ref(0);
const params = ref({ const params = ref({
keywords: "", keywords: "",
status: "", status: "",
type: 'order_no' type: 'order_no'
}) });
const myListRef = ref(null);
const myListRef = ref(null)
const search = ({ value }) => { const search = ({ value }) => {
myListRef.value.upData({ myListRef.value.upData({
keywords: value, keywords: value,
classify_id: classify_id.value, classify_id: classify_id.value,
status: params.value.status - 1 status: params.value.status - 1
}) });
} };
const searchType = ref('订单编号')
const popover = ref(false) const searchType = ref('订单编号');
const popover = ref(false);
const status = ref([ const status = ref([
{ { content: '全部' },
content: '全部' { content: '未付款' },
}, { content: '待发货' },
{ { content: '已发货' },
content: '未付款' { content: '已完成' },
}, { content: '已取消' },
{ { content: '待处理' },
content: '待发货' { content: '回收站' }
}, ]);
{
content: '已发货'
},
{
content: '已完成'
},
{
content: '已取消'
},
{
content: '待处理'
},
{
content: '回收站'
}
])
const menu = ref([ const menu = ref([
{ { content: '订单编号' },
content: '订单编号' { content: '商品名称' },
}, { content: '手机号' },
{ { content: '会员昵称' },
content: '商品名称' { content: '收货人' },
}, ]);
{
content: '手机号' /**
}, * 切换搜索类型
{ * @param {Object} item - 切换的项
content: '会员昵称' */
},
{
content: '收货人'
},
])
function changeSearchType({ item, index }) { function changeSearchType({ item, index }) {
searchType.value = item.content searchType.value = item.content;
console.log(searchType.value);
if (item.content == '订单编号') { if (item.content == '订单编号') {
params.value.type = "order_no" params.value.type = "order_no";
} }
if (item.content == '商品名称') { if (item.content == '商品名称') {
params.value.type = "goods_name" params.value.type = "goods_name";
} }
if (item.content == '手机号') { if (item.content == '手机号') {
params.value.type = "receiver_phone" params.value.type = "receiver_phone";
} }
if (item.content == '会员昵称') { if (item.content == '会员昵称') {
params.value.type = "nickname" params.value.type = "nickname";
} }
if (item.content == '收货人') { if (item.content == '收货人') {
params.value.type = "receiver_name" params.value.type = "receiver_name";
} }
} }
/**
* 更改状态
* @param {Object} row - 行数据
*/
const changeS = (row) => { const changeS = (row) => {
//
// goods.goodsEditAttribute({ // goods.goodsEditAttribute({
// id: item.id, // id: item.id,
// value: [1, 0][item.status], // value: [1, 0][item.status],
// type: "status" // type: "status"
// }).then(res => { // }).then(res => {
// if (res.code == 0) { // if (res.code == 0) {
// toast.success('') // toast.success('')
// item.status = [1, 0][item.status] // item.status = [1, 0][item.status]
// } else { // } else {
// showNotify({ type: 'error', message: '' }) // showNotify({ type: 'error', message: '' })
// } // }
// }) // })
} };
const expressList = ref([]) const expressList = ref([]);
const GetExpressList = () => {
order.GetExpressList().then(res => {
/**
* 获取物流公司列表
*/
const getExpressList = () => {
order.GetExpressList().then(res => {
expressList.value = Object.entries(res.data).reduce((express, item) => { expressList.value = Object.entries(res.data).reduce((express, item) => {
express.push({ label: item[1], value: item[0] }) express.push({ label: item[1], value: item[0] });
return express return express;
}, []) }, []);
});
};
}) //
} getExpressList();
GetExpressList()
const shipmentsModel = ref({ const shipmentsModel = ref({
send_type: 2, send_type: 2,
delivery_company: "" delivery_company: ""
}) });
/**
* 处理发货操作
* @param {Object} row - 行数据
*/
const shipments = (row) => { const shipments = (row) => {
message message
.confirm({ .confirm({
@ -299,56 +307,55 @@ const shipments = (row) => {
order.orderSend({ order.orderSend({
id: row.id, id: row.id,
send_type: "2" send_type: "2"
}) });
row.status = 2 row.status = 2;
toast.success('操作成功') toast.success('操作成功');
setTimeout(() => { setTimeout(() => {
shipmentsModel.value = { shipmentsModel.value = {
send_type: 2, send_type: 2,
delivery_company: "" delivery_company: ""
} };
}, 300); }, 300);
} }
if (shipmentsModel.value.send_type == 1) { if (shipmentsModel.value.send_type == 1) {
if (shipmentsModel.value.delivery_company && shipmentsModel.value.delivery_no) { if (shipmentsModel.value.delivery_company && shipmentsModel.value.delivery_no) {
order.orderSend({ order.orderSend({
id: row.id, id: row.id,
send_type: "1", send_type: "1",
delivery_company: shipmentsModel.value.delivery_company, delivery_company: shipmentsModel.value.delivery_company,
delivery_no: shipmentsModel.value.delivery_no, delivery_no: shipmentsModel.value.delivery_no,
}) });
row.status = 2 row.status = 2;
row.success('操作成功') row.success('操作成功');
setTimeout(() => { setTimeout(() => {
shipmentsModel.value = { shipmentsModel.value = {
send_type: 2, send_type: 2,
delivery_company: "" delivery_company: ""
} };
}, 300); }, 300);
} else { } else {
toast.error('发货失败,请完善选择填写') toast.error('发货失败,请完善选择填写');
shipments(row) shipments(row);
} }
} }
}) })
.catch((error) => { .catch((error) => {
console.log(error) console.log(error);
setTimeout(() => { setTimeout(() => {
shipmentsModel.value = { shipmentsModel.value = {
send_type: 2, send_type: 2,
delivery_company: "" delivery_company: ""
} };
}, 300); }, 300);
}) });
} };
/**
* 处理打印小票操作
* @param {Object} row - 行数据
*/
const printing = (row) => { const printing = (row) => {
message1 message1
.confirm({ .confirm({
@ -360,18 +367,21 @@ const printing = (row) => {
send_type: "2" send_type: "2"
}).then(res => { }).then(res => {
if (res.code == 0) { if (res.code == 0) {
toast.success('调用成功') toast.success('调用成功');
} else { } else {
toast.error('调用失败') toast.error('调用失败');
} }
}) });
}) })
.catch((error) => { .catch((error) => {
console.log(error) console.log(error);
}) });
} };
/**
* 处理订单备注操作
* @param {Object} row - 行数据
*/
const orderNotes = (row) => { const orderNotes = (row) => {
message1 message1
.prompt({ .prompt({
@ -383,17 +393,21 @@ const orderNotes = (row) => {
notes: resp.value notes: resp.value
}).then(res => { }).then(res => {
if (res.code == 0) { if (res.code == 0) {
toast.success('操作成功') toast.success('操作成功');
} else { } else {
toast.error('操作失败') toast.error('操作失败');
} }
}) });
}) })
.catch((error) => { .catch((error) => {
console.log(error) console.log(error);
}) });
} };
/**
* 处理退款审批操作
* @param {Object} row - 行数据
*/
const orderApproval = (row) => { const orderApproval = (row) => {
message1 message1
.confirm({ .confirm({
@ -408,15 +422,14 @@ const orderApproval = (row) => {
handle_status: 1 handle_status: 1
}).then(res => { }).then(res => {
if (res.code == 0) { if (res.code == 0) {
toast.success('操作成功') toast.success('操作成功');
row.apply_cancel = 0 row.apply_cancel = 0;
} else { } else {
toast.error('操作失败') toast.error('操作失败');
} }
}) });
}) })
.catch((error) => { .catch((error) => {
if (error.action == 'cancel') { if (error.action == 'cancel') {
order.confirmCancel({ order.confirmCancel({
id: row.id, id: row.id,
@ -424,18 +437,15 @@ const orderApproval = (row) => {
handle_status: 0 handle_status: 0
}).then(res => { }).then(res => {
if (res.code == 0) { if (res.code == 0) {
toast.success('操作成功') toast.success('操作成功');
row.apply_cancel = 0 row.apply_cancel = 0;
} else { } else {
toast.error('操作失败') toast.error('操作失败');
} }
}) });
}
})
} }
});
};
</script> </script>

@ -0,0 +1,284 @@
<template>
<view>
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<view class="w-full mb-12">
<wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城设置'">
<template #right>
<view @click="utils.loginOut()">
退出登录
</view>
</template>
</wd-navbar>
</view>
<wd-form ref="form" :model="storeData" :rules="formRules">
<!-- 基础信息 -->
<wd-cell-group title="基础信息" border>
<wd-input label="商城名称" label-width="100px" v-model="storeData.name" />
<!-- 商城LOGO -->
<wd-cell-group class="flex py-2 w-full" title="商城LOGO">
<view class="ml-3">
<myUpload v-model="storeData.logo_url" :size="1"></myUpload>
</view>
</wd-cell-group>
<!-- <wd-input label="联系人" label-width="100px" v-model="storeData.contact" /> -->
<wd-input label="联系方式" label-width="100px" v-model="storeData.mobile" />
<!-- 其他基础信息字段可以根据需要添加 -->
</wd-cell-group>
<!-- 地址信息 -->
<wd-cell-group class="flex py-2 w-full" title="所在地区">
<view class="ml-3">
<!-- 省市区选择器 -->
<uni-data-picker placeholder="请选择省市区" popup-title="" :localdata="addrList" :map="{
text: 'name',
value: 'id',
}" v-model="storeData.district" @change="select">
</uni-data-picker>
</view>
</wd-cell-group>
<!-- <wd-cell-group class="flex py-2 w-full" title="经纬度">
<view class="ml-3">
<wd-input label-width="100px" v-model="storeData.latlngCurrent" />
</view>
</wd-cell-group> -->
<!-- 其他信息 -->
<wd-cell-group title="订单设置" border>
<wd-input label="支付时间" label-width="100px" v-model="storeData.pay_time" use-suffix-slot>
<template #suffix>
<view>分钟</view>
</template>
</wd-input>
<wd-input label="自动收货时间" label-width="100px" v-model="storeData.confirm_time" use-suffix-slot>
<template #suffix>
<view></view>
</template>
</wd-input>
<wd-input label="售后时间" label-width="100px" v-model="storeData.sale_time" use-suffix-slot>
<template #suffix>
<view></view>
</template>
</wd-input>
<wd-cell-group class=" py-2 w-full" title="支付方式">
<view class="ml-3">
<wd-checkbox-group v-model="storeData.pay_type">
<div class="px-4 pb-4 flex flex-wrap ">
<wd-checkbox class="w-full" v-for="option in paymentOptions" :key="option.value"
:model-value="option.value" shape="button">{{ option.label }}</wd-checkbox>
</div>
</wd-checkbox-group>
</view>
</wd-cell-group>
<wd-cell-group class=" py-2 w-full" title="发货方式">
<view class="ml-3">
<wd-checkbox-group v-model="storeData.delivery_type">
<div class="px-4 pb-4">
<wd-checkbox class="w-full" v-for="option in shippingOptions" :key="option.value"
:model-value="option.value" shape="button">{{ option.label }}</wd-checkbox>
</div>
</wd-checkbox-group>
</view>
</wd-cell-group>
<wd-cell-group title="其他信息" border>
<!-- 收件人表单项 -->
<wd-form-item label="收件人 (售后)" prop="recipient">
<wd-input v-model="storeData.after_sale_name" placeholder="请输入收件人姓名" clearable />
</wd-form-item>
<!-- 电话表单项 -->
<wd-form-item label="电话 (售后)" prop="phone">
<wd-input v-model="storeData.after_sale_phone" placeholder="请输入联系电话" clearable />
</wd-form-item>
<!-- 地址表单项 -->
<wd-form-item label="地址 (售后)" prop="address">
<wd-input v-model="storeData.after_sale_address" placeholder="请输入详细地址" clearable />
</wd-form-item>
<!-- 阿里云物流查询 App Code 表单项 -->
<wd-form-item label="阿里云物流查询 App Code" prop="ali_express_app_code">
<wd-input v-model="storeData.ali_express_app_code" placeholder="请输入阿里云物流查询 App Code" clearable />
</wd-form-item>
<!-- 云喇叭通知表单项 -->
<wd-form-item label="云喇叭通知:" prop="zhangyou_device_name">
<wd-input v-model="storeData.zhangyou_device_name" placeholder="请输入设备编号" clearable />
<div style="color: #666;font-size: 12px;">
掌优4G云喇叭编号
</div>
</wd-form-item>
</wd-cell-group>
</wd-cell-group>
<div class="h-[80px] bg-slate-50"></div>
<!-- 提交按钮 -->
<view class="mt-2 fixed left-0 right-0 bottom-0 px-12 py-3 bg-slate-50">
<wd-button type="primary" size="large" @click="handleSubmit" block>
保存
</wd-button>
</view>
</wd-form>
</view>
</template>
<script>
import { ref } from 'vue';
import myUpload from "@/components/myUpload/index.vue";
import uniDataPicker from "@/components/uni-data-picker/components/uni-data-picker/uni-data-picker.vue";
import system from '@/api/modules/system.js';
import index from '@/api/store/index.js';
import kevyloading from "@/components/kevy-loading/kevy-loading";
import utils from '@/utils/utils.js'
/**
* 从本地存储中获取用户信息
*/
const user_info = uni.getStorageSync("user_info");
export default {
components: {
myUpload, uniDataPicker, kevyloading
},
data() {
return {
utils,
user_info,
//
storeData: {
name: '',
logo_url: '',
mobile: '',
district: null,
latlngCurrent: '',
pay_time: '',
confirm_time: '',
sale_time: '',
pay_type: [],
delivery_type: [],
after_sale_name: '',
after_sale_phone: '',
after_sale_address: '',
ali_express_app_code: '',
zhangyou_device_name: '',
},
paymentOptions: [
{ label: "支付宝", value: 1 },
{ label: "微信", value: 2 },
{ label: "余额", value: 3 },
{ label: "货到付款", value: 4 },
],
shippingOptions: [
{ label: "邮寄", value: 1 },
{ label: "自提", value: 2 },
{ label: "同城", value: 3 },
],
//
formRules: {
name: [{ required: true, message: "请输入门店名称", trigger: "blur" }],
//
},
//
addrList: [
//
],
loading: false
};
},
created() {
this.getDistrict();
this.getStoreSetting();
},
methods: {
/**
* 获取省市区数据
*/
async getDistrict() {
const res = await system.getDistrict();
this.addrList = res.data;
},
/**
* 获取门店设置
*/
async getStoreSetting() {
this.loading = true;
const res = await index.getStoreSetting();
if (res.data.id) {
this.storeData = res.data;
}
this.loading = false;
},
/**
* 处理省市区选择变化
* @param {Object} value - 选择的值
*/
areaChange(value) {
//
},
/**
* 处理省市区选择
* @param {Object} detail - 选择器详细信息
*/
select({ detail }) {
if (detail.value.length) {
const [province_id, city_id, district_id] = detail.value.map(
(el) => el.value
);
this.storeData.province_id = province_id;
this.storeData.city_id = city_id;
this.storeData.district_id = district_id;
this.storeData.district = [province_id, city_id, district_id];
}
},
/**
* 处理表单提交
*/
async handleSubmit() {
//
const res = await index.setStoreSetting({
...this.storeData
});
await this.getStoreSetting();
if (res.code == 0) {
setTimeout(() => {
uni.showToast({
title: '保存成功!',
icon: 'success'
});
}, 100);
// uni.navigateBack()
}
},
},
};
</script>
<style>
/* 在这里添加样式,根据需要自定义表单样式 */
</style>

@ -0,0 +1,221 @@
<template>
<view>
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<wd-form ref="form" :model="storeData" :rules="formRules">
<!-- 基础信息 -->
<wd-cell-group title="基础信息" border>
<wd-input label="商城名称" label-width="100px" v-model="storeData.name" />
<!-- 商城LOGO -->
<wd-cell-group class="flex py-2 w-full" title="商城LOGO">
<view class="ml-3">
<myUpload v-model="storeData.logo_url" :size="1"></myUpload>
</view>
</wd-cell-group>
<!-- 门头照图片 -->
<wd-cell-group class="flex py-2 w-full" title="门头照图片">
<view class="ml-3">
<myUpload v-model="storeData.store_url" :size="1"></myUpload>
</view>
</wd-cell-group>
<!-- <wd-input label="联系人" label-width="100px" v-model="storeData.contact" /> -->
<wd-input label="联系方式" label-width="100px" v-model="storeData.mobile" />
<!-- 其他基础信息字段可以根据需要添加 -->
</wd-cell-group>
<!-- 地址信息 -->
<wd-cell-group class="flex py-2 w-full" title="所在地区">
<view class="ml-3">
<!-- 省市区选择器 -->
<uni-data-picker placeholder="请选择省市区" popup-title="" :localdata="addrList" :map="{
text: 'name',
value: 'id',
}" v-model="storeData.district" @change="select">
</uni-data-picker>
</view>
</wd-cell-group>
<wd-input label="详细地址" label-width="100px" v-model="storeData.detail" use-suffix-slot>
</wd-input>
<!-- 其他信息 -->
<wd-cell-group title="其他信息" border>
<!-- 云喇叭通知表单项 -->
<wd-form-item label="云喇叭通知:" prop="zhangyou_device_name">
<wd-input v-model="storeData.zhangyou_device_name" placeholder="请输入设备编号" clearable />
<div style="color: #666;font-size: 12px;">
掌优4G云喇叭编号
</div>
</wd-form-item>
</wd-cell-group>
<view class="p-3 bg-white rounded mb-2">
<div class="name mb-2 text-xs">非营业时间下单</div>
<view class="bg-white px-3 py-2 rounded flex items-center">
<wd-switch v-model="storeData.is_opening" :active-value="1" :inactive-value="0" />
</view>
</view>
<view class="p-3 bg-white rounded mb-2">
<div class="name mb-2 text-xs">状态</div>
<view class="bg-white px-3 py-2 rounded flex items-center">
<wd-switch v-model="storeData.status" :active-value="1" :inactive-value="0" />
</view>
</view>
<!-- 提交按钮 -->
<view class="mt-2 px-12 py-3 bg-slate-50">
<wd-button type="primary" size="large" @click="handleSubmit" block>
保存
</wd-button>
</view>
</wd-form>
</view>
</template>
<script>
import { ref } from 'vue';
import myUpload from "@/components/myUpload/index.vue";
import uniDataPicker from "@/components/uni-data-picker/components/uni-data-picker/uni-data-picker.vue";
import system from '@/api/modules/system.js';
import index from '@/api/store/index.js';
import kevyloading from "@/components/kevy-loading/kevy-loading";
import utils from '@/utils/utils.js'
import shop from '@/api/store/shop.js';
/**
* 从本地存储中获取用户信息
*/
const user_info = uni.getStorageSync("user_info");
export default {
components: {
myUpload, uniDataPicker, kevyloading
},
data() {
return {
utils,
user_info,
//
storeData: {
name: '',
logo_url: '',
mobile: '',
district: null,
latlngCurrent: '',
pay_time: '',
confirm_time: '',
sale_time: '',
pay_type: [],
delivery_type: [],
after_sale_name: '',
after_sale_phone: '',
after_sale_address: '',
ali_express_app_code: '',
zhangyou_device_name: '',
},
shippingOptions: [
{ label: "邮寄", value: 1 },
{ label: "自提", value: 2 },
],
//
formRules: {
name: [{ required: true, message: "请输入门店名称", trigger: "blur" }],
//
},
//
addrList: [
//
],
loading: false
};
},
onLoad(e) {
this.getDistrict();
// this.getStoreSetting();
this.storeData = JSON.parse(e.edit)
},
methods: {
/**
* 获取省市区数据
*/
async getDistrict() {
const res = await system.getDistrict();
this.addrList = res.data;
},
/**
* 获取门店设置
*/
async getStoreSetting() {
this.loading = true;
const res = await index.getStoreSetting();
if (res.data.id) {
this.storeData = res.data;
}
this.loading = false;
},
/**
* 处理省市区选择变化
* @param {Object} value - 选择的值
*/
areaChange(value) {
//
},
/**
* 处理省市区选择
* @param {Object} detail - 选择器详细信息
*/
select({ detail }) {
if (detail.value.length) {
const [province_id, city_id, district_id] = detail.value.map(
(el) => el.value
);
this.storeData.province_id = province_id;
this.storeData.city_id = city_id;
this.storeData.district_id = district_id;
this.storeData.district = [province_id, city_id, district_id];
}
},
/**
* 处理表单提交
*/
async handleSubmit() {
//
const res = await shop.edit({
...this.storeData
});
if (res.code == 0) {
setTimeout(() => {
uni.showToast({
title: '保存成功!',
icon: 'success'
});
}, 100);
uni.navigateBack()
}
},
},
};
</script>
<style>
/* 在这里添加样式,根据需要自定义表单样式 */
</style>

@ -0,0 +1,168 @@
<template>
<view class="content">
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<!-- <view class="w-full">
<wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城首页'">
<template #right>
<wd-icon @click="utils.toUrl('/store/setup/index')" name="setting" size="22px"></wd-icon>
</template>
</wd-navbar>
</view> -->
<div class="grid p-2">
<div v-for="shop of shopList" class="rounded-md overflow-hidden">
<wd-card class="rounded-md overflow-hidden" type="rectangle">
<template #title>
<view class="title">
<view>ID{{ shop.id }}</view>
<view class="title-tip">
{{ shop.status ? "启用" : "停用" }}
</view>
</view>
</template>
<view style="height: 40px;" class="shopBox">
<image mode="aspectFill" :src="shop.logo_url" :alt="shop.name"
style="width: 60px;height: 60px;border-radius: 4px; margin-right: 12px;" />
<view>
<view style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ shop.name }}</view>
<view style="color: rgba(0,0,0,0.25); font-size: 12px;">{{ shop.detail }}</view>
</view>
</view>
<template #footer>
<view class="flex">
<wd-button style="margin-right: auto;margin-left: 0;" @click="syncGoods(shop)" size="small">同步商品</wd-button>
<view>
<wd-button @click="changeS(shop)" v-if="shop.status == 1" size="small" plain
style="margin-right: 8px;">关闭</wd-button>
<wd-button @click="changeS(shop)" v-if="shop.status !== 1" size="small" plain style="margin-right: 8px;">
开启</wd-button>
<wd-button @click="utils.toUrl('/store/shop/edit?edit=' + JSON.stringify(shop))" size="small"
style="margin-right: 0px;">编辑</wd-button>
</view>
</view>
</template>
</wd-card>
</div>
</div>
<view class="h-[64px]"></view>
<view class="fixed left-2 right-2 bottom-4 z-50">
<myTabbar tab="shop"></myTabbar>
</view>
<wd-toast />
<wd-message-box></wd-message-box>
</view>
</template>
<script setup>
import { ref } from 'vue';
import utils from '@/utils/utils.js';
import shop from '@/api/store/shop.js';
import myTabbar from "../components/myTabbar/index.vue";
import kevyloading from "@/components/kevy-loading/kevy-loading";
import { useMessage } from '@/uni_modules/wot-design-uni';
import { useToast } from '@/uni_modules/wot-design-uni'
const toast = useToast()
const message1 = useMessage();
import {
onShow,
} from "@dcloudio/uni-app";
/**
* @type {Ref<boolean>}
* 控制页面加载状态的 Ref
*/
const loading = ref(false);
/**
* 从本地存储中获取用户信息
*/
const user_info = uni.getStorageSync("user_info");
const shopList = ref({});
const changeS = (row) => {
shop.editStatus({
id: row.id,
status: [1, 0][row.status],
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
row.status = [1, 0][row.status]
} else {
showNotify({ type: 'error', message: '出错了' })
}
})
}
const syncGoods = (row) => {
message1
.confirm({
title: '同步商品',
})
.then((resp) => {
toast.loading('请稍后...')
shop.synchronousGoods({
id: row.id,
}).then(res => {
if (res.code == 0) {
toast.success('同步成功');
} else {
toast.error('同步失败');
}
});
})
.catch((error) => {
console.log(error);
});
};
/**
* 获取数据的函数
*/
const getShopList = () => {
loading.value = true
shop.list().then(res => {
shopList.value = res.data;
shopList.value.ok = true;
loading.value = false
});
};
//
onShow(() => {
getShopList();
})
</script>
<style lang="scss" scoped>
.shopBox,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.shopBox {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
</style>

@ -0,0 +1,281 @@
<template>
<view class="content bg-gray-50">
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<view class="grid">
<wd-card class="rounded-md overflow-hidden" type="rectangle">
<template #title>
<view class="title">
<view>ID{{ userInfo.id }}</view>
<view @click="utils.copy(userInfo.user_merge.mobile)" class="title-tip" v-if="userInfo.user_merge">
{{ userInfo.user_merge.mobile }}
<wd-icon name="file-copy" size="14px"></wd-icon>
</view>
</view>
</template>
<view style="height: 40px;" class="userInfoBox">
<image mode="aspectFill" :src="userInfo.avatar_pic" :alt="userInfo.name"
style="width: 60px;height: 60px;border-radius: 4px; margin-right: 12px;" />
<view>
<view style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ userInfo.nickname }}
</view>
<view style="color: rgba(0,0,0,0.25); font-size: 12px;">
<wd-tag class="mx-1" size="small" :type="originType[userInfo.origin]">
{{ userInfo.origin_text }}
</wd-tag>
</view>
</view>
</view>
<template #footer>
<view v-if="userInfo.user_merge" class="bg-gray-50 p-2 mb-2.5 flex justify-between" style="font-size: 22rpx;">
<view>余额{{ userInfo.user_merge.balance }} </view>
<view>积分{{ userInfo.user_merge.integral }} </view>
<view>佣金{{ userInfo.user_merge.money }} </view>
</view>
<view v-if="userInfo.user_merge" class="flex justify-between items-center">
<view></view>
<view>
<wd-button @click="showActions({ typeAc: 1 })" size="small" style="margin-right: 8px;">编辑余额</wd-button>
<wd-button @click="showActions({ typeAc: 2 })" size="small" style="margin-right: 0px;">编辑积分</wd-button>
</view>
</view>
</template>
</wd-card>
</view>
<view v-if="!loading">
<wd-tabs v-model="tab">
<block v-for="item in 1" :key="item + '余额记录'">
<wd-tab title="余额记录">
<myList height="64vh" v-if="userInfo.id" ref="myListRef" :apiObj="user.getLog"
:params="{ model: 'balance', id: userInfo.id }">
<template #default="{ list }">
<div class="pt-3 bg-gray-50">
<view v-for="item of list" class="bg-gray-50">
<wd-card :title='(item.type == 1 ? "余额增加 + " : "余额减少 - ") + item.change'>
<view class="bg-gray-50 p-2 mb-2.5 flex flex-col justify-between" style="font-size: 22rpx;">
<view class="mb-1">变动时间{{ item.create_time }} </view>
<view class="mb-1">变动前{{ item.before }} </view>
<view class="mb-1">变动后<span>{{ item.after }}</span> </view>
<view class="mb-1">描述{{ item.desc }} </view>
</view>
<template #footer>
<view>
ID{{ item.id }}
</view>
</template>
</wd-card>
</view>
</div>
</template>
</myList>
</wd-tab>
</block>
<block v-for="item in 1" :key="item + '积分记录'">
<wd-tab title="积分记录">
<myList height="64vh" v-if="userInfo.id" ref="myListRef" :apiObj="user.getLog"
:params="{ model: 'integral', id: userInfo.id }">
<template #default="{ list }">
<div class="pt-3 bg-gray-50">
<view v-for="item of list" class="bg-gray-50">
<wd-card :title='(item.type == 1 ? "积分增加 + " : "积分减少 - ") + item.change'>
<view class="bg-gray-50 p-2 mb-2.5 flex flex-col justify-between" style="font-size: 22rpx;">
<view class="mb-1">变动时间{{ item.create_time }} </view>
<view class="mb-1">变动前{{ item.before }} </view>
<view class="mb-1">变动后<span>{{ item.after }}</span> </view>
<view class="mb-1">描述{{ item.desc }} </view>
</view>
<template #footer>
<view>
ID{{ item.id }}
</view>
</template>
</wd-card>
</view>
</div>
</template>
</myList>
</wd-tab>
</block>
</wd-tabs>
</view>
<wd-toast />
<wd-action-sheet v-model="showAc" :actions="actions" @select="select" />
<wd-message-box></wd-message-box>
</view>
</template>
<script setup>
import { ref } from 'vue';
import utils from '@/utils/utils.js';
import user from '@/api/store/user.js';
import myList from "/components/myList/index.vue";
import kevyloading from "@/components/kevy-loading/kevy-loading";
import { useMessage } from '@/uni_modules/wot-design-uni'
const message = useMessage()
import {
onShow, onLoad
} from "@dcloudio/uni-app";
const tab = ref(0)
const model = ref({})
const baseForm = ref({})
const showAc = ref(false)
const typeAc = ref(1)
const userInfo = ref({});
const actions = [
{
name: '增加'
},
{
name: '减少'
}
]
function showActions(e) {
showAc.value = true
typeAc.value = e.typeAc
}
function close() {
showAc.value = false
}
function select({ item, index }) {
let textAc = ''
if (typeAc.value == 1) {
if (item.name == "增加") {
textAc = "增加余额"
} else {
textAc = "减少余额"
}
}
if (typeAc.value == 2) {
if (item.name == "增加") {
textAc = "增加积分"
} else {
textAc = "减少积分"
}
}
message
.prompt({
title: textAc,
})
.then((resp) => {
let model = ''
if (typeAc.value == 1) {
model = 'balance'
}
if (typeAc.value == 2) {
model = 'integral'
}
let type = ''
if (item.name == "增加") {
type = 1
} else {
type = 2
}
loading.value = true
user.changeInformation({
id: userInfo.value.id,
value: resp.value,
type, model
}).then(res => {
loading.value = false
})
})
.catch((error) => {
})
}
const originType = ref({
100: 'success',
101: 'success',
200: 'info',
201: 'danger',
300: 'warning',
})
/**
* @type {Ref<boolean>}
* 控制页面加载状态的 Ref
*/
const loading = ref(false);
//
onShow(() => {
// getuserInfoList();
})
onLoad(async (e) => {
loading.value = true
const res = await user.userItem({
id: e.id
});
userInfo.value = res.data
loading.value = false
})
</script>
<style lang="scss" scoped>
.userInfoBox,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.userInfoBox {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
</style>

@ -0,0 +1,289 @@
<template>
<view class="content">
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<!-- <view class="w-full">
<wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城首页'">
<template #right>
<wd-icon @click="utils.toUrl('/store/setup/index')" name="setting" size="22px"></wd-icon>
</template>
</wd-navbar>
</view> -->
<view class=" bg-white sticky top-0 z-50">
<wd-search @search="search({ value: params.keywords })" @clear="search({ value: params.keywords = '' })"
v-model="params.keywords" hide-cancel>
<template #prefix>
<wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType">
<view class="search-type">
<text>{{ searchType }}</text>
<wd-icon custom-class="icon-arrow" name="fill-arrow-down"></wd-icon>
</view>
</wd-popover>
</template>
</wd-search>
</view>
<div class="grid p-2">
<myList height="90vh" ref="myListRef" :apiObj="user.userList" :params="{ ...params }">
<template #default="{ list: userList }">
<div v-for="user of userList" class="rounded-md overflow-hidden">
<wd-card class="rounded-md overflow-hidden" type="rectangle">
<template #title>
<view class="title">
<view>ID{{ user.id }}</view>
<view @click="utils.copy(user.user_merge.mobile)" class="title-tip" v-if="user.user_merge">
{{ user.user_merge.mobile }}
<wd-icon name="file-copy" size="14px"></wd-icon>
</view>
</view>
</template>
<view style="height: 40px;" class="userBox">
<image mode="aspectFill" :src="user.avatar_pic" :alt="user.name"
style="width: 60px;height: 60px;border-radius: 4px; margin-right: 12px;" />
<view>
<view style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ user.nickname }}
</view>
<view style="color: rgba(0,0,0,0.25); font-size: 12px;">
<wd-tag class="mx-1" size="small" :type="originType[user.origin]">
{{ user.origin_text }}
</wd-tag>
</view>
</view>
</view>
<template #footer>
<view v-if="user.user_merge" class="bg-gray-50 p-2 mb-2.5 flex justify-between" style="font-size: 22rpx;">
<view>余额{{ user.user_merge.balance }} </view>
<view>积分{{ user.user_merge.integral }} </view>
<view>佣金{{ user.user_merge.money }} </view>
</view>
<view class="flex justify-between items-center">
<view></view>
<view>
<!-- <wd-button @click="changeS(user)" v-if="user.status == 1" size="small" plain
style="margin-right: 8px;">关闭</wd-button>
<wd-button @click="changeS(user)" v-if="user.status !== 1" size="small" plain
style="margin-right: 8px;">
开启</wd-button> -->
<wd-button @click="utils.toUrl('/store/user/edit?id=' + user.id)" size="small"
style="margin-right: 0px;">详情</wd-button>
</view>
</view>
</template>
</wd-card>
</div>
</template>
</myList>
</div>
<view class="h-[64px]"></view>
<view class="fixed left-2 right-2 bottom-4 z-50">
<myTabbar tab="user"></myTabbar>
</view>
<wd-toast />
<wd-message-box></wd-message-box>
</view>
</template>
<script setup>
import { ref } from 'vue';
import utils from '@/utils/utils.js';
import user from '@/api/store/user.js';
import myTabbar from "../components/myTabbar/index.vue";
import kevyloading from "@/components/kevy-loading/kevy-loading";
import { useMessage } from '@/uni_modules/wot-design-uni';
import { useToast } from '@/uni_modules/wot-design-uni'
import myList from "/components/myList/index.vue";
import {
onShow,
} from "@dcloudio/uni-app";
const toast = useToast()
const message1 = useMessage();
const originType = ref({
100: 'success',
101: 'success',
200: 'info',
201: 'danger',
300: 'warning',
})
const myListRef = ref(null);
const searchType = ref('昵称');
const popover = ref(false);
const search = ({ value }) => {
if (searchType.value == '昵称') {
myListRef.value.upData({
nickname: params.value.keywords,
mobile: ''
});
}
if (searchType.value == '手机号') {
myListRef.value.upData({
nickname: '',
mobile: params.value.keywords
});
}
};
const menu = ref([
{ content: '昵称' },
{ content: '手机号' },
]);
const params = ref({
nickname: "",
mobile: "",
origin: '',
value: ''
});
/**
* 切换搜索类型
* @param {Object} item - 切换的项
*/
function changeSearchType({ item, index }) {
searchType.value = item.content;
search(params.value.keywords)
}
/**
* @type {Ref<boolean>}
* 控制页面加载状态的 Ref
*/
const loading = ref(false);
/**
* 从本地存储中获取用户信息
*/
const user_info = uni.getStorageSync("user_info");
const userList = ref({});
const changeS = (row) => {
user.editStatus({
id: row.id,
status: [1, 0][row.status],
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
row.status = [1, 0][row.status]
} else {
showNotify({ type: 'error', message: '出错了' })
}
})
}
const syncGoods = (row) => {
message1
.confirm({
title: '同步商品',
})
.then((resp) => {
toast.loading('请稍后...')
user.synchronousGoods({
id: row.id,
}).then(res => {
if (res.code == 0) {
toast.success('同步成功');
} else {
toast.error('同步失败');
}
});
})
.catch((error) => {
console.log(error);
});
};
/**
* 获取数据的函数
*/
// const getuserList = () => {
// loading.value = true
// user.list().then(res => {
// userList.value = res.data;
// userList.value.ok = true;
// loading.value = false
// });
// };
//
onShow(() => {
// getuserList();
})
</script>
<style lang="scss" scoped>
.search-type {
position: relative;
height: 30px;
line-height: 30px;
padding: 0 8px 0 16px;
font-size: 24rpx;
color: rgba(0, 0, 0, .45);
}
.search-type::after {
position: absolute;
content: '';
width: 1px;
right: 0;
top: 5px;
bottom: 5px;
background: rgba(0, 0, 0, 0.25);
}
.search-type {
:deep(.icon-arrow) {
display: inline-block;
font-size: 20px;
vertical-align: middle;
}
}
.userBox,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.userBox {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
</style>

@ -0,0 +1,320 @@
## 2.5.0-202301012023-01-01
- 秋云图表组件 修改条件编译顺序确保uniapp的cli方式的项目依赖不完整时可以正常显示
- 秋云图表组件 恢复props属性directory的使用以修复vue3项目中开启echarts后echarts目录识别错误的bug
- uCharts.js 修复区域图、混合图只有一个数据时图表显示不正确的bug
- uCharts.js 修复折线图、区域图中时间轴类别图表tooltip指示点显示不正确的bug
- uCharts.js 修复x轴使用labelCount时并且boundaryGap = 'justify' 并且关闭Y轴显示的时候最后一个坐标值不显示的bug
- uCharts.js 修复折线图只有一组数据时 ios16 渲染颜色不正确的bug
- uCharts.js 修复玫瑰图半径显示不正确的bug
- uCharts.js 柱状图、山峰图增加正负图功能y轴网格如果需要显示0轴则由 min max 及 splitNumber 确定后续版本优化自动显示0轴
- uCharts.js 柱状图column增加 opts.extra.column.labelPosition数据标签位置有效值为 outside外部, insideTop内顶部, center内中间, bottom内底部
- uCharts.js 雷达图radar增加 opts.extra.radar.labelShow否显示各项标识文案是默认true
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.boxPadding提示窗边框填充距离默认3px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.fontSize提示窗字体大小配置默认13px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.lineHeight提示窗文字行高默认20px
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShow是否显示左侧图例默认true
- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShape图例形状图例标识样式有效值为 auto自动跟随图例, diamond◆, circle●, triangle▲, square■, rect▬, line-
- uCharts.js 标记线markLine增加 opts.extra.markLine.labelFontSize字体大小配置默认13px
- uCharts.js 标记线markLine增加 opts.extra.markLine.labelPadding标签边框内填充距离默认6px
- uCharts.js 折线图line增加 opts.extra.line.linearType渐变色类型可选值 none关闭渐变色custom 自定义渐变色。使用自定义渐变色时请赋值serie.linearColor作为颜色值
- uCharts.js 折线图line增加 serie.linearColor渐变色数组格式为2维数组[起始位置,颜色值],例如[[0,'#0EE2F8'],[0.3,'#2BDCA8'],[0.6,'#1890FF'],[1,'#9A60B4']]
- uCharts.js 折线图line增加 opts.extra.line.onShadow是否开启折线阴影开启后请赋值serie.setShadow阴影设置
- uCharts.js 折线图line增加 serie.setShadow阴影配置格式为4位数组[offsetX,offsetY,blur,color]
- uCharts.js 折线图line增加 opts.extra.line.animation动画效果方向可选值为vertical 垂直动画效果horizontal 水平动画效果
- uCharts.js X轴xAxis增加 opts.xAxis.lineHeightX轴字体行高默认20px
- uCharts.js X轴xAxis增加 opts.xAxis.marginTopX轴文字距离轴线的距离默认0px
- uCharts.js X轴xAxis增加 opts.xAxis.title当前X轴标题
- uCharts.js X轴xAxis增加 opts.xAxis.titleFontSize标题字体大小默认13px
- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetY标题纵向偏移距离负数为向上偏移正数向下偏移
- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetX标题横向偏移距离负数为向左偏移正数向右偏移
- uCharts.js X轴xAxis增加 opts.xAxis.titleFontColor标题字体颜色默认#666666
## 报错TypeError: Cannot read properties of undefined (reading 'length')
- 如果是uni-modules版本组件请先登录HBuilderX账号
- 在HBuilderX中的manifest.json点击重新获取uniapp的appid或者删除appid重新粘贴重新运行
- 如果是cli项目请使用码云上的非uniCloud版本组件
- 或者添加uniCloud的依赖
- 或者使用原生uCharts
## 2.4.5-202211302022-11-30
- uCharts.js 优化tooltip当文字很多变为左侧显示时如果画布仍显显示不下提示框错位置变为以左侧0位置起画
- uCharts.js 折线图修复特殊情况下只有单点数据并改变线宽后点变为圆形的bug
- uCharts.js 修复Y轴disabled启用后无效并报错的bug
- uCharts.js 修复仪表盘起始结束角度特殊情况下显示不正确的bug
- uCharts.js 雷达图新增参数 opts.extra.radar.radius , 自定义雷达图半径
- uCharts.js 折线图、区域图增加tooltip指示点opts.extra.line.activeType/opts.extra.area.activeType可选值"none"不启用激活指示点,"hollow"空心点模式,"solid"实心点模式
## 2.4.4-202211022022-11-02
- 秋云图表组件 修复使用echarts时reload、reshow无法调用重新渲染的bug[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/40)
- 秋云图表组件 修复使用echarts时初始化时宽高不正确的bug[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/42)
- 秋云图表组件 修复uniapp的h5使用history模式时无法加载echarts的bug
- 秋云图表组件 小程序端@complete、@scrollLeft、@scrollRight、@getTouchStart、@getTouchMove、@getTouchEnd事件增加opts参数传出方便一些特殊需求的交互获取数据。
- uCharts.js 修复calTooltipYAxisData方法内formatter格式化方法未与y轴方法同步的问题[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/43)
- uCharts.js 地图新增参数opts.series[i].fillOpacity以透明度方式来设置颜色过度效果[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/38)
- uCharts.js 地图新增参数opts.extra.map.active是否启用点击激活变色
- uCharts.js 地图新增参数opts.extra.map.activeTextColor是否启用点击激活变色
- uCharts.js 地图新增渲染完成事件renderComplete
- uCharts.js 漏斗图修复当部分数据相同时tooltip提示窗点击错误的bug
- uCharts.js 漏斗图新增参数series.data[i].centerText 居中标签文案
- uCharts.js 漏斗图新增参数series.data[i].centerTextSize 居中标签文案字体大小默认opts.fontSize
- uCharts.js 漏斗图新增参数series.data[i].centerTextColor 居中标签文案字体颜色,默认#FFFFFF
- uCharts.js 漏斗图新增参数opts.extra.funnel.minSize 最小值的最小宽度默认0
- uCharts.js 进度条新增参数opts.extra.arcbar.direction动画方向可选值为cw顺时针、ccw逆时针
- uCharts.js 混合图新增参数opts.extra.mix.line.width折线的宽度默认2
- uCharts.js 修复tooltip开启horizentalLine水平横线标注时图表显示错位的bug
- uCharts.js 优化tooltip当文字很多变为左侧显示时如果画布仍显显示不下提示框错位置变为以左侧0位置起画
- uCharts.js 修复开启滚动条后X轴文字超出绘图区域后的隐藏逻辑
- uCharts.js 柱状图、条状图修复堆叠模式不能通过{value,color}赋值单个柱子颜色的问题
- uCharts.js 气泡图修复不识别series.textSize和series.textColor的bug
## 报错TypeError: Cannot read properties of undefined (reading 'length')
1. 如果是uni-modules版本组件请先登录HBuilderX账号
2. 在HBuilderX中的manifest.json点击重新获取uniapp的appid或者删除appid重新粘贴重新运行
3. 如果是cli项目请使用码云上的非uniCloud版本组件
4. 或者添加uniCloud的依赖
5. 或者使用原生uCharts
## 2.4.3-202205052022-05-05
- 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时再次赋值后画布闪动的bug
- 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug
- uCharts.js 雷达图新增参数opts.extra.radar.gridEval数据点位网格抽希默认1
- uCharts.js 雷达图新增参数opts.extra.radar.axisLabel 是否显示刻度点值默认false
- uCharts.js 雷达图新增参数opts.extra.radar.axisLabelTofix刻度点值小数位数默认0
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointShow是否显示末端刻度圆点默认false
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointRadius刻度圆点的半径默认3
- uCharts.js 雷达图新增参数opts.extra.radar.labelPointColor刻度圆点的颜色默认#cccccc
- uCharts.js 雷达图新增参数opts.extra.radar.linearType渐变色类型可选值"none"关闭渐变,"custom"开启渐变
- uCharts.js 雷达图新增参数opts.extra.radar.customColor自定义渐变颜色数组类型对应series的数组长度以匹配不同series颜色的不同配色方案例如["#FA7D8D", "#EB88E2"]
- uCharts.js 雷达图优化支持series.textColor、series.textSize属性
- uCharts.js 柱状图中温度计式图标优化支持全圆角类型修复边框有缝隙的bug详见官网【演示】中的温度计图表
- uCharts.js 柱状图新增参数opts.extra.column.activeWidth当前点击柱状图的背景宽度默认一个单元格单位
- uCharts.js 混合图增加opts.extra.mix.area.gradient 区域图是否开启渐变色
- uCharts.js 混合图增加opts.extra.mix.area.opacity 区域图透明度默认0.2
- uCharts.js 饼图、圆环图、玫瑰图、漏斗图增加opts.series[0].data[i].labelText自定义标签文字避免formatter格式化的繁琐详见官网【演示】中的饼图
- uCharts.js 饼图、圆环图、玫瑰图、漏斗图增加opts.series[0].data[i].labelShow自定义是否显示某一个指示标签避免因饼图类别太多导致标签重复或者居多导致图形变形的问题详见官网【演示】中的饼图
- uCharts.js 增加opts.series[i].legendText/opts.series[0].data[i].legendText与series.name同级自定义图例显示文字的方法
- uCharts.js 优化X轴、Y轴formatter格式化方法增加形参统一为fromatter:function(value,index,opts){}
- uCharts.js 修复横屏模式下无法使用双指缩放方法的bug
- uCharts.js 修复当只有一条数据或者多条数据值相等的时候Y轴自动计算的最大值错误的bug
- 【官网模板】增加外部自定义图例与图表交互的例子,[点击跳转](https://www.ucharts.cn/v2/#/layout/info?id=2)
## 注意非unimodules 版本如因更新 hbx 至 3.4.7 导致报错如下,请到码云更新非 unimodules 版本组件,[点击跳转](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)
> Error in callback for immediate watcher "uchartsOpts": "SyntaxError: Unexpected token u in JSON at position 0"
## 2.4.2-202204212022-04-21
- 秋云图表组件 修复HBX升级3.4.6.20220420版本后echarts报错的问题
## 2.4.2-202204202022-04-20
## 重要此版本uCharts新增了很多功能修复了诸多已知问题
- 秋云图表组件 新增onzoom开启双指缩放功能仅uCharts前提需要直角坐标系类图表类型并且ontouch为true、opts.enableScroll为true详见实例项目K线图
- 秋云图表组件 新增optsWatch是否监听opts变化关闭optsWatch后动态修改opts不会触发图表重绘
- 秋云图表组件 修复开启canvas2d功能后动态更新数据后画布闪动的bug
- 秋云图表组件 去除directory属性改为自动获取echarts.min.js路径升级不受影响
- 秋云图表组件 增加getImage()方法及@getImage事件通过ref调用getImage()方法获,触发@getImage事件获取当前画布的base64图片文件流。
- 秋云图表组件 支付宝、字节跳动、飞书、快手小程序支持开启canvas2d同层渲染设置。
- 秋云图表组件 新增加【非uniCloud】版本组件避免有些不需要uniCloud的使用组件发布至小程序需要提交隐私声明问题请到码云[【非uniCloud版本】](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)或npm[【非uniCloud版本】](https://www.npmjs.com/package/@qiun/uni-ucharts)下载使用。
- uCharts.js 新增dobuleZoom双指缩放功能
- uCharts.js 新增山峰图type="mount"数据格式为饼图类格式不需要传入categories具体详见新版官网在线演示
- uCharts.js 修复折线图当数据中存在null时tooltip报错的bug
- uCharts.js 修复饼图类当画布比较小时自动计算的半径是负数报错的bug
- uCharts.js 统一各图表类型的series.formatter格式化方法的形参为(val, index, series, opts),方便格式化时有更多参数可用
- uCharts.js 标记线功能增加labelText自定义显示文字增加labelAlign标签显示位置左侧或右侧增加标签显示位置微调labelOffsetX、labelOffsetY
- uCharts.js 修复条状图当数值很小时开启圆角后样式错误的bug
- uCharts.js 修复X轴开启disabled后X轴仍占用空间的bug
- uCharts.js 修复X轴开启滚动条并且开启rotateLabel后X轴文字与滚动条重叠的bug
- uCharts.js 增加X轴rotateAngle文字旋转自定义角度取值范围(-90至90)
- uCharts.js 修复地图文字标签层级显示不正确的bug
- uCharts.js 修复饼图、圆环图、玫瑰图当数据全部为0的时候不显示数据标签的bug
- uCharts.js 修复当opts.padding上边距为0时Y轴顶部刻度标签位置不正确的bug
## 另外我们还开发了各大原生小程序组件已发布至码云和npm
[https://gitee.com/uCharts/uCharts](https://gitee.com/uCharts/uCharts)
[https://www.npmjs.com/~qiun](https://www.npmjs.com/~qiun)
## 对于原生uCharts文档我们已上线新版官方网站详情点击下面链接进入官网
[https://www.uCharts.cn/v2/](https://www.ucharts.cn/v2/)
## 2.3.7-202201222022-01-22
## 重要使用vue3编译请使用cli模式并升级至最新依赖HbuilderX编译需要使用3.3.8以上版本
- uCharts.js 修复uni-app平台组件模式使用vue3编译到小程序报错的bug。
## 2.3.7-202201182022-01-18
## 注意使用vue3的前提是需要3.3.8.20220114-alpha版本的HBuilder
## 2.3.67-202201182022-01-18
- 秋云图表组件 组件初步支持vue3全端编译会有些问题具体详见下面修改
1. 小程序端运行时在uni_modules文件夹的qiun-data-charts.js中搜索 new uni_modules_qiunDataCharts_js_sdk_uCharts_uCharts.uCharts将.uCharts去掉。
2. 小程序端发行时在uni_modules文件夹的qiun-data-charts.js中搜索 new e.uCharts将.uCharts去掉变为 new e。
3. 如果觉得上述步骤比较麻烦如果您的项目只编译到小程序端可以修改u-charts.js最后一行导出方式将 export default uCharts;变更为 export default { uCharts: uCharts }; 这样变更后H5和App端的renderjs会有问题请开发者自行选择。此问题非组件问题请等待DC官方修复Vue3的小程序端
## 2.3.6-202201112022-01-11
- 秋云图表组件 修改组件 props 属性中的 background 默认值为 rgba(0,0,0,0)
## 2.3.6-202112012021-12-01
- uCharts.js 修复bar条状图开启圆角模式时值很小时圆角渲染错误的bug
## 2.3.5-202110142021-10-15
- uCharts.js 增加vue3的编译支持仅原生uChartsqiun-data-charts组件后续会支持请关注更新
## 2.3.4-202110122021-10-12
- 秋云图表组件 修复 mac os x 系统 mouseover 事件丢失的 bug
## 2.3.3-202107062021-07-06
- uCharts.js 增加雷达图开启数据点值opts.dataLabel的显示
## 2.3.2-202106272021-06-27
- 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
## 2.3.1-202106162021-06-16
- uCharts.js 修复圆角柱状图使用4角圆角时当数值过大时不正确的bug
## 2.3.0-202106122021-06-12
- uCharts.js 【重要】uCharts增加nvue兼容可在nvue项目中使用gcanvas组件渲染uCharts[详见码云uCharts-demo-nvue](https://gitee.com/uCharts/uCharts)
- 秋云图表组件 增加tapLegend属性是否开启图例点击交互事件
- 秋云图表组件 getIndex事件中增加返回uCharts实例中的opts参数以便在页面中调用参数
- 示例项目 pages/other/other.vue增加app端自定义tooltip的方法详见showOptsTooltip方法
## 2.2.1-202106032021-06-03
- uCharts.js 修复饼图、圆环图、玫瑰图当起始角度不为0时tooltip位置不准确的bug
- uCharts.js 增加温度计式柱状图开启顶部半圆形的配置
## 2.2.0-202105292021-05-29
- uCharts.js 增加条状图type="bar"
- 示例项目 pages/ucharts/ucharts.vue增加条状图的demo
## 2.1.7-202105242021-05-24
- uCharts.js 修复大数据量模式下曲线图不平滑的bug
## 2.1.6-202105232021-05-23
- 秋云图表组件 修复小程序端开启滚动条更新数据后滚动条位置不符合预期的bug
## 2.1.5-20210517022021-05-17
- uCharts.js 修复自定义Y轴min和max值为0时不能正确显示的bug
## 2.1.5-202105172021-05-17
- uCharts.js 修复Y轴自定义min和max时未按指定的最大值最小值显示坐标轴刻度的bug
## 2.1.4-202105162021-05-16
- 秋云图表组件 优化onWindowResize防抖方法
- 秋云图表组件 修复APP端uCharts更新数据时清空series显示loading图标后再显示图表图表抖动的bug
- uCharts.js 修复开启canvas2d后x轴、y轴、series自定义字体大小未按比例缩放的bug
- 示例项目 修复format-e.vue拼写错误导致app端使用uCharts渲染图表
## 2.1.3-202105132021-05-13
- 秋云图表组件 修改uCharts变更chartData数据为updateData方法支持带滚动条的数据动态打点
- 秋云图表组件 增加onWindowResize防抖方法 fix by ど誓言,如尘般染指流年づ
- 秋云图表组件 H5或者APP变更chartData数据显示loading图表时原数据闪现的bug
- 秋云图表组件 props增加errorReload禁用错误点击重新加载的方法
- uCharts.js 增加tooltip显示categoryx轴对应点位标题的功能opts.extra.tooltip.showCategory默认为false
- uCharts.js 修复mix混合图只有柱状图时tooltip的分割线显示位置不正确的bug
- uCharts.js 修复开启滚动条图表在拖动中动态打点滚动条位置不正确的bug
- uCharts.js 修复饼图类数据格式为echarts数据格式series为空数组报错的bug
- 示例项目 修改uCharts.js更新到v2.1.2版本后,@getIndex方法获取索引值变更为e.currentIndex.index
- 示例项目 pages/updata/updata.vue增加滚动条拖动更新数据动态打点的demo
- 示例项目 pages/other/other.vue增加errorReload禁用错误点击重新加载的demo
## 2.1.2-202105092021-05-09
秋云图表组件 修复APP端初始化时就传入chartData或lacaldata不显示图表的bug
## 2.1.1-202105092021-05-09
- 秋云图表组件 变更ECharts的eopts配置在renderjs内执行支持在config-echarts.js配置文件内写function配置。
- 秋云图表组件 修复APP端报错Prop being mutated: "onmouse"错误的bug。
- 秋云图表组件 修复APP端报错Error: Not FoundPage[6][-1,27] at view.umd.min.js:1的bug。
## 2.1.0-202105072021-05-07
- 秋云图表组件 修复初始化时就有数据或者数据更新的时候loading加载动画闪动的bug
- uCharts.js 修复x轴format方法categories为字符串类型时返回NaN的bug
- uCharts.js 修复series.textColor、legend.fontColor未执行全局默认颜色的bug
## 2.1.0-202105062021-05-06
- 秋云图表组件 修复极个别情况下报错item.properties undefined的bug
- 秋云图表组件 修复极个别情况下关闭加载动画reshow不起作用无法显示图表的bug
- 示例项目 pages/ucharts/ucharts.vue 增加时间轴折线图type="tline"、时间轴区域图type="tarea"、散点图type="scatter"、气泡图demotype="bubble"、倒三角形漏斗图opts.extra.funnel.type="triangle"、金字塔形漏斗图opts.extra.funnel.type="pyramid"
- 示例项目 pages/format-u/format-u.vue 增加X轴format格式化示例
- uCharts.js 升级至v2.1.0版本
- uCharts.js 修复 玫瑰图面积模式点击tooltip位置不正确的bug
- uCharts.js 修复 玫瑰图点击图例只剩一个类别显示空白的bug
- uCharts.js 修复 饼图类图点击图例其他图表tooltip位置某些情况下不准的bug
- uCharts.js 修复 x轴为矢量轴时间轴情况下点击tooltip位置不正确的bug
- uCharts.js 修复 词云图获取点击索引偶尔不准的bug
- uCharts.js 增加 直角坐标系图表X轴format格式化方法原生uCharts.js用法请使用formatter
- uCharts.js 增加 漏斗图扩展配置倒三角形opts.extra.funnel.type="triangle"金字塔形opts.extra.funnel.type="pyramid"
- uCharts.js 增加 散点图opts.type="scatter"、气泡图opts.type="bubble"
- 后期计划 完善散点图、气泡图增加markPoints标记点增加横向条状图。
## 2.0.0-202105022021-05-02
- uCharts.js 修复词云图获取点击索引不正确的bug
## 2.0.0-202105012021-05-01
- 秋云图表组件 修复QQ小程序、百度小程序在关闭动画效果情况下v-for循环使用图表显示不正确的bug
## 2.0.0-202104262021-04-26
- 秋云图表组件 修复QQ小程序不支持canvas2d的bug
- 秋云图表组件 修复钉钉小程序某些情况点击坐标计算错误的bug
- uCharts.js 增加 extra.column.categoryGap 参数柱状图类每个category点位X轴点柱子组之间的间距
- uCharts.js 增加 yAxis.data[i].titleOffsetY 参数,标题纵向偏移距离,负数为向上偏移,正数向下偏移
- uCharts.js 增加 yAxis.data[i].titleOffsetX 参数,标题横向偏移距离,负数为向左偏移,正数向右偏移
- uCharts.js 增加 extra.gauge.labelOffset 参数仪表盘标签文字径向便宜距离默认13px
## 2.0.0-20210422-22021-04-22
秋云图表组件 修复 formatterAssign 未判断 args[key] == null 的情况导致栈溢出的 bug
## 2.0.0-202104222021-04-22
- 秋云图表组件 修复H5、APP、支付宝小程序、微信小程序canvas2d模式下横屏模式的bug
## 2.0.0-202104212021-04-21
- uCharts.js 修复多行图例的情况下图例在上方或者下方时图例float为左侧或者右侧时第二行及以后的图例对齐方式不正确的bug
## 2.0.0-202104202021-04-20
- 秋云图表组件 修复微信小程序开启canvas2d模式后windows版微信小程序不支持canvas2d模式的bug
- 秋云图表组件 修改非uni_modules版本为v2.0版本qiun-data-charts组件
## 2.0.0-202104192021-04-19
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧绿色【使用HBuilderX导入插件】即可使用示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件请重启HBuilderX如仍不好用请重启电脑
## 如果是cli项目请尝试清理node_modules重新install还不行就删除项目再重新install。
## 此问题已于DCloud官方确认HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍右侧蓝色按钮示例项目请看2遍 </font>
## [DEMO演示及在线生成工具v2.0文档https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 修复混合图中柱状图单独设置颜色不生效的bug
- uCharts.js 修复多Y轴单独设置fontSize时开启canvas2d后未对应放大字体的bug
## 2.0.0-202104182021-04-18
- 秋云图表组件 增加directory配置修复H5端history模式下如果发布到二级目录无法正确加载echarts.min.js的bug
## 2.0.0-202104162021-04-16
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧绿色【使用HBuilderX导入插件】即可使用示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件请重启HBuilderX如仍不好用请重启电脑
## 如果是cli项目请尝试清理node_modules重新install还不行就删除项目再重新install。
## 此问题已于DCloud官方确认HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍右侧蓝色按钮示例项目请看2遍 </font>
## [DEMO演示及在线生成工具v2.0文档https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复APP端某些情况下报错`Not Found Page`的bugfix by 高级bug开发技术员
- 示例项目 修复APP端v-for循环某些情况下报错`Not Found Page`的bugfix by 高级bug开发技术员
- uCharts.js 修复非直角坐标系tooltip提示窗右侧超出未变换方向显示的bug
## 2.0.0-202104152021-04-15
- 秋云图表组件 修复H5端发布到二级目录下echarts无法加载的bug
- 秋云图表组件 修复某些情况下echarts.off('finished')移除监听事件报错的bug
## 2.0.0-202104142021-04-14
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧绿色【使用HBuilderX导入插件】即可使用示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件请重启HBuilderX如仍不好用请重启电脑
## 如果是cli项目请尝试清理node_modules重新install还不行就删除项目再重新install。
## 此问题已于DCloud官方确认HBuilderX下个版本会修复。
## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍右侧蓝色按钮示例项目请看2遍 </font>
## [DEMO演示及在线生成工具v2.0文档https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复H5端在cli项目下ECharts引用地址错误的bug
- 示例项目 增加ECharts的formatter用法的示例(详见示例项目format-e.vue)
- uCharts.js 增加圆环图中心背景色的配置extra.ring.centerColor
- uCharts.js 修复微信小程序安卓端柱状图开启透明色后显示不正确的bug
## 2.0.0-202104132021-04-13
- 秋云图表组件 修复百度小程序多个图表真机未能正确获取根元素dom尺寸的bug
- 秋云图表组件 修复百度小程序横屏模式方向不正确的bug
- 秋云图表组件 修改ontouch时@getTouchStart@getTouchMove@getTouchEnd的触发条件
- uCharts.js 修复饼图类数据格式series属性不生效的bug
- uCharts.js 增加时序区域图 详见示例项目中ucharts.vue
## 2.0.0-20210412-22021-04-12
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧绿色【使用HBuilderX导入插件】即可使用示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件请重启HBuilderX。如仍不好用请重启电脑此问题已于DCloud官方确认HBuilderX下个版本会修复。
## [DEMO演示及在线生成工具v2.0文档https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- 秋云图表组件 修复uCharts在APP端横屏模式下不能正确渲染的bug
- 示例项目 增加ECharts柱状图渐变色、圆角柱状图、横向柱状图条状图的示例
## 2.0.0-202104122021-04-12
- 秋云图表组件 修复created中判断echarts导致APP端无法识别改回mounted中判断echarts初始化
- uCharts.js 修复2d模式下series.textOffset未乘像素比的bug
## 2.0.0-202104112021-04-11
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧绿色【使用HBuilderX导入插件】即可使用示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
## 初次使用如果提示未注册<qiun-data-charts>组件请重启HBuilderX并清空小程序开发者工具缓存。
## [DEMO演示及在线生成工具v2.0文档https://demo.ucharts.cn](https://demo.ucharts.cn)
## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 折线图区域图增加connectNulls断点续连的功能详见示例项目中ucharts.vue
- 秋云图表组件 变更初始化方法为created变更type2d默认值为true优化2d模式下组件初始化后dom获取不到的bug
- 秋云图表组件 修复左右布局时右侧图表点击坐标错误的bug修复tooltip柱状图自定义颜色显示object的bug
## 2.0.0-202104102021-04-10
- 修复左右布局时右侧图表点击坐标错误的bug修复柱状图自定义颜色tooltip显示object的bug
- 增加标记线及柱状图自定义颜色的demo
## 2.0.0-202104092021-04-08
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧【使用HBuilderX导入插件】即可体验DEMO演示及在线生成工具v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
## 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
- uCharts.js 修复钉钉小程序百度小程序measureText不准确的bug修复2d模式下饼图类activeRadius为按比例放大的bug
- 修复组件在支付宝小程序端点击位置不准确的bug
## 2.0.0-202104082021-04-07
- 修复组件在支付宝小程序端不能显示的bug目前支付宝小程不能点击交互后续修复
- uCharts.js 修复高分屏下柱状图类,圆弧进度条 自定义宽度不能按比例放大的bug
## 2.0.0-202104072021-04-06
## v1.0版本已停更建议转uni_modules版本组件方式调用点击右侧【使用HBuilderX导入插件】即可体验DEMO演示及在线生成工具v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
## 增加 通过tofix和unit快速格式化y轴的demo add by `howcode`
## 增加 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651)
## 2.0.0-202104062021-04-05
# 秋云图表组件+uCharts v2.0版本同步上线使用方法详见https://demo.ucharts.cn帮助页
## 2.0.02021-04-05
# 秋云图表组件+uCharts v2.0版本同步上线使用方法详见https://demo.ucharts.cn帮助页

File diff suppressed because one or more lines are too long

@ -0,0 +1,162 @@
<template>
<view class="container loading1">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading1',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading1 {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading1 .shape1 {
-webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
animation: animation1shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
@keyframes animation1shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, 16px);
transform: translate(16px, 16px);
}
}
.loading1 .shape2 {
-webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
animation: animation1shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
@keyframes animation1shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, 16px);
transform: translate(-16px, 16px);
}
}
.loading1 .shape3 {
-webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
animation: animation1shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
@keyframes animation1shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(16px, -16px);
transform: translate(16px, -16px);
}
}
.loading1 .shape4 {
-webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
animation: animation1shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
@keyframes animation1shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-16px, -16px);
transform: translate(-16px, -16px);
}
}
</style>

@ -0,0 +1,170 @@
<template>
<view class="container loading2">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading2',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading2 {
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
.container.loading2 .shape {
border-radius: 5px;
}
.container.loading2{
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading2 .shape1 {
-webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
animation: animation2shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
@keyframes animation2shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, 20px);
transform: translate(20px, 20px);
}
}
.loading2 .shape2 {
-webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
animation: animation2shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
@keyframes animation2shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, 20px);
transform: translate(-20px, 20px);
}
}
.loading2 .shape3 {
-webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
animation: animation2shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
@keyframes animation2shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(20px, -20px);
transform: translate(20px, -20px);
}
}
.loading2 .shape4 {
-webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
animation: animation2shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
@keyframes animation2shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-20px, -20px);
transform: translate(-20px, -20px);
}
}
</style>

@ -0,0 +1,173 @@
<template>
<view class="container loading3">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading3',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading3 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading3 .shape1 {
border-top-left-radius: 10px;
}
.container.loading3 .shape2 {
border-top-right-radius: 10px;
}
.container.loading3 .shape3 {
border-bottom-left-radius: 10px;
}
.container.loading3 .shape4 {
border-bottom-right-radius: 10px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading3 .shape1 {
-webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
animation: animation3shape1 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
@keyframes animation3shape1 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, 5px);
transform: translate(5px, 5px);
}
}
.loading3 .shape2 {
-webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
animation: animation3shape2 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
@keyframes animation3shape2 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, 5px);
transform: translate(-5px, 5px);
}
}
.loading3 .shape3 {
-webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
animation: animation3shape3 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
@keyframes animation3shape3 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(5px, -5px);
transform: translate(5px, -5px);
}
}
.loading3 .shape4 {
-webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
animation: animation3shape4 0.5s ease 0s infinite alternate;
}
@-webkit-keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
@keyframes animation3shape4 {
from {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
to {
-webkit-transform: translate(-5px, -5px);
transform: translate(-5px, -5px);
}
}
</style>

@ -0,0 +1,222 @@
<template>
<view class="container loading5">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading5',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading5 .shape {
width: 15px;
height: 15px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading5 .shape1 {
animation: animation5shape1 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
@keyframes animation5shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
50% {
-webkit-transform: translate(15px, 15px);
transform: translate(15px, 15px);
}
75% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
}
.loading5 .shape2 {
animation: animation5shape2 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
@keyframes animation5shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
50% {
-webkit-transform: translate(-15px, 15px);
transform: translate(-15px, 15px);
}
75% {
-webkit-transform: translate(0, 15px);
transform: translate(0, 15px);
}
}
.loading5 .shape3 {
animation: animation5shape3 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
@keyframes animation5shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(15px, 0);
transform: translate(15px, 0);
}
50% {
-webkit-transform: translate(15px, -15px);
transform: translate(15px, -15px);
}
75% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
}
.loading5 .shape4 {
animation: animation5shape4 2s ease 0s infinite reverse;
}
@-webkit-keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
@keyframes animation5shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -15px);
transform: translate(0, -15px);
}
50% {
-webkit-transform: translate(-15px, -15px);
transform: translate(-15px, -15px);
}
75% {
-webkit-transform: translate(-15px, 0);
transform: translate(-15px, 0);
}
}
</style>

@ -0,0 +1,229 @@
<template>
<view class="container loading6">
<view class="shape shape1"></view>
<view class="shape shape2"></view>
<view class="shape shape3"></view>
<view class="shape shape4"></view>
</view>
</template>
<script>
export default {
name: 'loading6',
data() {
return {
};
}
}
</script>
<style scoped="true">
.container {
width: 30px;
height: 30px;
position: relative;
}
.container.loading6 {
-webkit-animation: rotation 1s infinite;
animation: rotation 1s infinite;
}
.container.loading6 .shape {
width: 12px;
height: 12px;
border-radius: 2px;
}
.container .shape {
position: absolute;
width: 10px;
height: 10px;
border-radius: 1px;
}
.container .shape.shape1 {
left: 0;
background-color: #1890FF;
}
.container .shape.shape2 {
right: 0;
background-color: #91CB74;
}
.container .shape.shape3 {
bottom: 0;
background-color: #FAC858;
}
.container .shape.shape4 {
bottom: 0;
right: 0;
background-color: #EE6666;
}
.loading6 .shape1 {
-webkit-animation: animation6shape1 2s linear 0s infinite normal;
animation: animation6shape1 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
@keyframes animation6shape1 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
50% {
-webkit-transform: translate(18px, 18px);
transform: translate(18px, 18px);
}
75% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
}
.loading6 .shape2 {
-webkit-animation: animation6shape2 2s linear 0s infinite normal;
animation: animation6shape2 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
@keyframes animation6shape2 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
50% {
-webkit-transform: translate(-18px, 18px);
transform: translate(-18px, 18px);
}
75% {
-webkit-transform: translate(0, 18px);
transform: translate(0, 18px);
}
}
.loading6 .shape3 {
-webkit-animation: animation6shape3 2s linear 0s infinite normal;
animation: animation6shape3 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
@keyframes animation6shape3 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(18px, 0);
transform: translate(18px, 0);
}
50% {
-webkit-transform: translate(18px, -18px);
transform: translate(18px, -18px);
}
75% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
}
.loading6 .shape4 {
-webkit-animation: animation6shape4 2s linear 0s infinite normal;
animation: animation6shape4 2s linear 0s infinite normal;
}
@-webkit-keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
@keyframes animation6shape4 {
0% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
25% {
-webkit-transform: translate(0, -18px);
transform: translate(0, -18px);
}
50% {
-webkit-transform: translate(-18px, -18px);
transform: translate(-18px, -18px);
}
75% {
-webkit-transform: translate(-18px, 0);
transform: translate(-18px, 0);
}
}
</style>

@ -0,0 +1,36 @@
<template>
<view>
<Loading1 v-if="loadingType==1"/>
<Loading2 v-if="loadingType==2"/>
<Loading3 v-if="loadingType==3"/>
<Loading4 v-if="loadingType==4"/>
<Loading5 v-if="loadingType==5"/>
</view>
</template>
<script>
import Loading1 from "./loading1.vue";
import Loading2 from "./loading2.vue";
import Loading3 from "./loading3.vue";
import Loading4 from "./loading4.vue";
import Loading5 from "./loading5.vue";
export default {
components:{Loading1,Loading2,Loading3,Loading4,Loading5},
name: 'qiun-loading',
props: {
loadingType: {
type: Number,
default: 2
},
},
data() {
return {
};
},
}
</script>
<style>
</style>

@ -0,0 +1,422 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 通用配置项
// 主题颜色配置如每个图表类型需要不同主题请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
const cfe = {
//demotype为自定义图表类型
"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
//增加自定义图表类型如果需要categories请在这里加入您的图表类型例如最后的"demotype"
"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
//instance为实例变量承载属性option为eopts承载属性不要删除
"instance": {},
"option": {},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter":{
"tooltipDemo1":function(res){
let result = ''
for (let i in res) {
if (i == 0) {
result += res[i].axisValueLabel + '年销售额'
}
let value = '--'
if (res[i].data !== null) {
value = res[i].data
}
// #ifdef H5
result += '\n' + res[i].seriesName + '' + value + ' 万元'
// #endif
// #ifdef APP-PLUS
result += '<br/>' + res[i].marker + res[i].seriesName + '' + value + ' 万元'
// #endif
}
return result;
},
legendFormat:function(name){
return "自定义图例+"+name;
},
yAxisFormatDemo:function (value, index) {
return value + '元';
},
seriesFormatDemo:function(res){
return res.name + '年' + res.value + '元';
}
},
//这里演示了自定义您的图表类型的option可以随意命名之后在组件上 type="demotype" 后组件会调用这个花括号里的option如果组件上还存在eopts参数会将demotype与eopts中option合并后渲染图表。
"demotype":{
"color": color,
//在这里填写echarts的option即可
},
//下面是自定义配置,请添加项目所需的通用配置
"column": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'bar',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"line": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"barwidth": 20,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"area": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'axis'
},
"grid": {
"top": 30,
"bottom": 50,
"right": 15,
"left": 40
},
"legend": {
"bottom": 'left',
},
"toolbox": {
"show": false,
},
"xAxis": {
"type": 'category',
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
"boundaryGap": true,
"data": []
},
"yAxis": {
"type": 'value',
"axisTick": {
"show": false,
},
"axisLabel": {
"color": '#666666'
},
"axisLine": {
"lineStyle": {
"color": '#CCCCCC'
}
},
},
"seriesTemplate": {
"name": '',
"type": 'line',
"data": [],
"areaStyle": {},
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"pie": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": '50%',
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
},
},
"ring": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"grid": {
"top": 40,
"bottom": 30,
"right": 15,
"left": 15
},
"legend": {
"bottom": 'left',
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": ['40%', '70%'],
"avoidLabelOverlap": false,
"label": {
"show": true,
"color": "#666666",
"position": 'top',
},
"labelLine": {
"show": true
},
},
},
"rose": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item'
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'pie',
"data": [],
"radius": "55%",
"center": ['50%', '50%'],
"roseType": 'area',
},
},
"funnel": {
"color": color,
"title": {
"text": ''
},
"tooltip": {
"trigger": 'item',
"formatter": "{b} : {c}%"
},
"legend": {
"top": 'bottom'
},
"seriesTemplate": {
"name": '',
"type": 'funnel',
"left": '10%',
"top": 60,
"bottom": 60,
"width": '80%',
"min": 0,
"max": 100,
"minSize": '0%',
"maxSize": '100%',
"sort": 'descending',
"gap": 2,
"label": {
"show": true,
"position": 'inside'
},
"labelLine": {
"length": 10,
"lineStyle": {
"width": 1,
"type": 'solid'
}
},
"itemStyle": {
"bordercolor": '#fff',
"borderwidth": 1
},
"emphasis": {
"label": {
"fontSize": 20
}
},
"data": [],
},
},
"gauge": {
"color": color,
"tooltip": {
"formatter": '{a} <br/>{b} : {c}%'
},
"seriesTemplate": {
"name": '业务指标',
"type": 'gauge',
"detail": {"formatter": '{value}%'},
"data": [{"value": 50, "name": '完成率'}]
},
},
"candle": {
"xAxis": {
"data": []
},
"yAxis": {},
"color": color,
"title": {
"text": ''
},
"dataZoom": [{
"type": 'inside',
"xAxisIndex": [0, 1],
"start": 10,
"end": 100
},
{
"show": true,
"xAxisIndex": [0, 1],
"type": 'slider',
"bottom": 10,
"start": 10,
"end": 100
}
],
"seriesTemplate": {
"name": '',
"type": 'k',
"data": [],
},
}
}
export default cfe;

@ -0,0 +1,606 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 主题颜色配置如每个图表类型需要不同主题请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
//事件转换函数主要用作格式化x轴为时间轴根据需求自行修改
const formatDateTime = (timeStamp, returnType)=>{
var date = new Date();
date.setTime(timeStamp * 1000);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if(returnType == 'full'){return y + '-' + m + '-' + d + ' '+ h +':' + minute + ':' + second;}
if(returnType == 'y-m-d'){return y + '-' + m + '-' + d;}
if(returnType == 'h:m'){return h +':' + minute;}
if(returnType == 'h:m:s'){return h +':' + minute +':' + second;}
return [y, m, d, h, minute, second];
}
const cfu = {
//demotype为自定义图表类型一般不需要自定义图表类型只需要改根节点上对应的类型即可
"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","mount","bar","area","radar","gauge","candle","mix","tline","tarea","scatter","bubble","demotype"],
"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","山峰图","条状图","区域图","雷达图","仪表盘","K线图","混合图","时间轴折线","时间轴区域","散点图","气泡图","自定义类型"],
//增加自定义图表类型如果需要categories请在这里加入您的图表类型例如最后的"demotype"
//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴矢量x轴类图表没有categories不需要加入categories
"categories":["line","column","mount","bar","area","radar","gauge","candle","mix","demotype"],
//instance为实例变量承载属性不要删除
"instance":{},
//option为opts及eopts承载属性不要删除
"option":{},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter":{
"yAxisDemo1":function(val, index, opts){return val+'元'},
"yAxisDemo2":function(val, index, opts){return val.toFixed(2)},
"xAxisDemo1":function(val, index, opts){return val+'年';},
"xAxisDemo2":function(val, index, opts){return formatDateTime(val,'h:m')},
"seriesDemo1":function(val, index, series, opts){return val+'元'},
"tooltipDemo1":function(item, category, index, opts){
if(index==0){
return '随便用'+item.data+'年'
}else{
return '其他我没改'+item.data+'天'
}
},
"pieDemo":function(val, index, series, opts){
if(index !== undefined){
return series[index].name+''+series[index].data+'元'
}
},
},
//这里演示了自定义您的图表类型的option可以随意命名之后在组件上 type="demotype" 后组件会调用这个花括号里的option如果组件上还存在opts参数会将demotype与opts中option合并后渲染图表。
"demotype":{
//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2
},
}
},
//下面是自定义配置,请添加项目所需的通用配置
"pie":{
"type": "pie",
"color": color,
"padding": [5,5,5,5],
"extra": {
"pie": {
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
}
},
"ring":{
"type": "ring",
"color": color,
"padding": [5,5,5,5],
"rotate": false,
"dataLabel": true,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"title": {
"name": "收益率",
"fontSize": 15,
"color": "#666666"
},
"subtitle": {
"name": "70%",
"fontSize": 25,
"color": "#7cb5ec"
},
"extra": {
"ring": {
"ringWidth":30,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
},
},
"rose":{
"type": "rose",
"color": color,
"padding": [5,5,5,5],
"legend": {
"show": true,
"position": "left",
"lineHeight": 25,
},
"extra": {
"rose": {
"type": "area",
"minRadius": 50,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": false,
"borderWidth": 2,
"borderColor": "#FFFFFF"
},
}
},
"word":{
"type": "word",
"color": color,
"extra": {
"word": {
"type": "normal",
"autoColors": false
}
}
},
"funnel":{
"type": "funnel",
"color": color,
"padding": [15,15,0,15],
"extra": {
"funnel": {
"activeOpacity": 0.3,
"activeWidth": 10,
"border": true,
"borderWidth": 2,
"borderColor": "#FFFFFF",
"fillOpacity": 1,
"labelAlign": "right"
},
}
},
"map":{
"type": "map",
"color": color,
"padding": [0,0,0,0],
"dataLabel": true,
"extra": {
"map": {
"border": true,
"borderWidth": 1,
"borderColor": "#666666",
"fillOpacity": 0.6,
"activeBorderColor": "#F04864",
"activeFillColor": "#FACC14",
"activeFillOpacity": 1
},
}
},
"arcbar":{
"type": "arcbar",
"color": color,
"title": {
"name": "百分比",
"fontSize": 25,
"color": "#00FF00"
},
"subtitle": {
"name": "默认标题",
"fontSize": 15,
"color": "#666666"
},
"extra": {
"arcbar": {
"type": "default",
"width": 12,
"backgroundColor": "#E9E9E9",
"startAngle": 0.75,
"endAngle": 0.25,
"gap": 2
}
}
},
"line":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"line": {
"type": "straight",
"width": 2,
"activeType": "hollow"
},
}
},
"tline":{
"type": "line",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": false,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"line": {
"type": "curve",
"width": 2,
"activeType": "hollow"
},
}
},
"tarea":{
"type": "area",
"color": color,
"padding": [15,10,0,15],
"xAxis": {
"disableGrid": true,
"boundaryGap":"justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data":[
{
"min":0,
"max":80
}
]
},
"legend": {
},
"extra": {
"area": {
"type": "curve",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": true,
"activeType": "hollow"
},
}
},
"column":{
"type": "column",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"column": {
"type": "group",
"width": 30,
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"mount":{
"type": "mount",
"color": color,
"padding": [15,15,0,5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"data":[{"min":0}]
},
"legend": {
},
"extra": {
"mount": {
"type": "mount",
"widthRatio": 1.5,
},
}
},
"bar":{
"type": "bar",
"color": color,
"padding": [15,30,0,5],
"xAxis": {
"boundaryGap":"justify",
"disableGrid":false,
"min":0,
"axisLine":false
},
"yAxis": {
},
"legend": {
},
"extra": {
"bar": {
"type": "group",
"width": 30,
"meterBorde": 1,
"meterFillColor": "#FFFFFF",
"activeBgColor": "#000000",
"activeBgOpacity": 0.08
},
}
},
"area":{
"type": "area",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {
},
"extra": {
"area": {
"type": "straight",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": false,
"activeType": "hollow"
},
}
},
"radar":{
"type": "radar",
"color": color,
"padding": [5,5,5,5],
"dataLabel": false,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"extra": {
"radar": {
"gridType": "radar",
"gridColor": "#CCCCCC",
"gridCount": 3,
"opacity": 0.2,
"max": 200,
"labelShow": true
},
}
},
"gauge":{
"type": "gauge",
"color": color,
"title": {
"name": "66Km/H",
"fontSize": 25,
"color": "#2fc25b",
"offsetY": 50
},
"subtitle": {
"name": "实时速度",
"fontSize": 15,
"color": "#1890ff",
"offsetY": -50
},
"extra": {
"gauge": {
"type": "default",
"width": 30,
"labelColor": "#666666",
"startAngle": 0.75,
"endAngle": 0.25,
"startNumber": 0,
"endNumber": 100,
"labelFormat": "",
"splitLine": {
"fixRadius": 0,
"splitNumber": 10,
"width": 30,
"color": "#FFFFFF",
"childNumber": 5,
"childWidth": 12
},
"pointer": {
"width": 24,
"color": "auto"
}
}
}
},
"candle":{
"type": "candle",
"color": color,
"padding": [15,15,0,15],
"enableScroll": true,
"enableMarkLine": true,
"dataLabel": false,
"xAxis": {
"labelCount": 4,
"itemCount": 40,
"disableGrid": true,
"gridColor": "#CCCCCC",
"gridType": "solid",
"dashLength": 4,
"scrollShow": true,
"scrollAlign": "left",
"scrollColor": "#A6A6A6",
"scrollBackgroundColor": "#EFEBEF"
},
"yAxis": {
},
"legend": {
},
"extra": {
"candle": {
"color": {
"upLine": "#f04864",
"upFill": "#f04864",
"downLine": "#2fc25b",
"downFill": "#2fc25b"
},
"average": {
"show": true,
"name": ["MA5","MA10","MA30"],
"day": [5,10,20],
"color": ["#1890ff","#2fc25b","#facc14"]
}
},
"markLine": {
"type": "dash",
"dashLength": 5,
"data": [
{
"value": 2150,
"lineColor": "#f04864",
"showLabel": true
},
{
"value": 2350,
"lineColor": "#f04864",
"showLabel": true
}
]
}
}
},
"mix":{
"type": "mix",
"color": color,
"padding": [15,15,0,15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"disabled": false,
"disableGrid": false,
"splitNumber": 5,
"gridType": "dash",
"dashLength": 4,
"gridColor": "#CCCCCC",
"padding": 10,
"showTitle": true,
"data": []
},
"legend": {
},
"extra": {
"mix": {
"column": {
"width": 20
}
},
}
},
"scatter":{
"type": "scatter",
"color":color,
"padding":[15,15,0,15],
"dataLabel":false,
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
},
"legend": {
},
"extra": {
"scatter": {
},
}
},
"bubble":{
"type": "bubble",
"color":color,
"padding":[15,15,0,15],
"xAxis": {
"disableGrid": false,
"gridType":"dash",
"splitNumber":5,
"boundaryGap":"justify",
"min":0,
"max":250
},
"yAxis": {
"disableGrid": false,
"gridType":"dash",
"data":[{
"min":0,
"max":150
}]
},
"legend": {
},
"extra": {
"bubble": {
"border":2,
"opacity": 0.5,
},
}
}
}
export default cfu;

@ -0,0 +1,5 @@
# uCharts JSSDK说明
1、如不使用uCharts组件可直接引用u-charts.js打包编译后会`自动压缩`,压缩后体积约为`120kb`。
2、如果120kb的体积仍需压缩请手到uCharts官网通过在线定制选择您需要的图表。
3、config-ucharts.js为uCharts组件的用户配置文件升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
4、config-echarts.js为ECharts组件的用户配置文件升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,80 @@
{
"id": "qiun-data-charts",
"displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
"version": "2.5.0-20230101",
"description": "uCharts 新增正负柱状图支持H5及APP用 ucharts echarts 渲染图表uniapp可视化首选组件",
"keywords": [
"ucharts",
"echarts",
"f2",
"图表",
"可视化"
],
"repository": "https://gitee.com/uCharts/uCharts",
"engines": {
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": "474119"
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/~qiun",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"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"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,84 @@
![logo](https://img-blog.csdnimg.cn/4a276226973841468c1be356f8d9438b.png)
[![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
[![fork](https://gitee.com/uCharts/uCharts/badge/fork.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/members)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![npm package](https://img.shields.io/npm/v/@qiun/ucharts.svg?style=flat-square)](https://www.npmjs.com/~qiun)
## uCharts简介
`uCharts`是一款基于`canvas API`开发的适用于所有前端应用的图表库,开发者编写一套代码,可运行到 Web、iOS、Android基于 uni-app / taro )、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等更多支持 canvas API 的平台。
## 官方网站
## [https://www.ucharts.cn](https://www.ucharts.cn)
## 快速体验
一套代码编到多个平台依次扫描二维码亲自体验uCharts图表跨平台效果其他平台请自行编译。
![](https://www.ucharts.cn/images/web/guide/qrcode20220224.png)
![](https://img-blog.csdnimg.cn/7d0115593ff24ac39a224fb7c6ed72a4.png)
## 致开发者
感谢各位开发者`五年`来对秋云及uCharts的支持uCharts的进步离不开各位开发者的鼓励与贡献。为更好的帮助各位开发者使用图表工具我们推出了新版官网增加了在线定制、问答社区、在线配置等一些增值服务为确保您能更好的应用图表组件建议您先`仔细阅读官网指南`以及`常见问题`,而不是下载下来`直接使用`。如仍然不能解决,请到`官网社区`或开通会员后加入`专属VIP会员群`提问将会很快得到回答。
## 视频教程
## [uCharts新手入门教程](https://www.bilibili.com/video/BV1qA411Q7se/?share_source=copy_web&vd_source=42a1242f9aaade6427736af69eb2e1d9)
## 社群支持
uCharts官方拥有5个2000人的QQ群及专属VIP会员群支持庞大的用户量证明我们一直在努力请各位放心使用uCharts的开源图表组件的开发团队付出了大量的时间与精力经过四来的考验不会有比较明显的bug请各位放心使用。如果您有更好的想法可以在`码云提交Pull Requests`以帮助更多开发者完成需求再次感谢各位对uCharts的鼓励与支持
#### 官方交流群
- 交流群1371774600已满
- 交流群2619841586已满
- 交流群3955340127已满
- 交流群4641669795已满
- 交流群5236294809只能扫码加入
![](https://www.ucharts.cn/images/web/qq5.jpg)
- 口令`uniapp`
#### 专属VIP会员群
- 开通会员后详见【账号详情】页面中顶部的滚动通知
- 口令`您的用户ID`
## 版权信息
uCharts始终坚持开源遵循 [Apache Licence 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) 开源协议意味着您无需支付任何费用即可将uCharts应用到您的产品中。
注意这并不意味着您可以将uCharts应用到非法的领域比如涉及赌博暴力等方面。如因此产生纠纷或法律问题uCharts相关方及秋云科技不承担任何责任。
## 合作伙伴
[![DIY官网](https://www.ucharts.cn/images/web/guide/links/diy-gw.png)](https://www.diygw.com/)
[![HasChat](https://www.ucharts.cn/images/web/guide/links/haschat.png)](https://gitee.com/howcode/has-chat)
[![uViewUI](https://www.ucharts.cn/images/web/guide/links/uView.png)](https://www.uviewui.com/)
[![图鸟UI](https://www.ucharts.cn/images/web/guide/links/tuniao.png)](https://ext.dcloud.net.cn/plugin?id=7088)
[![thorui](https://www.ucharts.cn/images/web/guide/links/thorui.png)](https://ext.dcloud.net.cn/publisher?id=202)
[![FirstUI](https://www.ucharts.cn/images/web/guide/links/first.png)](https://www.firstui.cn/)
[![nProUI](https://www.ucharts.cn/images/web/guide/links/nPro.png)](https://ext.dcloud.net.cn/plugin?id=5169)
[![GraceUI](https://www.ucharts.cn/images/web/guide/links/grace.png)](https://www.graceui.com/)
## 更新记录
详见官网指南中说明,[点击此处查看](https://www.ucharts.cn/v2/#/guide/index?id=100)
## 相关链接
- [uCharts官网](https://www.ucharts.cn)
- [DCloud插件市场地址](https://ext.dcloud.net.cn/plugin?id=271)
- [uCharts码云开源托管地址](https://gitee.com/uCharts/uCharts) [![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
- [uCharts npm开源地址](https://www.ucharts.cn)
- [ECharts官网](https://echarts.apache.org/zh/index.html)
- [ECharts配置手册](https://echarts.apache.org/zh/option.html)
- [图表组件在项目中的应用 ReportPlus数据报表](https://www.ucharts.cn/v2/#/layout/info?id=1)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,16 +1,25 @@
## 0.2.32023-12-27 ## 0.2.52023-12-28
## 0.2版本正式发布支持Form自定义表单校验 ## [0.2.5](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.4...v0.2.5) (2023-12-28)
> 请注意Input组件有破坏性更新
### [0.2.3](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.2...v0.2.3) (2023-12-27)
### ✏️ Documentation | 文档 ### Bug Fixes | Bug 修复
* ✏️ 修复动态表单演示页面标题错误的问题 ([7c65359](https://github.com/Moonofweisheng/wot-design-uni/commit/7c65359c88614ae53c4800d0946d8e09ef547a26)) * 修复 Form 导入FormRules、ErrorMessage时未指定为type的问题 ([c88c84e](https://github.com/Moonofweisheng/wot-design-uni/commit/c88c84e8b71fc2404643a623c28f4953ffe36e71))
* 修复 SwipeAction 组件在H5端导致页面无法上下滚动的问题 ([1f68ce1](https://github.com/Moonofweisheng/wot-design-uni/commit/1f68ce13c8109dd92ca4bf055f66aa8dff24c83d)), closes [#149](https://github.com/Moonofweisheng/wot-design-uni/issues/149)
# 更新日志 # 更新日志
### [0.2.5](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.4...v0.2.5) (2023-12-28)
### 🐛 Bug Fixes | Bug 修复
* 🐛 修复 Form 导入FormRules、ErrorMessage时未指定为type的问题 ([c88c84e](https://github.com/Moonofweisheng/wot-design-uni/commit/c88c84e8b71fc2404643a623c28f4953ffe36e71))
* 🐛 修复 SwipeAction 组件在H5端导致页面无法上下滚动的问题 ([1f68ce1](https://github.com/Moonofweisheng/wot-design-uni/commit/1f68ce13c8109dd92ca4bf055f66aa8dff24c83d)), closes [#149](https://github.com/Moonofweisheng/wot-design-uni/issues/149)
### [0.2.4](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.3...v0.2.4) (2023-12-27)
### [0.2.3](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.2...v0.2.3) (2023-12-27) ### [0.2.3](https://github.com/Moonofweisheng/wot-design-uni/compare/v0.2.2...v0.2.3) (2023-12-27)

@ -1,4 +1,4 @@
import { getCurrentInstance, inject, onMounted, onBeforeMount, ref, watch } from 'vue' import { getCurrentInstance, inject, onBeforeMount, ref, watch } from 'vue'
export function useCell() { export function useCell() {
const border = ref<boolean>(false) // 是否展示边框 const border = ref<boolean>(false) // 是否展示边框

@ -1,12 +1,12 @@
import { import {
VNode,
provide, provide,
reactive, reactive,
InjectionKey,
getCurrentInstance, getCurrentInstance,
VNodeNormalizedChildren, type VNode,
ComponentPublicInstance, type InjectionKey,
ComponentInternalInstance type VNodeNormalizedChildren,
type ComponentPublicInstance,
type ComponentInternalInstance
} from 'vue' } from 'vue'
// 小程序端不支持从vue导出的isVNode方法参考uni-mp-vue的实现 // 小程序端不支持从vue导出的isVNode方法参考uni-mp-vue的实现

@ -1,4 +1,13 @@
import { ref, inject, computed, onUnmounted, InjectionKey, getCurrentInstance, ComponentPublicInstance, ComponentInternalInstance } from 'vue' import {
ref,
inject,
computed,
onUnmounted,
type InjectionKey,
getCurrentInstance,
type ComponentPublicInstance,
type ComponentInternalInstance
} from 'vue'
type ParentProvide<T> = T & { type ParentProvide<T> = T & {
link(child: ComponentInternalInstance): void link(child: ComponentInternalInstance): void

@ -117,7 +117,7 @@ import { dayjs } from '../common/dayjs'
import { deepClone, isArray, isEqual, padZero } from '../common/util' import { deepClone, isArray, isEqual, padZero } from '../common/util'
import { getWeekNumber, isRange } from '../wd-calendar-view/utils' import { getWeekNumber, isRange } from '../wd-calendar-view/utils'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
const defaultDisplayFormat = (value, type) => { const defaultDisplayFormat = (value, type) => {

@ -60,7 +60,7 @@ export default {
import { computed } from 'vue' import { computed } from 'vue'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
interface Props { interface Props {
title?: string title?: string

@ -97,7 +97,7 @@ export default {
import { computed, getCurrentInstance, onMounted, ref, watch } from 'vue' import { computed, getCurrentInstance, onMounted, ref, watch } from 'vue'
import { debounce, getRect, getType } from '../common/util' import { debounce, getRect, getType } from '../common/util'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
const $container = '.wd-col-picker__selected-container' const $container = '.wd-col-picker__selected-container'

@ -144,7 +144,7 @@ import { computed, getCurrentInstance, nextTick, onBeforeMount, onMounted, ref,
import { deepClone, getType, isArray, isDef, isEqual, padZero } from '../common/util' import { deepClone, getType, isArray, isDef, isEqual, padZero } from '../common/util'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { type DateTimeType, getPickerValue } from '../wd-datetime-picker-view/type' import { type DateTimeType, getPickerValue } from '../wd-datetime-picker-view/type'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
interface Props { interface Props {
customClass?: string customClass?: string

@ -36,7 +36,7 @@ export default {
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
import WdCell from '../wd-cell/wd-cell.vue' import WdCell from '../wd-cell/wd-cell.vue'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
interface Props { interface Props {
prop: string prop: string

@ -19,7 +19,7 @@ export default {
import { reactive, watch } from 'vue' import { reactive, watch } from 'vue'
import { deepClone, getPropByPath, isDef, isPromise } from '../common/util' import { deepClone, getPropByPath, isDef, isPromise } from '../common/util'
import { useChildren } from '../composables/useChildren' import { useChildren } from '../composables/useChildren'
import { FormRules, FORM_KEY, ErrorMessage, FormItemRule } from './types' import { type FormRules, FORM_KEY, type ErrorMessage } from './types'
interface Props { interface Props {
// //

@ -88,7 +88,7 @@ export default {
import { computed, onBeforeMount, ref, watch } from 'vue' import { computed, onBeforeMount, ref, watch } from 'vue'
import { objToStyle, requestAnimationFrame } from '../common/util' import { objToStyle, requestAnimationFrame } from '../common/util'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
interface Props { interface Props {

@ -1,24 +1,20 @@
<template> <template>
<view <view :class="`wd-picker ${disabled ? 'is-disabled' : ''} ${size ? 'is-' + size : ''} ${cell.border.value ? 'is-border' : ''} ${alignRight ? 'is-align-right' : ''
:class="`wd-picker ${disabled ? 'is-disabled' : ''} ${size ? 'is-' + size : ''} ${cell.border.value ? 'is-border' : ''} ${ } ${error ? 'is-error' : ''} ${customClass}`">
alignRight ? 'is-align-right' : ''
} ${error ? 'is-error' : ''} ${customClass}`"
>
<!--文案--> <!--文案-->
<view class="wd-picker__field" @click="showPopup"> <view class="wd-picker__field" @click="showPopup">
<slot v-if="useDefaultSlot"></slot> <slot v-if="useDefaultSlot"></slot>
<view v-else class="wd-picker__cell"> <view v-else class="wd-picker__cell">
<view <view v-if="label || useLabelSlot"
v-if="label || useLabelSlot"
:class="`wd-picker__label ${customLabelClass} ${isRequired ? 'is-required' : ''}`" :class="`wd-picker__label ${customLabelClass} ${isRequired ? 'is-required' : ''}`"
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''" :style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''">
>
<template v-if="label">{{ label }}</template> <template v-if="label">{{ label }}</template>
<slot v-else name="label"></slot> <slot v-else name="label"></slot>
</view> </view>
<view class="wd-picker__body"> <view class="wd-picker__body">
<view class="wd-picker__value-wraper"> <view class="wd-picker__value-wraper">
<view :class="`wd-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${showValue ? '' : 'wd-picker__placeholder'}`"> <view
:class="`wd-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${showValue ? '' : 'wd-picker__placeholder'}`">
{{ showValue ? showValue : placeholder }} {{ showValue ? showValue : placeholder }}
</view> </view>
<wd-icon v-if="!disabled && !readonly" custom-class="wd-picker__arrow" name="arrow-right" /> <wd-icon v-if="!disabled && !readonly" custom-class="wd-picker__arrow" name="arrow-right" />
@ -28,16 +24,8 @@
</view> </view>
</view> </view>
<!--弹出层picker-view 在隐藏时修改值会触发多次change事件从而导致所有列选中第一项因此picker在关闭时不隐藏 --> <!--弹出层picker-view 在隐藏时修改值会触发多次change事件从而导致所有列选中第一项因此picker在关闭时不隐藏 -->
<wd-popup <wd-popup v-model="popupShow" position="bottom" :hide-when-close="false" :close-on-click-modal="closeOnClickModal"
v-model="popupShow" :z-index="zIndex" :safe-area-inset-bottom="safeAreaInsetBottom" @close="onCancel" custom-class="wd-picker__popup">
position="bottom"
:hide-when-close="false"
:close-on-click-modal="closeOnClickModal"
:z-index="zIndex"
:safe-area-inset-bottom="safeAreaInsetBottom"
@close="onCancel"
custom-class="wd-picker__popup"
>
<view class="wd-picker__wraper"> <view class="wd-picker__wraper">
<!--toolBar--> <!--toolBar-->
<view class="wd-picker__toolbar" @touchmove="noop"> <view class="wd-picker__toolbar" @touchmove="noop">
@ -53,21 +41,10 @@
</view> </view>
</view> </view>
<!--pickerView--> <!--pickerView-->
<wd-picker-view <wd-picker-view ref="pickerViewWd" :custom-class="customViewClass" v-model="pickerValue" :columns="displayColumns"
ref="pickerViewWd" :loading="isLoading" :loading-color="loadingColor" :columns-height="columnsHeight" :value-key="valueKey"
:custom-class="customViewClass" :label-key="labelKey" @change="pickerViewChange" @pickstart="onPickStart" @pickend="onPickEnd"
v-model="pickerValue" :column-change="columnChange" />
:columns="displayColumns"
:loading="isLoading"
:loading-color="loadingColor"
:columns-height="columnsHeight"
:value-key="valueKey"
:label-key="labelKey"
@change="pickerViewChange"
@pickstart="onPickStart"
@pickend="onPickEnd"
:column-change="columnChange"
/>
</view> </view>
</wd-popup> </wd-popup>
</view> </view>
@ -89,7 +66,7 @@ import { getCurrentInstance, onBeforeMount, ref, watch, computed, onMounted, nex
import { deepClone, defaultDisplayFormat, getType, isDef } from '../common/util' import { deepClone, defaultDisplayFormat, getType, isDef } from '../common/util'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { type ColumnItem, formatArray } from '../wd-picker-view/type' import { type ColumnItem, formatArray } from '../wd-picker-view/type'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
interface Props { interface Props {
@ -229,6 +206,7 @@ watch(
(newValue) => { (newValue) => {
pickerValue.value = newValue pickerValue.value = newValue
// , // ,
if (isDef(newValue)) { if (isDef(newValue)) {
if (pickerViewWd.value && pickerViewWd.value.getSelects) { if (pickerViewWd.value && pickerViewWd.value.getSelects) {
nextTick(() => { nextTick(() => {

@ -112,7 +112,7 @@ import { getCurrentInstance, onBeforeMount, ref, watch, nextTick, computed } fro
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { getRect, getType, isArray, isDef, requestAnimationFrame } from '../common/util' import { getRect, getType, isArray, isDef, requestAnimationFrame } from '../common/util'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
type SelectPickerType = 'checkbox' | 'radio' type SelectPickerType = 'checkbox' | 'radio'

@ -3,9 +3,8 @@
<view <view
:class="`wd-swipe-action ${customClass}`" :class="`wd-swipe-action ${customClass}`"
@click.stop="onClick()" @click.stop="onClick()"
@touchmove="stopPropagation ? nothing : ''"
@touchstart="startDrag" @touchstart="startDrag"
@touchmove.prevent="onDrag" @touchmove="onDrag"
@touchend="endDrag" @touchend="endDrag"
@touchcancel="endDrag" @touchcancel="endDrag"
> >
@ -58,7 +57,6 @@ const props = withDefaults(defineProps<Props>(), {
const queue = inject<Queue | null>(queueKey, null) const queue = inject<Queue | null>(queueKey, null)
const wrapperStyle = ref<string>('') const wrapperStyle = ref<string>('')
const stopPropagation = ref<boolean>(false)
// wrapper // wrapper
const originOffset = ref<number>(0) const originOffset = ref<number>(0)
@ -131,8 +129,7 @@ function changeState(value: string, old?: string) {
} }
}) })
} }
/** 防穿透函数的占位符 **/
function nothing() {}
/** /**
* @description 获取左/右操作按钮的宽度 * @description 获取左/右操作按钮的宽度
* @return {Promise<[Number, Number]>} 左宽度右宽度 * @return {Promise<[Number, Number]>} 左宽度右宽度
@ -202,12 +199,11 @@ function onDrag(event) {
if (props.disabled) return if (props.disabled) return
touch.touchMove(event) touch.touchMove(event)
if (touch.direction.value === 'vertical') { if (touch.direction.value === 'vertical') {
stopPropagation.value = false
return return
} else { } else {
stopPropagation.value = true event.preventDefault()
event.stopPropagation()
} }
touching.value = true touching.value = true
@ -238,7 +234,6 @@ function endDrag() {
if (props.disabled) return if (props.disabled) return
// "" // ""
const THRESHOLD = 0.3 const THRESHOLD = 0.3
stopPropagation.value = false
touching.value = false touching.value = false
getWidths().then(([leftWidth, rightWidth]) => { getWidths().then(([leftWidth, rightWidth]) => {

@ -78,7 +78,7 @@ export default {
import { computed, onBeforeMount, ref, watch } from 'vue' import { computed, onBeforeMount, ref, watch } from 'vue'
import { objToStyle, requestAnimationFrame } from '../common/util' import { objToStyle, requestAnimationFrame } from '../common/util'
import { useCell } from '../composables/useCell' import { useCell } from '../composables/useCell'
import { FORM_KEY, FormItemRule } from '../wd-form/types' import { FORM_KEY, type FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent' import { useParent } from '../composables/useParent'
type ConfirmType = 'send' | 'search' | 'next' | 'go' | 'done' type ConfirmType = 'send' | 'search' | 'next' | 'go' | 'done'

@ -491,7 +491,6 @@ async function drawImageOffScreen(
img.crossOrigin = 'anonymous' img.crossOrigin = 'anonymous'
img.referrerPolicy = 'no-referrer' img.referrerPolicy = 'no-referrer'
img.referrerPolicy = 'no-referrer'
if (isBase64Image(image)) { if (isBase64Image(image)) {
img.src = image img.src = image
} else { } else {

@ -2,7 +2,7 @@
"id": "wot-design-uni", "id": "wot-design-uni",
"name": "wot-design-uni", "name": "wot-design-uni",
"displayName": "wot-design-uni 基于vue3+Typescript的高颜值组件库", "displayName": "wot-design-uni 基于vue3+Typescript的高颜值组件库",
"version": "0.2.3", "version": "0.2.5",
"description": "一个基于Vue3+TS开发的uni-app组件库提供60+高质量组件,支持暗黑模式和自定义主题。", "description": "一个基于Vue3+TS开发的uni-app组件库提供60+高质量组件,支持暗黑模式和自定义主题。",
"keywords": [ "keywords": [
"wot-design-uni", "wot-design-uni",

@ -4,11 +4,8 @@ import {
} from "./app"; } from "./app";
import utils from "./utils"; import utils from "./utils";
let extConfig = {};
const env = { const env = {
..._env, ..._env,
...extConfig
} }
/** /**
@ -21,18 +18,14 @@ export function request(options) {
Authorization: `Bearer ${uni.getStorageSync("token")}`, Authorization: `Bearer ${uni.getStorageSync("token")}`,
} }
if (options.externalRequest) {
} else {
options.noclient ? (options.url = env.host + options.url) : (options.url = env.host + "" + options.url); options.noclient ? (options.url = env.host + options.url) : (options.url = env.host + "" + options.url);
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.request({ uni.request({
url: options.url, url: options.url,
timeout: env.NETWORK_TIME_OUT, timeout: env.NETWORK_TIME_OUT,
// data: { ...options.data, store_id: env.store_id, mini_id: env.mini_id, origin: getOrigin() }, // data: { ...options.data, store_id: env.store_id, mini_id: env.mini_id, origin: getOrigin() },
data: { ...options.data, ...env, origin: getOrigin() }, data: { ...options.data, ...env, },
header: options.header, header: options.header,
method: options.method, method: options.method,
success: (res) => { success: (res) => {
@ -53,20 +46,19 @@ export function request(options) {
default: default:
console.log("请求失败(" + statusCode + ")") console.log("请求失败(" + statusCode + ")")
reject(res) reject(res)
uni.$u.toast(res?.data?.message || "出错了"); uni.showToast({
title: `请求服务器无响应!`,
icon: 'none'
})
break; break;
} }
}, },
fail: (res) => { fail: (res) => {
console.log(res, 'reslogin') uni.showToast({
// #ifdef MP-ALIPAY title: `请求服务器无响应!`,
if (res.statusCode == 401) { icon: 'none'
setTimeout(() => { })
utils.loginOut();
}, 300)
}
// #endif
reject(res.data.data); reject(res.data.data);
}, },
}); });
@ -139,3 +131,42 @@ export function uploadFile({
}); });
}) })
} }
const uploadImage = async ({ filePath, formData, name } = {}) => {
return new Promise(async (resolve, reject) => {
try {
const token = uni.getStorageSync("token");
const header = {
Authorization: `Bearer ${token}`
};
const formData = {
parent_id: 0,
type: "image",
};
uni.uploadFile({
url: 'https://saasdemo.byin.vip/admin/system/uploadImage',
filePath: filePath,
name: name || 'file', // 表单中文件字段的名称
formData: formData,
header: header,
success: (uploadFileRes) => {
const result = JSON.parse(uploadFileRes.data);
resolve(result)
}
});
} catch (error) {
reject(error)
}
})
};
export { uploadImage };

@ -57,7 +57,10 @@ export default {
uni.setClipboardData({ uni.setClipboardData({
data, data,
success: () => { success: () => {
uni.$u.toast(toast); uni.showToast({
title: toast,
icon: 'none'
})
}, },
}); });
}, },
@ -105,7 +108,7 @@ export default {
getRouterInfo() { getRouterInfo() {
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组 let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
let curRoute = routes[routes.length - 1].route // 获取当前页面路由,也就是最后一个打开的页面路由 let curRoute = routes[routes.length - 1].route // 获取当前页面路由,也就是最后一个打开的页面路由
let curParam = routes[routes.length - 1].options; //获取路由参数 let curParam = routes[routes.length - 1].options || []; //获取路由参数
const params = Object.entries(curParam).reduce((param, [key, val], index) => { const params = Object.entries(curParam).reduce((param, [key, val], index) => {
if (index === 0) { if (index === 0) {
@ -124,7 +127,7 @@ export default {
uni.removeStorageSync("token"); uni.removeStorageSync("token");
uni.removeStorageSync("user_info"); uni.removeStorageSync("user_info");
this.toUrl("/subPackages/login/login/index", "redirectTo"); this.toUrl("/pages/login/index", "redirectTo");
}, },
kmUnit(m) { kmUnit(m) {

Loading…
Cancel
Save