Skip to content

Commit

Permalink
Merge branch 'master' of github.com:szuprefix/vue-django
Browse files Browse the repository at this point in the history
  • Loading branch information
szuprefix committed Jun 8, 2021
2 parents ee013e0 + 8717329 commit 7e10a98
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-django",
"version": "0.9.4",
"version": "0.9.5",
"description": "个人实验项目, 本框架的目标是借鉴并超越django admin的自动化思想, 实现UI前端的极简快速定制开发",
"main": "index.js",
"files": [
Expand Down
27 changes: 17 additions & 10 deletions src/components/form/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,25 @@ export const defaultProps = {
type: String, default: '提交'
}
}
export function joinErrors (errors) {
export function joinErrors(errors) {
let es = {}
for (let n in errors) {
es[n] = errors[n].join('')
}
return es
}
export function defaultWidget (f) {
return f.type === 'boolean' ? 'checkbox' : (['date', 'datetime', 'time'].includes(f.type) ? f.type : ( ['integer', 'decimal'].includes(f.type) ? 'number' : 'text'))
export function defaultWidget(f) {
if ('choice' === f.type && f.choices) {
let size = f.choices.length
return size <= 2 ? 'switch' : (size <= 4 ? 'radio' : 'select')
}
if(f.read_only && !f.choices) {
return 'readonly'
}
return f.type === 'boolean' ? 'switch' : (['date', 'datetime', 'time'].includes(f.type) ? f.type : ( ['integer', 'decimal'].includes(f.type) ? 'number' : 'text'))
}

export function defaultRuleType (f){
export function defaultRuleType(f) {
if (f.multiple) {
return 'array'
}
Expand All @@ -43,7 +50,7 @@ export function defaultRuleType (f){
return f.model ? 'number' : (['field', 'time', 'datetime'].includes(f.type) ? 'string' : (['integer', 'decimal'].includes(f.type) ? 'number' : f.type))
}

export function defaultSpan (f){
export function defaultSpan(f) {
return f.widget === 'textarea' ? {xs: 24, sm: 24, md: 24, lg: 24, xl: 24} : {
xs: 24,
sm: 24,
Expand All @@ -52,7 +59,7 @@ export function defaultSpan (f){
xl: 8
}
}
export function defaultRules (f){
export function defaultRules(f) {
let rs = []
if (f.required) {
rs.push({
Expand All @@ -69,7 +76,7 @@ export function defaultRules (f){
}
return rs
}
export function normalizeItem (i) {
export function normalizeItem(i) {
let a = Object.assign({}, i)
a.label = a.label || a.name
a.rules = a.rules || defaultRules(a)
Expand All @@ -79,10 +86,10 @@ export function normalizeItem (i) {
a.span = Object.assign({}, defaultSpan(a), a.span)
return a
}
export function normalizeItems (items) {
return arrayNormalize(items,{}, normalizeItem)
export function normalizeItems(items) {
return arrayNormalize(items, {}, normalizeItem)
}
export function getItemRules (items) {
export function getItemRules(items) {
let d = {}
Object.keys(items).forEach((i) => {
let f = items[i]
Expand Down
8 changes: 4 additions & 4 deletions src/components/form/Widget.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<span v-if="field.widget === 'readonly'" style="white-space: pre-wrap">{{value[field.name]}}</span>
<span v-if="field.widget === 'readonly'" style="white-space: pre-wrap"><a v-if="isLink(value[field.name])" :href="value[field.name]" target="_blank">{{value[field.name]}}</a><template v-else>{{value[field.name]}}</template></span>
<span v-else-if="typeof(field.widget) === 'function'" v-html="field.widget(value,field)"></span>
<el-radio-group v-model="value[field.name]" v-else-if="field.widget === 'radio'" @change="fieldValueChanged"
:disabled="field.disabled">
Expand All @@ -12,8 +12,8 @@
v-else-if="field.widget === 'select'">
<el-option :label="c.display_name" :value="c.value" v-for="c in field.choices" :key="c.value"></el-option>
</el-select>
<el-switch v-model="value[field.name]" v-else-if="field.widget === 'checkbox'"
@change="fieldValueChanged">
<el-switch v-model="value[field.name]" v-else-if="field.widget === 'switch'"
@change="fieldValueChanged" v-bind="[field]">
</el-switch>
<el-input-number v-model="value[field.name]" v-else-if="field.widget === 'number'" v-bind="[field]"
controls-position="right" :controls="field.type === 'integer'" @change="fieldValueChanged">
Expand Down Expand Up @@ -89,7 +89,7 @@
console.log('do nothing')
},
isLink(v) {
return v && (v.startsWith('http://') || v.startsWith('https://'))
return v && (typeof v === 'string') && (v.startsWith('http://') || v.startsWith('https://'))
},
goLink() {
window.open(this.value[this.field.name])
Expand Down
29 changes: 23 additions & 6 deletions src/components/layout/Actions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
</el-button-group>
</template>
<script>
import serverResponse from '../../mixins/server_response'
import arrayNormalize from '../../utils/array_normalize'
export default{
mixins: [serverResponse],
props: {
items: Array,
context: Object,
Expand All @@ -48,16 +50,31 @@
this.normalizeItems()
},
methods: {
handleCommand (action) {
let command = action.do
if(typeof command === 'function') {
return command(this.context)
getConfirm(action) {
if (action.confirm instanceof Function) {
return action.confirm
} else if (action.confirm) {
return (action) => this.$confirm(action.notice, `确定要执行"${action.label || action.title}"操作吗?`, {type: action.type || 'warning'})
} else {
return (action) => Promise.resolve()
}
this.$store.state.bus.$emit('opendrawer', {component: command, context: {...action.drawer, ...this.context}})
},
handleCommand (action) {
let confirmFunc = this.getConfirm(action)
confirmFunc(action).then(() => {
let command = action.do
if (typeof command === 'function') {
return command(this.context)
}
this.$store.state.bus.$emit('opendrawer', {
component: command,
context: {...action.drawer, ...this.context}
})
}).catch(this.onServerResponseError)
},
normalizeItem(a)
{
if(a instanceof Array) {
if (a instanceof Array) {
return arrayNormalize(a, this.map, this.normalizeItem)
}
if (!a.show && this.permissionFunction && a.permission) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/model/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
if (f.type == 'field' && f.model) {
return RelatedSelect
} else if (['field', 'choice'].includes(f.type) && f.choices) {
return f.choices.length <= 2 ? (f.multiple ? 'checkbox' : 'radio') : 'select'
return f.choices.length <= 2 ? (f.multiple ? 'switch' : 'radio') : 'select'
}
},
getItems () {
Expand Down
2 changes: 1 addition & 1 deletion src/components/model/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
icon: 'pencil',
title: '编辑',
do: this.toEditModel,
show: () => this.checkPermission('update') || this.checkPermission('partial_update')
show: () => this.checkPermission('update') || this.checkPermission('partial_update') || this.checkPermission('retrieve')
},
'delete': {
icon: 'trash',
Expand Down
124 changes: 120 additions & 4 deletions src/components/stats/ChartGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@
return data
},
genDailyOption(item, data){
console.log(data)
item.fields = item.fields || ['日期', item.title]
item.fields = arrayNormalise(item.fields, {})
item.fields = arrayNormalise(item.fields || [], {})
let columns = item.fields.map(a => a.name)
if(!(data instanceof Array)) {
columns = data.columns
data = data.data
}
let series = [{
type: 'line',
Expand Down Expand Up @@ -114,6 +120,83 @@
series
}
},
genLineBarOption(item, data){
let type = item.type
let columns
if(!(data instanceof Array)) {
columns = data.columns
data = data.data
}
if(item.fields) {
item.fields = arrayNormalise(item.fields, {})
columns = item.fields.map(a => a.name)
}
if(!type){
if(data.length>0 && /^\d+-\d+-\d+$/.test(data[0][0])){
type = 'daily'
}
}
let dataZoom = []
let axisLabel = {}
let grid = undefined
if (type !== 'daily') {
if (data.length >= 8) {
axisLabel = {rotate: 30, interval: 0}
}
if (data.length >= 16) {
dataZoom.push(
{
id: 'dataZoomX',
type: 'slider',
xAxisIndex: [0],
filterMode: 'filter',
show: true,
start: 0,
end: 900 / data.length
})
grid = {
bottom: '25%',
}
}
}
let series = [{
type: 'line',
smooth: true,
name: columns[1] || '数量',
}]
let yAxis = [{
type: 'value',
name: columns[1]
}]
if (columns.length >= 3) {
series.push({
type: 'bar',
yAxisIndex: 1,
name: columns[2] || '数量2',
})
yAxis.push({
type: 'value',
name: columns[2]
})
}
// console.log('genLineBarOption', item.title, type)
return {
dataZoom,
dataset: {
source: data
},
xAxis: {
type: 'category',
axisLabel,
// name: columns[0]
},
grid,
yAxis,
series
}
},
genTreeMapOption(item, data){
},
Expand Down Expand Up @@ -173,7 +256,6 @@
let axisLabel = {}
let grid = undefined
if (data.length >= 8) {
axisLabel = {rotate: 30, interval: 0}
}
if (data.length >= 16) {
Expand Down Expand Up @@ -211,6 +293,34 @@
}]
}
},
genStackOptions(item, data) {
item.fields = arrayNormalise(item.fields || [], {})
let columns = item.fields.map(a => a.name)
if(!(data instanceof Array)) {
columns = data.columns
data = data.data
}
return {
dataset: {
source: data
},
xAxis: {
type: 'category',
// name: columns[0]
},
yAxis: {
type: 'value',
name: columns[1][0]
},
series: columns.slice(1).map( c => {
return {
type: 'bar',
stack: c[0],
name: c[1]
}
})
}
},
loadTimeData(period){
period = period instanceof Array ? `${period[0]}${period[1]}` : period
let context = {measures: this.items.map((a) => a.name), period, time_field: this.$attrs.timeField}
Expand All @@ -226,15 +336,21 @@
if (this.base) {
ds = ds[this.base]
}
this.chartData = Object.assign({}, ds)
this.chartData = {...ds}
}).catch(this.onServerResponseError)
},
},
computed: {
chartOptions(){
let res = {}
this.items.forEach((a) => {
let optionFunc = a.type == 'daily' ? this.genDailyOption : (a.type === 'funnel' ? this.genFunnelOption : this.genBarOption)
let om = {
daily: this.genLineBarOption,
funnel: this.genFunnelOption,
linebar: this.genLineBarOption,
stack: this.genStackOptions
}
let optionFunc = om[a.type] || this.genLineBarOption
res[a.name] = {
...COMMON_OPTIONS,
title: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/table/RemoteTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</template>
</x-table>
<!--<div class="pager-container">-->
<el-pagination v-if="showPagger && count>pageSize"
<el-pagination v-if="showPagger"
background
layout="total, sizes, prev, pager, next, jumper"
:page-size="pageSize"
Expand Down Expand Up @@ -90,7 +90,7 @@
}).then(data => {
this.loading = false
this.data = data
this.$emit("loaded", data)
this.$emit("loaded", {data, count:this.count})
}).catch(this.onServerResponseError)
},
onSearch(){
Expand Down
4 changes: 2 additions & 2 deletions src/components/table/Search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
<el-select v-model="form[f.name]" clearable :placeholder="`请选择${f.label}`" v-if="f.widget =='boolean'"
:title="f.label" :style="`width:${f.label.length+5}rem;min-width:8rem;`" @change="onSearch"
:key="f.name">
<el-option :label="f.label" :value="true"></el-option>
<el-option :label="getBoolFieldFalseLabel(f.label)" :value="false"></el-option>
<el-option :label="f.label" :value="f.useNumber? 1 : true"></el-option>
<el-option :label="getBoolFieldFalseLabel(f.label)" :value="f.useNumber? 0 : false"></el-option>
</el-select>
<el-select v-model="form[f.name]" clearable :placeholder="`请选择${f.label}`"
v-else-if="f.widget === 'select'" :key="f.name"
Expand Down

0 comments on commit 7e10a98

Please sign in to comment.