提交 5202e075 编写于 作者: LukeLiou's avatar LukeLiou

first commit

上级
<script>
import checkUpdate from '@/uni_modules/uni-upgrade-center-app/utils/check-update';
export default {
onLaunch: function() {
console.log('App Launch')
checkUpdate()//更新升级
},
mounted() {
// #ifdef H5
//const VConsole = require('@/common/js/vconsole.min.js')
//new VConsole()
// #endif
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
/* #ifndef APP-NVUE */
view{
box-sizing: border-box;
}
@font-face {
font-family: "iconfont";
src: url('https://at.alicdn.com/t/font_2354462_s00xh8caffp.ttf');
}
.ico{
font-family: iconfont;
}
/* #endif */
</style>
## 1.3.1(2022-03-09)
修改错误的变量名称
## 1.3.0(2022-02-25)
新增[云对象](https://uniapp.dcloud.net.cn/uniCloud/cloud-obj)基础示例
## 1.2.9(2021-12-30)
新增适用于:数据表记录量较大时的联表查询示例:通过`getTemp`先过滤处理获取临时表再联表查询,提升查询性能。[详情](https://uniapp.dcloud.io/uniCloud/jql?id=lookup)
## 1.2.7(2021-10-12)
默认版本为:`Vue2`
## 1.2.6(2021-10-03)
修改入口页`main.js` 使用`import {createSSRApp} from 'vue' `
## 1.2.5(2021-08-30)
新增Redis使用示例
## 1.2.4(2021-08-24)
兼容vue3
## 1.2.3(2021-04-28)
删除多余的node_modules文件夹
## 1.2.2(2021-04-27)
优化留言板示例中多余的代码
## 1.2.1(2021-04-22)
移除多余的node_modules文件
## 1.2.0(2021-04-22)
升级uni-id版本,修复某些情况下uni-popup-dialog输入框的值获取失败的问题
## 1.0.9(2021-04-09)
1. 新增升级中心
2. 调整为uni_modules目录
## 1.0.8(2021-04-08)
去除测试文件
此差异已折叠。
<template>
<!-- #ifdef MP -->
<view class="box isShow" @click="closeMe" v-if="isShow">
<!-- #endif -->
<!-- #ifndef MP -->
<view class="box" @click="closeMe" :class="{isShow:isShow}">
<!-- #endif -->
<!-- 小程序存在动画切换的bug本版本先用 v-if="isShow" 处理 -->
<scroll-view scroll-x scroll-y @click.stop="tapCode" class="scroll-view" style="overflow: auto;">
<show-code :codes="codes"></show-code>
</scroll-view>
</view>
</template>
<script>
function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
}
function purifyCodes(codes) {
const codesType = getType(codes)
switch (codesType) {
case 'object':
if ('affectedDocs' in codes) {
delete codes.affectedDocs
}
for (let key in codes) {
codes[key] = purifyCodes(codes[key])
}
break;
case 'array':
for (let i = 0; i < codes.length; i++) {
codes[i] = purifyCodes(codes[i])
}
break;
default:
return codes
}
return codes
}
export default {
data() {
return {
codes: {},
isShow: false
}
},
methods: {
open(codes) {
this.codes = purifyCodes(codes)
this.isShow = true
},
tapCode(e) {
console.log(e);
e.stopPropagation()
},
closeMe(e) {
console.log('closeMe', e);
this.isShow = false
}
}
}
</script>
<style scoped>
.box {
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.2);
position: fixed;
top: 0;
left: 100vw;
z-index: 999;
opacity: 0;
transition: opacity 0.3s;
justify-content: center;
align-items: center;
display: flex;
}
.scroll-view {
background-color: #FFFAE7;
padding: 14px 18rpx;
width: 610rpx;
max-height: 60vh;
}
.isShow {
opacity: 1;
left: 0;
}
</style>
{
"uni-forms": {
"include": ["uni-forms-item", "uni-dateformat"]
},
"uni-list": {
"include": ["uni-list-item", "uni-badge", "uni-icons"]
},
"uni-data-picker": {
"include": ["uni-data-pickerview", "uni-load-more"]
},
"uni-datetime-picker": {
"include": []
},
"uni-data-checkbox": {
"include": ["uni-load-more"]
},
"uni-easyinput": {
"include": ["uni-load-more"]
},
"uni-group": {
"include": []
},
"uni-fab": {
"include": []
}
}
<template>
<view>
<view class="input-box">
<uni-icons :type="leftIcon" size="30" :color="leftIconColor"></uni-icons>
<view class="right-box">
<text v-if="c_value" class="tip-title">{{subTitle}}</text>
<view class="input-content">
<input v-model="c_value" class="input" :style="{'height':changeHeight}"
:type="type" :maxlength="maxlength"
:placeholder="placeholder?placeholder:subTitle"/>
<uni-icons v-if="c_value&&clearIcon" @click="clearc_value" type="clear" size="18" color="#C0C0C0"></uni-icons>
</view>
</view>
<uni-icons v-if="rightIcon" type="arrowright" size="20" color="#C0C0C0"></uni-icons>
</view>
</view>
</template>
<script>
import uniIcons from "@/components/uni-icons/uni-icons.vue"
export default {
components: {uniIcons},
mounted() {
},
watch: {
c_value(c_value, oldValue) {
console.log(c_value);
this.$emit('update:value',c_value)
},
value:{
handler(value){
this.c_value = value
},
immediate:true
}
},
data() {
return {
c_value:"c_value"
};
},
props: {
leftIcon: {
type: String,
default: "contact"
},
leftIconColor: {
type: String,
default: "#999999"
},
rightIcon: {
type: Boolean,
default(){
return false
}
},
subTitle: {
type: String,
default(){
return "小标题"
}
},
value: {
default(){
return ""
}
},
type: {
type: String,
default(){
return "number"
}
},
placeholder: {
type: String,
default(){
return ""
}
},
maxlength: {
type: String,
default(){
return "32"
}
},
clearIcon: {
type: Boolean,
default(){
return true
}
},
},
computed:{
changeHeight(){
return this.c_value? "30px":"50px"
}
},
methods:{
clearc_value(){
this.c_value = ""
}
}
}
</script>
<style>
.input-box{
width:750rpx;
padding:20rpx;
flex-direction: row;
align-items: center;
background-color:#FFFFFF;
}
.right-box{
width:600rpx;
padding-left:20rpx;
margin-right:10rpx;
}
.tip-title{
font-size:26rpx;
color:#999999;
}
.input-content{
flex-direction: row;
align-items: center;
}
.input{
flex:1;
font-size:30rpx;
}
</style>
<template>
<text class="underline" @click="navigator" :style="{color}">{{text}}</text>
</template>
<script>
export default {
methods:{
navigator(){
uni.navigateTo({
url:"/pages/webview/webview?url="+this.url
})
}
},
props: {
url: {
type: String,
default(){
return ''
}
},
text: {
type: String,
default(){
return ''
}
},
color: {
type: String,
default(){
return '#586b95'
}
},
},
}
</script>
<style>
.underline{
text-decoration: underline;
}
</style>
<template>
<view class="root" :style="{width,height}">
<image :style="{width,height}" class="posterImg" :src="posterUrl" mode="aspectFit"></image>
<view :style="{width,height}" @click="play" class="box">
<image class="playIcon" src="../../static/play.png" mode="widthFix"></image>
</view>
<video
id="myVideo"
style="width: 1px;height: 1px;"
:src="src"
@timeupdate="timeupdate"
@fullscreenchange="fullscreenchange"
></video>
</view>
</template>
<script>
var videoContext;
export default {
mounted() {
videoContext = uni.createVideoContext('myVideo',this)
},
computed:{
posterUrl(){
if(this.poster) return this.poster
return this.src + '?x-oss-process=video/snapshot,t_'+(parseInt(this.currentTime*1000))+',f_jpg,w_800,m_fast'
}
},
methods:{
fullscreenchange(e){
console.log(e.detail.fullScreen);
this.state = e.detail.fullScreen
if(!e.detail.fullScreen){
videoContext.pause()
}
},
timeupdate(e){
console.log(e.detail);
this.duration = e.detail.duration
this.currentTime = e.detail.currentTime
},
play(){
videoContext.play()
videoContext.requestFullScreen({direction:this.direction})
}
},
watch: {
},
data() {
return {
state:false,
currentTime:0,
duration:0,
videoId:''
};
},
props: {
poster: {
type: [String,Boolean],
default(){
return ''
}
},
src: {
type: String,
default(){
return ''
}
},
title: {
type: String,
default(){
return ''
}
},
direction: {
type: Number,
default(){
return -90
}
},
width: {
type: String,
default(){
return "750rpx";
}
},
height: {
type: String,
default(){
return "450rpx";
}
}
},
}
</script>
<style scoped>
.root{
position:relative;
width: 750rpx;
height: 300px;
overflow: hidden;
}
.posterImg,.video,.box{
display: flex;
width: 750rpx;
height: 300px;
position:absolute;
}
.posterImg{
}
.box{
justify-content: center;
align-items: center;
}
.playIcon{
width: 100rpx;
}
</style>
<template name="page-head">
<view>
<view class="uni-page-heads">
<view class="uni-page-heads-title">{{title}}</view>
</view>
<view class="row">
<view class="">{{subTitle}}</view>
</view>
</view>
</template>
<script>
export default {
name: "page-head",
props: {
title: {
type: String,
default: ""
},
subTitle: {
type: String,
default: ""
}
}
}
</script>
<style lang="scss" scoped>
.uni-page-heads{
padding:35rpx;
text-align: center;
}
.uni-page-heads-title {
display: inline-block;
padding: 0 40rpx;
font-size: 30rpx;
height: 88rpx;
line-height: 88rpx;
color: #5c5b5d;
box-sizing: border-box;
border-bottom: 2rpx solid #D8D8D8;
}
.row{
width: 750rpx;
text-align: center;
margin-top: -30rpx;
color: #999999;
}
</style>
<template>
<view class="root">
<view v-if="showGuide" class="guide"></view>
<view class="box" :style="{width:170*roles.length+'rpx'}">
<text class="roles-item" v-for="(item,index) in roles" :key="item.value"
:class="{active:activeIndex==index}"
@click="activeIndex=index"
>{{item.text}}</text>
<text class="active-box" :style="{'left':170*activeIndex+'rpx'}"></text>
<image @click="showGuide=false" v-if="showGuide" class="guide-img" src="../../static/jian.png" mode="aspectFit"></image>
<!-- <uni-data-checkbox style="margin: 20rpx;" v-model="role" :localdata="roles" /> -->
</view>
</view>
</template>
<script>
export default {
data() {
return {
activeIndex:null,
role: 0,
roles: [{
"value": 0,
"text": "未登陆"
},
{
"value": "user",
"text": "用户"
},
{
"value": "auditor",
"text": "审核员"
},
{
"value": "admin",
"text": "管理员"
}
],
showGuide:false
};
},
watch: {
async activeIndex(activeIndex, oldRole) {
let role = this.roles[activeIndex].value;
uni.showLoading({
title: '切换账号类型中',
mask: true
});
if (!activeIndex) {
let res = await this.logout()
console.log(res.result.msg);
uni.setStorageSync('role_index', activeIndex)
uni.setStorageSync('uni_id_token', false)
uni.setStorageSync('uni_id_uid', false)
uni.setStorageSync('uni_id_token_expired',false)
this.$emit('change',{role,index:activeIndex})
uni.hideLoading()
return false
}
uniCloud.callFunction({
name: "user-center",
data: {
action: 'login',
params: {
username: role,
password: "123456",
needPermission: true
}
},
complete: (res) => {
uni.setStorageSync('role_index', activeIndex)
uni.setStorageSync('uni_id_token', res.result.token)
uni.setStorageSync('uni_id_uid', res.result.uid)
uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)
this.$emit('change',{role,index:activeIndex,uid:res.result.uid})
uni.hideLoading()
}
})
}
},
async beforeDestroy() {
//uni.setStorageSync('uni_id_token', '')
//uni.setStorageSync('uni_id_token_expired', '')
},
mounted() {
this.activeIndex = uni.getStorageSync('role_index')||0;
},
methods: {
async logout() {
return await uniCloud.callFunction({
name: 'user-center',
data: {
action: 'logout'
}
})
},
init(activeIndex){
this.activeIndex = activeIndex;
}
},
}
</script>
<style scoped>
/* #ifndef APP-NVUE */
view,text{
display: flex;
}
/* #endif */
.root{
position: fixed;
bottom: 20px;
width: 750rpx;
align-items: center;
justify-content: center;
}
.box{
position: relative;
justify-content: space-between;
background-color: #ffffff;
flex-direction: row;
flex-grow: 0;
border-radius: 20px;
height: 40px;
align-items: center;
box-shadow: 1px 1px 10px #aaa;
z-index: 200;
overflow: hidden;
}
.roles-item,.active-box{
border-radius: 20px;
height: 40px;
line-height: 40px;
color: #aaa;
font-size: 16px;
transition: color 0.5s;
width: 170rpx;
justify-content: center;
z-index: 2;
}
.active{
color: #FFFFFF;
}
.active-box{
position: absolute;
background-color: #007AFF;
z-index: 1;
transition: left 0.3s;
font-size: 28rpx;
border-radius: 0;
height: 39.9px;
line-height: 39.9px;
}
.guide{
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
opacity: 0.7;
background-color: #333333;
z-index: 100;
}
.guide-img{
position: fixed;
width: 350rpx;
height: 350rpx;
bottom: 90px;
left: 100rpx;
}
</style>
<template>
<view style="background-color: #FFFAE7;">
<view class="column">
<view class="row" v-if="!isObject" :class="{'val':e!=':'}">
<text :class="[codesType]">{{codes}}</text>
<text>{{e}}</text>
</view>
<view v-else class="column">
<text v-if="isJson">{{L}}</text>
<text v-else>{{La}}</text>
<view v-for="(value,key,k) in codes" :key="key" class="pr ml" :style="{'left':kl*8*-1+'px'}">
<template v-if="isJson">
<show-code :codes="key" e=":"></show-code>
</template>
<!-- #ifdef MP -->
<show-code :codes="value" :last="false" :kl="key.length"></show-code>
<!-- #endif -->
<!-- #ifndef MP -->
<show-code :codes="value" :last="isLast(codes,key,k)" :e="isLast(codes,key,k)?'':','" :kl="key.length"></show-code>
<!-- #endif -->
</view>
<view class="row" :style="{'left':kl*8*-1+'px'}">
<text v-if="isJson">{{R}}</text>
<text v-else>{{Ra}}</text>
<text class="comma" v-if="!last">,</text>
</view>
</view>
</view>
</view>
</template>
<script>
// #ifdef VUE2
import showCode from '@/components/show-code/show-code.vue';
// #endif
export default {
name: "show-code",
// #ifdef VUE2
components: {
"show-code": showCode
},
// #endif
data() {
return {
L: "{",
R: "}",
La: "[",
Ra: "]"
}
},
computed: {
codesType() {
return this.tf(this.codes)
},
isJson(){
return this.tf(this.codes) == 'json'
},
isObject(){
return typeof(this.codes) == 'object'
}
},
methods: {
classNNN(){
return this.tf(this.codes)
},
tf(codes) {
let cType = typeof(codes)
if (cType == 'object') {
if (!codes) {
return 'null'
} else if (Array.isArray(codes)) {
return 'array'
} else {
return 'json'
}
} else {
return cType
}
},
isLast(codes,key,k){
if(this.isJson){
return Object.keys(codes).length == k+1
}else{
// console.log(codes.length,k);
return codes.length == k+1
}
}
},
props: {
codes: {
default () {
return {}
}
},
kl: {
type: Number,
default () {
return 0
}
},
e: {
default () {
return ","
}
},
last: {
default () {
return true
}
},
},
}
</script>
<style scoped>
view,
text {
display: flex;
}
.column {
flex-direction: column;
flex-shrink: 0;
}
.row {
position: relative;
}
.pr{
position: relative;
}
text{
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-weight: 500;
color: #555;
}
.string {
color: #2f897d;
}
.string::before {
content: '"';
}
.string::after {
content: '"';
}
.boolean{
color: #34629d;
}
text.string{
color: #447b15;
}
.val text.string{
color: #2f897d;
}
.number {
color: #9661ef;
}
.ml{
margin-left: 15px;
}
</style>
<template>
<view class="uni-section" nvue>
<view v-if="type" class="uni-section__head">
<view :class="type" class="uni-section__head-tag" />
</view>
<view class="uni-section__content">
<text :class="{'distraction':!subTitle}" class="uni-section__content-title">{{ title }}</text>
<text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text>
</view>
<slot />
</view>
</template>
<script>
/**
* Section 标题栏
* @description 标题栏
* @property {String} type = [line|circle] 标题装饰类型
* @value line 竖线
* @value circle 圆形
* @property {String} title 主标题
* @property {String} subTitle 副标题
*/
export default {
name: 'UniSection',
props: {
type: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
subTitle: {
type: String,
default: ''
}
},
data() {
return {}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style scoped>
.uni-section {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
margin-top: 10px;
flex-direction: row;
align-items: center;
padding: 6px 10px;
/* height: 50px; */
background-color: #f8f8f8;
/* #ifdef APP-NVUE */
/* #endif */
font-weight: normal;
}
/* #ifndef APP-NVUE */
/* #endif */
.uni-section__head {
flex-direction: row;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.line {
height: 15px;
background-color: #c0c0c0;
border-radius: 5px;
width: 3px;
}
.circle {
width: 8px;
height: 8px;
border-top-right-radius: 50px;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
background-color: #c0c0c0;
}
.uni-section__content {
flex-direction: column;
flex: 1;
color: #333;
min-height: 30px;
justify-content: center;
}
.uni-section__content-title {
font-size: 16px;
font-weight: 600;
color: #333;
}
.distraction {
flex-direction: row;
align-items: center;
}
.uni-section__content-sub {
font-size: 12px;
color: #999;
}
</style>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>
\ No newline at end of file
import parser from './parser.js'
import {
getSafeProxy,
ErrorWithCode
} from './utils'
const authCallBacks = {}
const dbCallBacks = {}
class Stage {
constructor (content, prevStage, actionName) {
this.content = content
this.prevStage = prevStage
this.actionName = actionName
}
toJSON () {
let tempStage = this
const stages = [tempStage.content]
while (tempStage.prevStage) {
tempStage = tempStage.prevStage
stages.push(tempStage.content)
}
return {
$db: stages.reverse().map((item) => {
return {
$method: item.$method,
$param: item.$param
}
})
}
}
get useAggregate () {
let tempStage = this
let useAggregate = false
while (tempStage.prevStage) {
tempStage = tempStage.prevStage
const methodName = tempStage.content.$method
if (methodName === 'aggregate' || methodName === 'pipeline') {
useAggregate = true
break
}
}
return useAggregate
}
// 聚合count特殊处理
get count () {
if (!this.useAggregate) {
return function () {
return this._send('count', Array.from(arguments))
}
}
const that = this
return function () {
return getDbIns({
$method: 'count',
$param: parser(Array.from(arguments))
}, that, that.actionName)
}
}
get () {
return this._send('get', Array.from(arguments))
}
add () {
return this._send('add', Array.from(arguments))
}
remove () {
return this._send('remove', Array.from(arguments))
}
update () {
return this._send('update', Array.from(arguments))
}
end () {
return this._send('end', Array.from(arguments))
}
set () {
throw new Error('客户端禁止使用set方法')
}
_send (method, param) {
const command = this.toJSON()
command.$db.push({
$method: method,
$param: param
})
return uniCloud.callFunction({
name: 'uni-clientDB',
data: {
action: this.actionName,
command
}
}).then(res => {
const {
code,
message,
token,
tokenExpired
} = res.result
if (code) {
return Promise.reject(new ErrorWithCode(message, code))
}
// 保持旧版兼容authCallBacks
if (token && tokenExpired && authCallBacks.refreshToken) {
authCallBacks.refreshToken.forEach(func => {
func({
token,
tokenExpired
})
})
}
// 新版支持dbCallBacks
if (token && tokenExpired && dbCallBacks.refreshToken) {
dbCallBacks.refreshToken.forEach(func => {
func({
token,
tokenExpired
})
})
}
return Promise.resolve(res)
}).catch(err => {
const error = new ErrorWithCode(err.message, err.code || 'SYSTEM_ERROR')
if (dbCallBacks.error) {
dbCallBacks.error.forEach(func => {
func(error)
})
}
if (/fc_function_not_found|FUNCTION_NOT_FOUND/g.test(err.message)) {
console.warn('clientDB未初始化,请在web控制台保存一次schema以开启clientDB')
}
return Promise.reject(err)
})
}
}
const propList = ['db.Geo', 'db.command', 'command.aggregate']
function isProp (prev, key) {
return propList.indexOf(`${prev}.${key}`) > -1
}
function getDbIns (content, prevStage, actionName) {
const stage = new Stage(content, prevStage, actionName)
return getSafeProxy(stage, {
get (stage, key) {
let prevMethod = 'db'
if (stage && stage.content) {
prevMethod = stage.content.$method
}
if (isProp(prevMethod, key)) {
return getDbIns({
$method: key
}, stage, actionName)
}
return function () {
return getDbIns({
$method: key,
$param: parser(Array.from(arguments))
}, stage, actionName)
}
}
})
}
function getDbClass ({
path,
method
}) {
return class {
constructor () {
this.param = Array.from(arguments)
}
toJSON () {
return {
$newDb: [
...path.map(prop => { return { $method: prop } }),
{
$method: method,
$param: this.param
}]
}
}
}
}
const db = {
auth: {
on: (event, func) => {
authCallBacks[event] = authCallBacks[event] || []
if (authCallBacks[event].indexOf(func) > -1) {
return
}
authCallBacks[event].push(func)
},
off: (event, func) => {
authCallBacks[event] = authCallBacks[event] || []
const index = authCallBacks[event].indexOf(func)
if (index === -1) {
return
}
authCallBacks[event].splice(index, 1)
}
},
on: (event, func) => {
dbCallBacks[event] = dbCallBacks[event] || []
if (dbCallBacks[event].indexOf(func) > -1) {
return
}
dbCallBacks[event].push(func)
},
off: (event, func) => {
dbCallBacks[event] = dbCallBacks[event] || []
const index = dbCallBacks[event].indexOf(func)
if (index === -1) {
return
}
dbCallBacks[event].splice(index, 1)
},
env: getSafeProxy({}, {
get (env, prop) {
return {
$env: prop
}
}
}),
action (actionName) {
return getSafeProxy({}, {
get (db, key) {
if (isProp('db', key)) {
return getDbIns({
$method: key
}, null, actionName)
}
return function () {
return getDbIns({
$method: key,
$param: parser(Array.from(arguments))
}, null, actionName)
}
}
})
},
Geo: getSafeProxy({}, {
get (Geo, key) {
return getDbClass({
path: ['Geo'],
method: key
})
}
}),
get serverDate () {
return getDbClass({
path: [],
method: 'serverDate'
})
},
get RegExp () {
return getDbClass({
path: [],
method: 'RegExp'
})
}
}
const database = getSafeProxy(db, {
get (db, key) {
if (isProp('db', key)) {
return getDbIns({
$method: key
})
}
return function () {
return getDbIns({
$method: key,
$param: parser(Array.from(arguments))
})
}
}
})
export default database
# clientDB使用许可协议
本协议是数字天堂(北京)网络技术有限公司(以下称“DCloud”)与您之间达成的关于clientDB框架(以下简称本框架)的协议。
本协议签订地点为中华人民共和国北京市海淀区。
您使用本框架即视为您已阅读并同意受本协议的约束。
## 知识产权及使用授权
您可以自由下载、使用、复制本框架而不需要向DCloud付费。
DCloud所拥有的知识产权,包括但不限于商标、专利、著作权、商业秘密、专有数据、源码,并不发生转移或共享。
您使用本框架开发的代码及输出物,包括但不限于网站、移动应用,其知识产权归属您所有。
本框架未包含第三方软件或技术,不涉及额外遵循第三方软件的授权协议问题。
## 您的义务
您不得破解、反编译、逆向工程本框架,不得破解或劫持本框架网络请求,不得对DCloud服务进行网络攻击,不得利用DCloud系统漏洞谋利或侵害DCloud利益,不得替换、删改本框架自带的非用户自定义文件。
未经书面许可您不可利用DCloud产品的全部或部分文件、模块、组件来制作与DCloud争夺用户的产品(通过DCloud插件市场服务开发者不属于此范围)。
如果您违反您的义务,DCloud将有权停止您使用本框架,造成的损失由您自行承担。
如果您给DCloud造成重大损失,或者在接收到DCloud的停止违约通知后拒不改正,DCloud将有权停止对您的DCloud所有产品和服务的使用授权,冻结您在DCloud所有产品服务中的预付款项和应收款项,因此造成的损失由您自行承担。
如果您的行为产生法律问题,DCloud有权追责您的法律责任。
## 隐私条款
本框架未进行任何数据采集、发送等涉及数据隐私的行为。
## 安全
您理解并同意,本框架同其他软件一样,无法承诺绝对的安全性。
当DCloud发现本框架的任何安全漏洞时,将及时在[社区](https://ask.dcloud.net.cn/explore/)发送公告,并将及时发布紧急更新补丁和升级推送通知。
## 免责声明
DCloud不因开发者使用本框架而承担任何法律责任。
## 协议修订
根据发展,DCloud可能会对本协议进行修改。修改时,DCloud会在产品或者网页中显著的位置发布相关信息以便及时通知到用户。如果您选择继续使用本框架,即表示您同意接受这些修改。
{
"name": "uni-client-db",
"version": "2.0.5",
"main": "index.js",
"keywords": [],
"author": "DCloud",
"license": "SEE LICENSE IN license.md",
"description": ""
}
\ No newline at end of file
import {
getType,
SYMBOL_CLIENT_DB_INTERNAL
} from './utils.js'
export default function parser (param) {
switch (getType(param)) {
case 'array':
return param.map(item => parser(item))
case 'object':
if (param._internalType === SYMBOL_CLIENT_DB_INTERNAL) {
return param
}
Object.keys(param).forEach(key => {
param[key] = parser(param[key])
})
return param
case 'regexp':
return {
$regexp: {
source: param.source,
flags: param.flags
}
}
case 'date':
return {
$date: param.toISOString()
}
default:
return param
}
}
export const SYMBOL_CLIENT_DB_INTERNAL = Symbol('CLIENT_DB_INTERNAL')
export function getType (val) {
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
}
// handler内先只实现get
export function getSafeProxy (target, handler) {
target.then = 'DoNotReturnProxyWithAFunctionNamedThen'
target._internalType = SYMBOL_CLIENT_DB_INTERNAL
return new Proxy(target, {
get (obj, key, rec) {
if (hasOwn(obj, key) || obj[key] || typeof key !== 'string') {
return obj[key]
}
return handler.get(obj, key, rec)
}
})
}
export function hasOwn (obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key)
}
export class ErrorWithCode extends Error {
constructor (message, code) {
super(message)
this.code = code
}
}
// 表单校验规则由 DB-Schema 生成,不建议直接修改校验规则,而建议通过 DB-Schema 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
import test1 from '@/js_sdk/validator/validateFunction/test1.js'
import test2 from '@/js_sdk/validator/validateFunction/test2.js'
export default {
"organization": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "个人",
"value": 0
},
{
"text": "公司",
"value": 1
}
]
}
],
"defaultValue": 0,
"label": "组织机构"
},
"text1": {
"rules": [
{
"format": "string"
},
{
validateFunction: test1
}
],
"label": "组织名称"
},
"text2": {
"rules": [
{
"format": "string"
},
{
validateFunction: test2
}
],
"label": "备注"
},
"text3": {
"rules": [
{
"format": "string",
"errorMessage": "只能输入中文"
},
{
"pattern": "[一-龥]",
"errorMessage": "只能输入中文"
}
],
"label": "姓名"
},
"email": {
"rules": [
{
"format": "string"
},
{
"format": "email"
}
],
"label": "邮箱账号"
},
"dowload_url": {
"rules": [
{
"format": "string"
},
{
"format": "url"
}
],
"label": "下载地址"
},
"enum_link": {
"rules": [
{
"format": "string"
}
],
"label": "选项来源data-list表"
},
"address": {
"rules": [
{
"format": "string"
}
],
"label": "地址"
},
"user_number": {
"rules": [
{
"format": "int"
},
{
"minimum": -100,
"maximum": 100,
"exclusiveMinimum": true
}
],
"label": "整数框"
},
"birth_date": {
"rules": [
{
"format": "timestamp"
}
],
"label": "生产日期"
},
"charge": {
"rules": [
{
"format": "bool"
}
],
"label": "开关"
},
"system": {
"rules": [
{
"format": "array"
},
{
"range": [
{
"text": "Mac",
"value": "Mac"
},
{
"text": "Windows",
"value": "Windows"
},
{
"text": "Linux",
"value": "Linux"
}
]
}
],
"label": "多选框"
}
}
// 表单校验规则由 DB-Schema 生成,不建议直接修改校验规则,而建议通过 DB-Schema 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
export default {
"nickname": {
"rules": [
{
"format": "string"
}
]
},
"username": {
"rules": [
{
"format": "string"
}
]
},
"state": {
"rules": [
{
"format": "int"
}
],
"defaultValue": 0
},
"phone": {
"rules": [
{
"format": "string"
}
]
}
}
// 表单校验规则由 DB-Schema 生成,不建议直接修改校验规则,而建议通过 DB-Schema 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
export default {
"username": {
"rules": [
{
"format": "string"
}
],
"label": "用户名"
},
"password_secret_version": {
"rules": [
{
"format": "int"
}
],
"label": "passwordSecret"
},
"nickname": {
"rules": [
{
"format": "string"
}
],
"label": "昵称"
},
"gender": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "未知",
"value": 0
},
{
"text": "",
"value": 1
},
{
"text": "",
"value": 2
}
]
}
],
"defaultValue": 0,
"label": "性别"
},
"status": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "正常",
"value": 0
},
{
"text": "禁用",
"value": 1
},
{
"text": "审核中",
"value": 2
},
{
"text": "审核拒绝",
"value": 3
}
]
}
],
"defaultValue": 0,
"label": "用户状态"
},
"mobile": {
"rules": [
{
"format": "string"
},
{
"pattern": "^\\+?[0-9-]{3,20}$"
}
],
"label": "手机号码"
},
"mobile_confirmed": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "未验证",
"value": 0
},
{
"text": "已验证",
"value": 1
}
]
}
],
"defaultValue": 0,
"label": "手机号验证状态"
},
"email": {
"rules": [
{
"format": "string"
},
{
"format": "email"
}
],
"label": "邮箱"
},
"email_confirmed": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "未验证",
"value": 0
},
{
"text": "已验证",
"value": 1
}
]
}
],
"defaultValue": 0,
"label": "邮箱验证状态"
},
"avatar": {
"rules": [
{
"format": "string"
}
],
"label": "头像地址"
},
"wx_unionid": {
"rules": [
{
"format": "string"
}
]
},
"wx_openid": {
"rules": [
{
"format": "object"
}
]
},
"ali_openid": {
"rules": [
{
"format": "string"
}
]
},
"comment": {
"rules": [
{
"format": "string"
}
],
"label": "备注"
},
"realname_auth": {
"rules": [
{
"format": "object"
}
]
},
"last_login_date": {
"rules": [
{
"format": "timestamp"
}
]
},
"last_login_ip": {
"rules": [
{
"format": "string"
}
]
},
"token": {
"rules": [
{
"format": "array"
}
]
},
"inviter_uid": {
"rules": [
{
"format": "array"
}
]
},
"my_invite_code": {
"rules": [
{
"format": "string"
}
]
}
}
// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
import word_filter from './validateFunction/word_filter.js'
const validator = {
"username": {
"rules": [
{
"format": "string",
"errorMessage": "只能输入中文"
},
{
"pattern": "^[\\u4e00-\\u9fa5]+$",
"errorMessage": "只能输入中文"
}
],
"label": "真实姓名"
},
"gender": {
"rules": [
{
"format": "int"
},
{
"range": [
{
"text": "未知",
"value": 0
},
{
"text": "",
"value": 1
},
{
"text": "",
"value": 2
}
]
}
],
"defaultValue": 0,
"label": "性别"
},
"birth_date": {
"rules": [
{
"format": "timestamp"
}
],
"label": "生日"
},
"weight": {
"rules": [
{
"format": "int"
},
{
"minimum": 50,
"maximum": 500,
"exclusiveMinimum": false,
"exclusiveMaximum": true
}
],
"label": "体重"
},
"mobile": {
"rules": [
{
"format": "string"
},
{
"pattern": "^\\+?[0-9-]{3,20}$"
}
],
"label": "手机号码"
},
"email": {
"rules": [
{
"format": "string"
},
{
"format": "email"
}
],
"label": "邮箱账号"
},
"url": {
"rules": [
{
"format": "string"
},
{
"format": "url"
}
],
"label": "个人博客"
},
"favorite_book_id": {
"rules": [
{
"format": "string"
}
],
"label": "喜欢的书"
},
"address_code": {
"rules": [
{
"format": "string"
}
],
"label": "地址"
},
"party_member": {
"rules": [
{
"format": "bool"
}
],
"label": "是否为党员"
},
"hobby": {
"rules": [
{
"format": "array"
},
{
"range": [
{
"text": "唱歌",
"value": "Sing"
},
{
"text": "跳舞",
"value": "dance"
},
{
"text": "画画",
"value": "draw"
}
]
}
],
"label": "业余爱好"
},
"comment": {
"rules": [
{
"format": "string"
},
{
validateFunction: word_filter
}
],
"label": "备注"
}
}
const enumConverter = {
"gender_valuetotext": {
"0": "未知",
"1": "",
"2": ""
},
"hobby_valuetotext": [
{
"text": "唱歌",
"value": "Sing"
},
{
"text": "跳舞",
"value": "dance"
},
{
"text": "画画",
"value": "draw"
}
]
}
function filterToWhere(filter, command) {
let where = {}
for (let field in filter) {
let { type, value } = filter[field]
switch (type) {
case "search":
if (typeof value === 'string' && value.length) {
where[field] = new RegExp(value)
}
break;
case "select":
if (value.length) {
let selectValue = []
for (let s of value) {
selectValue.push(command.eq(s))
}
where[field] = command.or(selectValue)
}
break;
case "range":
if (value.length) {
let gt = value[0]
let lt = value[1]
where[field] = command.and([command.gte(gt), command.lte(lt)])
}
break;
case "date":
if (value.length) {
let [s, e] = value
let startDate = new Date(s)
let endDate = new Date(e)
where[field] = command.and([command.gte(startDate), command.lte(endDate)])
}
break;
case "timestamp":
if (value.length) {
let [startDate, endDate] = value
where[field] = command.and([command.gte(startDate), command.lte(endDate)])
}
break;
}
}
return where
}
export { validator, enumConverter, filterToWhere }
// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
import type_name_check from '@/js_sdk/validator/validateFunction/type_name_check.js'
import word_filter from '@/js_sdk/validator/validateFunction/word_filter.js'
const validator = {
"type": {
"rules": [
{
"required": true
},
{
"format": "int"
},
{
"range": [
{
"text": "个人",
"value": 0
},
{
"text": "企业",
"value": 1
}
]
}
],
"label": "主体"
},
"type_name": {
"rules": [
{
"required": true
},
{
"format": "string"
},
{
validateFunction: type_name_check
}
],
"label": "主体名称"
},
"comment": {
"rules": [
{
"format": "string"
},
{
validateFunction: word_filter
}
],
"label": "备注"
},
"username": {
"rules": [
{
"format": "string",
"errorMessage": "只能输入中文"
},
{
"pattern": "[一-龥]",
"errorMessage": "只能输入中文"
}
],
"label": "负责人姓名"
},
"email": {
"rules": [
{
"format": "string"
},
{
"format": "email"
}
],
"label": "邮箱"
},
"dowload_url": {
"rules": [
{
"format": "string"
},
{
"format": "url"
}
],
"label": "下载地址"
},
"weight": {
"rules": [
{
"format": "int"
},
{
"minimum": 50,
"maximum": 500,
"exclusiveMinimum": false,
"exclusiveMaximum": true
}
],
"label": "体重"
},
"favorite_book": {
"rules": [
{
"format": "string"
}
],
"label": "喜欢的书"
},
"party_member": {
"rules": [
{
"format": "bool"
}
],
"label": "是否为党员"
},
"hobby": {
"rules": [
{
"format": "array"
},
{
"range": [
{
"text": "唱歌",
"value": "Sing"
},
{
"text": "跳舞",
"value": "dance"
},
{
"text": "画画",
"value": "draw"
}
]
}
],
"label": "业余爱好"
},
"address": {
"rules": [
{
"format": "string"
}
],
"label": "地址"
}
}
const enumConverter = {
"type_valuetotext": {
"0": "个人",
"1": "企业"
},
"hobby_valuetotext": [
{
"text": "唱歌",
"value": "Sing"
},
{
"text": "跳舞",
"value": "dance"
},
{
"text": "画画",
"value": "draw"
}
]
}
export { validator, enumConverter }
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema?id=validatefunction
// 扩展校验函数示例
module.exports = function (rule, value, data, callback) {
console.log('vvvvv',data);
if(data.type===0&&data.type_name.length>5){
callback('姓名不能超过5位数')
}
if(data.type===1&&data.type_name.length<4){
callback('企业名称不能低于4位数')
}
}
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema?id=validatefunction
// 扩展校验函数示例
module.exports = function (rule, value, data, callback) {
// rule 当前规则
// value 当前规则校验数据
// data 全部校验数据
// callback 可选,一般用于自定义 errorMessage,如果执行了callback return 值无效,callback 传入的 message 将替换 errorMessage
// callback(new Error('message')) 传入 Error 类型时校验不通过
// callback('message') 传入 String 类型时通过
//if(uniCloud.httpclient){
/* 你可以在此连接某个文字过滤api实现文字舆情管理 */
/* let apiUrl = "https://xxx"
const res = await uniCloud.httpclient.request(apiUrl, {
method: 'GET',
data: {},
dataType: 'text' // 指定返回值为json格式,自动进行parse
})
console.log(res); */
if (value.indexOf('test') != -1) {
return '拒绝,内容含有:test'
}
//}
}
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {createSSRApp} from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
\ No newline at end of file
{
"name" : "luke-unicloud",
"appid" : "",
"description" : "为开发者提供的基于 serverless 模式和 js 编程的云开发平台。示例代码",
"versionName" : "1.2.8",
"versionCode" : 21122901,
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {
"VideoPlayer" : {},
"OAuth" : {}
},
"distribute" : {
"android" : {
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
},
"ios" : {},
"sdkConfigs" : {
"maps" : {},
"ad" : {},
"share" : {},
"payment" : {},
"oauth" : {
"weixin" : {
"appid" : "",
"appsecret" : "",
"UniversalLinks" : ""
}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false,
"es6" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"h5" : {
"template" : "",
"router" : {
"mode" : "hash",
"base" : "/tcb/"
},
"sdkConfigs" : {
"maps" : {}
}
},
"vueVersion" : "2"
}
{
"id": "uni-cloud",
"displayName": "hello uniCloud",
"version": "1.3.1",
"description": "为开发者提供的基于 serverless 模式和 js 编程的云开发平台。示例代码",
"keywords": [
"uniCloud示例"
],
"repository": "https://gitee.com/dcloud/hello-uniCloud",
"engines": {
"HBuilderX": "^3.3.12"
},
"dcloudext": {
"category": [
"uniCloud",
"云端一体项目模板"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "y",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/cloudFunction/cloudFunction",
"style": {
"navigationBarTitleText": "云函数",
"enablePullDownRefresh": false
}
},
{
"path": "pages/cloudObject/cloudObject",
"style": {
"navigationBarTitleText": "云对象",
"enablePullDownRefresh": false
}
},
{
"path": "pages/test/test",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/unicloud-db-demo/unicloud-db-demo",
"style": {
"navigationBarTitleText": "unicloud-db demo",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/demo/demo",
"style": {
"navigationBarTitleText": "留言板",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission-table-simple/permission-table-simple",
"style": {
"navigationBarTitleText": "表级-简单权限控制",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission-table-compound/permission-table-compound",
"style": {
"navigationBarTitleText": "表级-复杂权限控制",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/clientDB",
"style": {
"navigationBarTitleText": "前端操作数据库",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user-info/add",
"style": {
"navigationBarTitleText": "新增"
}
}, {
"path": "pages/user-info/edit",
"style": {
"navigationBarTitleText": "修改"
}
}, {
"path": "pages/user-info/list",
"style": {
"navigationBarTitleText": "列表"
}
}, {
"path": "pages/user-info/detail",
"style": {
"navigationBarTitleText": "详情"
}
},
{
"path": "pages/storage/storage",
"style": {
"navigationBarTitleText": "云存储",
"enablePullDownRefresh": false
}
},
{
"path": "pages/schema2code/schema2code",
"style": {
"navigationBarTitleText": "schema2code",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission/permission",
"style": {
"navigationBarTitleText": "角色权限",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission-demo/permission-demo",
"style": {
"navigationBarTitleText": "角色权限",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission-demo/readme",
"style": {
"navigationBarTitleText": "角色权限",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/permission-field-simple/permission-field-simple",
"style": {
"navigationBarTitleText": "简单-字段级权限控制",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/clientDB-api/clientDB-api",
"style": {
"navigationBarTitleText": "前端操作数据库的API",
"enablePullDownRefresh": false
}
},
{
"path": "pages/clientDB/validate/validate",
"style": {
"navigationBarTitleText": "字段值域验证",
"enablePullDownRefresh": false
}
}, {
"path": "pages/validate-demo/add",
"style": {
"navigationBarTitleText": "新增"
}
}, {
"path": "pages/validate-demo/edit",
"style": {
"navigationBarTitleText": "修改"
}
}, {
"path": "pages/validate-demo/list",
"style": {
"navigationBarTitleText": ""
}
}, {
"path": "pages/validate-demo/detail",
"style": {}
}, {
"path": "pages/webview/webview",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
"style": {
"disableScroll": true,
"app-plus": {
"backgroundColorTop": "transparent",
"background": "transparent",
"titleNView": false,
"scrollIndicator": false,
"popGesture": "none",
"animationType": "fade-in",
"animationDuration": 200
}
}
}, {
"path": "pages/cloudFunction/redis/redis",
"style": {
"navigationBarTitleText": "扩展能力Redis",
"enablePullDownRefresh": false
}
}
],
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#1296db",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/cloudFunction/cloudFunction",
"iconPath": "static/tabbar/fn.png",
"selectedIconPath": "static/tabbar/fn1.png",
"text": "云函数"
},
{
"pagePath": "pages/cloudObject/cloudObject",
"iconPath": "static/tabbar/obj.png",
"selectedIconPath": "static/tabbar/obj1.png",
"text": "云对象"
},
{
"pagePath": "pages/storage/storage",
"iconPath": "static/tabbar/storage.png",
"selectedIconPath": "static/tabbar/storage1.png",
"text": "云存储"
},
{
"pagePath": "pages/clientDB/clientDB",
"iconPath": "static/tabbar/yun.png",
"selectedIconPath": "static/tabbar/yun1.png",
"text": "clientDB"
}, {
"pagePath": "pages/schema2code/schema2code",
"iconPath": "/static/tabbar/st-code.png",
"selectedIconPath": "static/tabbar/st-code1.png",
"text": "schema2code"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
}
}
<template>
<view>
<alertCode ref="alertCode"></alertCode>
<view class="tips">
<view>schema配置详见uniCloud-aliyun/database下的book.schema.json、order.schema.json</view>
</view>
<uni-section title="简单查询" subTitle="在符合schema设置的前提下,直接在前端查询云端数据库的数据" type="line"></uni-section>
<button @click="getData('book')" plain type="primary">查图书book表的数据</button>
<button @click="getData('order')" plain type="primary">查订单order表的数据</button>
<uni-section title="查询列表分页" subTitle="设置每页查询数量和页码查询" type="line"></uni-section>
<view class="item">
<text>页码:</text>
<uni-number-box class="num-box1" :min="1" @change="pageCurrent = $event/1" :value="pageCurrent">
</uni-number-box>
</view>
<view class="item">
<text>每页查询数量:</text>
<uni-number-box class="num-box2" :min="1" @change="pageSize = $event/1"
:value="pageSize"></uni-number-box>
</view>
<button @click="getPageData('order')" plain type="primary">分页查图书book表的数据</button>
<uni-section title="联表查询-订单和图书" subTitle="只需在db schema中,将两个表的关联字段建立映射关系,即可实现联表查询。" type="line">
</uni-section>
<button @click="getOrderByGetTemp" plain type="primary">数据表较大时,高性能查询</button>
<button @click="getOrder" plain type="primary">数据表较小时,便捷查询</button>
<uni-section title="getOne" subTitle="使用clientDB时可以在get方法内传入getOne:true来返回一条数据" type="line"></uni-section>
<button @click="getOneBook" plain type="primary">查询一本图书数据</button>
<uni-section title="getCount" subTitle="使用clientDB时可以在get方法内传入getCount:true来同时返回总数" type="line"></uni-section>
<button @click="getBookHasCount" plain type="primary">查询结果返回总数</button>
<uni-section title="field" subTitle="查询时可以使用field方法指定返回字段,在<uni-clientDB>组件中也支持field属性。不使用field方法时会返回所有字段"
type="line"></uni-section>
<button @click="getBookTitle" plain type="primary">仅查询图书数据的书名</button>
<!-- <uni-section title="loadMore" subTitle="查询列表分页" type="line"></uni-section>
<button @click="getUserData" type="primary">加载下一页</button>
<button @click="getUserData" type="primary">点击页码按钮切换不同页</button> -->
<uni-section title="name as cname" subTitle="如:author as book_author,意思是将数据库的author字段重命名为book_author"
type="line"></uni-section>
<button @click="getBookAs" plain type="primary">获得被设置别名的数据</button>
<uni-section title="orderBy" subTitle="orderBy方法内可以传入一个字符串来指定排序规则。如:订单表order根据quantity销量字段排序" type="line">
</uni-section>
<button @click="getOrderOrderBy('quantity asc')" type="primary" plain>按销量升序</button>
<button plain @click="getOrderOrderBy('create_date desc')" type="primary">按创建时间降序</button>
<button plain @click="getOrderOrderBy('quantity asc, create_date desc')" type="primary">销量相同时,按创建时间降序</button>
<uni-section title="查询树形数据"
subTitle="树形数据,在数据库里一般不会按照tree的层次来存储,因为按tree结构通过json对象的方式存储不同层级的数据,不利于对tree上的某个节点单独做增删改查。一般存储树形数据,tree上的每个节点都是一条单独的数据表记录,然后通过类似parent_id来表达父子关系。如部门的数据表,里面有2条数据,一条数据记录是“总部”,parent_id为空;另一条数据记录“一级部门A”,parent_id为总部的_id"
type="line"></uni-section>
<button plain @click="getTreeFn" type="primary">查询树形数据</button>
<uni-section title="新增数据记录add" subTitle="获取到db的表对象后,通过add方法新增数据记录" type="line"></uni-section>
<button @click="addData2TestDb()" plain type="primary">
<text>
在test表里新增一条
"data=当前时间戳"的记录
</text>
</button>
<button @click="addMoreData2TestDb()" plain type="primary">
<text>
在test表里新增5条
"data=随机数"的记录
</text>
</button>
<uni-section title="更新数据记录update" subTitle="collection.doc().update(Object data)" type="line"></uni-section>
<button @click="updateData2TestDb()" plain type="primary">
<text>
更新test表里的一条记录
</text>
</button>
<uni-section title="删除数据记录remove" subTitle="获取到db的表对象,然后指定要删除的记录,通过remove方法删除。" type="line"></uni-section>
<button @click="removeData2TestDb()" plain type="primary">
<text>
删除test表里的一条记录
</text>
</button>
<button @click="removeAllData2TestDb()" plain type="primary">
<text>
删除test表里的所有数据
</text>
</button>
</view>
</template>
<script>
const db = uniCloud.database();
export default {
data() {
return {
msg: {
result: {
data: ''
}
},
pageCurrent: 1,
pageSize: 2
}
},
methods: {
addMoreData2TestDb() {
uni.showLoading({
mask: false
});
let dataList = [];
for (var i = 0; i < 5; i++) {
dataList.push({
"data": Math.ceil(Math.random() * 999)
})
}
db.collection('test').add(dataList).then(res => {
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
},
addData2TestDb() {
uni.showLoading({
mask: false
});
db.collection('test').add({
data: Date.now()
}).then(res => {
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
},
updateData2TestDb() {
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
testDb.get({
getOne: true
}).then(({
result: {
data
}
}) => {
if (data) {
testDb.doc(data._id).update({
data: Date.now()
}).then(res => {
console.log(res);
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
} else {
uni.showToast({
title: 'test表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
})
},
removeData2TestDb() {
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
testDb.get({
getOne: true
}).then(({
result: {
data
}
}) => {
if (data) {
testDb.doc(data._id).remove().then(res => {
console.log(res);
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
} else {
uni.showToast({
title: 'test表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
})
},
async removeAllData2TestDb() {
let index = 1
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
let {
result: {
data
}
} = await testDb.get()
console.log(data);
if (data.length) {
//用一个不存在的条件来删除所有数据
let {
result: {
deleted
}
} = await testDb.where('data!="不存在的条件"').remove();
uni.showToast({
title: '成功删除' + deleted + '条数据!',
icon: 'none'
});
} else {
uni.showToast({
title: 'test表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
},
async getData(tableName) {
console.log(tableName);
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection(tableName)
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
console.log(res.result.data, "111");
return res.result.data
}).catch(err => {
console.error(err)
return err
})
.finally((e) => {
console.log(e, 9527);
uni.hideLoading()
})
},
async getOrderByGetTemp() {
//当数据表记录数较大时,务必使用本方法
uni.showLoading({mask: true});
const orderQuery = db.collection('order').field('book_id,quantity').getTemp() // 使用getTemp先过滤处理获取临时表再联表查询
const bookQuery = db.collection('book').field('_id,author,title').getTemp()
const res = await db.collection(orderQuery,bookQuery).field('book_id as books_info,quantity').get()
uni.hideLoading()
this.$refs.alertCode.open(res.result)
console.log(res.result.data, "111");
},
async getOrder() {
//直接关联多个表为虚拟表再进行查询。仅数据表字段内容较少时使用,否者将查询超时
uni.showLoading({mask: true});
// 客户端联表查询
return await db.collection('order,book') // 注意collection方法内需要传入所有用到的表名,用逗号分隔,主表需要放在第一位
//.where('book_id.title == "三国演义"') // 查询order表内书名为“三国演义”的订单
.field('book_id{title,author} as books_info,quantity') // 这里联表查询book表返回book表内的title、book表内的author、order表内的quantity
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
console.log(res.result.data, "111");
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getOneBook() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.get({
getOne: true
})
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getBookTitle() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.field('title')
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getBookAs() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.field('title,author as book_author')
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getOrderOrderBy(str) {
uni.showLoading({
mask: true
});
return await db.collection('order')
.orderBy(str)
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getBookHasCount() {
uni.showLoading({
mask: true
});
return await db.collection('book')
.get({
"getCount": true
})
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},
async getTreeFn() {
uni.showLoading({
mask: true
});
return await db.collection("department").get({
getTree: {
limitLevel: 10, // 最大查询层级(不包含当前层级),可以省略默认10级,最大15,最小1
// startWith: "parent_code==''" // 第一层级条件,此初始条件可以省略,不传startWith时默认从最顶级开始查询
}
})
.then((res) => {
const resdata = res.result.data
console.log("resdata", );
this.$refs.alertCode.open(resdata)
return resdata
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
return err
}).finally(() => {
uni.hideLoading()
})
},
async getPageData() {
uni.showLoading({
mask: false
});
let res = await db.collection("book")
.skip((this.pageCurrent - 1) * this.pageSize)
.limit(this.pageSize)
.get()
console.log(res);
this.$refs.alertCode.open(res.result.data)
uni.hideLoading()
return res.result.data
}
}
}
</script>
<style>
.tips {
color: #999999;
font-size: 14px;
padding: 15px 20px;
border: dashed 1px #EEEEEE;
border-radius: 5px;
margin: 10px;
}
button {
width: 500rpx;
margin: 10px 125rpx;
font-size: 16px;
}
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar {
width: 5px;
height: 5px;
background-color: #fafafa;
}
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
border-radius: 10px;
background-color: #fafafa;
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
background-color: #e1e0ed;
}
.item {
display: flex;
width: 750rpx;
justify-content: flex-start;
align-items: center;
padding-top: 20px;
padding-left: 36rpx;
flex-direction: row;
}
</style>
<template>
<view>
<uni-list>
<uni-list-item class="item" title="API操作数据库" note="增删改查、分页查询、联表查询、tree查询" to="./clientDB-api/clientDB-api" link>
<text slot="header" class="ico">&#xe650;</text>
</uni-list-item>
<uni-list-item class="item" title="unicloud-db组件" note="一个数据库查询组件,它是对clientDB的js库的再封装。前端通过组件方式直接获取uniCloud的云端数据库中的数据,并绑定在界面上进行渲染。" to="./unicloud-db-demo/unicloud-db-demo" link>
<text slot="header" class="ico">&#xe603;</text>
</uni-list-item>
<uni-list-item class="item" title="控制前端操作数据库的权限" note="从表级,字段级根据:账户角色、权限、记录字段、账户uid等控制操作权限" to="./permission/permission" link>
<text slot="header" class="ico">&#xe61f;</text>
</uni-list-item>
<uni-list-item class="item" title="字段值域校验" note="是否必填(required)、数据类型(bsonType)、数字范围(maximum、minimum)、字符串长度范围(minLength、maxLength)、format、pattern正则表达式" to="./validate/validate" link>
<text slot="header" class="ico">&#xe651;</text>
</uni-list-item>
<uni-list-item class="item" title="完整示例" to="./demo/demo" note="结合schema的api和组件前端操作数据库,权限控制,actions、foreignKey等,做一个:不同账户权限浏览、删除、审核的系统" link>
<text slot="header" class="ico">&#xe61b;</text>
</uni-list-item>
</uni-list>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.ico{
font-size: 14px;
color: #007AFF;
padding-right:6px;
margin-top: 5px;
}
</style>
<template>
<view class="page">
<uniNoticeBar v-if="noticeData.data" showIcon="true" :text="noticeData.data"></uniNoticeBar>
<text class="view_count">阅读量:{{noticeData.view_count}}</text>
<view class="hader-box">
<view class="let-box">
<text>体验说明</text>
<uni-icons size="14" color="#aaaaaa" @click="$refs.helpPopup.open()" type="info"></uni-icons>
</view>
<text @click="options.selfId?$refs.dialog.open():tipLogin()" class="comment-btn">写留言</text>
</view>
<unicloud-db ref="udb" v-slot:default="{data, loading, error, options}" :options="options" page-data="replace"
collection="comment,uni-id-users" field="uid{username,_id},text,_id,state" :where="options.where">
<scroll-view :show-scrollbar="true" scroll-y v-if="data.length" class="comment-list">
<view class="comment-item" v-for="(item,index) in data" :key="item._id">
<image class="userImg" :src="'../../../static/userImg/'+item.uid[0].username+'.png'" mode=""></image>
<view class="content">
<view style="flex-direction: column;">
<text style="color: #666;font-size: 14px;font-weight:700;">{{item.uid[0].username}}</text>
<text style="color: #888;font-size: 14px;">{{item.text}}</text>
</view>
<view style="flex-direction: row;">
<switch v-if="options.role.index>1" class="switch" :checked="item.state==1"
@change="updateState($event,item._id)" />
<template v-if="options.selfId == item.uid[0]._id || options.role.index>1">
<text class="in-review" v-if="options.role.index===1&&item.state==0">审核中</text>
<uni-icons v-else color="#cdcfd4" class="ico" size="16" type="compose"
@click="clickIcon(0,item)"></uni-icons>
<uni-icons color="#cdcfd4" class="ico" size="16" type="trash"
@click="clickIcon(1,item)"></uni-icons>
</template>
</view>
</view>
</view>
</scroll-view>
</unicloud-db>
<uni-popup ref="dialog" type="dialog">
<uni-popup-dialog mode="input" @confirm="submitComment" title="提交留言" placeholder="留言内容不能含单词test">
</uni-popup-dialog>
</uni-popup>
<uni-popup ref="upDataDialog" type="dialog">
<uni-popup-dialog mode="input" :value="defaultText" @confirm="updateComment" title="更新留言"
placeholder="留言内容不能含单词test"></uni-popup-dialog>
</uni-popup>
<uni-popup ref="helpPopup" type="center">
<uni-section title="demo说明" type="line"></uni-section>
<uni-list-item title="发表留言" note="未登陆用户不能发表留言,你可以尝试切换账号类型为未登陆,发表留言后会被拒绝请求" />
<uni-list-item title="敏感词过滤" note="发表留言内容含test会被拦截请求" />
<uni-list-item title="编辑/删除留言" note="限用户编辑或删除自己发表的留言.管理员可以删除/编辑任何人的留言" />
<uni-list-item title="公告的阅读量" note="1.读取,限登陆用户查看文章阅读量; \n 2.自增,阅读量自动增加由特殊的云函数add_view_count完成" />
<uni-list-item title="数据查询" note="完整留言数据,由comment,uni-id-users连张表,通过foreignKey联查获取" />
</uni-popup>
<set-permission @change="changePermission"></set-permission>
</view>
</template>
<script>
const db = uniCloud.database()
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue'
export default {
components: {
uniNoticeBar
},
data() {
return {
currentRole: 0,
options: {
"selfId": "",
"where": "state==1",
role: {
index: 0
},
},
noticeData: {
"_id": null
},
activeNoticeId: false,
defaultText: "",
fields: "data",
swipeActionOptions: [{
text: '编辑',
style: {
backgroundColor: '#007aff'
}
},
{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}
],
}
},
onLoad() {
this.getNoticeData()
},
onReady() {},
methods: {
tipLogin() {
uni.showModal({
content: '未登陆游客不能写留言!可在底部工具条切换成其他角色体验',
showCancel: false,
confirmText: "知道了"
});
},
changePermission(role) {
console.log("role: ", role);
this.options.selfId = role.uid
switch (role.index) {
case 0:
this.options.where = "state==1"
break;
case 1:
this.options.where = "state==1 || uid._id==$env.uid"
break;
case 2:
this.options.where = {}
break;
case 3:
this.options.where = {}
break;
default:
break;
}
this.options.role = role
this.currentRole = role.role
console.log("this.currentRole: ", this.currentRole);
},
async getNoticeData() {
let res = await db.action('add_view_count')
.collection('notice')
.field('data,_id,update_time,view_count')
.get();
this.noticeData = res.result.data[0]
},
async clickIcon(e, item) {
if (e) {
let res = await this.$refs.udb.remove(item._id);
return res
} else {
this.defaultText = item.text
this.activeNoticeId = item._id
this.$refs.upDataDialog.open()
}
},
async updateState(e, _id) {
console.log(e.detail.value, _id);
uni.showLoading({
mask: true
});
return await db.collection('comment')
.doc(_id)
.update({
"state": e.detail.value / 1
})
.then(({
code,
message
}) => {
uni.showToast({
title: '已切换为:' + (e.detail.value ? '审核通过' : '审核中'),
icon: 'none',
duration: 3000
});
console.log(code, message);
return message
}).catch(({
code,
message
}) => {
console.log(code, message);
return message
}).finally(e => {
uni.hideLoading()
this.$refs.upDataDialog.close()
return e
})
},
async updateComment(text) {
console.log(text);
console.log(this.activeNoticeId);
if (this.defaultText == text) {
uni.showToast({
title: '内容未被修改',
icon: 'none'
});
this.$refs.upDataDialog.close()
return false
}
uni.showLoading({
mask: true
});
return await this.$refs.udb.update(this.activeNoticeId, {
text
}, {
action: "up_comment",
toastTitle: '修改成功', // toast提示语
success: (res) => { // 更新成功后的回调
const {
code,
message
} = res
console.log(code, message);
//过度,后续unicloudDb的api会自动更新对应的数据
this.$refs.udb.dataList.forEach((item, index) => {
if (item._id == this.activeNoticeId) {
this.$refs.udb.dataList[index].text = text
if (this.options.role.index === 1) {
this.$refs.udb.dataList[index].state = 0
}
}
})
return message
},
fail: (err) => { // 更新失败后的回调
const {
message
} = err
return message
},
complete: () => { // 完成后的回调
uni.hideLoading()
this.$refs.upDataDialog.close()
}
})
},
async submitComment(text) {
console.log(text);
if (!text) {
uni.showToast({
title: '留言内容不能为空',
icon: 'none'
});
return false
}
this.$refs.dialog.close()
return await db.collection('comment').add({
text
}).then(res => {
console.log(res);
this.getNewData()
return res.result
}).catch(({
code,
message
}) => {
if (code == 'TOKEN_INVALID_ANONYMOUS_USER') {
uni.showModal({
content: '未登陆游客不能写留言',
showCancel: false
});
}
if (code == 'VALIDATION_ERROR') {
uni.showModal({
content: message,
showCancel: false
});
}
console.log(code, message);
return message
})
},
getNewData() {
//console.log(this.$refs.udb);
this.$refs.udb.refresh() //{clear:true}
},
getUserImg(e) {
switch (e) {
case "admin":
return '../../../static/userImg/2.png';
break;
case "user":
return '../../../static/userImg/0.png';
break;
case "auditor":
return '../../../static/userImg/1.png';
break;
default:
return '../../../static/userImg/0.png';
break;
}
},
}
}
</script>
<style scoped>
view {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
text {
font-size: 14px;
}
.icon {
font-size: 26rpx;
}
.page {
height: 100vh;
width: 750rpx;
overflow-x: hidden;
}
.row {
background-color: #FFFFFF;
flex-direction: row;
}
.let-box {
flex-direction: row;
color: #999999;
}
.let-box text,
.let-box icon {
line-height: 22px;
}
.bottom-box {
width: 650rpx;
padding: 0 50rpx;
bottom: 0;
position: fixed;
background-color: #FFFFFF;
flex-direction: column;
display: flex;
}
.ico {
margin-right: 10px;
}
.hader-box {
flex-direction: row;
justify-content: space-between;
padding: 10px;
}
.add-comment-box {
flex-direction: row;
}
.comment-list {
flex: 1;
width: 750rpx;
padding: 16rpx;
}
.comment-item {
width: 750rpx;
margin-bottom: 20px;
flex-direction: row;
}
.comment-item .content {
flex-direction: row;
width: 660rpx;
justify-content: space-between;
align-items: center;
padding-left: 16rpx;
}
.userImg {
width: 70rpx;
height: 70rpx;
border-radius: 100px;
background-color: #EFEFF4;
}
.comment-btn {
color: #586b95;
font-size: 16px;
}
.view_count {
font-size: 14px;
padding: 0 16rpx;
color: #666666;
}
.set-permission-box {
position: fixed;
width: 750rpx;
align-items: center;
bottom: 100px;
}
.switch {
transform: scale(0.7);
}
.in-review {
color: #DD524D;
margin-right: 15rpx;
}
</style>
<template>
<view class="page">
<view class="uni-container">
<uni-forms ref="form" :value="formData" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="nickname" label="昵称">
<uni-easyinput :disabled="rulo_index!=1" v-model="formData.nickname" />
</uni-forms-item>
<uni-forms-item name="username" label="姓名">
<uni-easyinput @click.native="formData.state==0?showTip():''" :disabled="rulo_index!=1||formData.state==0" v-model="formData.username" />
</uni-forms-item>
<uni-forms-item name="state" label="状态" v-if="rulo_index>0">
<uni-data-checkbox v-if="rulo_index>1" @change="setState" :value="formData.state" :multiple="false" :localdata='stateOption' />
<text class="tip">{{states}}</text>
<template v-if="rulo_index==1">
<text class="tip" v-if="formData.state">
\n你可以修改“姓名”数据,然后会再次进入“审核中”状态。审核期间,用户名不能修改。
</text>
<text class="tip" v-else>
\n审核期间,用户名不能修改。
你可以切换到管理员角色,更改审核状态后再来更新姓名内容。
但审核期间你可以更新你的昵称和电话数据
</text>
</template>
<text class="tip" v-if="rulo_index>1">
<text v-if="formData.state">
可以在底部工具条切换其他为用户角色,更新编辑姓名字段
</text>
<text v-else>你可以点击checkbox编辑审核状态</text>
</text>
</uni-forms-item>
<uni-forms-item name="phone" label="电话">
<uni-easyinput :disabled="!rulo_index===1" v-if="formData.phone" v-model="formData.phone" />
<text v-else class="tip">未登陆,账号获取不到phone字段,可以在底部工具条切换其他为用户角色查看</text>
</uni-forms-item>
<view class="uni-button-group" v-if="rulo_index===1&&formData._id">
<button type="primary" class="uni-button" @click="submit">更新</button>
</view>
</uni-forms>
</view>
<set-permission ref="set-permission" @change="changePermission"></set-permission>
</view>
</template>
<script>
import validator from '@/js_sdk/validator/permission-test.js';
//import db from '@/js_sdk/uni-clientDB/index.js'
const db = uniCloud.database();
const dbCmd = db.command;
const dbCollectionName = 'permission-test';
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: {
"_id": false,
"nickname": "",
"username": "",
"state": 0,
"phone": ""
},
formOptions: {},
rules: {
...getValidator(["nickname", "username", "state", "phone"])
},
stateOption: [
// {text:"审核中",value:0},
{
text: "审核通过",
value: 1
},
{
text: "审核拒绝",
value: -1
}
],
rulo_index: 0
}
},
mounted() {
this.$refs['set-permission'].init(1)
},
computed: {
states() {
let _text;
[{
text: "审核中",
value: 0
},
{
text: "审核通过",
value: 1
},
{
text: "审核拒绝",
value: -1
}
].forEach(({
text,
value
}) => {
if (value == this.formData.state) {
_text = text
}
})
return "当前为"+_text+"状态。\n"
}
},
methods: {
setState(e){
console.log(e.detail.value);
db.collection(dbCollectionName).update({
state:e.detail.value
}).then((res) => {
this.formData.state = e.detail.value
uni.showToast({
icon: 'none',
title: '更新成功'
})
}).catch((err) => {
console.log(err);
console.log(JSON.stringify(err));
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
showTip() {
uni.showToast({
title: '审核中不能编辑',
icon: 'none'
});
},
changePermission({role,index}){
console.log('index', index);
console.log('role', role);
this.rulo_index = index
let field = "_id,username,nickname,state";
let where = {}
if (index>0) {
field += ',phone';
}
if (index==1) {
where = "uid == $env.uid"
}
db.collection('permission-test')
.where(where)
.field(field).get().then(e => {
console.log(e.result.data);
if (e.result.data[0]){
this.formData = e.result.data[0]
}else{
uni.showLoading({
title: '正在初始化数据',
mask: false
});
this.addDefaultData()
}
}).catch((errors) => {
console.log(errors);
uni.hideLoading()
})
},
/**
* 触发表单提交
*/
submit() {
uni.showLoading({
mask: true
})
this.$refs.form.submit().then((res) => {
this.submitForm(res)
}).catch((errors) => {
uni.hideLoading()
})
},
addDefaultData() {
console.log('addDefaultData');
db.collection(dbCollectionName).add({
"nickname":"默认昵称",
"username":"默认姓名",
"phone":"1888888888"
}).then((res) => {
console.log(res.result.id);
this.formData._id = res.result.id
uni.showToast({
icon: 'none',
title: '新增成功'
})
this.$refs['set-permission'].init(0)
}).catch((err) => {
console.log(err);
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
submitForm(value) {
// 使用 uni-clientDB 提交数据
console.log('value._id------------------------------------------------------', this.formData._id);
if (this.formData._id) {
console.log(this.formData.state);
if(this.formData.state===0){
delete value.username
}
if (this.rulo_index <= 1) { //非管理员提交数据。state只能=0,即改状态为审核中,否则会被权限拒绝
delete value.state
}
console.log(value);
db.action('permission_test_update')
.collection(dbCollectionName)
.where("uid == $env.uid")
.update(value)
.then((res) => {
console.log( JSON.stringify(res.result) );
if (this.rulo_index <= 1 && res.result.changeState) { //非管理员提交数据。state只能=0,即改状态为审核中,否则会被权限拒绝
this.formData.state = 0
}
uni.showToast({
icon: 'none',
title: '更新成功'
})
console.log("33333333333: ",33333333333);
}).catch((err) => {
console.log(err.message);
console.log(JSON.stringify(err));
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
console.log("44444444: ",33333333333);
}).finally(() => {
uni.hideLoading()
console.log("5555555555: ",33333333333);
})
} else {
console.log('err 9527');
console.log("6666666666: ",33333333333);
}
}
}
}
</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;
}
.tip{
color: #DD524D;
}
</style>
|操作描述 |拥有权限的角色 |
|-- |-- |
|新增一条数据 {text:"demo"} |学生、管理员 |
|删除所有数据 |仅管理员 |
|改数据的text="pass" |老师、管理员 |
|改数据text="pass"的值为{text:"demo2"}|学生、管理员 |
|查数据 |学生、老师、管理员 |
|查字段text="demo2"的数据 |未登陆用户、学生、老师、管理员 |
<template>
<view class="page">
<alertCode ref="alertCode"></alertCode>
<uniNoticeBar showIcon="true" iconType="info" text="管理员(admin)拥有任何权限,权限控制对其无效。"></uniNoticeBar>
<view class="uni-title tip">
一、示例简介
<text>\n 演示了:
1.用户可以编辑自己的个人资料。
2.审核员,审核资料的username字段。
3.审核期间用户不能修改username字段。
4.未登陆的游客看不到用户的phone字段 \n \n</text>
二、需要的资源,schema路径:
<text>\n uniCloud/database/permission-test.schema.json \n \n</text>
三、数据的介绍,表字段:
<text>\n username(姓名), state(审核状态), nickname(昵称), phone(手机号码)</text>
</view>
<button @click="toDemo" plain type="primary">查看示例</button>
<view class="tips">
<text>DB Schema的permission规则,分为两部分,一边是对操作数据的指定,一边是对角色的指定,规则中对两者进行关联,匹配则校验通过。</text>
</view>
<page-head title="表级权限控制" subTitle="包括增删改查四种权限,分别称为:create、delete、update、read"></page-head>
<uni-section title="根据true和false控制数据库的相关操作" type="circle" ></uni-section>
<view class="uni-title pl10">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"permission":{
"read":true
}
}'></show-code>
</scroll-view>
<text>含义解释:允许任何账户读取本表</text>
</view>
<button @click="getFn('uid,username,nickname,state')" plain type="primary">读取表全部数据</button>
<view class="uni-title pl10">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"permission":{
"delete":false
}
}'></show-code>
</scroll-view>
<text>含义解释: 禁止任何账户执行删除表中的记录操作</text>
<text>\n 但管理员账号不受schema限制,可在底部工具条切换成管理员角色体验</text>
</view>
<button @click="removeFn" plain type="primary">删除全部记录数据</button>
<!-- 你可以尝试切换任何账号,点击如上:读取和删除按钮体验。 -->
<uni-section title="根据操作的用户id、角色和权限数组" type="circle" ></uni-section>
<view class="uni-title pl10">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"permission":{
"create":"auth.uid != null"
}
}'></show-code>
</scroll-view>
<text>含义解释:表示仅已登陆后的用户才能执行创建操作</text>
</view>
<button @click="addFn()" plain type="primary">创建一条数据</button>
<uni-section title="根据数据库中的目标数据记录"
type="circle"
></uni-section>
<view class="uni-title pl10 uni-common-mt">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"permission":{
"create":"auth.uid==doc.uid || AUDITOR in auth.role || UPDATE_USER_INFO in auth.permission"
}
}'></show-code>
</scroll-view>
<!--
<text>{</text>
<text space="emsp">\n "permission":{</text>
<text space="emsp">\n "update":</text>
<text class="light2" space="ensp">\n </text>
<text space="emsp">\n }\n</text>
<text space="emsp">}</text>
</view> -->
<text>含义解释:\n 1.数据创建者 \n 2.角色为审核员 \n 3.拥有编辑权限; \n 三种情况,拥有字段更新权限
</text>
</view>
<button @click="updateFn({nickname:'新昵称'},'uid == $env.uid')" plain type="primary"><text>更新nickname="新昵称"\n(仅当前用户为创建者的数据)</text></button>
<button @click="updateFn({nickname:'新昵称'})" plain type="primary"><text>更新nickname="新昵称"\n(表中全部数据)</text></button>
<page-head title="字段级权限控制"></page-head>
<uni-section title="修改指定字段需要特殊角色" type="circle" ></uni-section>
<view class="uni-title pl10 uni-common-mt">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"properties":{
"state":{
"permission":{
"write":"AUDITOR in auth.role"
}
}
}
}'></show-code>
</scroll-view>
<!-- <view class="code-box">
<text space="emsp">"properties":{</text>
<text space="emsp">\n "state":{</text>
<text space="emsp">\n "permission":{ </text>
<text space="emsp">\n "write":</text>
<text class="light2">"AUDITOR' in auth.role"</text>
<text space="emsp">\n }</text>
<text space="emsp">\n }</text>
<text space="emsp">\n}</text>
</view> -->
</view>
<button @click="updateFn({state:1})" plain type="primary"><text>更新 state = 1</text></button>
<view class="uni-title pl10 uni-common-mt">
<text>含义解释:限角色为审核员才能更新,字段state</text>
</view>
<uni-section title="修改指定字段时,当前记录的某个字段应当满足某种条件" type="circle" ></uni-section>
<view class="uni-title pl10 uni-common-mt">
<view>配置规则:</view><!-- 字段的: -->
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"properties":{
"username":{
"permission":{
"write":"doc.state != 0"
}
}
}
}'></show-code>
</scroll-view>
<!-- <view class="code-box">
<text space="emsp">"properties":{</text>
<text space="emsp">\n "username":{</text>
<text space="emsp">\n "permission":{ </text>
<text space="emsp">\n "write":</text>
<text class="light2">"doc.state != 0"</text>
<text space="emsp">\n }</text>
<text space="emsp">\n }</text>
<text space="emsp">\n}</text>
</view> -->
<text>含义解释:表示执行该操作需要满足,update的表级权限控制外,还需要满足正在被操作的记录的字段state!=0</text>
</view>
<button @click='updateFn({username:"新姓名"})' plain type="primary"><text>更新 username:'新姓名' \n(表中全部数据)</text></button>
<button @click='updateFn({username:"新姓名"},"uid == $env.uid")' plain type="primary"><text>更新 username:'新姓名' \n(仅当前角色为创建者的数据)</text></button>
<!-- <view class="uni-title pl10 uni-common-mt">
<view>注意:</view>
<text>新创建的数据,默认字段state=0,\n</text>
<text>通过按钮3,新建1条数据。然后通过按钮5执行本操作,你会得到被拒绝的提示。\n</text>
<text>如果你执行步骤改为,按钮3-4-5将会顺利执行当前操作:修改username</text>
</view> -->
<uni-section title="控制特殊字段不可读" type="circle"></uni-section>
<view class="uni-title pl10 uni-common-mt">
配置规则:<!-- phone字段的read:"auth.uid != null" -->
<scroll-view scroll-x class="code-box">
<show-code :codes='{
"properties":{
"phone":{
"permission":{
"read":"auth.uid != null"
}
}
}
}'></show-code>
</scroll-view>
<!-- <view class="code-box">
<text space="emsp">"properties":{</text>
<text space="emsp">\n "phone":{</text>
<text space="emsp">\n "permission":{ </text>
<text space="emsp">\n "read":</text>
<text class="light2">"auth.uid != null"</text>
<text space="emsp">\n }</text>
<text space="emsp">\n }</text>
<text space="emsp">\n}</text>
</view> -->
<text>含义解释:综合表级任何用户可读的条件下,新增了未登录游客不能读取phone字段</text>
</view>
<button @click="getFn('uid,username,nickname,state')" plain type="primary">读不带phone字段的数据</button>
<button @click="getFn('uid,username,nickname,state,phone')" plain type="primary">读带phone字段的数据</button>
<set-permission ref="set-permission" @change="changePermission"></set-permission>
</view>
</template>
<script>
//import db from '@/js_sdk/uni-clientDB/index.js'
const db = uniCloud.database()
const ptDb = db.collection('permission-test')
import alertCode from '@/components/alertCode/alertCode.vue';
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue'
export default {
components: {
uniNoticeBar,alertCode
},
data() {
return {
currentRole:""
}
},
mounted() {
uni.setStorageSync('uni_id_token', '')
uni.setStorageSync('uni_id_token_expired', '')
},
onShow() {
this.$nextTick(()=>{
this.$refs['set-permission'].init(0)
})
},
methods: {
toDemo(){
uni.navigateTo({
url:"./permission-demo"
})
},
previewImage(url){
uni.previewImage({
urls:[url]
})
},
async addFn(){
uni.showLoading({mask:true})
return await ptDb.add({
nickname:"默认昵称",
username:"默认姓名",
phone:"18888888888"
}).then(e=>{
console.log(e);
uni.showModal({
content: '成功写入一条数据:\n{ "nickname":"默认昵称",\n "username":"默认姓名",\n "phone":"18888888888" }',
showCancel: false,
confirmText:"知道了"
});
return e
}).catch(err=>{
console.log(err);
uni.showModal({
title:"未登录游客不能写入数据",
content: "请在底部工具条切换其他角色重试",
showCancel: false,
confirmText:"知道了"
});
return err
}).finally(() => {
uni.hideLoading()
})
},
async removeFn(){
uni.showLoading({mask:true})
return await ptDb.remove().then(e=>{
console.log(e,"123");
uni.showModal({
content: JSON.stringify(e.result),
showCancel: false,
confirmText:"知道了"
});
return e
}).catch(err=>{
console.log(JSON.stringify(err));
uni.showModal({
title:"当前角色没有该权限",
content: `管理员角色不受schema限制,请在底部工具条切换为管理员角色重试`,
showCancel: false,
confirmText:"知道了"
});
return err
}).finally(() => {
uni.hideLoading()
})
},
updateNickname(self){
},
async updateFn(data,where={}){
console.log("data");
console.log(data);
uni.showLoading({mask:true})
return await ptDb
.where(where)
.update(data)
.then(e=>{
console.log(e);
uni.showModal({
content: JSON.stringify(e.result),
showCancel: false,
confirmText:"知道了"
});
return e
}).catch(err=>{
if('nickname' in data){
uni.showModal({
title:"被拒绝,普通用户角色,只能更新自己创建的数据。",
content: '请在底部工具条切换为审核员角色重试',
showCancel: false,
confirmText:"知道了"
});
}else if('state' in data){
uni.showModal({
title:"当前角色无该操作权限",
content: '请在底部工具条切换为审核员角色重试',
showCancel: false,
confirmText:"知道了"
});
}else if("username" in data){
if(Object.keys(where).length === 0){
uni.showModal({
title:"根据表级updat权限设置,普通用户角色限更新自己的数据",
content:"请在底部工具条切换为审核员角色重试",
showCancel:false,
confirmText:"知道了"
})
}else{
uni.showModal({
title:"被拒绝,更新的数据含字段state==0的数据",
content:"请在底部工具条切换为审核员角色,将全部数据的state更新为1后重试",
showCancel:false,
confirmText:"知道了"
});
}
}else{
uni.showModal({
title:err.message,
showCancel: false,
confirmText:"知道了"
});
}
console.log("错误------",err);
console.log("错误------",err.message);
return err
//console.log(err);
/*
*/
/* uni.showModal({
title:"执行更新操作失败!",
content: "schema配置了,更新该字段限:\n 1、数据创建者,2、审核员,3、当然还有无任何权限限制的管理员",
showCancel: false,
confirmText:"知道了"
}); */
}).finally(() => {
uni.hideLoading()
})
},
async getFn(field='uid,username,nickname,state'){
// console.time('getFn');
uni.showLoading({mask:true})
return await ptDb.field(field).get()
.then(e=>{
// console.timeEnd('getFn');
console.log(e,"1111");
if(e.result.data.length){
console.log(e.result.data.length);
//console.log(this.$refs.alertCode);
this.$refs.alertCode.open(e.result.data)
}else{
uni.showModal({
title:"查询执行成功",
content:"但目前数据库为空,\n 请滚动页面找到【创建一条数据】点击后重试!",
showCancel: false,
confirmText:"知道了"
});
}
return e.result
}).catch(err=>{
// console.timeEnd('getFn');
console.log(err,"err---");
uni.showModal({
title:"当前角色无权访问含phone字段数据",
content: "请在底部工具条切换其他角色重试",
showCancel: false,
confirmText:"知道了"
});
return err
}).finally(() => {
uni.hideLoading()
})
},
changePermission(e){
console.log(e, '切换完成');
this.currentRole = e.role
console.log("this.currentRole",this.currentRole);
}
}
}
</script>
<style scoped>
.code-box{
background-color:#fffae7;
padding:5px 15px;
width: 600rpx;
}
.navigator{
padding: 16rpx;
color: #586b95;
}
.page{
padding-bottom: 100px;
background-color: #FFFFFF;font-size: 12px;
}
.tip{
border: dashed 1px #EEEEEE;
border-radius: 5px;
}
.uni-title {
width: 700rpx;
margin:0 25rpx;
font-size:12px;
font-weight:500;
padding:8rpx 20rpx;
line-height:1.5;
}
.uni-title text{
font-size:24rpx;
color:#888;
word-break: break-word;
}
.pl10{
padding-left: 20rpx;
}
.title {
color: #555555;
font-size: 16px;
padding:10px 10px;
}
.tips {
color: #444;
font-size: 14px;
padding:10px 20px;
}
.btn-box{
}
button{
width: 480rpx;
margin:10px auto;
font-size: 14px;
text-align: center;
line-height: 22px;
padding: 10rpx;
}
</style>
<template>
<view class="page">
<view class="top-view">
<uniNoticeBar showIcon="true" iconType="info" text="管理员(admin)拥有任何权限,权限控制对其无效。"></uniNoticeBar>
<uni-segmented-control @clickItem="typeIndex = $event.currentIndex" :values="types.map(({text})=>text)"></uni-segmented-control>
</view>
<alertCode ref="alertCode"></alertCode>
<template v-for="(item,index) in permissionList">
<view class="item" v-if="item.exclude !== type">
<view class="msg">{{item.msg}}</view>
<text style="color: #999999;">schema路径:uniCloud/database/permission-test-{{index+10}}.schema.json\n</text>
<view class="code">
配置规则
<scroll-view scroll-x class="code-box">
<show-code :codes="item.codes[type]"></show-code>
</scroll-view>
<text>含义解释:{{item.explain}}</text>
<text>{{typeText}}</text>
<text>{{item.explain_end}}</text>
</view>
<button type="primary" size="mini" plain @click="myFn({type,index})">
{{typeText}}
<text v-if="type!='create'">记录全部字段</text>
<text v-else>一条记录</text>
</button>
<template v-if="[0,1,2].includes(index)">
<button type="primary" size="mini" @click="myFn({type,index,field:'_id,state,create_time,text'})">{{typeText}}不含字段{{item.field}}的记录</button>
</template>
</view>
</template>
<set-permission @change="changePermission"></set-permission>
</view>
</template>
<script>
const db = uniCloud.database()
import alertCode from '@/components/alertCode/alertCode.vue';
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue'
export default {
components: {
uniNoticeBar,alertCode
},
computed: {
type() {
return this.types[this.typeIndex].value
},
typeText() {
return this.types[this.typeIndex].text
}
},
data() {
return {
currentRole:0,
types: [{
text: "创建",
value: "create"
},
{
text: "读取",
value: "read"
},
{
text: "更新",
value: "update"
},
/* {
text: "删除",
value: "delete"
} */
],
typeIndex: 0,
permissionList: [
{
"msg": "直接禁止",
"field":"ip",
"code": false,
"explain": "禁止任何角色",
"explain_end": "含字段ip的记录,管理员角色除外"
},
{
"msg": "需要登陆",
"field":"ip",
"code": "auth.uid != null",
"explain": "禁止未登陆的游客",
"explain_end": "含字段ip的记录"
},
{
"msg": "指定角色",
"field":"ip",
"code": "'AUDITOR' in auth.role",
"explain": "限角色为审核",
"explain_end": "含字段【ip】的记录"
}
]
}
},
created() {
for (var j = 0; j < this.types.length; j++) {
let type = this.types[j].value
console.log(type);
for (let i = 0; i < this.permissionList.length; i++) {
let jsonString = `{
"properties":{
"${this.permissionList[i].field}":{
"permission":{
"${type}":"${this.permissionList[i].code}"
}
}
}
}`
if(!this.permissionList[i].codes) this.permissionList[i].codes = {}
this.permissionList[i].codes[type] = JSON.parse(jsonString)
}
}
console.log(this.permissionList);
},
mounted() {
uni.setStorageSync('uni_id_token', '')
uni.setStorageSync('uni_id_token_expired', '')
},
methods: {
async myFn(e) { // {type:'',tableName:'',index,action:'',where:{}}
console.log('myFun' + JSON.stringify(e));
e.where = e.where || {}
e.field = e.field || '_id,state,create_time,text,ip'
let item = this.permissionList[e.index]
let tableName = item.tableName || 'permission-test-' + (e.index + 10)
uni.showLoading({
mask: true
});
let hasIp = {}
if(e.field.indexOf('ip') != -1){
hasIp = {"ip":"虚拟ip"+Date.now()};
}
console.log(
'表名称:' + tableName +
',操作:' + this.typeText +
'\n 条件:' + JSON.stringify(e.where),
'\n field:'+ e.field,
'\n data:'+ JSON.stringify({
"text": "数据" + Date.now(),
...hasIp
}),
);
let res;
try {
switch (e.type) {
case 'read':
res = await db.action(e.action).collection(tableName).field(e.field).where(e.where).get()
return res
break;
case 'create':
res = await db.action(e.action).collection(tableName)
.add({
"text": "默认写入的数据" + Date.now(),
...hasIp
})
return res
break;
case 'update':
res = await db.action(e.action).collection(tableName).where(e.where)
.update({
"text": "更新后的数据" + Date.now(),
...hasIp
})
return res
break;
case 'delete':
res = await db.action(e.action).collection(tableName).where(e.where).remove()
return res
break;
default:
console.log('err 未定义事件类型');
break;
}
} catch (err) {
console.log('TODO handle the exception', err);
uni.showModal({
title: '错误:' + err.message+','+ err.code,
content: item.explain +''+ this.typeText+'字段'+item.field+'' + (item.explain_end?item.explain_end:''),
showCancel: false
});
//return false
return err.message
} finally{
uni.hideLoading()
}
this.$refs.alertCode.open(res.result)
},
changePermission(e) {
console.log(e, '切换完成');
console.log("this.typeIndex: ",this.typeIndex);
this.currentRole = e.role
console.log("this.currentRole",this.currentRole);
}
}
}
</script>
<style scoped>
.top-view {
background-color: #FFFFFF;
position: sticky;
top: 0;
/* #ifdef H5 */
top: 44px;
/* #endif */
left: 0;
z-index: 999;
}
.top-view .segmented-control {
padding: 0 20rpx;
}
.item {
padding: 20rpx 20rpx 0 20rpx;
border-bottom: dashed 1px #E9E9EB;
}
.msg{
font-weight: 500;
font-size: 16px;
}
.msg::before{
content:'·';
width: 10px;
height: 10px;
line-height: 14px;
top: 5px;
position: relative;
font-size: 30px;
}
.code-box {
background-color: #fffae7;
padding: 5px 30rpx;
width: 650rpx;
}
.code-box text {
font-size: 16px !important;
color: #2b8300 !important;
}
.code-box .light {
color: #0077cc !important;
}
.code-box .light2 {
color: #009891 !important;
}
.navigator {
padding: 16rpx;
color: #586b95;
}
.page {
padding-bottom: 100px;
background-color: #FFFFFF;
font-size: 14px;
}
button {
margin: 8rpx 16rpx;
}
</style>
<template>
<view class="page">
<view class="top-view">
<uniNoticeBar showIcon="true" iconType="info" text="管理员(admin)拥有任何权限,权限控制对其无效。"></uniNoticeBar>
<uni-segmented-control @clickItem="typeIndex = $event.currentIndex" :current="typeIndex" :values="types.map(({text})=>text)"></uni-segmented-control>
</view>
<alertCode ref="alertCode"></alertCode>
<template v-for="(item,index) in permissionList">
<view class="item" v-if="item.exclude !== type">
<view class="msg">{{item.msg}}</view>
<text style="color: #999999;">schema路径:uniCloud/database/permission-test-{{index+8}}.schema.json\n</text>
<view class="code">
配置规则:
<scroll-view scroll-x class="code-box">
<show-code :codes="item.codes[type]"></show-code>
</scroll-view>
<text>含义解释:{{item.explain}}</text>
<text>{{types[typeIndex].text}}</text>
<text>{{item.explain_end}}</text>
</view>
<template v-if="index===0&&type!='create'">
<button type="primary" size="mini" @click="myFn({type:'create',index})">创建数据</button>
<button type="primary" size="mini" @click="myFn({type:'read',index,where:'create_time > '+(Date.now()-60000)})">{{typeText}}一分钟内的数据</button>
</template>
<button type="primary" size="mini" plain @click="myFn({type,index})">
{{types[typeIndex].text}}
<text v-if="type!='create'">表全部数据</text>
<text v-else>一条记录</text>
</button>
<template v-if="index===1">
<button type="primary" size="mini" @click="myFn({type,index,action:'add_view_count'})">带action{{types[typeIndex].text}}</button>
</template>
</view>
</template>
<set-permission @change="changePermission"></set-permission>
</view>
</template>
<script>
const db = uniCloud.database()
import alertCode from '@/components/alertCode/alertCode.vue';
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue'
export default {
components: {
uniNoticeBar,alertCode
},
computed: {
type() {
return this.types[this.typeIndex].value
},
typeText() {
return this.types[this.typeIndex].text
}
},
created() {
for (var j = 0; j < this.types.length; j++) {
let type = this.types[j].value
console.log(type);
for (let i = 0; i < this.permissionList.length; i++) {
let jsonString = `{
"permission":{
"${type}":"${this.permissionList[i].code}"
}
}`
if(!this.permissionList[i].codes) this.permissionList[i].codes = {}
this.permissionList[i].codes[type] = JSON.parse(jsonString)
}
}
console.log(this.permissionList);
},
data() {
return {
currentRole:0,
types:[
{
text:"创建",
value:"create"
},
{
text:"读取",
value:"read"
},
{
text:"更新",
value:"update"
},
{
text:"删除",
value:"delete"
}
],
typeIndex:0,
permissionList: [
{
"msg": "交集表达式",
"code": "doc.create_time > (now - 60000) && 'AUDITOR' in auth.role",
"explain": "限1分钟内的数据,“且”角色必须为审核员",
"exclude":"create"
},
{
"msg": "并集表达式",
"code": "auth.uid != null || 'add_view_count' in action",
"explain": "限非未登陆的游客,“或”带action",
"tableName":"permission-test-9"
}
]
}
},
mounted() {
uni.setStorageSync('uni_id_token', '')
uni.setStorageSync('uni_id_token_expired', '')
},
methods: {
async myFn(e) { // {type:'',tableName:'',index,action:'',where:{}}
console.log('myFun' + JSON.stringify(e));
e.where = e.where || {}
let item = this.permissionList[e.index]
let tableName = item.tableName || 'permission-test-' + (e.index + 8)
uni.showLoading({
mask: true
});
console.log(
'表名称:' + tableName +
'\n 条件:' + JSON.stringify(e.where)
);
let res;
try {
switch (e.type) {
case 'read':
res = await db.action(e.action).collection(tableName).where(e.where).get()
if(res.result.data.length == 0){
uni.showModal({
title: "数据为空,请先点击创建数据",
showCancel: false
});
return false
}
return res
break;
case 'create':
res = await db.action(e.action).collection(tableName).add({
"text": "默认写入的数据" + Date.now()
})
break;
case 'update':
res = await db.action(e.action).collection(tableName).where(e.where).update({
"text": "更新后的数据" + Date.now()
})
break;
case 'delete':
res = await db.action(e.action).collection(tableName).where(e.where).remove()
break;
default:
console.log('err 未定义事件类型');
break;
}
} catch (err) {
console.log('TODO handle the exception', err);
uni.showModal({
title: '错误:' + err.message+','+ err.code,
content: item.explain +''+ this.typeText+'数据】' + (item.explain_end?item.explain_end:''),
showCancel: false
});
//return false
return err.message
} finally{
uni.hideLoading()
}
this.$refs.alertCode.open(res.result)
},
changePermission(e) {
console.log(e, '切换完成');
console.log("this.typeIndex: ",this.typeIndex);
this.currentRole = e.role
console.log("this.currentRole",this.currentRole);
}
}
}
</script>
<style scoped>
.top-view{
background-color: #FFFFFF;
position: sticky;
top: 0;
/* #ifdef H5 */
top: 44px;
/* #endif */
left: 0;
z-index: 999;
}
.top-view .segmented-control{
padding: 0 20rpx;
}
.item {
padding:20rpx 20rpx 0 20rpx;
border-bottom: dashed 1px #E9E9EB;
}
.msg{
font-weight: 500;
font-size: 16px;
}
.msg::before{
content:'·';
width: 10px;
height: 10px;
line-height: 14px;
top: 5px;
position: relative;
font-size: 30px;
}
.code-box {
background-color: #fffae7;
padding: 5px 15px;
width: 650rpx;
}
.code-box text {
font-size: 16px !important;
color: #2b8300 !important;
}
.code-box .light {
color: #0077cc !important;
}
.code-box .light2 {
color: #009891 !important;
}
.navigator {
padding: 16rpx;
color: #586b95;
}
.page {
padding-bottom: 100px;
background-color: #FFFFFF;
font-size: 14px;
}
button{
margin: 8rpx 16rpx;
}
</style>
<template>
<view class="page">
<view class="tips">
<text>
DB Schema的permission规则,分为两部分,一边是对操作数据的指定,一边是对角色的指定,规则中对两者进行关联,匹配则校验通过。\n
</text>
<text>权限中的角色基于uni-id </text>
<j-link text="详情" url="https://uniapp.dcloud.io/uniCloud/uni-id"></j-link>
</view>
<uni-list-item class="table-item" title="表级-简单表达式权限控制" to="../permission-table-simple/permission-table-simple" link></uni-list-item>
<uni-list-item class="table-item" title="表级-组合表达式权限控制" to="../permission-table-compound/permission-table-compound" link></uni-list-item>
<uni-list-item class="table-item" title="字段级-简单表达式权限控制" to="../permission-field-simple/permission-field-simple" link></uni-list-item>
<uni-list-item class="table-item" title="组合表与字段级权限控制示例项目" to="../permission-demo/readme" link></uni-list-item>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
.tips {
color: #999999;
font-size: 14px;
padding: 10px 20px;
}
</style>
此差异已折叠。
<template>
<view class="page">
<uni-segmented-control class="segmented-control" :current="current" :values="items" @clickItem="clickItem"></uni-segmented-control>
<view class="content">
<view v-show="current === 0">
<myForm></myForm>
</view>
<view v-show="current === 1">
<uni-list>
<uni-section title="函数验证器 validateFunction" type="line"></uni-section>
<uni-list-item title="表级跨字段动态验证" rightText="主体名称" note="这是一种可跨字段的表级验证器,会随着表中其中一个字段的值改变另一个字段的验证规则;如:主体为企业、个人时分别设置验证规则。\n 个人:最多输入5个字;企业:最少输入4个字。\n 你可以尝试切换不同的主体类型,输入主体名称测试" />
<uni-list-item title="可联网的验证" rightText="备注" note="典型功能:敏感词过滤.需要连网调用api验证。" />
<uni-section title="常规验证 pattern" type="line"></uni-section>
<uni-list-item title="正则验证" rightText="姓名" note="通过正则表达式满足各类验证需求" />
<uni-section title="内置验证器format" type="line"></uni-section>
<uni-list-item title="邮箱、网址" note="后续会持续新增" rightText="email、url" />
<uni-section title="数据类型 bsonType" type="line"></uni-section>
<uni-list-item title="整数" note='数值框,如本示例中的体重' rightText="int" />
<uni-list-item title="数组" note='如:单选/多选框,如本示例中的喜欢的书和体重' rightText="array" />
<uni-list-item title="布尔值" note='如:开关switch,如本示例中的是否党员' rightText="bool" />
<uni-section title="数值规范" type="line"></uni-section>
<uni-list-item title="数值范围" note="最大值:maximum,最小值minimum \n 含最大值exclusiveMaximum,含最小值exclusiveMinimum" />
<uni-list-item title="字符串长度" note="maxLength限输入的文本长度不超过10" />
<uni-list-item title="是否必填" note="required:[type, type_name]列举必填字段" rightText="文本框、slider" />
</uni-list>
</view>
<view v-show="current === 2">
<uni-section title="enum完全列举" type="line"></uni-section>
<uni-list-item title="完全列举范围" note="enum支持三种类型:简单数组、支持描述的复杂数组、数据查询; \n schema2code不支持简单数组" rightText="多选单选框" />
<uni-list-item title="来源数据查询" note="一个数据查询而来。也即,在enum中可以配置jql查询语句。本示例的地址就是从表opendb-city-china中查询" rightText="地址" />
<uni-section title="设置变量的值" type="line"></uni-section>
<uni-list-item title="预置字段值 defaultValue" note="为字段设置默认值,可用schema直接修改" rightText="" />
<uni-list-item title="强制字段值 forceDefaultValue" note="强制设置字段值,无法用schema直接修改;但可以通过云函数(含action)修改。支持插入:当前时间戳、当前客户端IP、当前用户Id。"
rightText="" />
</view>
</view>
</view>
</template>
<script>
import myForm from '../../validate-demo/add.vue';
/*
注意:“myForm”是由schema2code生成的页面,为演示说明需要将页面作为组件放到 /pages/clientDB/validate内
故本示例修改了onReady为mounted,并关闭了 140-141行代码,关于提交数据并返回到页面的逻辑
*/
export default {
components: {
myForm
},
data() {
return {
items: ['实例demo', '值校验文档', '域校验文档'],
current: 0
}
},
methods: {
clickItem(e) {
console.log(e);
this.current = e.currentIndex
}
}
}
</script>
<style scoped>
.page {
padding-top: 45px;
}
.segmented-control {
//margin-top: -45px;
background-color: #FFFFFF;
position: fixed;
width: 700rpx;
left: 25rpx;
top: 0;
/* #ifdef H5 */
top: 45px;
/* #endif */
z-index: 99;
}
pre {
padding: 16rpx 26rpx;
white-space: pre-wrap;
}
</style>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册