diff --git a/src/api/article.js b/src/api/article.js index c062cbb777f3ad71fae74b654f9da54e6db8ba2d..682cc3ab2ba9cfd35e33e60e2393ada10db74d6c 100644 --- a/src/api/article.js +++ b/src/api/article.js @@ -1,7 +1,7 @@ -import { tpFetch } from 'utils/fetch'; +import { fetch } from 'utils/fetch'; export function getList() { - return tpFetch({ + return fetch({ url: '/article/list', method: 'get' }); diff --git a/src/api/article_table.js b/src/api/article_table.js new file mode 100644 index 0000000000000000000000000000000000000000..5f0d4595040d372fac45b09c283001cf3f818668 --- /dev/null +++ b/src/api/article_table.js @@ -0,0 +1,48 @@ +import { fetch } from 'utils/fetch'; +import { param } from 'utils'; + +// export function calendarsList(query) { +// return fetch({ +// url: '/finfo/calendars?' + param(query), +// method: 'get' +// }); +// } + +export function fetchList(query) { + return fetch({ + url: '/article_table/list', + method: 'get' + }); +} + + +export function calendarCreate(data) { + return fetch({ + url: '/finfo/calendar/create', + method: 'post', + data + }); +} + +export function calendarDelete(id) { + return fetch({ + url: '/finfo/calendar/delete', + method: 'post', + data: { id } + }); +} + +export function calendarUpdate(data) { + return fetch({ + url: '/finfo/calendar/update', + method: 'post', + data + }); +} + +export function calcountriesList() { + return fetch({ + url: '/finfo/calcountries', + method: 'get' + }); +} diff --git a/src/assets/iconfont/iconfont.js b/src/assets/iconfont/iconfont.js index acba8d0e82a2a7cfa3e91851b9c84b8923375d62..d988ec76e0c0f8b155e78fa549741bfd6ba09c94 100644 --- a/src/assets/iconfont/iconfont.js +++ b/src/assets/iconfont/iconfont.js @@ -38,6 +38,12 @@ '' + '</symbol>' + '' + + '<symbol id="icon-wujiaoxing" viewBox="0 0 1024 1024">' + + '' + + '<path d="M565.272827 34.627285l112.095872 237.542288c8.706637 18.321022 25.411424 31.051641 44.82285 33.996289l250.776598 38.081157c48.697387 7.411435 68.22505 70.046082 32.933559 105.979639l-181.494353 184.937155c-13.998147 14.230618-20.352386 34.815477-17.05903 54.93539l42.819161 261.127145c8.346858 50.695541-42.64204 89.451974-86.225039 65.51841l-224.307979-123.271141c-17.285968-9.525824-37.992596-9.525824-55.278564 0l-224.313514 123.271141c-43.582999 23.933565-94.571897-14.822869-86.219504-65.51841l42.813626-261.127145c3.321031-20.119914-3.088559-40.704772-17.086706-54.93539l-181.439002-184.937155c-35.285956-35.933557-15.819179-98.57374 32.933559-105.979639l250.748923-38.081157c19.350541-2.939112 36.083003-15.675267 44.75643-33.996289l112.123547-237.542288C480.497972-11.540583 543.509003-11.540583 565.272827 34.627285z" ></path>' + + '' + + '</symbol>' + + '' + '<symbol id="icon-EXCEL" viewBox="0 0 1024 1024">' + '' + '<path d="M625.664 132.608V199.68h309.76v43.008h-309.76V312.32h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.096h309.76v43.008h-309.76v89.088H1024v-757.76h-398.336zM0 914.944L577.024 1024V0L0 109.056" ></path>' + diff --git a/src/mock/article_table.js b/src/mock/article_table.js new file mode 100644 index 0000000000000000000000000000000000000000..d82629b884cd02dfdc6b59d0504dc1fd95ce2cbe --- /dev/null +++ b/src/mock/article_table.js @@ -0,0 +1,45 @@ +import Mock from 'mockjs'; + + +const List = []; +const count = 50; + +for (let i = 0; i < count; i++) { + List.push(Mock.mock({ + id: '@increment', + timestamp: +Mock.Random.date('T'), + author: '@cname', + title: '@ctitle(10, 20)', + forecast: '@float(0, 100, 2, 2)', + importance: '@integer(1, 3)', + 'calendar_type|1': ['FD', 'FE', 'BI', 'VN'], + 'status|1': ['published', 'draft', 'deleted'] + })); +} + +export default { + getList: config => + // let {page, sortWay, startTime, endTime, userName, age} = config.params; + // let mockUsers = _Users.filter(user => { + // if (startTime && user.date < startTime) return false; + // if (endTime && user.date > endTime) return false; + // if (userName && user.name !== userName) return false; + // if (age && user.age !== age) return false; + // return true; + // }); + // if (sortWay) { + // let {order, prop} = sortWay; + // mockUsers = mockUsers.sort((u1, u2) => order === 'ascending' ? u1[prop] - u2[prop] : u2[prop] - u1[prop]); + // } + // if (page === 0) page++; + // mockUsers = mockUsers.filter((u, index) => index < 20 * page && index >= 20 * (page - 1)); + new Promise(resolve => { + setTimeout(() => { + resolve([200, { + total: List.length, + items: List + }]); + }, 100); + }) + +}; diff --git a/src/mock/index.js b/src/mock/index.js index 9a125c4f58345bd10e4aa6c37569286d4b5f6610..081c2757568ee66175aee98dc93dbdd6eff54d40 100644 --- a/src/mock/index.js +++ b/src/mock/index.js @@ -1,6 +1,7 @@ import axios from 'axios'; import Mock from 'mockjs'; import MockAdapter from 'axios-mock-adapter'; +import article_tableAPI from './article_table' const mock = new MockAdapter(axios); const articleList = { @@ -15,4 +16,10 @@ const articleList = { } const data = JSON.stringify(Mock.mock(articleList)) mock.onGet('/article/list').reply(200, data); + + +mock.onGet('/article_table/list').reply(article_tableAPI.getList); + + + export default mock; diff --git a/src/router/index.js b/src/router/index.js index a19fdbe73e05f346ac215649d3ce83571f31d807..1f7d593e7ae4200cd9b82e59cba4d4d25f200478 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -50,6 +50,7 @@ const Theme = resolve => require(['../views/theme/index'], resolve); /* example*/ const DynamicTable = resolve => require(['../views/example/dynamictable'], resolve); +const Table = resolve => require(['../views/example/table'], resolve); /* admin*/ @@ -168,7 +169,8 @@ export default new Router({ name: '综åˆå®žä¾‹', icon: 'zonghe', children: [ - { path: 'dynamictable', component: DynamicTable, name: '动æ€table' } + { path: 'dynamictable', component: DynamicTable, name: '动æ€table' }, + { path: 'table', component: Table, name: '综åˆtable' } ] }, // { diff --git a/src/utils/fetch.js b/src/utils/fetch.js index 7b07bd6d4b0a3284315d133d26fe203d75743ee9..9110f7746b532008ea88baf371d8b3f2285feb1c 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -3,7 +3,7 @@ import { Message } from 'element-ui'; import store from '../store'; import router from '../router'; -export default function fetch(options) { +export default function _fetch(options) { return new Promise((resolve, reject) => { const instance = axios.create({ baseURL: process.env.BASE_API, @@ -49,10 +49,10 @@ export default function fetch(options) { }); } -export function tpFetch(options) { +export function fetch(options) { return new Promise((resolve, reject) => { const instance = axios.create({ - // timeout: 2000, + timeout: 2000 // 超时 }); instance(options) .then(response => { diff --git a/src/views/example/table.vue b/src/views/example/table.vue new file mode 100644 index 0000000000000000000000000000000000000000..197bb3833ebd0d9f5e2d274fc44798a789a15a9e --- /dev/null +++ b/src/views/example/table.vue @@ -0,0 +1,317 @@ +<template> + <div class="app-container calendar-list-container"> + <div class="filter-container"> + <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="æ ‡é¢˜" v-model="listQuery.title"> + </el-input> + + <el-date-picker class="filter-item" v-model="time" type="daterange" align="left" placeholder="选择日期范围" :picker-options="pickerOptions" + @input="timeFilter" style="width: 210px"> + </el-date-picker> + + <el-select clearable style="width: 90px" class="filter-item" v-model="listQuery.importance" placeholder="é‡è¦æ€§"> + <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item"> + </el-option> + </el-select> + + <el-select clearable class="filter-item" style="width: 130px" v-model="listQuery.calendar_type" placeholder="类型"> + <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key"> + </el-option> + </el-select> + + <el-button class="filter-item" type="primary" v-waves icon="search" @click="handleFilter">æœç´¢</el-button> + <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate" type="primary" icon="edit">æ·»åŠ </el-button> + <el-button class="filter-item" type="primary" icon="document" @click="handleDownload">导出</el-button> + </div> + + <el-table :data="list" v-loading.body="listLoading" border fit highlight-current-row style="width: 100%"> + + <el-table-column align="center" label="åºå·" width="65"> + <template scope="scope"> + <span>{{scope.row.id}}</span> + </template> + </el-table-column> + + <el-table-column width="180px" align="center" label="时间"> + <template scope="scope"> + <span>{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}</span> + </template> + </el-table-column> + + <el-table-column min-width="300px" label="æ ‡é¢˜"> + <template scope="scope"> + <span class="link-type" @click="handleUpdate(scope.row)">{{scope.row.title}}</span> + <el-tag>{{scope.row.calendar_type | typeFilter}}</el-tag> + </template> + </el-table-column> + + <el-table-column width="110px" align="center" label="作者"> + <template scope="scope"> + <span>{{scope.row.author}}</span> + </template> + </el-table-column> + + + <el-table-column width="80px" label="é‡è¦æ€§"> + <template scope="scope"> + <wscn-icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n" /> + </template> + </el-table-column> + + <el-table-column class-name="status-col" label="状æ€" width="90"> + <template scope="scope"> + <el-tag :type="scope.row.status | statusFilter">{{scope.row.status}}</el-tag> + </template> + </el-table-column> + + <el-table-column align="center" label="æ“作" width="150"> + <template scope="scope"> + <el-button v-if="scope.row.status!='published'" size="small" type="success" @click="handleModifyStatus(scope.row,'published')">å‘布 + </el-button> + <el-button v-if="scope.row.status!='draft'" size="small" @click="handleModifyStatus(scope.row,'draft')">è‰ç¨¿ + </el-button> + <el-button v-if="scope.row.status!='deleted'" size="small" type="danger" @click="handleModifyStatus(scope.row,'deleted')">åˆ é™¤ + </el-button> + </template> + </el-table-column> + + </el-table> + + <div v-show="!listLoading" class="pagination-container"> + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.cursor" :page-sizes="[10,20,30, 50]" + :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total"> + </el-pagination> + </div> + + <el-dialog :title="textMap[dialogStatus]" v-model="dialogFormVisible"> + <el-form class="small-space" :model="temp" label-position="left" label-width="70px" style='width: 400px; margin-left:50px;'> + <el-form-item label="类型"> + <el-select class="filter-item" v-model="temp.calendar_type" placeholder="请选择"> + <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"> + </el-option> + </el-select> + </el-form-item> + + <el-form-item label="状æ€"> + <el-select class="filter-item" v-model="temp.status" placeholder="请选择"> + <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item"> + </el-option> + </el-select> + </el-form-item> + + <el-form-item label="时间"> + <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="选择日期时间"> + </el-date-picker> + </el-form-item> + + <el-form-item label="æ ‡é¢˜"> + <el-input v-model="temp.title"></el-input> + </el-form-item> + + <el-form-item label="é‡è¦æ€§"> + <el-rate style="margin-top:8px;" v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']"></el-rate> + </el-form-item> + + <el-form-item label="点评"> + <el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}" placeholder="请输入内容" v-model="temp.remark"> + </el-input> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button @click="dialogFormVisible = false">å– æ¶ˆ</el-button> + <el-button v-if="dialogStatus=='create'" type="primary" @click="create">ç¡® 定</el-button> + <el-button v-else type="primary" @click="update">ç¡® 定</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> + import { fetchList } from 'api/article_table'; + import { parseTime, objectMerge, pickerOptions } from 'utils'; + + const calendarTypeOptions = [ + { key: 'FD', display_name: 'ç»æµŽæ•°æ®' }, + { key: 'FE', display_name: 'è´¢ç»å¤§äº‹' }, + { key: 'BI', display_name: '国债å‘è¡Œ' }, + { key: 'VN', display_name: 'å‡æœŸæŠ¥å‘Š' } + ]; + + // arr to obj + const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { + acc[cur.key] = cur.display_name; + return acc + }, {}); + + export default { + name: 'table_demo', + data() { + return { + list: null, + total: null, + listLoading: true, + listQuery: { + cursor: 1, + limit: 20, + start: undefined, + end: undefined, + importance: undefined, + title: undefined + }, + temp: { + id: undefined, + importance: 0, + remark: '', + timestamp: 0, + title: '', + calendar_type: '', + status: 'published' + }, + time: '', // 时间ç›é€‰é¡¹ + importanceOptions: [1, 2, 3], + calendarTypeOptions, + statusOptions: ['published', 'draft', 'deleted'], + dialogFormVisible: false, + dialogStatus: '', + textMap: { + update: '编辑', + create: '创建' + }, + pickerOptions: { + shortcuts: pickerOptions + } + } + }, + created() { + this.getList(); + }, + filters: { + statusFilter(status) { + const statusMap = { + published: 'success', + draft: 'gray', + deleted: 'danger' + }; + return statusMap[status] + }, + typeFilter(type) { + return calendarTypeKeyValue[type] + } + }, + methods: { + getList() { + this.listLoading = true; + fetchList(this.listQuery).then(response => { + console.log(response) + this.list = response.items; + this.total = response.total; + this.listLoading = false; + }) + }, + handleFilter() { + this.getList(); + }, + handleSizeChange(val) { + this.listQuery.limit = val; + this.getList(); + }, + handleCurrentChange(val) { + this.listQuery.cursor = val; + this.getList(); + }, + timeFilter(time) { + if (!time[0]) { + this.listQuery.start = undefined; + this.listQuery.end = undefined; + return; + } + this.listQuery.start = parseInt(+time[0] / 1000); + this.listQuery.end = parseInt((+time[1] + 3600 * 1000 * 24) / 1000); + }, + handleModifyStatus(row, status) { + this.$message({ + message: 'æ“作æˆåŠŸ', + type: 'success' + }); + row.status = status; + }, + handleCreate() { + this.resetTemp(); + this.dialogStatus = 'create'; + this.dialogFormVisible = true; + }, + handleUpdate(row) { + objectMerge(this.temp, row) + this.dialogStatus = 'update'; + this.dialogFormVisible = true; + }, + handleDelete(row) { + this.$notify({ + title: 'æˆåŠŸ', + message: 'åˆ é™¤æˆåŠŸ', + type: 'success', + duration: 2000 + }); + const index = this.list.indexOf(row); + this.list.splice(index, 1); + }, + create() { + this.temp.id = parseInt(Math.random() * 100) + 1024; + this.temp.timestamp = +new Date(); + this.temp.author = '原创作者'; + this.list.unshift(this.temp); + this.dialogFormVisible = false; + this.$notify({ + title: 'æˆåŠŸ', + message: '创建æˆåŠŸ', + type: 'success', + duration: 2000 + }); + }, + update() { + this.temp.timestamp = +this.temp.timestamp; + for (const v of this.list) { + if (v.id === this.temp.id) { + objectMerge(v, this.temp); + break; + } + } + this.dialogFormVisible = false; + this.$notify({ + title: 'æˆåŠŸ', + message: 'æ›´æ–°æˆåŠŸ', + type: 'success', + duration: 2000 + }); + }, + resetTemp() { + this.temp = { + id: undefined, + importance: 0, + remark: '', + timestamp: 0, + title: '', + status: 'published', + calendar_type: '' + }; + }, + handleDownload() { + require.ensure([], () => { + const { export_json_to_excel } = require('vendor/Export2Excel'); + const tHeader = ['时间', '地区', '类型', 'æ ‡é¢˜', 'é‡è¦æ€§']; + const filterVal = ['timestamp', 'province', 'calendar_type', 'title', 'importance']; + const data = this.formatJson(filterVal, this.list); + export_json_to_excel(tHeader, data, 'tableæ•°æ®'); + }) + }, + formatJson(filterVal, jsonData) { + return jsonData.map(v => filterVal.map(j => { + if (j === 'timestamp') { + return parseTime(v[j]) + } else { + return v[j] + } + })) + } + } + } +</script>