Commit 8c6849d9 authored by 332784038@qq.com's avatar 332784038@qq.com

Merge branch 'refactor-currency-rate' into pre-release

# Conflicts:
#	src/utils/dict.js
parents a59e848f 0422189d
import request from '@/utils/request'
// 创建
export async function createCurrencyRate({ sourceId, targetId, sourceAmount, targetAmount, countries, expiration, remarks, }) {
return await request.post('/ecw/currency-rate/create', { sourceId, targetId, sourceAmount, targetAmount, countries, expiration, remarks, })
}
// 更新
export async function updateCurrencyRate(id, { sourceAmount, targetAmount, expiration, remarks, }) {
return await request.put('/ecw/currency-rate/update', { sourceAmount, targetAmount, expiration, remarks, }, { params: { id, }, })
}
// 删除
export async function deleteCurrencyRate(id) {
return await request.delete('/ecw/currency-rate/delete', { params: { id, }, })
}
// 获得
export async function getCurrencyRate({ sourceId, targetId, }) {
return await request.get('/ecw/currency-rate/get', { params: { sourceId, targetId, }, })
}
// 获得分页
export async function getCurrencyRatePage({ sourceId, targetId, countries, expired, expiration, page, rows, }) {
return await request.get('/ecw/currency-rate/page', { params: { sourceId, targetId, countries, expired, expirationAfter: expiration[0], expirationBefore: expiration[1], page, rows, }, })
}
// 获得日志分页
export async function getCurrencyRateLogs({ id, page, rows, }) {
return await request.get('/ecw/currency-rate/logs', { params: { id, page, rows, }})
}
......@@ -289,6 +289,8 @@ export const DICT_TYPE = {
ATTRIBUTION_OF_INCOME: "attribution_of_income", //收入归属
PICKUP_RATE_COMPARISON_SYMBOLS: "pickup_rate_comparison_symbols" //提货率比较符号
}
CURRENCY_RATE_STATUS: "currency_rate_status", // 货币汇率状态
};
/**
* 获取 dictType 对应的数据字典数组
......
<template>
<div>
<div class="remarks">{{ row.remarks || '' }}</div>
<div><i>{{ row.updateAt }}</i> <b>{{ row.updateBy }}</b></div>
</div>
</template>
<script>
import Vue from 'vue'
export default Vue.extend({
props: {
row: {
type: Object,
required: true,
},
},
})
</script>
<style scoped>
::v-deep .remarks {
color: darkgray;
font-style: italic;
}
</style>
<template>
<el-dialog :visible="visible" @close="close" @open="open" width="640px">
<template slot="title">
<div class="el-dialog__title">{{ update ? '编辑' : '新增' }}</div>
</template>
<el-form label-width="100px" :rules="rules" :model="model" ref="form">
<el-form-item :label="$t('币种')" prop="currencies">
<el-col :span="11">
<el-select v-model="model.sourceId" :placeholder="$t('请选择原币种')" :disabled="update" clearable style="width: 100%">
<el-option v-for="item in currencies" :key="item.id" :label="`${$l(item, 'title')} ${item.fuhao}`" :value="item.id"/>
</el-select>
</el-col>
<el-col :span="2" class="center">
<el-tooltip :content="$t('交换币种')" placement="top">
<el-button size="mini" type="text" @click="swap" icon="el-icon-sort" style="transform: rotate(90deg)" :disabled="update"/>
</el-tooltip>
</el-col>
<el-col :span="11">
<el-select v-model="model.targetId" :placeholder="$t('请选择支付币种')" :disabled="update" clearable style="width: 100%">
<el-option v-for="item in currencies" :key="item.id" :label="`${$l(item, 'title')} ${item.fuhao}`" :value="item.id"/>
</el-select>
</el-col>
</el-form-item>
<el-form-item :label="$t('金额')" prop="amounts">
<el-col :span="11">
<el-input-number :max="100000000" :precision="4" style="width: 100%" v-model="model.sourceAmount" :min="0.0001" :placeholder="$t('请输入金额')"/>
</el-col>
<el-col :span="2" class="center">:</el-col>
<el-col :span="11">
<el-input-number :max="100000000" :precision="4" style="width: 100%" v-model="model.targetAmount" :min="0.0001" :placeholder="$t('请输入金额')"/>
</el-col>
</el-form-item>
<el-form-item :label="$t('汇率')" prop="rate">
<el-col :span="11">
<el-input :value="1" disabled/>
</el-col>
<el-col :span="2" class="center">:</el-col>
<el-col :span="11">
<el-input :value="rate" disabled/>
</el-col>
</el-form-item>
<el-form-item :label="$t('国家')" prop="countries">
<el-select v-model="model.countries" clearable filterable multiple :placeholder="$t('请选择国家')" style="width: 100%" :disabled="update">
<el-option v-for="item in countries" :key="item.id" :label="$l(item, 'name')" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('有效期')" prop="expiration">
<el-col :span="11">
<el-date-picker v-model="model.expiration" type="date" :placeholder="$t('请选择有效期')" :picker-options="pickerOptions" style="width: 100%"/>
</el-col>
<el-col :span="2">&nbsp;</el-col>
<el-col :span="11">
<div>
<i v-if="model.expiration && expires > 0" class="diff">{{ expires }}天后过期</i>
<i v-if="model.expiration && expires <= 0" class="diff expired">已过期{{ 0 - expires }}天</i>
</div>
</el-col>
</el-form-item>
<el-form-item :label="$t('备注')" prop="remarks">
<el-input type="textarea" v-model="model.remarks" :placeholder="$t('请输入备注')"/>
</el-form-item>
</el-form>
<template slot="footer">
<el-button type="primary" @click="submit">{{ $t('确定') }}</el-button>
<el-button @click="close">{{ $t('取消') }}</el-button>
</template>
</el-dialog>
</template>
<script>
import { createCurrencyRate, updateCurrencyRate } from '@/api/ecw/currencyRate'
import dayjs from 'dayjs'
import Decimal from 'decimal.js'
import Vue from 'vue'
const modelDefaults = {
remarks: '',
countries: [],
sourceAmount: 1,
targetAmount: 1,
}
const props = {
id: {},
data: { type: Object, required: true, },
visible: { type: Boolean, default: false, },
countries: { type: Array, default: [], },
currencies: { type: Array, default: [], },
}
export default Vue.extend({
props,
computed: {
update() {
return !!this.id
},
rate() {
return this.decimal(this.model.targetAmount).dividedBy(this.model.sourceAmount).toFixed(8)
},
expires() {
return dayjs(this.model.expiration).diff(dayjs().startOf('day'), 'day')
},
pickerOptions() {
return {
disabledDate(time) {
return dayjs(time).isBefore(dayjs().startOf('day').add(1, 'day'))
},
shortcuts: [
{ text: this.$t('一周'), onClick(picker) { picker.$emit('pick', dayjs().add(7, 'day')) }, },
{ text: this.$t('一个月'), onClick(picker) { picker.$emit('pick', dayjs().add(1, 'month')) }, },
{ text: this.$t('三个月'), onClick(picker) { picker.$emit('pick', dayjs().add(3, 'month')) }, },
{ text: this.$t('半年'), onClick(picker) { picker.$emit('pick', dayjs().add(6, 'month')) }, },
{ text: this.$t('一年'), onClick(picker) { picker.$emit('pick', dayjs().add(1, 'year')) }, },
],
}
},
},
watch: {
data(v) {
this.model = { ...modelDefaults, ...v, }
},
},
model: {
prop: 'visible',
event: 'update',
},
data() {
return {
model: { ...modelDefaults, ...this.data, },
rules: {
currencies: { required: true, validator: this.validateCurrencies, },
countries: { required: true, message: this.$t('请至少选择一个国家'), },
amounts: { required: true, validator: this.validateAmounts, required: true, },
expiration: { required: true, message: this.$t('请选择有效期'), },
},
}
},
methods: {
decimal(a) {
return new Decimal(a || 0)
},
swap() {
this.model = { ...this.model, sourceId: this.model.targetId, targetId: this.model.sourceId, }
},
async submit() {
if (await this.$refs['form'].validate().catch(() => {})) {
if (this.update) {
await updateCurrencyRate(this.model.id, this.model)
}
await createCurrencyRate(this.model)
this.$emit('update:model', this.model)
this.close()
}
},
open() {
},
close() {
this.$emit('update:visible', false)
this.$refs['form'].resetFields()
},
validateAmounts(r, v, callback) {
const { sourceAmount, targetAmount } = this.model
if (this.decimal(sourceAmount).lt(0.0001) || this.decimal(targetAmount).lt(0.0001)) {
callback(new Error(this.$t('金额不能小于0.0001')))
} else {
callback()
}
},
validateCurrencies(r, v, callback) {
if (!(this.model.sourceId && this.model.targetId)) {
callback(new Error(this.$t('原币种或支付币种不能为空')))
} else if (this.model.sourceId == this.model.targetId) {
callback(new Error(this.$t('两个币种不能相同')))
} else {
callback()
}
},
},
})
</script>
<style scoped>
.text-right {
text-align: right;
}
.expired {
color: red!important;
}
.center {
text-align: center;
}
.diff {
color: green;
}
.rate {
font-size: 120%;
font-weight: bold;
}
</style>
<template>
<div class="app-container">
<query :show="query.show" v-model="query.params" :countries="dict.countries" :currencies="dict.currencies" @query="pagination"/>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" v-hasPermi="['ecw:currency:rate:create']" @click="add">{{ $t('新增') }}</el-button>
</el-col>
<right-toolbar :showSearch.sync="query.show" @queryTable="pagination"></right-toolbar>
</el-row>
<el-table v-loading="query.loading" :data="query.result.list">
<el-table-column type="index" align="center" :label="$t('序号')" width="50"/>
<el-table-column align="right" :label="$t('金额')" width="200">
<template v-slot="{ row }">
<div class="title"><i>{{ $l(currency(row.sourceId), 'title') }}</i> <i class="amount">{{ row.sourceAmount }}</i></div>
<div class="title"><i>{{ $l(currency(row.targetId), 'title') }}</i> <i class="amount">{{ row.targetAmount }}</i></div>
</template>
</el-table-column>
<el-table-column align="left" :label="$t('汇率')" width="200">
<template v-slot="{ row }">
<div>{{ currency(row.sourceId).fuhao }} : {{ currency(row.targetId).fuhao }}</div>
<div>1 : <i class="rate">{{ rate(row) }}</i></div>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('有效期')" width="120">
<template v-slot="{ row }">
<div>{{ row.expiration }}</div>
<dict-tag :type="DICT_TYPE.CURRENCY_RATE_STATUS" :value="row.expired" />
</template>
</el-table-column>
<el-table-column align="left" :label="$t('国家')" prop="countries" :formatter="countries"/>
<el-table-column align="left" :label="$t('最后修改')" width="200">
<template v-slot="{ row }"><audit :row="row"/></template>
</el-table-column>
<el-table-column align="center" :label="$t('操作')" width="300">
<template v-slot="{ row }">
<el-button size="mini" type="text" icon="el-icon-edit" v-hasPermi="['ecw:currency:rate:update']" @click="edit(row)">{{ $t('修改') }}</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" v-hasPermi="['ecw:currency:rate:delete']" @click="remove(row)">{{ $t('删除') }}</el-button>
<el-button size="mini" type="text" icon="el-icon-tickets" v-hasPermi="['ecw:currency:rate:history']" @click="logs(row)">{{ $t('日志') }}</el-button>
<el-button size="mini" type="text" icon="el-icon-link" v-hasPermi="['ecw:currency:rate:update']" @click="reverse(row)">{{ $t('反向') }}</el-button>
</template>
</el-table-column>
</el-table>
<pagination :total="query.result.total" :page.sync="query.params.page" :limit.sync="query.params.rows" @pagination="pagination"/>
<form-dialog :visible.sync="dialogs.form.visible" :id="dialogs.form.id" :data="dialogs.form.data" :countries="dict.countries" :currencies="dict.currencies"/>
<logs-dialog :visible.sync="dialogs.logs.visible" :id="dialogs.logs.id" :source="dialogs.logs.source" :target="dialogs.logs.target"/>
</div>
</template>
<script>
import { getCountryListAll } from '@/api/ecw/country'
import { getCurrencyList } from '@/api/ecw/currency'
import { deleteCurrencyRate, getCurrencyRate, getCurrencyRatePage } from '@/api/ecw/currencyRate'
import Vue from 'vue'
import FormDialog from './form.vue'
import LogsDialog from './logs.vue'
import Query from './query.vue'
import Audit from './audit.vue'
import Decimal from 'decimal.js'
export default Vue.extend({
components: {
FormDialog, LogsDialog, Query, Audit,
},
data() {
return {
map: {
countries: {},
currencies: {},
},
dict: {
countries: [],
currencies: [],
},
form: {
rules: {},
},
query: {
show: true,
loading: false,
params: {
page: 1,
rows: 10,
expiration: ['', ''],
},
result: {
list: [],
total: 0,
},
},
dialogs: {
form: { visible: false, update: false, data: {}, },
logs: { visible: false, source: null, target: null, },
}
}
},
methods: {
async pagination() {
this.query.loading = true
try {
this.query.result = (await getCurrencyRatePage(this.query.params)).data
} finally {
this.query.loading = false
}
},
amount(row) {
const source = this.currency(row.sourceId)
const target = this.currency(row.targetId)
return `${source.fuhao} ${row.sourceAmount} : ${target.fuhao} ${row.targetAmount}`
},
rate(row) {
return this.decimal(row.targetAmount).dividedBy(row.sourceAmount).toFixed(8)
},
add() {
this.dialogs.form = { visible: true, id: null, data: {}, }
},
edit(row) {
this.dialogs.form = { visible: true, id: row.id, data: {...row, }, }
},
remove(row) {
this.$confirm(this.$t('确定要删除吗?'), this.$t('确认'), { type: 'warning' }).then(() => deleteCurrencyRate(row.id)).catch(() => {}).finally(this.pagination)
},
logs(row) {
this.dialogs.logs = { visible: true, id: row.id, source: this.currency(row.sourceId), target: this.currency(row.targetId), }
},
async reverse(row) {
var swap = { sourceId: row.targetId, targetId: row.sourceId, }
const saved = await getCurrencyRate(swap).then(it => it.data)
swap = saved || { ...swap, sourceAmount: row.targetAmount, targetAmount: row.sourceAmount, countries: row.countries, expiration: row.expiration, }
this.dialogs.form = { visible: true, id: swap.id, data: { ...swap, }, }
},
decimal(a) {
return new Decimal(a)
},
country(id) {
return this.map.countries[id]
},
countries(row) {
return row.countries.map(this.country).map(c => this.$l(c, 'name')).join(',')
},
currency(id) {
return this.map.currencies[id]
},
},
async mounted() {
this.dict.countries = await getCountryListAll().then(it => it.data)
this.dict.currencies = await getCurrencyList().then(it => it.data)
this.map.countries = this.dict.countries.reduce((m, e) => (m[e.id] = e, m), {})
this.map.currencies = this.dict.currencies.reduce((m, e) => (m[e.id] = e, m), {})
this.pagination()
},
})
</script>
<style scoped>
.rate {
color: black;
white-space: nowrap;
font-size: 110%;
font-family: monospace;
}
</style>
<template>
<el-dialog :visible="visible" @close="close" @open="open">
<template slot="title">
<div class="el-dialog__title">{{ $t('日志') }}: {{ $l(source, 'title') }} - {{ $l(target, 'title') }}</div>
</template>
<el-table class="logs" :data="list" v-loading="loading">
<el-table-column type="index" :label="$t('序号')" align="center"/>
<el-table-column :label="$t('修改人')">
<template v-slot="{ row }"><audit :row="row"/></template>
</el-table-column>
<el-table-column :label="$t('金额修改')" align="right">
<template v-slot="{ row }">
<div v-if="row.sourceAmount1 == row.sourceAmount2 && row.targetAmount1 == row.targetAmount2">
<div>{{ amount(row.sourceAmount1, row.targetAmount1) }}</div>
</div>
<div v-else>
<div class="after">{{ amount(row.sourceAmount2, row.targetAmount2) }}</div>
<div class="before">{{ amount(row.sourceAmount1, row.targetAmount1) }}</div>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('汇率变化')" align="left">
<template v-slot="{ row }">
<div v-if="row.sourceAmount1 == row.sourceAmount2 && row.targetAmount1 == row.targetAmount2">
<div>1 : {{ rate(row.sourceAmount1, row.targetAmount1) }}</div>
</div>
<div v-else>
<div class="after">1 : {{ rate(row.sourceAmount2, row.targetAmount2) }}</div>
<div class="before">1 : {{ rate(row.sourceAmount1, row.targetAmount1) }}</div>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('日期变化')">
<template v-slot="{ row }">
<div v-if="row.sourceExpiration != row.targetExpiration">
<div class="after">{{ row.targetExpiration }}</div>
<div class="before">{{ row.sourceExpiration }}</div>
</div>
<div v-else>
<div>{{ row.sourceExpiration }}</div>
</div>
</template>
</el-table-column>
<!-- <el-table-column :label="$t('修改前')" align="right" class-name="before">
<template v-slot="{ row }">
<div>{{ amount(row.sourceAmount1, row.targetAmount1) }}</div>
<div>1 : <i>{{ rate(row.sourceAmount1, row.targetAmount1) }}</i>, {{ row.sourceExpiration }}</div>
</template>
</el-table-column>
<el-table-column :label="$t('修改后')" align="right" class-name="after">
<template v-slot="{ row }">
<div>{{ amount(row.sourceAmount2, row.targetAmount2) }}</div>
<div>1 : <i>{{ rate(row.sourceAmount2, row.targetAmount2) }}</i>, {{ row.targetExpiration }}</div>
</template>
</el-table-column> -->
</el-table>
<pagination v-show="total > 0" :background="false" small layout="total,prev,pager,next,jumper" :total="total" :page.sync="page" :limit.sync="limit" @pagination="pagination"/>
</el-dialog>
</template>
<script>
import { getCurrencyRateLogs } from '@/api/ecw/currencyRate'
import Decimal from 'decimal.js'
import Vue from 'vue'
import audit from './audit.vue'
export default Vue.extend({
components: { audit },
props: {
visible: {
type: Boolean,
default: false,
},
id: Number,
source: {
},
target: {
},
},
model: {
prop: 'visible',
event: 'update',
},
data() {
return {
loading: false,
page: 1,
limit: 10,
list: [],
total: 0,
}
},
methods: {
close() {
this.$emit('update:visible', false)
},
decimal(a) {
return new Decimal(a)
},
amount(amount1, amount2) {
return `${this.source.fuhao} ${amount1} : ${this.target.fuhao} ${amount2}`
},
rate(amount1, amount2) {
return this.decimal(amount1).dividedBy(amount2).toFixed(8)
},
async pagination() {
this.loading = true
try {
const data = await getCurrencyRateLogs({ id: this.id, page: this.page, rows: this.limit, }).then(it => it.data)
this.list = data.list
this.total = data.total
} finally {
this.loading = false
}
},
async open() {
await this.pagination()
},
},
})
</script>
<style scoped>
::v-deep .before {
color: gray;
text-decoration: line-through;
}
::v-deep .after {
color: green;
}
::v-deep .logs .el-table__cell {
padding: 4px 0;
}
</style>
<template>
<el-form v-model="params" inline v-show="show">
<el-form-item :label="$t('原币种')" prop="source">
<el-select v-model="params.source" :placeholder="$t('请选择币种')" clearable>
<el-option v-for="item in currencies" :key="item.id" :label="`${$l(item, 'title')} ${item.fuhao}`" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('支付币种')" prop="target">
<el-select v-model="params.target" :placeholder="$t('请选择币种')" clearable>
<el-option v-for="item in currencies" :key="item.id" :label="`${$l(item, 'title')} ${item.fuhao}`" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('国家')" prop="countries">
<el-select v-model="params.countries" filterable multiple :multiple-limit="5" :placeholder="$t('请选择国家')" clearable>
<el-option v-for="item in countries" :key="item.id" :label="$l(item, 'name')" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('状态')" prop="expired">
<el-select v-model="params.expired" :placeholder="$t('状态')" clearable>
<el-option v-for="item in getDictDatas(DICT_TYPE.CURRENCY_RATE_STATUS)" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('有效期')" prop="expiration">
<el-date-picker v-model="params.expiration" type="daterange" value-format="yyyy-MM-dd" :start-placeholder="$t('开始日期')" :end-placeholder="$t('结束日期')"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="submit">{{ $t('搜索') }}</el-button>
<el-button @click="clear">{{ $t('重置') }}</el-button>
</el-form-item>
</el-form>
</template>
<script>
import Vue from 'vue'
export default Vue.extend({
props: {
show: {
type: Boolean,
default: false,
},
value: {
type: Object,
default: {},
},
countries: {
type: Array,
default: [],
},
currencies: {
type: Array,
default: [],
},
},
model: {
prop: 'value',
event: 'update',
},
data() {
return {
params: this.value,
}
},
methods: {
submit() {
this.$emit('query', this.params)
},
clear() {
console.log('query', this.params)
this.$emit('update:value', this.params = {})
},
},
})
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment