提交 fa27cd1f 编写于 作者: L linju

123

...@@ -67,7 +67,18 @@ ...@@ -67,7 +67,18 @@
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, { }, {
"path": "pages/ucenter/uni-feedback/uni-feedback", "path": "uni_modules/opendb-feedback/pages/opendb-feedback/list",
"style": {
"navigationBarTitleText": "反馈列表",
"enablePullDownRefresh":true
}
}, {
"path": "uni_modules/opendb-feedback/pages/opendb-feedback/add",
"style": {
"navigationBarTitleText": "问题反馈"
}
}, {
"path": "uni_modules/opendb-feedback/pages/opendb-feedback/detail",
"style": { "style": {
"navigationBarTitleText": "问题反馈" "navigationBarTitleText": "问题反馈"
} }
......
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
], ],
[{ [{
title: '反馈', title: '反馈',
to: '/pages/ucenter/uni-feedback/uni-feedback' to: '/uni_modules/opendb-feedback/pages/opendb-feedback/list' // /pages/ucenter/uni-feedback/uni-feedback uni_modules/opendb-feedback/pages/opendb-feedback/list
}, { }, {
title: '设置', title: '设置',
to: '/pages/ucenter/settings/settings' to: '/pages/ucenter/settings/settings'
......
{
"bsonType": "object",
"permission": {
"read": "doc.uid == auth.uid && doc.article_status == 0 || doc.article_status == 1",
"create": true,
"update": "doc.uid == auth.uid",
"delete": "doc.uid == auth.uid"
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"user_id": {
"bsonType": "string",
"description": "留言反馈用户ID\/回复留言用户ID,参考uni-id-users表",
"foreignKey": "uni-id-users._id"
},
"create_date": {
"bsonType": "timestamp",
"description": "留言时间\/回复留言时间"
},
"content": {
"bsonType": "string",
"description": "留言内容\/回复内容",
"trim": "right"
},
"imgs": {
"bsonType": "array",
"description": "图片列表"
},
"is_reply": {
"bsonType": "bool",
"description": "是否是回复类型"
},
"feedback_id": {
"bsonType": "string",
"description": "被回复留言ID"
},
"contact": {
"bsonType": "string",
"description": "联系人",
"trim": "both"
},
"mobile": {
"bsonType": "string",
"description": "联系电话",
"trim": "both"
},
"reply_count": {
"bsonType": "int",
"description": "被回复条数"
}
}
}
<template> <template>
<view class="page"> <view class="feedback-body feedback-uploader">
<view class="feedback-title"> <view class="uni-uploader">
<text>问题和意见</text> <view class="uni-uploader-head" v-if="isChoose">
<text class="feedback-quick" @tap="chooseMsg">快速键入</text> <view class="uni-uploader-title">点击预览图片</view>
</view> <view class="uni-uploader-info">{{ imgs.length }}/5</view>
<view class="feedback-body"><textarea placeholder="请详细描述你的问题和意见..." v-model="sendDate.content" </view>
class="feedback-textare"></textarea></view> <view class="uni-uploader-body">
<view class="feedback-title"><text>图片(选填,提供问题截图,总大小10M以下)</text></view> <view class="uni-uploader__files">
<view class="feedback-body feedback-uploader"> <block v-for="(image, index) in imgs" :key="index">
<view class="uni-uploader"> <view class="uni-uploader__file" style="position: relative;">
<view class="uni-uploader-head"> <image class="uni-uploader__img" :src="image" @tap="previewImage(index)">
<view class="uni-uploader-title">点击预览图片</view> </image>
<view class="uni-uploader-info">{{ imageList.length }}/5</view> <view class="close-view" v-if="isChoose" @click="close(index)">x</view>
</view>
<view class="uni-uploader-body">
<view class="uni-uploader__files">
<block v-for="(image, index) in imageList" :key="index">
<view class="uni-uploader__file" style="position: relative;">
<image class="uni-uploader__img" :src="image" @tap="previewImage(index)"></image>
<view class="close-view" @click="close(index)">x</view>
</view>
</block>
<view class="uni-uploader__input-box" v-show="imageList.length < 5">
<view class="uni-uploader__input" @tap="chooseImg"></view>
</view> </view>
</block>
<view class="uni-uploader__input-box" v-show="isChoose && imgs.length < 5">
<view class="uni-uploader__input" @tap="chooseImg"></view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<view class="feedback-title"><text>联系方式</text></view>
<view class="feedback-body"><input class="feedback-input" v-model="sendDate.contact"
placeholder="(选填,方便我们联系你 )" /></view>
<view class="feedback-title feedback-star-view">
<text>应用评分</text>
<view class="feedback-star-view">
<uni-rate v-model="sendDate.score" color="#bbb"></uni-rate>
</view>
</view>
<button type="default" class="feedback-submit" @tap="send">提交</button>
<view class="feedback-title"><text>用户反馈的结果可在app打包后于DCloud开发者中心查看</text></view>
</view> </view>
</template> </template>
<script> <script>
const db = uniCloud.database();
const dbCmd = db.command;
export default { export default {
data() { name:"feedback-imgs",
return { props:{
msgContents: ['界面显示错乱', '启动缓慢,卡出翔了', 'UI无法直视,丑哭了', '偶发性崩溃'], imgs:{
stars: [1, 2, 3, 4, 5], type:Array,
imageList: [], default:()=>[]
sendDate: { },
score: 0, isChoose:{
content: '', type:Boolean,
contact: '' default:false
} }
};
},
onLoad() {
// #ifdef APP-PLUS
this.deviceInfo = {
appid: plus.runtime.appid,
imei: plus.device.imei, //设备标识
p: plus.os.name === 'Android' ? 'a' : 'i', //平台类型,i表示iOS平台,a表示Android平台。
md: plus.device.model, //设备型号
app_version: plus.runtime.version,
plus_version: plus.runtime.innerVersion, //基座版本号
os: plus.os.version,
net: '' + plus.networkinfo.getCurrentType()
};
//#endif
this.deviceInfo = uni.getSystemInfo();
// #ifndef APP-PLUS
//#endif
this.sendDate = Object.assign(this.deviceInfo, this.sendDate);
}, },
methods: { methods:{
/** /**
* 关闭图片 * 关闭图片
* @param {Object} e * @param {Object} e
*/ */
close(e) { close(e) {
this.imageList.splice(e, 1); this.$emit( 'close', e)
}, },
/**
* 快速输入
*/
chooseMsg() {
uni.showActionSheet({
itemList: this.msgContents,
success: res => {
this.sendDate.content = this.msgContents[res.tapIndex];
}
});
},
/** /**
* 选择图片 * 选择图片
*/ */
chooseImg() { chooseImg() {
//选择图片 this.$emit('chooseImg');
uni.chooseImage({
sourceType: ['camera', 'album'],
sizeType: 'compressed',
count: 5 - this.imageList.length,
success: res => {
this.imageList = this.imageList.concat(res.tempFilePaths);
}
});
},
/**
* 评分
* @param {Object} e
*/
chooseStar(e) {
//点击评星
this.sendDate.score = e;
}, },
/** /**
* 预览图片 * 预览图片
...@@ -126,247 +56,200 @@ ...@@ -126,247 +56,200 @@
*/ */
previewImage(index) { previewImage(index) {
uni.previewImage({ uni.previewImage({
urls: this.imageList, urls: this.imgs,
current: this.imageList[index] current: this.imgs[index]
});
},
/**
* 提交
*/
send() {
//发送反馈
if (this.sendDate.content.length === 0) {
uni.showModal({
content: '请输入问题和意见',
showCancel: false
});
return;
}
uni.showLoading({
title: '上传中...'
});
let imgs = this.imageList.map((value, index) => {
return {
name: 'images' + index,
uri: value
};
}); });
// TODO 服务端限制上传文件一次最大不超过 2M, 图片一次最多不超过5张
this.request(this.sendDate, imgs)
.then(res => {
console.log(res);
if(res.success){
this.sendDate.content = '';
this.imageList = [];
return uni.showToast({
title: '反馈成功',
icon: 'none'
});
}
uni.showToast({
title: `err${res.result?.code}:${res.result?.message}`,
icon: 'none'
});
})
.catch(err => {
console.log(err);
})
.finally(()=>{
uni.hideLoading();
})
}, },
/**
* 发送请求到后台
*/
async request(sendDate, imgs) {
let cloud_list = [];
for (let i = 0; i < imgs.length; i++) {
let res = await uniCloud.uploadFile({
filePath: imgs[i].uri,
cloudPath: 'feedback.jpg',
onUploadProgress: function(progressEvent) {}
})
cloud_list.push(res.fileID);
}
console.log('cloud_', cloud_list);
return db.collection('opendb-feedback').add({
// ...sendDate,
"create_date": Date.now(),
"content": this.sendDate.content,
"mobile": this.sendDate.contact,
imgs: cloud_list
})
}
} }
}; }
</script> </script>
<style> <style>
page {
background-color: #efeff4; .close-view {
} text-align: center;
line-height: 14px;
height: 16px;
width: 16px;
border-radius: 50%;
background: #ff5053;
color: #ffffff;
position: absolute;
top: -6px;
right: -4px;
font-size: 12px;
}
/* 上传 */
.uni-uploader {
flex: 1;
flex-direction: column;
}
.uni-uploader-head {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.uni-uploader-info {
color: #B2B2B2;
}
.uni-uploader-body {
margin-top: 16rpx;
}
.uni-uploader__files {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.uni-uploader__file {
margin: 10rpx;
width: 210rpx;
height: 210rpx;
}
.uni-uploader__img {
display: block;
width: 210rpx;
height: 210rpx;
}
.uni-uploader__input-box {
position: relative;
margin: 10rpx;
width: 208rpx;
height: 208rpx;
border: 2rpx solid #D9D9D9;
}
.uni-uploader__input-box:before,
.uni-uploader__input-box:after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #D9D9D9;
}
.uni-uploader__input-box:before {
width: 4rpx;
height: 79rpx;
}
.uni-uploader__input-box:after {
width: 79rpx;
height: 4rpx;
}
.uni-uploader__input-box:active {
border-color: #999999;
}
.uni-uploader__input-box:active:before,
.uni-uploader__input-box:active:after {
background-color: #999999;
}
.uni-uploader__input {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
/*问题反馈*/
.feedback-title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 20rpx;
color: #8f8f94;
font-size: 28rpx;
}
.feedback-star-view.feedback-title {
justify-content: flex-start;
margin: 0;
}
.feedback-quick {
position: relative;
padding-right: 40rpx;
}
.feedback-quick:after {
font-family: uniicons;
font-size: 40rpx;
content: '\e581';
position: absolute;
right: 0;
top: 50%;
color: #bbb;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.feedback-body {
background: #fff;
}
.feedback-textare {
height: 200rpx;
font-size: 34rpx;
line-height: 50rpx;
width: 100%;
box-sizing: border-box;
padding: 20rpx 30rpx 0;
}
.feedback-input {
font-size: 34rpx;
height: 50rpx;
min-height: 50rpx;
padding: 15rpx 20rpx;
line-height: 50rpx;
}
.feedback-uploader {
padding: 22rpx 20rpx;
}
.feedback-star {
font-family: uniicons;
font-size: 40rpx;
margin-left: 6rpx;
}
.feedback-star-view {
margin-left: 20rpx;
}
.feedback-star:after {
content: '\e408';
}
.feedback-star.active {
color: #FFB400;
}
.feedback-star.active:after {
content: '\e438';
}
.feedback-submit {
background: #007AFF;
color: #FFFFFF;
margin: 20rpx;
}
.input-view {
font-size: 28rpx;
}
.close-view {
text-align: center;
line-height: 14px;
height: 16px;
width: 16px;
border-radius: 50%;
background: #ff5053;
color: #ffffff;
position: absolute;
top: -6px;
right: -4px;
font-size: 12px;
}
/* 上传 */
.uni-uploader {
flex: 1;
flex-direction: column;
}
.uni-uploader-head {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.uni-uploader-info {
color: #B2B2B2;
}
.uni-uploader-body {
margin-top: 16rpx;
}
.uni-uploader__files {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.uni-uploader__file {
margin: 10rpx;
width: 210rpx;
height: 210rpx;
}
.uni-uploader__img {
display: block;
width: 210rpx;
height: 210rpx;
}
.uni-uploader__input-box {
position: relative;
margin:10rpx;
width: 208rpx;
height: 208rpx;
border: 2rpx solid #D9D9D9;
}
.uni-uploader__input-box:before,
.uni-uploader__input-box:after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #D9D9D9;
}
.uni-uploader__input-box:before {
width: 4rpx;
height: 79rpx;
}
.uni-uploader__input-box:after {
width: 79rpx;
height: 4rpx;
}
.uni-uploader__input-box:active {
border-color: #999999;
}
.uni-uploader__input-box:active:before,
.uni-uploader__input-box:active:after {
background-color: #999999;
}
.uni-uploader__input {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
/*问题反馈*/
.feedback-title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 20rpx;
color: #8f8f94;
font-size: 28rpx;
}
.feedback-star-view.feedback-title {
justify-content: flex-start;
margin: 0;
}
.feedback-quick {
position: relative;
padding-right: 40rpx;
}
.feedback-quick:after {
font-family: uniicons;
font-size: 40rpx;
content: '\e581';
position: absolute;
right: 0;
top: 50%;
color: #bbb;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.feedback-body {
background: #fff;
}
.feedback-textare {
height: 200rpx;
font-size: 34rpx;
line-height: 50rpx;
width: 100%;
box-sizing: border-box;
padding: 20rpx 30rpx 0;
}
.feedback-input {
font-size: 34rpx;
height: 50rpx;
min-height: 50rpx;
padding: 15rpx 20rpx;
line-height: 50rpx;
}
.feedback-uploader {
padding: 22rpx 20rpx;
}
.feedback-star {
font-family: uniicons;
font-size: 40rpx;
margin-left: 6rpx;
}
.feedback-star-view {
margin-left: 20rpx;
}
.feedback-star:after {
content: '\e408';
}
.feedback-star.active {
color: #FFB400;
}
.feedback-star.active:after {
content: '\e438';
}
.feedback-submit {
background: #007AFF;
color: #FFFFFF;
margin: 20rpx;
}
</style> </style>
// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
const validator = {
"user_id": {
"rules": [
{
"format": "string"
}
]
},
"create_date": {
"rules": [
{
"format": "timestamp"
}
]
},
"content": {
"rules": [
{
"format": "string"
}
]
},
"imgs": {
"rules": [
{
"format": "array"
}
]
},
"is_reply": {
"rules": [
{
"format": "bool"
}
]
},
"feedback_id": {
"rules": [
{
"format": "string"
}
]
},
"contact": {
"rules": [
{
"format": "string"
}
]
},
"mobile": {
"rules": [
{
"format": "string"
}
]
},
"reply_count": {
"rules": [
{
"format": "int"
}
]
}
}
const enumConverter = {}
export { validator, enumConverter }
{
"id": "opendb-feedback",
"displayName": "opendb-feedback",
"version": "1.0.0",
"description": "",
"keywords": [
"opendb-feedback"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"uniCloud",
"Admin插件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uni-dateformat",
"uni-badge",
"uni-icons",
"uni-link",
"uni-load-more",
"uni-forms",
"uni-group",
"uni-list",
"uni-fab",
"uni-datetime-picker",
"uni-file-picker",
"uni-easyinput",
"uni-data-checkbox",
"switch"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
\ No newline at end of file
<template>
<view class="uni-container">
<uni-forms ref="form" :value="formData" :rules="rules" validate-trigger="submit" err-show-type="toast">
<!-- <uni-forms-item name="user_id" label="">
<uni-easyinput placeholder="留言反馈用户ID/回复留言用户ID,参考uni-id-users表" v-model="formData.user_id" />
</uni-forms-item> -->
<!-- <uni-forms-item name="create_date" label="">
<uni-datetime-picker return-type="timestamp" :value="formData.create_date" />
</uni-forms-item> -->
<uni-forms-item name="content" label="反馈内容">
<uni-easyinput placeholder="请输入反馈内容" type="textarea" v-model="formData.content" trim="right" />
</uni-forms-item>
<uni-forms-item name="imgs" label="反馈截图">
<!-- <uni-data-checkbox :multiple="true" v-model="formData.imgs" /> -->
<feedback-imgs :isChoose="true" :imgs="formData.imgs" @close="close" @chooseImg="chooseImg"></feedback-imgs>
</uni-forms-item>
<!-- <uni-forms-item name="is_reply" label="">
<switch @change="binddata('is_reply', $event.detail.value)" :checked="formData.is_reply" />
</uni-forms-item> -->
<!-- <uni-forms-item name="feedback_id" label="">
<uni-easyinput placeholder="被回复留言ID" v-model="formData.feedback_id" />
</uni-forms-item> -->
<uni-forms-item name="contact" label="联系人">
<uni-easyinput placeholder="请输入联系人" v-model="formData.contact" trim="both" />
</uni-forms-item>
<uni-forms-item name="mobile" label="联系方式">
<uni-easyinput placeholder="请输入手机号/邮箱" v-model="formData.mobile" trim="both" />
</uni-forms-item>
<!-- <uni-forms-item name="reply_count" label="">
<uni-easyinput placeholder="被回复条数" type="number" v-model="formData.reply_count" />
</uni-forms-item> -->
<view class="uni-button-group">
<button type="primary" class="uni-button" @click="submit">提交</button>
</view>
</uni-forms>
</view>
</template>
<script>
const db = uniCloud.database();
const dbCollectionName = 'opendb-feedback';
import feedbackImgs from '../../components/feedback-imgs';
export default {
components:{feedbackImgs},
data() {
return {
formData: {
"user_id": (uni.getStorageSync('userInfo') || {
_id: ''
})._id,
"create_date": null,
"content": "",
"imgs": [],
"is_reply": null,
"feedback_id": "",
"contact": "",
"mobile": "",
"reply_count": null
},
formOptions: {},
rules: {
content: {
rules: [{
required: true,
errorMessage: '请填写反馈内容',
}]
},
contact:{
rules:[{
required: true,
errorMessage: '请填写联系人',
}]
},
mobile:{
rules:[{
required: true,
errorMessage: '请填写联系方式',
}]
}
}
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
/**
* 触发表单提交
*/
async submit() {
uni.showLoading({
mask: true
})
this.$refs.form.submit().then((res) => {
this.uploadImgs(res.imgs)
.then(imgs=>{
res.imgs = imgs;
res.create_date = Date.now();
this.submitForm(res)
});
}).catch((errors) => {
console.log(errors);
uni.hideLoading()
})
},
/**
* 上传图片
*/
async uploadImgs(imgs){
let cloud_list = [];
for (let i = 0; i < imgs.length; i++) {
let img = await uniCloud.uploadFile({
filePath: imgs[i],
cloudPath: 'feedback.jpg'
});
cloud_list.push(img.fileID);
}
return cloud_list;
},
submitForm(value) {
// 使用 clientDB 提交数据
db.collection(dbCollectionName).add(value).then((res) => {
uni.showToast({
icon: 'none',
title: '新增成功'
})
this.getOpenerEventChannel().emit('refreshData')
setTimeout(() => uni.navigateBack(), 500)
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
/**
* 关闭图片
* @param {Object} e
*/
close(e) {
this.formData.imgs.splice(e, 1);
},
/**
* 选择图片
*/
chooseImg() {
//选择图片
uni.chooseImage({
sourceType: ['camera', 'album'],
sizeType: 'compressed',
count: 5 - this.formData.imgs.length,
success: res => {
this.formData.imgs = this.formData.imgs.concat(res.tempFilePaths);
}
});
},
}
}
</script>
<style>
.uni-container {
padding: 15px;
}
.uni-input-border,
.uni-textarea-border {
width: 100%;
font-size: 14px;
color: #666;
border: 1px #e5e5e5 solid;
border-radius: 5px;
box-sizing: border-box;
}
.uni-input-border {
padding: 0 10px;
height: 35px;
}
.uni-textarea-border {
padding: 10px;
height: 80px;
}
.uni-button-group {
margin-top: 50px;
display: flex;
justify-content: center;
}
.uni-button {
width: 184px;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
line-height: 1;
margin: 0;
}
.uni-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
</style>
<template>
<view class="container">
<unicloud-db ref="udb" v-slot:default="{data, loading, error, options}" :options="options"
collection="opendb-feedback"
field="user_id,create_date,content,imgs,is_reply,feedback_id,contact,mobile,reply_count" :where="queryWhere"
:getone="true" :manual="true">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">
<uni-load-more :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view v-else-if="data">
<uni-forms-item name="content" label="反馈内容">
<uni-easyinput :disabled="true" placeholder="请输入反馈内容" type="textarea" v-model="data.content" trim="right" />
</uni-forms-item>
<uni-forms-item v-if="data.imgs.length>0" name="imgs" label="反馈截图">
<feedback-imgs :imgs="data.imgs"></feedback-imgs>
</uni-forms-item>
<uni-forms-item name="contact" label="联系人">
<uni-easyinput :disabled="true" placeholder="请输入联系人" v-model="data.contact" trim="both" />
</uni-forms-item>
<uni-forms-item name="mobile" label="联系方式">
<uni-easyinput :disabled="true" placeholder="请输入手机号/邮箱" v-model="data.mobile" trim="both" />
</uni-forms-item>
</view>
</unicloud-db>
</view>
</template>
<script>
// 由schema2code生成,包含校验规则和enum静态数据
import {
enumConverter
} from '../../js_sdk/validator/opendb-feedback.js';
import feedbackImgs from '../../components/feedback-imgs';
export default {
components:{feedbackImgs},
data() {
return {
queryWhere: '',
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
},
options: {
// 将scheme enum 属性静态数据中的value转成text
...enumConverter
}
}
},
onLoad(e) {
this._id = e.id
},
onReady() {
if (this._id) {
this.queryWhere = '_id=="' + this._id + '"'
}
}
}
</script>
<style>
.container {
padding: 10px;
}
.btns {
margin-top: 10px;
display: flex;
flex-direction: row;
}
.btns button {
flex: 1;
}
.btn-delete {
margin-left: 10px;
}
</style>
<template>
<view class="uni-container">
<uni-forms ref="form" :value="formData" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="user_id" label="">
<uni-easyinput placeholder="留言反馈用户ID/回复留言用户ID,参考uni-id-users表" v-model="formData.user_id" />
</uni-forms-item>
<uni-forms-item name="create_date" label="">
<uni-datetime-picker return-type="timestamp" :value="formData.create_date" />
</uni-forms-item>
<uni-forms-item name="content" label="">
<uni-easyinput placeholder="留言内容/回复内容" v-model="formData.content" trim="right" />
</uni-forms-item>
<uni-forms-item name="imgs" label="">
<uni-data-checkbox :multiple="true" v-model="formData.imgs" />
</uni-forms-item>
<uni-forms-item name="is_reply" label="">
<switch @change="binddata('is_reply', $event.detail.value)" :checked="formData.is_reply" />
</uni-forms-item>
<uni-forms-item name="feedback_id" label="">
<uni-easyinput placeholder="被回复留言ID" v-model="formData.feedback_id" />
</uni-forms-item>
<uni-forms-item name="contact" label="">
<uni-easyinput placeholder="联系人" v-model="formData.contact" trim="both" />
</uni-forms-item>
<uni-forms-item name="mobile" label="">
<uni-easyinput placeholder="联系电话" v-model="formData.mobile" trim="both" />
</uni-forms-item>
<uni-forms-item name="reply_count" label="">
<uni-easyinput placeholder="被回复条数" type="number" v-model="formData.reply_count" />
</uni-forms-item>
<view class="uni-button-group">
<button type="primary" class="uni-button" @click="submit">提交</button>
</view>
</uni-forms>
</view>
</template>
<script>
import { validator } from '../../js_sdk/validator/opendb-feedback.js';
const db = uniCloud.database();
const dbCollectionName = 'opendb-feedback';
function getValidator(fields) {
let reuslt = {}
for (let key in validator) {
if (fields.indexOf(key) > -1) {
reuslt[key] = validator[key]
}
}
return reuslt
}
export default {
data() {
return {
formData: {
"user_id": "",
"create_date": null,
"content": "",
"imgs": [],
"is_reply": null,
"feedback_id": "",
"contact": "",
"mobile": "",
"reply_count": null
},
formOptions: {},
rules: {
...getValidator(["user_id","create_date","content","imgs","is_reply","feedback_id","contact","mobile","reply_count"])
}
}
},
onLoad(e) {
const id = e.id
this.formDataId = id
this.getDetail(id)
},
onReady() {
this.$refs.form.setRules(this.rules)
},
methods: {
/**
* 触发表单提交
*/
submit() {
uni.showLoading({
mask: true
})
this.$refs.form.submit().then((res) => {
this.submitForm(res)
}).catch((errors) => {
uni.hideLoading()
})
},
submitForm(value) {
// 使用 clientDB 提交数据
db.collection(dbCollectionName).doc(this.formDataId).update(value).then((res) => {
uni.showToast({
icon: 'none',
title: '修改成功'
})
this.getOpenerEventChannel().emit('refreshData')
setTimeout(() => uni.navigateBack(), 500)
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
/**
* 获取表单数据
* @param {Object} id
*/
getDetail(id) {
uni.showLoading({
mask: true
})
db.collection(dbCollectionName).doc(id).field('user_id,create_date,content,imgs,is_reply,feedback_id,contact,mobile,reply_count').get().then((res) => {
const data = res.result.data[0]
if (data) {
this.formData = data
}
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
}
}
}
</script>
<style>
.uni-container {
padding: 15px;
}
.uni-input-border,
.uni-textarea-border {
width: 100%;
font-size: 14px;
color: #666;
border: 1px #e5e5e5 solid;
border-radius: 5px;
box-sizing: border-box;
}
.uni-input-border {
padding: 0 10px;
height: 35px;
}
.uni-textarea-border {
padding: 10px;
height: 80px;
}
.uni-button-group {
margin-top: 50px;
display: flex;
justify-content: center;
}
.uni-button {
width: 184px;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
line-height: 1;
margin: 0;
}
</style>
<template>
<view class="container">
<unicloud-db ref="udb" v-slot:default="{data, pagination, loading, hasMore, error}" collection="opendb-feedback" field="user_id,create_date,content,imgs,is_reply,feedback_id,contact,mobile,reply_count">
<view v-if="error">{{error.message}}</view>
<view v-else-if="data">
<uni-list>
<uni-list-item v-for="(item, index) in data" :key="index" showArrow :clickable="true" @click="handleItemClick(item._id)">
<view slot="body">
<!-- 此处默认显示为_id,请根据需要自行修改为其他字段 -->
{{item.content}}
</view>
</uni-list-item>
</uni-list>
</view>
<uni-load-more :status="loading?'loading':(hasMore ? 'more' : 'noMore')"></uni-load-more>
</unicloud-db>
<uni-fab ref="fab" horizontal="right" vertical="bottom" :pop-menu="false" @fabClick="fabClick" />
</view>
</template>
<script>
export default {
data() {
return {
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
}, (res) => {
uni.stopPullDownRefresh()
})
},
onReachBottom() {
this.$refs.udb.loadMore()
},
methods: {
handleItemClick(id) {
uni.navigateTo({
url: './detail?id=' + id
})
},
fabClick() {
// 打开新增页面
uni.navigateTo({
url: './add',
events: {
// 监听新增数据成功后, 刷新当前页面数据
refreshData: () => {
this.$refs.udb.loadData({
clear: true
})
}
}
})
}
}
}
</script>
<style>
</style>
# opendb-feedback
\ No newline at end of file
{
"bsonType": "object",
"permission": {
"read": "auth.uid && doc.uid == auth.uid",
"create": true,
"update": false,
"delete": false
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"user_id": {
"bsonType": "string",
"description": "留言反馈用户ID/回复留言用户ID,参考uni-id-users表",
"foreignKey": "uni-id-users._id"
},
"create_date": {
"bsonType": "timestamp",
"description": "留言时间/回复留言时间"
},
"content": {
"bsonType": "string",
"description": "留言内容/回复内容",
"trim": "right"
},
"imgs": {
"bsonType": "array",
"description": "图片列表"
},
"is_reply": {
"bsonType": "bool",
"description": "是否是回复类型"
},
"feedback_id": {
"bsonType": "string",
"description": "被回复留言ID"
},
"contact": {
"bsonType": "string",
"description": "联系人",
"trim": "both"
},
"mobile": {
"bsonType": "string",
"description": "联系电话",
"trim": "both"
},
"reply_count": {
"bsonType": "int",
"description": "被回复条数"
}
}
}
\ No newline at end of file
<template> <template>
<text v-if="text" :class="inverted ? 'uni-badge--' + type + ' uni-badge--' + size + ' uni-badge--' + type + '-inverted' : 'uni-badge--' + type + ' uni-badge--' + size" <text v-if="text" :class="inverted ? 'uni-badge--' + type + ' uni-badge--' + size + ' uni-badge--' + type + '-inverted' : 'uni-badge--' + type + ' uni-badge--' + size"
:style="badgeStyle" class="uni-badge" @click="onClick()">{{ text }}</text> :style="badgeStyle" class="uni-badge" @click="onClick()">{{ text }}</text>
</template> </template>
<script> <script>
/** /**
* Badge 数字角标 * Badge 数字角标
* @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景 * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21 * @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容 * @property {String} text 角标内容
* @property {String} type = [default|primary|success|warning|error] 颜色类型 * @property {String} type = [default|primary|success|warning|error] 颜色类型
* @value default 灰色 * @value default 灰色
* @value primary 蓝色 * @value primary 蓝色
* @value success 绿色 * @value success 绿色
* @value warning 黄色 * @value warning 黄色
* @value error 红色 * @value error 红色
* @property {String} size = [normal|small] Badge 大小 * @property {String} size = [normal|small] Badge 大小
* @value normal 一般尺寸 * @value normal 一般尺寸
* @value small 小尺寸 * @value small 小尺寸
* @property {String} inverted = [true|false] 是否无需背景颜色 * @property {String} inverted = [true|false] 是否无需背景颜色
* @event {Function} click 点击 Badge 触发事件 * @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge> * @example <uni-badge text="1"></uni-badge>
*/ */
export default { export default {
name: 'UniBadge', name: 'UniBadge',
props: { props: {
type: { type: {
type: String, type: String,
default: 'default' default: 'default'
}, },
inverted: { inverted: {
type: Boolean, type: Boolean,
default: false default: false
}, },
text: { text: {
type: [String, Number], type: [String, Number],
default: '' default: ''
}, },
size: { size: {
type: String, type: String,
default: 'normal' default: 'normal'
} }
}, },
data() { data() {
return { return {
badgeStyle: '' badgeStyle: ''
}; };
}, },
watch: { watch: {
text() { text() {
this.setStyle() this.setStyle()
} }
}, },
mounted() { mounted() {
this.setStyle() this.setStyle()
}, },
methods: { methods: {
setStyle() { setStyle() {
this.badgeStyle = `width: ${String(this.text).length * 8 + 12}px` this.badgeStyle = `width: ${String(this.text).length * 8 + 12}px`
}, },
onClick() { onClick() {
this.$emit('click'); this.$emit('click');
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$bage-size: 12px; $bage-size: 12px;
$bage-small: scale(0.8); $bage-small: scale(0.8);
$bage-height: 20px; $bage-height: 20px;
.uni-badge { .uni-badge {
/* #ifndef APP-PLUS */ /* #ifndef APP-PLUS */
display: flex; display: flex;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
/* #endif */ /* #endif */
justify-content: center; justify-content: center;
flex-direction: row; flex-direction: row;
height: $bage-height; height: $bage-height;
line-height: $bage-height; line-height: $bage-height;
color: $uni-text-color; color: $uni-text-color;
border-radius: 100px; border-radius: 100px;
background-color: $uni-bg-color-hover; background-color: $uni-bg-color-hover;
background-color: transparent; background-color: transparent;
text-align: center; text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif; font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: $bage-size; font-size: $bage-size;
padding: 0px 6px; padding: 0px 6px;
/* #ifdef H5 */ /* #ifdef H5 */
cursor: pointer; cursor: pointer;
/* #endif */ /* #endif */
} }
.uni-badge--inverted { .uni-badge--inverted {
padding: 0 5px 0 0; padding: 0 5px 0 0;
color: $uni-bg-color-hover; color: $uni-bg-color-hover;
} }
.uni-badge--default { .uni-badge--default {
color: $uni-text-color; color: $uni-text-color;
background-color: $uni-bg-color-hover; background-color: $uni-bg-color-hover;
} }
.uni-badge--default-inverted { .uni-badge--default-inverted {
color: $uni-text-color-grey; color: $uni-text-color-grey;
background-color: transparent; background-color: transparent;
} }
.uni-badge--primary { .uni-badge--primary {
color: $uni-text-color-inverse; color: $uni-text-color-inverse;
background-color: $uni-color-primary; background-color: $uni-color-primary;
} }
.uni-badge--primary-inverted { .uni-badge--primary-inverted {
color: $uni-color-primary; color: $uni-color-primary;
background-color: transparent; background-color: transparent;
} }
.uni-badge--success { .uni-badge--success {
color: $uni-text-color-inverse; color: $uni-text-color-inverse;
background-color: $uni-color-success; background-color: $uni-color-success;
} }
.uni-badge--success-inverted { .uni-badge--success-inverted {
color: $uni-color-success; color: $uni-color-success;
background-color: transparent; background-color: transparent;
} }
.uni-badge--warning { .uni-badge--warning {
color: $uni-text-color-inverse; color: $uni-text-color-inverse;
background-color: $uni-color-warning; background-color: $uni-color-warning;
} }
.uni-badge--warning-inverted { .uni-badge--warning-inverted {
color: $uni-color-warning; color: $uni-color-warning;
background-color: transparent; background-color: transparent;
} }
.uni-badge--error { .uni-badge--error {
color: $uni-text-color-inverse; color: $uni-text-color-inverse;
background-color: $uni-color-error; background-color: $uni-color-error;
} }
.uni-badge--error-inverted { .uni-badge--error-inverted {
color: $uni-color-error; color: $uni-color-error;
background-color: transparent; background-color: transparent;
} }
.uni-badge--small { .uni-badge--small {
transform: $bage-small; transform: $bage-small;
transform-origin: center center; transform-origin: center center;
} }
</style> </style>
## 0.1.4(2021-04-09)
- 修复 nvue 下无法选中的问题
## 0.1.3(2021-03-22) ## 0.1.3(2021-03-22)
- 新增 disabled属性 - 新增 disabled属性
## 0.1.2(2021-02-24) ## 0.1.2(2021-02-24)
......
{ {
"id": "uni-data-checkbox", "id": "uni-data-checkbox",
"displayName": "DataCheckbox 数据选择器", "displayName": "DataCheckbox 数据选择器",
"version": "0.1.3", "version": "0.1.4",
"description": "通过数据驱动的单选框和复选框", "description": "通过数据驱动的单选框和复选框",
"keywords": [ "keywords": [
"checkbox", "checkbox",
......
## DataCheckbox 数据驱动的单选复选框 ## DataCheckbox 数据驱动的单选复选框
> **组件名:uni-data-checkbox**
> 代码块: `uDataCheckbox` > 代码块: `uDataCheckbox`
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data 在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 > 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装 > - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 本组件为数据驱动,目的是快速投入使用,只可通过 style 覆盖有限样式,不支持自定义更多样式 > - 本组件为数据驱动,目的是快速投入使用,只可通过 style 覆盖有限样式,不支持自定义更多样式
......
...@@ -59,13 +59,7 @@ function getDate(time) { ...@@ -59,13 +59,7 @@ function getDate(time) {
} }
switch (typeof time) { switch (typeof time) {
case 'string': case 'string':
{ return new Date(time.replace(/-/g, '/'))
// 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
if (time.indexOf('T') > -1) {
return new Date(time)
}
return new Date(time.replace(/-/g, '/'))
}
default: default:
return new Date(time) return new Date(time)
} }
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
___点击 picker 默认值规则:___ ___点击 picker 默认值规则:___
- 若设置初始值 value, 会显示在 picker 显示框中; 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中 - 若设置初始值 value, 会显示在 picker 显示框中; 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
- 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
- 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
- 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
- 无起始终止时间,则初始值为 value - 无起始终止时间,则初始值为 value
### 安装方式 ### 安装方式
......
/** /**
* @desc 函数防抖 * @desc 函数防抖
* @param func 目标函数 * @param func 目标函数
* @param wait 延迟执行毫秒数 * @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行 * @param immediate true - 立即执行, false - 延迟执行
*/ */
export const debounce = function(func, wait = 1000, immediate = true) { export const debounce = function(func, wait = 1000, immediate = true) {
let timer; let timer;
console.log(1); console.log(1);
return function() { return function() {
console.log(123); console.log(123);
let context = this, let context = this,
args = arguments; args = arguments;
if (timer) clearTimeout(timer); if (timer) clearTimeout(timer);
if (immediate) { if (immediate) {
let callNow = !timer; let callNow = !timer;
timer = setTimeout(() => { timer = setTimeout(() => {
timer = null; timer = null;
}, wait); }, wait);
if (callNow) func.apply(context, args); if (callNow) func.apply(context, args);
} else { } else {
timer = setTimeout(() => { timer = setTimeout(() => {
func.apply(context, args); func.apply(context, args);
}, wait) }, wait)
} }
} }
} }
/** /**
* @desc 函数节流 * @desc 函数节流
* @param func 函数 * @param func 函数
* @param wait 延迟执行毫秒数 * @param wait 延迟执行毫秒数
* @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发 * @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
*/ */
export const throttle = (func, wait = 1000, type = 1) => { export const throttle = (func, wait = 1000, type = 1) => {
let previous = 0; let previous = 0;
let timeout; let timeout;
return function() { return function() {
let context = this; let context = this;
let args = arguments; let args = arguments;
if (type === 1) { if (type === 1) {
let now = Date.now(); let now = Date.now();
if (now - previous > wait) { if (now - previous > wait) {
func.apply(context, args); func.apply(context, args);
previous = now; previous = now;
} }
} else if (type === 2) { } else if (type === 2) {
if (!timeout) { if (!timeout) {
timeout = setTimeout(() => { timeout = setTimeout(() => {
timeout = null; timeout = null;
func.apply(context, args) func.apply(context, args)
}, wait) }, wait)
} }
} }
} }
} }
## 0.0.6(2021-04-09)
- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
## 0.0.5(2021-04-09)
- 优化 更新组件示例
## 0.0.4(2021-04-09)
- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
## 0.0.3(2021-02-05) ## 0.0.3(2021-02-05)
- 调整为uni_modules目录规范 - 调整为uni_modules目录规范
- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug - 修复 微信小程序不指定 fileExtname 属性选择失败的Bug
...@@ -2,185 +2,185 @@ ...@@ -2,185 +2,185 @@
Object.defineProperty(exports, '__esModule', { value: true }); Object.defineProperty(exports, '__esModule', { value: true });
const ERR_MSG_OK = 'chooseAndUploadFile:ok'; const ERR_MSG_OK = 'chooseAndUploadFile:ok';
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
function chooseImage(opts) { function chooseImage(opts) {
const { count, sizeType, sourceType, extension } = opts; const { count, sizeType, sourceType, extension } = opts;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.chooseImage({ uni.chooseImage({
count, count,
sizeType, sizeType,
sourceType, sourceType,
extension, extension,
success(res) { success(res) {
resolve(normalizeChooseAndUploadFileRes(res, 'image')); resolve(normalizeChooseAndUploadFileRes(res, 'image'));
}, },
fail(res) { fail(res) {
reject({ reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
}); });
}, },
}); });
}); });
} }
function chooseVideo(opts) { function chooseVideo(opts) {
const { camera, compressed, maxDuration, sourceType, extension } = opts; const { camera, compressed, maxDuration, sourceType, extension } = opts;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.chooseVideo({ uni.chooseVideo({
camera, camera,
compressed, compressed,
maxDuration, maxDuration,
sourceType, sourceType,
extension, extension,
success(res) { success(res) {
const { tempFilePath, duration, size, height, width } = res; const { tempFilePath, duration, size, height, width } = res;
resolve(normalizeChooseAndUploadFileRes({ resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok', errMsg: 'chooseVideo:ok',
tempFilePaths: [tempFilePath], tempFilePaths: [tempFilePath],
tempFiles: [ tempFiles: [
{ {
name: (res.tempFile && res.tempFile.name) || '', name: (res.tempFile && res.tempFile.name) || '',
path: tempFilePath, path: tempFilePath,
size, size,
type: (res.tempFile && res.tempFile.type) || '', type: (res.tempFile && res.tempFile.type) || '',
width, width,
height, height,
duration, duration,
fileType: 'video', fileType: 'video',
cloudPath: '', cloudPath: '',
}, },
], ],
}, 'video')); }, 'video'));
}, },
fail(res) { fail(res) {
reject({ reject({
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
}); });
}, },
}); });
}); });
} }
function chooseAll(opts) { function chooseAll(opts) {
const { count, extension } = opts; const { count, extension } = opts;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let chooseFile = uni.chooseFile; let chooseFile = uni.chooseFile;
if (typeof wx !== 'undefined' && if (typeof wx !== 'undefined' &&
typeof wx.chooseMessageFile === 'function') { typeof wx.chooseMessageFile === 'function') {
chooseFile = wx.chooseMessageFile; chooseFile = wx.chooseMessageFile;
} }
if (typeof chooseFile !== 'function') { if (typeof chooseFile !== 'function') {
return reject({ return reject({
errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。', errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
}); });
} }
chooseFile({ chooseFile({
type: 'all', type: 'all',
count, count,
extension, extension,
success(res) { success(res) {
resolve(normalizeChooseAndUploadFileRes(res)); resolve(normalizeChooseAndUploadFileRes(res));
}, },
fail(res) { fail(res) {
reject({ reject({
errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL), errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
}); });
}, },
}); });
}); });
} }
function normalizeChooseAndUploadFileRes(res, fileType) { function normalizeChooseAndUploadFileRes(res, fileType) {
res.tempFiles.forEach((item, index) => { res.tempFiles.forEach((item, index) => {
if (!item.name) { if (!item.name) {
item.name = item.path.substring(item.path.lastIndexOf('/') + 1); item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
} }
if (fileType) { if (fileType) {
item.fileType = fileType; item.fileType = fileType;
} }
item.cloudPath = item.cloudPath =
Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.')); Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
}); });
// wx.chooseMessageFile // wx.chooseMessageFile
if (!res.tempFilePaths) { if (!res.tempFilePaths) {
res.tempFilePaths = res.tempFiles.map((file) => file.path); res.tempFilePaths = res.tempFiles.map((file) => file.path);
} }
return res; return res;
} }
function uploadCloudFiles(res, max = 5, onUploadProgress) { function uploadCloudFiles(res, max = 5, onUploadProgress) {
res = Object.assign({}, res); res = Object.assign({}, res);
res.errMsg = ERR_MSG_OK; res.errMsg = ERR_MSG_OK;
const files = res.tempFiles; const files = res.tempFiles;
const len = files.length; const len = files.length;
let count = 0; let count = 0;
return new Promise((resolve) => { return new Promise((resolve) => {
while (count < max) { while (count < max) {
next(); next();
} }
function next() { function next() {
let cur = count++; let cur = count++;
if (cur >= len) { if (cur >= len) {
!files.find((item) => !item.url && !item.errMsg) && resolve(res); !files.find((item) => !item.url && !item.errMsg) && resolve(res);
return; return;
} }
const fileItem = files[cur]; const fileItem = files[cur];
uniCloud uniCloud
.uploadFile({ .uploadFile({
filePath: fileItem.path, filePath: fileItem.path,
cloudPath: fileItem.cloudPath, cloudPath: fileItem.cloudPath,
fileType: fileItem.fileType, fileType: fileItem.fileType,
onUploadProgress(res) { onUploadProgress(res) {
res.index = cur; res.index = cur;
res.tempFile = fileItem; res.tempFile = fileItem;
res.tempFilePath = fileItem.path; res.tempFilePath = fileItem.path;
onUploadProgress && onUploadProgress &&
onUploadProgress(res); onUploadProgress(res);
}, },
}) })
.then((res) => { .then((res) => {
fileItem.url = res.fileID; fileItem.url = res.fileID;
if (cur < len) { if (cur < len) {
next(); next();
} }
}) })
.catch((res) => { .catch((res) => {
// fileItem.errMsg = res.message; // fileItem.errMsg = res.message;
fileItem.errMsg = res.errMsg || res.message; fileItem.errMsg = res.errMsg || res.message;
if (cur < len) { if (cur < len) {
next(); next();
} }
}); });
} }
}); });
} }
function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) { function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) {
return choosePromise return choosePromise
.then((res) => { .then((res) => {
if (onChooseFile) { if (onChooseFile) {
const customChooseRes = onChooseFile(res); const customChooseRes = onChooseFile(res);
if (typeof customChooseRes !== 'undefined') { if (typeof customChooseRes !== 'undefined') {
return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? res : chooseRes); return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? res : chooseRes);
} }
} }
return res; return res;
}) })
.then((res) => { .then((res) => {
if (res === false) { if (res === false) {
return { return {
errMsg: ERR_MSG_OK, errMsg: ERR_MSG_OK,
tempFilePaths: [], tempFilePaths: [],
tempFiles: [], tempFiles: [],
}; };
} }
return uploadCloudFiles(res, 5, onUploadProgress); return uploadCloudFiles(res, 5, onUploadProgress);
}); });
} }
function chooseAndUploadFile(opts = { type: 'all' }) { function chooseAndUploadFile(opts = { type: 'all' }) {
if (opts.type === 'image') { if (opts.type === 'image') {
return uploadFiles(chooseImage(opts), opts); return uploadFiles(chooseImage(opts), opts);
} }
else if (opts.type === 'video') { else if (opts.type === 'video') {
return uploadFiles(chooseVideo(opts), opts); return uploadFiles(chooseVideo(opts), opts);
} }
return uploadFiles(chooseAll(opts), opts); return uploadFiles(chooseAll(opts), opts);
} }
exports.chooseAndUploadFile = chooseAndUploadFile; exports.chooseAndUploadFile = chooseAndUploadFile;
{ {
"id": "uni-file-picker", "id": "uni-file-picker",
"displayName": "FilePicker 文件选择上传", "displayName": "FilePicker 文件选择上传",
"version": "0.0.3", "version": "0.0.6",
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间", "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
"keywords": [ "keywords": [
"uni-ui", "uni-ui",
......
## FilePicker 文件选择上传 ## FilePicker 文件选择上传
> **组件名:uni-file-picker**
> 代码块: `uFilePicker` > 代码块: `uFilePicker`
文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 > 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装 > - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 使用组件需要绑定服务空间 > - 使用组件需要绑定服务空间
...@@ -31,7 +33,7 @@ ...@@ -31,7 +33,7 @@
| title | String | - | - | 组件标题,右侧显示上传计数 | | title | String | - | - | 组件标题,右侧显示上传计数 |
| mode | String | list | list/grid | 选择文件后的文件列表样式 | | mode | String | list | list/grid | 选择文件后的文件列表样式 |
| file-mediatype| String | image | image/video/all | 选择文件类型,all 只支持 H5 和微信小程序平台 | | file-mediatype| String | image | image/video/all | 选择文件类型,all 只支持 H5 和微信小程序平台 |
| file-extname | Array | - | - | 选择文件后缀,根据 `file-mediatype` 属性而不同| | file-extname | Array\String | - | - | 选择文件后缀,字符串的情况下需要用逗号分隔(推荐使用字符串),根据 `file-mediatype` 属性而不同|
| list-styles | Object | - | - | `mode:list` 时的样式 | | list-styles | Object | - | - | `mode:list` 时的样式 |
| image-styles | Object | - | - | `mode:grid` 时的样式 | | image-styles | Object | - | - | `mode:grid` 时的样式 |
...@@ -174,7 +176,7 @@ export default { ...@@ -174,7 +176,7 @@ export default {
配置 `file-mediatype` 属性为 `image`,限定只选择图片 配置 `file-mediatype` 属性为 `image`,限定只选择图片
配置 `file-extname` 属性为 `['png','jpg']`,限定只选择 `png``jpg`后缀的图片 配置 `file-extname` 属性为 `'png,jpg'`,限定只选择 `png``jpg`后缀的图片
配置 `limit` 属性为 1 ,则最多选择一张图片 配置 `limit` 属性为 1 ,则最多选择一张图片
...@@ -186,7 +188,7 @@ export default { ...@@ -186,7 +188,7 @@ export default {
v-model="imageValue" v-model="imageValue"
file-mediatype="image" file-mediatype="image"
mode="grid" mode="grid"
file-extname="['png','jpg']" file-extname="png,jpg"
:limit="1" :limit="1"
@progress="progress" @progress="progress"
@success="success" @success="success"
......
<template> <template>
<view class="uni-group" :class="['uni-group--'+mode ,margin?'group-margin':'']" :style="{marginTop: `${top}px` }"> <view class="uni-group" :class="['uni-group--'+mode ,margin?'group-margin':'']" :style="{marginTop: `${top}px` }">
<slot name="title"> <slot name="title">
<view v-if="title" class="uni-group__title" :style="{'padding-left':border?'30px':'15px'}"> <view v-if="title" class="uni-group__title" :style="{'padding-left':border?'30px':'15px'}">
<text class="uni-group__title-text">{{ title }}</text> <text class="uni-group__title-text">{{ title }}</text>
</view> </view>
</slot> </slot>
<view class="uni-group__content" :class="{'group-conent-padding':border}"> <view class="uni-group__content" :class="{'group-conent-padding':border}">
<slot /> <slot />
</view> </view>
</view> </view>
</template> </template>
<script> <script>
/** /**
* Group 分组 * Group 分组
* @description 表单字段分组 * @description 表单字段分组
* @tutorial https://ext.dcloud.net.cn/plugin?id=21002 * @tutorial https://ext.dcloud.net.cn/plugin?id=21002
* @property {String} title 主标题 * @property {String} title 主标题
* @property {Number} top 分组间隔 * @property {Number} top 分组间隔
*/ */
export default { export default {
name: 'uniGroup', name: 'uniGroup',
props: { props: {
title: { title: {
type: String, type: String,
default: '' default: ''
}, },
top: { top: {
type: [Number, String], type: [Number, String],
default: 10 default: 10
}, },
mode: { mode: {
type: String, type: String,
default: 'default' default: 'default'
} }
}, },
data() { data() {
return { return {
margin: false, margin: false,
border: false border: false
} }
}, },
watch: { watch: {
title(newVal) { title(newVal) {
if (uni.report && newVal !== '') { if (uni.report && newVal !== '') {
uni.report('title', newVal) uni.report('title', newVal)
} }
} }
}, },
created() { created() {
this.form = this.getForm() this.form = this.getForm()
if (this.form) { if (this.form) {
this.margin = true this.margin = true
this.border = this.form.border this.border = this.form.border
} }
}, },
methods: { methods: {
/** /**
* 获取父元素实例 * 获取父元素实例
*/ */
getForm() { getForm() {
let parent = this.$parent; let parent = this.$parent;
let parentName = parent.$options.name; let parentName = parent.$options.name;
while (parentName !== 'uniForms') { while (parentName !== 'uniForms') {
parent = parent.$parent; parent = parent.$parent;
if (!parent) return false if (!parent) return false
parentName = parent.$options.name; parentName = parent.$options.name;
} }
return parent; return parent;
}, },
onClick() { onClick() {
this.$emit('click') this.$emit('click')
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.uni-group { .uni-group {
background: #fff; background: #fff;
margin-top: 10px; margin-top: 10px;
// border: 1px red solid; // border: 1px red solid;
} }
.group-margin { .group-margin {
// margin: 0 -15px; // margin: 0 -15px;
} }
.uni-group__title { .uni-group__title {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding-left: 15px; padding-left: 15px;
height: 40px; height: 40px;
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
font-weight: normal; font-weight: normal;
color: $uni-text-color; color: $uni-text-color;
} }
.uni-group__content { .uni-group__content {
padding: 15px; padding: 15px;
// padding-bottom: 5px; // padding-bottom: 5px;
// background-color: #FFF; // background-color: #FFF;
} }
.group-conent-padding { .group-conent-padding {
padding: 0 15px; padding: 0 15px;
} }
.uni-group__title-text { .uni-group__title-text {
font-size: $uni-font-size-base; font-size: $uni-font-size-base;
color: $uni-text-color; color: $uni-text-color;
} }
.distraction { .distraction {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} }
.uni-group--card { .uni-group--card {
margin: 10px; margin: 10px;
border-radius: 5px; border-radius: 5px;
overflow: hidden; overflow: hidden;
box-shadow: 0 0 5px 1px rgba($color: #000000, $alpha: 0.08); box-shadow: 0 0 5px 1px rgba($color: #000000, $alpha: 0.08);
} }
</style> </style>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册