Commit 9867ce34 authored by huyf's avatar huyf

Merge remote-tracking branch 'origin/dev' into dev

parents 1c2d746a f1b93a10
......@@ -5,7 +5,7 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
*.stackdump
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
......
{
"ExpandedNodes": [
"",
"\\src"
],
"SelectedNode": "\\src\\main.js",
"PreviewInSolutionExplorer": false
}
\ No newline at end of file
File added
......@@ -94,16 +94,16 @@ function checkOrTryHttp() {
//==获取LODOP对象主过程,判断是否安装、需否升级:==
function getLodop(oOBJECT, oEMBED) {
var strFontTag = "<br><font color='#FF00FF'>打印控件";
var strLodopInstall = strFontTag + "未安装!点击这里<a href='install_lodop32.exe' target='_self'>执行安装</a>";
var strLodopUpdate = strFontTag + "需要升级!点击这里<a href='install_lodop32.exe' target='_self'>执行升级</a>";
var strLodop64Install = strFontTag + "未安装!点击这里<a href='install_lodop64.exe' target='_self'>执行安装</a>";
var strLodop64Update = strFontTag + "需要升级!点击这里<a href='install_lodop64.exe' target='_self'>执行升级</a>";
var strCLodopInstallA = "<br><font color='#FF00FF'>Web打印服务CLodop未安装启动,点击这里<a href='CLodop_Setup_for_Win32NT.exe' target='_self'>下载执行安装</a>";
var strLodopInstall = strFontTag + "未安装!点击这里<a href='/static/install_lodop32.exe' target='_self'>执行安装</a>";
var strLodopUpdate = strFontTag + "需要升级!点击这里<a href='/static/install_lodop32.exe' target='_self'>执行升级</a>";
var strLodop64Install = strFontTag + "未安装!点击这里<a href='/static/install_lodop64.exe' target='_self'>执行安装</a>";
var strLodop64Update = strFontTag + "需要升级!点击这里<a href='/static/install_lodop64.exe' target='_self'>执行升级</a>";
var strCLodopInstallA = "<br><font color='#FF00FF'>Web打印服务CLodop未安装启动,点击这里<a href='/static/CLodop_Setup_for_Win32NT.exe' target='_self'>下载执行安装</a>";
var strCLodopInstallB = "<br>(若此前已安装过,可<a href='CLodop.protocol:setup' target='_self'>点这里直接再次启动</a>)";
var strCLodopUpdate = "<br><font color='#FF00FF'>Web打印服务CLodop需升级!点击这里<a href='CLodop_Setup_for_Win32NT.exe' target='_self'>执行升级</a>";
var strCLodopUpdate = "<br><font color='#FF00FF'>Web打印服务CLodop需升级!点击这里<a href='/static/CLodop_Setup_for_Win32NT.exe' target='_self'>执行升级</a>";
var strLodop7FontTag = "<br><font color='#FF00FF'>Web打印服务Lodop7";
var strLodop7HrefX86 = "点击这里<a href='Lodop7_Linux_X86_64.tar.gz' target='_self'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
var strLodop7HrefARM = "点击这里<a href='Lodop7_Linux_ARM64.tar.gz' target='_self'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
var strLodop7HrefX86 = "点击这里<a href='/static/Lodop7_Linux_X86_64.tar.gz' target='_self'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
var strLodop7HrefARM = "点击这里<a href='/static/Lodop7_Linux_ARM64.tar.gz' target='_self'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
var strLodop7Install_X86 = strLodop7FontTag + "未安装启动," + strLodop7HrefX86;
var strLodop7Install_ARM = strLodop7FontTag + "未安装启动," + strLodop7HrefARM;
var strLodop7Update_X86 = strLodop7FontTag + "需升级," + strLodop7HrefX86;
......
......@@ -42,7 +42,8 @@
'directionalityltr', 'directionalityrtl', 'indent', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
'link', 'unlink', 'anchor', '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
'simpleupload'
// 'simpleupload',
'insertimage'
// , 'insertimage', 'emotion', 'scrawl', 'insertvideo', 'music', 'attachment', 'map', 'gmap', 'insertframe', 'insertcode', 'webapp', 'pagebreak', 'template', 'background', '|',
// 'horizontal', 'date', 'time', 'spechars', 'snapscreen', 'wordimage', '|',
// 'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols', 'charts', '|',
......@@ -105,7 +106,7 @@
//,fullscreen : false //是否开启初始化时即全屏,默认关闭
//,imagePopup:true //图片操作的浮层开关,默认打开
,imagePopup:true //图片操作的浮层开关,默认打开
//,autoSyncData:true //自动同步编辑器要提交的数据
//,emotionLocalization:false //是否开启表情本地化,默认关闭。若要开启请确保emotion文件夹下包含官网提供的images表情文件夹
......@@ -296,7 +297,7 @@
//,toolbarTopOffset:400
//设置远程图片是否抓取到本地保存
//,catchRemoteImageEnable: true //设置是否抓取远程图片
,catchRemoteImageEnable: true //设置是否抓取远程图片
//pageBreakTag
//分页标识符,默认是_ueditor_page_break_tag_
......
......@@ -31,4 +31,54 @@ export default {
margin-right:10px;
}
}
.flex{
display: flex;
}
.flex-1{
flex: 1;
}
.center{
align-content: center;
text-align: center;
}
.flex-center{
display: flex;
align-items: center;
justify-content: center;
}
.empty-placeholder{
padding: 50px;
text-align: center;
}
$sizes: 0, 10,20,30,50,100,150,200,500,800,1000;
@for $i from 1 through length($sizes){
$item: nth($sizes, $i);
.ml-#{$item}{
margin-left: #{$item}px !important;
}
.mr-#{$item}{
margin-right: #{$item}px !important;
}
.mb-#{$item}{
margin-bottom: #{$item}px !important;
}
.mt-#{$item}{
margin-top: #{$item}px !important;
}
.pl-#{$item}{
margin-left: #{$item}px !important;
}
.pr-#{$item}{
margin-right: #{$item}px !important;
}
.pb-#{$item}{
margin-bottom: #{$item}px !important;
}
.pt-#{$item}{
margin-top: #{$item}px !important;
}
.w-#{$item}{
width: #{$item}px !important;
}
}
</style>
......@@ -33,6 +33,14 @@ export function orderWarehouseInDelete(data){
data:data,
})
}
//获取退仓审批详情
export function getRollbackApprovalInfo(params){
return request({
url:'/order/order-warehouse-in/get-rollback-approval-info',
method:'get',
params
})
}
//通过bpmFormId 获得仓库审核单详情
export function warehouseApprovalGetByFormId(params){
return request({
......@@ -56,3 +64,36 @@ export function warehouseApprovalGetById(params){
params,
})
}
//调仓-查看状态
export function adjustApplyStatus(params){
return request({
url:'/order/order-warehouse-in/adjust-apply-status',
method:'get',
params
})
}
//调仓-撤销
export function cancelAdjustApply(data){
return request({
url:'/order/order-warehouse-in/cancel-adjust-apply',
method:'post',
data
})
}
//调仓审核
export function warehouseApprovalCancel(params,reason){
return request({
url: `/order/order-warehouse-approval/cancel/${params}`,
method:'get',
params:{reason}
})
}
// 调仓-查看最近的调仓纪录和审核状态
export function adjustLastWithStatus(params){
return request({
url:'/order/order-warehouse-in/adjust-last-with-status',
method:'get',
params,
})
}
import request from '@/utils/request'
import request from "@/utils/request";
// 创建出货
export function createbox(data) {
return request({
url: '/shipment/box/create',
method: 'post',
data: data
})
url: "/shipment/box/create",
method: "post",
data: data,
});
}
// 更新出货
export function updatebox(data) {
return request({
url: '/shipment/box/update',
method: 'put',
data: data
})
url: "/shipment/box/update",
method: "put",
data: data,
});
}
// 删除出货
export function deletebox(id) {
return request({
url: '/shipment/box/delete?id=' + id,
method: 'delete'
})
url: "/shipment/box/delete?id=" + id,
method: "delete",
});
}
// 获得出货
export function getbox(id) {
return request({
url: '/shipment/box/get?id=' + id,
method: 'get'
})
url: "/shipment/box/get?id=" + id,
method: "get",
});
}
// 获得出货分页
export function getboxPage(query) {
return request({
url: '/shipment/box/page',
method: 'get',
params: query
})
url: "/shipment/box/page",
method: "get",
params: query,
});
}
// 导出出货 Excel
export function exportboxExcel(query) {
return request({
url: '/shipment/box/export-excel',
method: 'get',
url: "/shipment/box/export-excel",
method: "get",
params: query,
responseType: 'blob'
})
responseType: "blob",
});
}
// 创建费用登记
export function createCost(data) {
if (data.id) {
return request({
url: "/ecw/box-cost/update",
method: "put",
data,
});
}
return request({
url: "/ecw/box-cost/create",
method: "post",
data,
});
}
// 删除费用登记
export function deleteCost(id) {
return request({
url: '/ecw/box-cost/create',
method: 'post',
data
})
url: `/ecw/box-cost/delete?id=${id}`,
method: "delete",
});
}
// 审核详情
export function approvalDetail(data) {
return request({
url: '/ecw/box-approval/approvalDetail',
method: 'post',
url: "/ecw/box-approval/approvalDetail",
method: "post",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
data: jsonToFormData(data),
})
});
}
// 出货操作日志列表
export function getLogList(params) {
return request({
url: "/ecw/box-op-log/list",
method: "get",
params,
});
}
// 获得费用登记列表
export function getCostList(params) {
return request({
url: "/ecw/box-cost/list",
method: "get",
params,
});
}
// 获得出货异常记录列表
export function getAbnormalList(params) {
return request({
url: "/ecw/box-abnormal/list",
method: "get",
params,
});
}
// 获得制作提货单列表
export function getMakeBillList(params) {
return request({
url: "/shipment/make-bill-of-lading/getMakeLadingBillList",
method: "get",
params,
});
}
// 制作提货单
export function makeBillService(params) {
return request({
url: "/shipment/make-bill-of-lading/make",
method: "get",
params,
});
}
// 创建制作提货单
export function createBillService(data) {
return request({
url: "/shipment/make-bill-of-lading/create",
method: "post",
data,
});
}
// 取消制作提货单审核
export function cancelBillService(id) {
return request({
url: `/shipment/make-bill-of-lading/cancel?id=${id}`,
method: "delete",
});
}
// 下载提货单
export function downloadBillService(params) {
return request({
url: "/shipment/make-bill-of-lading/download",
responseType: "arraybuffer",
method: "get",
params,
});
}
// 更新制作提货单
export function updateBillService(data) {
return request({
url: "/shipment/make-bill-of-lading/update",
method: "put",
data,
});
}
// 删除制作提货单
export function deleteBillService(id) {
return request({
url: `/shipment/make-bill-of-lading/delete?id=${id}`,
method: "delete",
});
}
// 获得制作提货单
export function getBillService(params) {
return request({
url: "/shipment/make-bill-of-lading/get",
method: "get",
params,
});
}
// 打包下载提货单
export function zipDownload(params) {
return request({
url: "/shipment/make-bill-of-lading/zipDownload",
responseType: "arraybuffer",
method: "get",
params,
});
}
/**
* formData数据
*
* @param {*} params
* @return {*}
*/
function jsonToFormData(params) {
const formData = new FormData();
for (const [key, value] of Object.entries(params)) {
......
......@@ -334,6 +334,21 @@ export function approvalCreate(data) {
});
}
/**
* 取消审核
*
* @export
* @param {*} data
* @return {*}
*/
export function approvalCancel(data) {
return request({
url: `/ecw/box-approval/cancel`,
method: "delete",
data,
});
}
/**
* 异常登记
*
......@@ -505,6 +520,21 @@ export function orderTagList(data) {
});
}
/**
* 单个装柜
*
* @export
* @param {*} data
* @return {*}
*/
export function singleCreate(data) {
return request({
url: "/ecw/box-load-info/singleCreate",
method: "post",
data,
});
}
/**
* 批量装柜
*
......@@ -520,6 +550,21 @@ export function batchCreate(data) {
});
}
/**
* 单个删除已装柜标签
*
* @export
* @param {*} data
* @return {*}
*/
export function singleDelete(data) {
return request({
url: "/ecw/box-load-info/singleDelete",
method: "post",
data,
});
}
/**
* 批量删除已装柜标签
*
......@@ -565,6 +610,20 @@ export function boxUpdate(data) {
});
}
/**
* 拆单审核
*
* @param {*} params
* @returns
*/
export function createApproval(data) {
return request({
url: "/ecw/box-approval/create",
method: "post",
data,
});
}
/***************************** 装柜 end **********************************/
/***************************** 卸柜 start **********************************/
......@@ -695,27 +754,72 @@ export function extraCostList(params) {
/***************************** 报关费用 end **********************************/
/***************************** 理货 start **********************************/
/**
* 服务提示消息回调
* 理货列表
*
* @export
* @param {*} result
* @param {*} _vue
* @param {*} data
* @return {*}
*/
export function serviceMsg(result, _vue) {
return new Promise((resolve, reject) => {
const { code, msg } = result;
if (code === 0) {
_vue.$message.success("操作成功");
resolve();
} else {
_vue.$message.error(msg);
reject();
}
export function getTallyList(data) {
return request({
url: "/shipment/box/tallyList",
method: "post",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
data: jsonToFormData(data),
});
}
/**
* 理货移出
*
* @export
* @param {*} data
* @return {*}
*/
export function tallyRemove(data) {
return request({
url: "/ecw/box-preload-goods/remove",
method: "post",
data,
});
}
/**
* 理货
*
* @export
* @param {*} data
* @return {*}
*/
export function tallyLocationUpdate(data) {
return request({
url: "/shipment/box/batchOrderLocationUpdate",
method: "post",
data,
});
}
/**
* 理货提交
*
* @export
* @param {*} data
* @return {*}
*/
export function tallyCommit(data) {
return request({
url: "/shipment/box/tallyCommit",
method: "post",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
data: jsonToFormData(data),
});
}
/***************************** 理货 end **********************************/
function jsonToFormData(params) {
const formData = new FormData();
for (const [key, value] of Object.entries(params)) {
......
import request from "@/utils/request";
/**
* 二程起飞
*
* @export
* @param {*} data
* @return {*}
*/
export function takeoffCreate(data) {
if (data.id) {
return request({
url: "/ecw/box-takeoff/update",
method: "put",
data,
});
}
return request({
url: "/ecw/box-takeoff/create",
method: "post",
data,
});
}
/**
* 二程到港
*
* @export
* @param {*} data
* @return {*}
*/
export function arrivalCreate(data) {
if (data.id) {
return request({
url: "/ecw/box-arrival-air/update",
method: "put",
data,
});
}
return request({
url: "/ecw/box-arrival-air/create",
method: "post",
data,
});
}
\ No newline at end of file
......@@ -52,3 +52,12 @@ export function exportBusiPwdExcel(query) {
responseType: 'blob'
})
}
// 验证业务密码
export function validatePwd(data){
return request({
url: '/ecw/busi-pwd/validate-pwd',
method: 'post',
data: data
})
}
\ No newline at end of file
......@@ -61,3 +61,12 @@ export function exportChannelExcel(query) {
responseType: 'blob'
})
}
//
export function getChannelListByIds(params){
return request({
url: '/ecw/channel/list',
method: 'get',
params
})
}
......@@ -155,3 +155,76 @@ export function userMemberUserList(){
method:'get'
})
}
//查看某客户授权的品牌
export function getBrankByCustomer(data){
return request({
url:'/ecw/product-brank/getBrankByCustomer',
method:'post',
data,
})
}
//
export function levelLogPage(params){
return request({
url:'/customer/detail/infoList/levelLogPage',
method:'get',
params
})
}
//获取信用等级日志列表
export function customerCreditLogPage(params){
return request({
url:'/customer/detail/infoList/creditLogPage',
method:'get',
params
})
}
//客户详情订单分页
export function infoListOrderPage(params){
return request({
url:'/customer/detail/infoList/orderPage',
method:'get',
params
})
}
//客户详情 --- 报价
export function infoListOfferPage(params){
return request({
url:'/customer/detail/infoList/offerPage',
method:'get',
params
})
}
//客户数据
export function orderStatistics(params){
return request({
url:'/customer/detail/infoList/orderStatistics',
method:'get',
params
})
}
//创建客户信用日志
export function creditLogCreate(data){
return request({
url:'/customer/credit-log/create',
method:'post',
data
})
}
//获得客户统计
export function creditScoreStatistic(params){
return request({
url:'/customer/detail/infoList/creditScoreStatistic',
method:'get',
params
})
}
//获取账单数据
export function infoListReceiptPage(params){
return request({
url:'/customer/detail/infoList/receiptPage',
method:'get',
params
})
}
......@@ -29,3 +29,12 @@ export function exportCustomerCommissionExcel(query) {
})
}
//
export function getDarkReturnCommission(data){
return request({
url: '/ecw/customer-commission/get-dark-return-commission',
method: 'post',
data
})
}
\ No newline at end of file
......@@ -9,6 +9,24 @@ export function createReceipt(data) {
})
}
// 更新收款单
export function updateReceipt(data) {
return request({
url: '/ecw/receipt/update',
method: 'put',
data: data
})
}
// 获取收款单列表
export function getReceiptList(query) {
return request({
url: '/ecw/receipt/page',
method: 'get',
params: query
})
}
// 获取应收款列表
export function getReceivableList(query) {
return request({
......@@ -18,6 +36,162 @@ export function getReceivableList(query) {
})
}
// 获取应收款详情
export function getReceivableInfoByIds(query) {
return request({
url: '/ecw/receivable/get',
method: 'get',
params: query
})
}
// 修改优惠信息
export function updateReceivableDiscountById(query) {
return request({
url: '/ecw/receivable/updateReceivableDiscountById',
method: 'post',
data: query
})
}
// 得到应收优惠的最后操作人
export function getReceivableDiscountLogById(query) {
return request({
url: '/ecw/receivable/getReceivableDiscountLogById',
method: 'get',
params: query
})
}
// 根据订单ID获得需要预付应收款列表
export function getFirstReceivableListByOrderId(query) {
return request({
url: '/ecw/receivable/getFirstReceivableListByOrderId',
method: 'get',
params: query
})
}
// 核销收款单
// export function receiptVerification(id) {
// return request({
// url: '/ecw/receipt/verification/' + id,
// method: 'GET'
// })
// }
// 反核销收款单
// export function receiptVerificationCancel(id) {
// return request({
// url: '/ecw/receipt/verificationCancel/' + id,
// method: 'GET'
// })
// }
// 获取收款单详情
export function getReceiptInfoByIds(query) {
return request({
url: '/ecw/receipt/get',
method: 'get',
params: query
})
}
// 获取收款单明细列表
export function getReceivableItemDetail(query) {
return request({
url: '/ecw/receipt/getReceivableItemDetail',
method: 'get',
params: query
})
}
// 获取收款单明细
export function getInvoicingItem(query) {
return request({
url: '/ecw/receipt/getInvoicingItem',
method: 'get',
params: query
})
}
// 创建收款明细
export function receiptItemCreate(data) {
return request({
url: '/ecw/receipt-item/create',
method: 'post',
data: data
})
}
// 根据收款单ID获得收款明细列表
export function getReceivableItem(query) {
return request({
url: '/ecw/receipt-item/getReceivableItem',
method: 'get',
params: query
})
}
// 根据收款单ID获得收款账户细列表
export function getReceiptAccountList(query) {
return request({
url: '/ecw/receipt/getReceiptAccountList',
method: 'get',
params: query
})
}
// 删除收款明细
export function deleteReceiptItem(id) {
return request({
url: '/ecw/receipt-item/delete?id=' + id,
method: 'delete'
})
}
// 更新收款明细
export function updateReceiptItem(data) {
return request({
url: '/ecw/receipt-item/update',
method: 'put',
data: data
})
}
// 收款明细核销
export function receiptItemVerification(id) {
return request({
url: '/ecw/receipt-item/verification/' + id,
method: 'GET'
})
}
// 反核销收款单
export function receiptItemVerificationCancel(id) {
return request({
url: '/ecw/receipt-item/verificationCancel/' + id,
method: 'GET'
})
}
// 收款明细批量核销
export function receiptItemBatchVerification(query) {
return request({
url: '/ecw/receipt-item/batchVerification',
method: 'GET',
params: query
})
}
// 收款单全部核销
export function receiptItemAllVerification(id) {
return request({
url: '/ecw/receipt-item/allVerification/' + id,
method: 'GET'
})
}
// 根据获取应收款列表
// export function getReceivableListByIds(query) {
// return request({
......@@ -27,6 +201,42 @@ export function getReceivableList(query) {
// })
// }
// 导出收款单 Excel
export function receiptExportExcel(query) {
return request({
url: '/ecw/receipt/export-excel',
method: 'get',
responseType: 'blob',
params: query
})
}
// 删除收款单
export function deleteReceipt(id) {
return request({
url: '/ecw/receipt/delete?id=' + id,
method: 'delete'
})
}
// 获得收款单开票信息
export function getReceiptInvoicing(id) {
return request({
url: '/ecw/receipt/invoicing/info/' + id,
method: 'get'
})
}
// 更新收款单开票信息
export function updateReceiptInvoicing(data) {
return request({
url: '/ecw/receipt/invoicing/info',
method: 'put',
data: data
})
}
// 更新应付款
export function updatePayable(data) {
return request({
......
import request from '@/utils/request'
// 创建预定舱计划
export function createFutureBox(data) {
return request({
url: '/ecw/future-box/create',
method: 'post',
data: data
})
}
// 更新预定舱计划
export function updateFutureBox(data) {
return request({
url: '/ecw/future-box/update',
method: 'put',
data: data
})
}
// 删除预定舱计划
export function deleteFutureBox(id) {
return request({
url: '/ecw/future-box/delete?id=' + id,
method: 'delete'
})
}
// 获得预定舱计划
export function getFutureBox(id) {
return request({
url: '/ecw/future-box/get?id=' + id,
method: 'get'
})
}
// 获得预定舱计划分页
export function getFutureBoxPage(query) {
return request({
url: '/ecw/future-box/page',
method: 'get',
params: query
})
}
// 导出预定舱计划 Excel
export function exportFutureBoxExcel(query) {
return request({
url: '/ecw/future-box/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 根据运输方式ID得到已封柜方数
export function getBoxedVolume(params){
return request({
url: '/ecw/future-box/getBoxedVolume',
method: 'get',
params
})
}
// 根据运输方式ID得到待入仓方数
export function getToBeWareHousedVolume(params){
return request({
url: '/ecw/future-box/getToBeWareHousedVolume',
method: 'get',
params
})
}
// 根据运输方式ID得到已入仓方数
export function getWareHousedVolume(params){
return request({
url: '/ecw/future-box/getWareHousedVolume',
method: 'get',
params
})
}
\ No newline at end of file
......@@ -90,10 +90,11 @@ export function createOfferSpecial(data) {
}
// 特价详情
export function getOfferSpecial(offerProdId) {
export function getOfferSpecial(offerProdId, params) {
return request({
url: '/ecw/offer/special/info/' + offerProdId,
method: 'get'
method: 'get',
params
})
}
......@@ -105,3 +106,21 @@ export function getOfferSpecialByApproveId(approveId) {
})
}
// 取消报价管理
export function cancel(id) {
return request({
url: '/ecw/offer/cancel',
method: 'delete',
params: {id}
})
}
// 恢复取消的报价管理
export function recovery(id) {
return request({
url: '/ecw/offer/recovery',
method: 'delete',
params: {id}
})
}
\ No newline at end of file
......@@ -103,12 +103,12 @@ export function feeApplicationListByOrderId(query){
})
}
// 创建特殊
// 批量更新特需
export function specialNeedCreate(data){
return request({
url:'ecw/order-special-need/create',
method:'post',
data:data,
url:'ecw/order-special-need/updateBatch',
method:'put',
data,
})
}
// 创建特殊
......@@ -163,6 +163,32 @@ export function orderWarehouseIn(data){
})
}
// 入仓修改
export function orderWarehouseInUpdateApply(data){
return request({
url: '/order/order-warehouse-in/update-apply',
method: 'put',
data
})
}
// 入仓修改箱号
export function orderWarehouseInUpdateLabel(data){
return request({
url: '/order/order-warehouse-in/update-label',
method: 'post',
data
})
}
// 获取入仓修改审批单详情-审批使用
export function getWarehouseUpdateApprovalInfo(id) {
return request({
url: '/order/order-warehouse-in/get-update-approval-info?formId=' + id,
method: 'get'
})
}
// 入仓完成
export function orderWarehouseInFinish(data){
return request({
......@@ -181,6 +207,15 @@ export function rollbackApply(data){
})
}
// 退仓-订单项退仓(不审批)
export function rollbackDelete(data){
return request({
url: '/order/order-warehouse-in/rollback-order-item',
method: 'put',
data
})
}
//取消订单
export function cancelOrder(orderId){
return request({
......@@ -207,32 +242,6 @@ export function getMyOrderPage(query) {
}
// 创建提货
export function createOrderPickup(data){
return request({
url: '/ecw/order-pickup/create',
method: 'post',
data
})
}
// 批量提货
export function createOrderPickupBatch(data){
return request({
url: '/ecw/order-pickup/createBatch',
method: 'post',
data
})
}
// 分批提货
export function createOrderPickupSplitBatch(data){
return request({
url: '/ecw/order-pickup/createSplitBatch',
method: 'post',
data
})
}
//根据流程ID获得订单信息
export function applicationGetOrderByProcessId(params){
return request({
......@@ -300,3 +309,123 @@ export function listByOrderId(params){
params,
})
}
// 获取快递单号
export function getOrderCourierNumber(params){
return request({
url:'/ecw/order/courier/number',
method:'get',
params,
})
}
// 获取审核
export function getApproval(id){
return request({
url:'/order/approval/get?id=' + id,
method:'get'
})
}
// 特价申请
export function createOrderSpecial(data) {
return request({
url: '/ecw/order/special/apply',
method: 'put',
data: data
})
}
// 特价申请
export function cancelOrderSpecial(orderApprovalId,data) {
return request({
url: '/ecw/order/cancel/approval/'+orderApprovalId,
method: 'get',
params:data
})
}
// 获得订单特价申请详情
export function getOrderSpecial(offerProdId, type = 1) {
return request({
url: '/ecw/order/special/info/' + offerProdId + '/' + type,
method: 'get'
})
}
// 根据订单项商品ID与审批类型获得订单商品的特价申请详情
export function getOrderSpecialByApproveId(approveId) {
return request({
url: '/ecw/order/special/info?approveId=' + approveId,
method: 'get'
})
}
// 订单号检索功能
export function getOrderNoSearch(params) {
return request({
url: '/ecw/order/orderNoSearch',
method: 'get',
params
})
}
// 提单号检索功能
export function getBillNoSearch(params) {
return request({
url: '/ecw/order/billNoSearch',
method: 'get',
params
})
}
// 根据合并订单编号获得已合单的订单动态
export function getMergeLogByMergedOrderNo(params){
return request({
url: '/order/merge/getMergeLogByMergedOrderNo',
method: 'get',
params
})
}
// 导入装箱单
export function orderImport(data) {
return request({
url: '/ecw/order/import',
method: 'post',
data
})
}
// 下载装箱单模板
export function exportPackingList(){
return request({
url: '/ecw/order/export-packing-list',
method: 'get',
responseType: 'blob'
})
}
//获得特需
export function orderSpecialNeedGet(params){
return request({
url:'/ecw/order-special-need/get',
method:'get',
params
})
}
//取消调仓
export function cancelAdjust(data){
return request({
url:'/order/order-warehouse-in/cancel-adjust',
method:'post',
data
})
}
//取消订单费用申请
export function feeApplicationCancel(data){
return request({
url:'/order/fee-application/cancel',
method:'delete',
data
})
}
\ No newline at end of file
......@@ -25,4 +25,110 @@ export function create(data){
method: 'post',
data
})
}
// 创建订单控货人放货记录
export function createPick(data){
return request({
url: '/ecw/order-cargo-control-pick/create',
method: 'post',
data
})
}
//获得控货订单放货编辑详情
export function getRleaseInfo(orderId){
return request({
url:'/ecw/order-cargo-control/release/info/' + orderId,
method:'get'
})
}
// 获得控货订单放货详情
export function getPickRleaseInfo(orderId){
return request({
url:'/ecw/order-cargo-control-pick/release/info/' + orderId,
method:'get'
})
}
// 放货修改与反复核申请
export function updateApply(data){
return request({
url: '/ecw/order-cargo-control-pick/update/apply',
method: 'put',
data
})
}
// 复核(放货复核)
export function review(id){
return request({
url: '/ecw/order-cargo-control-pick/review/' + id,
method: 'put'
})
}
// 取消放货
export function cancel(id){
return request({
url: '/ecw/order-cargo-control-pick/cancel/' + id,
method: 'put'
})
}
// 取消审批
export function cancelApproval(approvalId, params){
return request({
url: '/ecw/order-cargo-control-pick/cancel/approval/' + approvalId,
method: 'get',
params
})
}
// 订单复核
export function orderReview(orderId){
return request({
url: '/ecw/order-cargo-control/review/' + orderId,
method: 'put'
})
}
// 根据订单id批量复合订单控货人放货
export function batchReview(data){
return request({
url: '/ecw/order-cargo-control-pick/review/',
method: 'put',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data
})
}
// 获得可调货的控货订单列表
export function seasoningCondimentsSelect(params){
return request({
url: '/ecw/order-cargo-control-pick/seasoning-condiments/cargo-control/order/select',
method: 'get',
params
})
}
// 根据放货ID查询控货订单放货修改审核详情
export function getPpickUpdateInfo(id){
return request({
url: '/ecw/order-cargo-control-pick/update/info/{id}/' + id,
method: 'get'
})
}
// 获得控货订单放货修改申请详情 {approveId: 1}
export function getPickUpdateApproveInfo(params){
return request({
url: '/ecw/order-cargo-control-pick/update/info',
method: 'get',
params
})
}
\ No newline at end of file
......@@ -83,3 +83,12 @@ export function getOrderItemById(id) {
method: 'get'
})
}
// 根据订ID获取所有费用及比例
export function getOrderFeeById(query) {
return request({
url: '/ecw/order-exception/getOrderFeeById',
method: 'get',
params: query
})
}
\ No newline at end of file
import request from '@/utils/request'
// 根据合并订单编号(或订单号)获得已合单列表和待合单列表
export function getMergeListByOrderNo(query){
return request({
url:'/order/merge/getMergeListByOrderNo',
method: 'get',
params: query,
})
}
//创建订单合单申请
export function createMerge(data) {
return request({
url: '/order/merge/create',
method: 'post',
data: data
})
}
// 取消订单拆单
export function cancelMerge(data) {
return request({
url: '/order/merge/cancel',
method: 'delete',
data:data
})
}
//拆单申请提交
export function splitApply(data) {
return request({
url: '/order/split/apply',
method: 'put',
data: data
})
}
// 创建订单拆单
export function createSplit(data) {
return request({
url: '/order/split/create',
method: 'post',
data: data
})
}
// 更新订单拆单
export function updateSplit(data) {
return request({
url: '/order/split/update',
method: 'put',
data: data
})
}
// 删除订单拆单
export function deleteSplit(id) {
return request({
url: '/order/split/delete?id=' + id,
method: 'delete'
})
}
//取消申请拆单
export function cancelApply(data) {
return request({
url: '/order/split/cancel-apply',
method: 'put',
data:data
})
}
// 获得订单拆单
export function getSplit(id) {
return request({
url: '/order/split/get?id=' + id,
method: 'get'
})
}
// 获得订单拆单分页
export function getSplitPage(query) {
return request({
url: '/order/split/page',
method: 'get',
params: query
})
}
// 导出订单拆单 Excel
export function exportSplitExcel(query) {
return request({
url: '/order/split/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}
//通过订单号获取拆单列表和拆单项明细
export function getSplitList(query) {
return request({
url: '/order/split/list-by-order-id',
method: 'get',
params: query
})
}
// 创建订单拆单项 - 放入
export function createSplitItem(data) {
return request({
url: '/order/split-item/create',
method: 'post',
data: data
})
}
// 删除订单拆单项
export function deleteSplitItem(id) {
return request({
url: '/order/split-item/delete?id=' + id,
method: 'delete'
})
}
// 根据合并编号获得订单信息、已合单列表和待合单列表
export function getMergeListByMergeId(params){
return request({
url: '/order/merge/getMergeListByMergeId',
method: 'get',
params
})
}
\ No newline at end of file
import request from '@/utils/request'
// 根据订单编号获得分批提货数据
export function getPickUpListByOrderNo(params){
return request({
url:'/ecw/order-pickup/getPickUpListByOrderNo',
method:'get',
params
})
}
// 创建提货
export function create(data){
return request({
url: '/ecw/order-pickup/create',
method: 'post',
data
})
}
// 批量提货
export function createBatch(data){
return request({
url: '/ecw/order-pickup/createBatch',
method: 'post',
data
})
}
// 分批提货
export function createSplitBatch(data){
return request({
url: '/ecw/order-pickup/createSplitBatch',
method: 'post',
data
})
}
// 获取提货日志
export function getAllPickUpListByOrderNo(params){
return request({
url: '/ecw/order-pickup/getAllPickUpListByOrderNo',
method: 'get',
params
})
}
// 撤销提货日志
export function deletePickup(params){
return request({
url: '/ecw/order-pickup/delete',
method: 'delete',
params
})
}
......@@ -18,6 +18,15 @@ export function updateProductBrank(data) {
})
}
// 修改品牌默认收费模式
export function changeFeeModel(data) {
return request({
url: '/ecw/product-brank/changeFeeMode',
method: 'put',
data: data
})
}
// 删除品牌
export function deleteProductBrank(id) {
return request({
......@@ -52,3 +61,21 @@ export function exportProductBrankExcel(query) {
responseType: 'blob'
})
}
// 更新品牌
export function setUnauthCustomerFeeType(data) {
return request({
url: '/ecw/product-brank/setUnauthCustomerFeeType',
method: 'put',
data: data
})
}
//
export function getFeeTypeByCustomerProduct(data){
return request({
url: '/ecw/product-brank/getFeeTypeByCustomerProduct',
method: 'post',
data
})
}
......@@ -70,3 +70,22 @@ export function batchUpdateProductPrice(query) {
data: query
})
}
// 批量拉黑
export function batchBlock(query) {
return request({
url: '/ecw/product-price/batchBlock',
method: 'get',
params: query
})
}
// 批量下架
export function batchOff(query) {
return request({
url: '/ecw/product-price/batchOff',
method: 'get',
params: query
})
}
......@@ -52,3 +52,12 @@ export function exportReceiptExcel(query) {
responseType: 'blob'
})
}
// 根据订单ID获得应收款列表
export function getReceivableListByOrderId(params){
return request({
url: '/ecw/receivable/getReceivableListByOrderId',
method: 'get',
params
})
}
\ No newline at end of file
......@@ -98,3 +98,12 @@ export function getTradeCityList(query) {
params: query
})
}
export function listByIds(params){
return request({
url: '/ecw/region/listByIds',
method: 'get',
params
})
}
\ No newline at end of file
......@@ -35,10 +35,11 @@ export function getWarehouseArea(id) {
}
// 获得仓库查询库域
export function getByWarehouseId() {
export function getByWarehouseId(params) {
return request({
url: '/ecw/warehouse-area/getByWarehouseId',
method: 'get'
method: 'get',
params
})
}
......
......@@ -34,6 +34,15 @@ export function getZhongPao(id) {
})
}
// 获得客户最优惠的重泡货配置
export function getZhongPaoBest(query) {
return request({
url: '/ecw/zhong-pao/get-customer-best-zhong-pao',
method: 'get',
params: query
})
}
// 获得重泡货配置分页
export function getZhongPaoPage(query) {
return request({
......
......@@ -36,11 +36,11 @@ export function getUser(id) {
}
// 获得用户分页
export function getUserPage(query) {
export function getUserPage(params) {
return request({
url: '/member/user/page',
method: 'get',
params: query
params: params
})
}
......@@ -104,8 +104,8 @@ export function memberUserAuditIdCard(query) {
export function memberUserAuditEnterprise(query) {
return request({
url: '/member/user/audit-enterprise',
method: 'get',
params: query,
method: 'put',
data: query,
})
}
......@@ -143,3 +143,11 @@ export function userCreateAuditEnterprise(data){
data:data,
})
}
//新增用户
export function createAuditIdCard(data){
return request({
url:'/member/user/create-audit-idcard',
method:'put',
data
})
}
......@@ -34,6 +34,14 @@ export function getNeedKnow(id) {
})
}
// 根据key获得须知
export function getNeedKnowByKey(key) {
return request({
url: '/system/need-know/getByKey?key=' + key,
method: 'get'
})
}
// 获得须知分页
export function getNeedKnowPage(query) {
return request({
......@@ -52,3 +60,13 @@ export function exportNeedKnowExcel(query) {
responseType: 'blob'
})
}
// 下载需知
export function download(query) {
return request({
url: '/system/need-know/download',
method: 'get',
params: query,
responseType: 'blob'
})
}
import request from '@/utils/request'
// 查询公告列表
export function panelData() {
return request({
url: '/system/panel/panelData',
method: 'get'
})
}
\ No newline at end of file
......@@ -49,7 +49,7 @@ a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
// color: inherit;
text-decoration: none;
}
......
......@@ -36,7 +36,7 @@ $base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$base-sidebar-width: 200px;
$base-sidebar-width: 250px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
......
<template>
<selector v-model="valueSync" :options="countryList" value-field="tel" key-field="id" :label-field="item => $l(item, 'name') + ' +' + item.tel" filterable clearable :disabled="disabled"></selector>
</template>
<script>
import {getCountryListAll} from '@/api/ecw/country'
import selector from '@/components/Selector'
export default {
components: {selector},
props: {
value: String,
disabled: Boolean
},
data(){
return {
valueSync: '',
countryList:[]
}
},
watch:{
valueSync(){
this.$emit('input', this.valueSync.replace('+', ''))
},
value(){
if(this.value)this.valueSync = this.value
}
},
created(){
if(this.value){
this.valueSync = this.value
}
getCountryListAll().then(res => {
this.countryList = res.data.map(item => {
item.tel = item.tel.replace('+', '')
return item
})
})
},
methods:{
}
}
</script>
\ No newline at end of file
<template>
<div>
<el-select v-model="formData.country">
<el-option v-for="(item) in treeList" :value="item.id" :label="item.titleZh" :key="item.id" />
<el-select v-model="formData.country" :disabled="readonly">
<el-option v-for="(item) in treeList" :value="item.id" :label="$l(item, 'title')" :key="item.id" />
</el-select>
<el-select v-model="formData.province">
<el-option v-for="(item) in provinceList" :value="item.id" :label="item.titleZh" :key="item.id" />
<el-select v-model="formData.province" class="ml-10" :disabled="readonly">
<el-option v-for="(item) in provinceList" :value="item.id" :label="$l(item, 'title')" :key="item.id" />
</el-select>
<el-select v-model="formData.city">
<el-option v-for="(item) in cityList" :value="item.id" :label="item.titleZh" :key="item.id" />
<el-select v-model="formData.city" class="ml-10" :disabled="readonly">
<el-option v-for="(item) in cityList" :value="item.id" :label="$l(item, 'title')" :key="item.id" />
</el-select>
</div>
</template>
......@@ -15,41 +15,75 @@
import { getListTree } from "@/api/ecw/region";
export default {
props:{
country: Number,
city: Number,
province: Number,
readonly: Boolean
},
data(){
return {
formData:{
country: undefined,
province: undefined,
city: undefined
},
treeList: [],
provinceList: [],
cityList:[]
// provinceList: [],
// cityList:[]
}
},
watch:{
city(val){
this.$set(this.formData, 'city', val)
},
province(val){
this.$set(this.formData, 'province', val)
},
country(val){
this.$set(this.formData, 'country', val)
},
'formData.city'(city){
this.$emit('cityChange', city)
},
'formData.country'(country){
this.$emit('countryChange', country)
this.treeList.forEach(item => {
/* this.treeList.forEach(item => {
if(item.id == country){
this.provinceList = item.children || []
}
})
}) */
},
'formData.province'(province){
this.$emit('provinceChange', province)
this.provinceList.forEach(item => {
/* this.provinceList.forEach(item => {
if(item.id == province){
this.cityList = item.children || []
}
})
}) */
}
},
computed:{
provinceList(){
if(!this.formData.country) return []
let country = this.treeList.find(item => item.id == this.formData.country)
return country && country.children || []
},
cityList(){
if(!this.provinceList.length) return []
let province = this.provinceList.find(item => item.id == this.formData.province)
return province && province.children || []
}
},
created(){
getListTree({treeType: 1}).then(response => {
this.treeList = response.data
})
this.formData = {
country: this.country,
province: this.province,
city: this.city
}
}
}
</script>
\ No newline at end of file
......@@ -2,8 +2,8 @@
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ $l(item.meta,'title') }}</span>
<a v-else @click.prevent="handleLink(item)">{{ $l(item.meta,'title') }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
......
<template>
<el-dialog title="选择联系人" visible :before-close="closeDialog" :close-on-click-modal="false">
<div class="header mb-10 flex-center">
<div class="flex-center">关键字:</div>
<el-input v-model="form.searchKey" clearable class="w-200"></el-input>
<el-button type="primary" class="ml-10" @click="handleQuery">搜索</el-button>
</div>
<div class="list">
<div class="list-item" v-for="item in list" :key="item.customerContactsId" @click="choose(item)">
<div class="item-box">
<div class="line">
<div class="label">姓名:</div>
<div class="value">{{item.contactsName}}</div>
</div>
<div class="line">
<div class="label">电话:</div>
<div class="value">{{item.areaCode}} {{item.phoneNew}}</div>
</div>
<div class="line">
<div class="label">邮箱:</div>
<div class="value">{{item.email}}</div>
</div>
<div class="line">
<div class="label">公司:</div>
<div class="value">{{item.company}}</div>
</div>
</div>
</div>
</div>
<pagination v-show="total > 0" :total="total" :page.sync="form.pageNo" :limit.sync="form.pageSize"
@pagination="loadList" />
</el-dialog>
</template>
<script>
import {getCustomerContactsSelect} from '@/api/ecw/customerContacts'
export default {
props:{
type: Number
},
data(){
return {
show: true,
form:{
pageNo: 1,
pageSize: 10,
searchKey: ''
},
list:[],
total: 0
}
},
created(){
this.show = true
this.loadList()
},
methods:{
handleQuery(){
this.form.pageNo = 1
this.loadList()
},
loadList(){
getCustomerContactsSelect(this.form).then(res => {
this.list = res.data.list
this.total = res.data.total
})
},
closeDialog(){
this.show = false
this.$emit('close');
},
choose(contact){
this.$emit('choose', contact)
}
}
}
</script>
<style lang="scss" scoped>
.header{
display: flex;
}
.list{
display: flex;
flex-wrap: wrap;
justify-content: center;
&-item{
background: #eee;
width: 300px;
margin: 10px;
padding: 5px;
border-radius: 10px;
border: 5px solid transparent;
background: linear-gradient(white,white) padding-box,repeating-linear-gradient(-45deg, red 0, red 12.5%, transparent 0, transparent 25%, #58a 0, #58a 37.5%, transparent 0, transparent 50%) 0/5em 5em;
.item-box{
/* background: #fbfaf5; */
padding: 20px;
}
.line{
display: flex;
/* .label{
width: 100px;
} */
.value{
flex: 1;
margin-left: 10px;
}
}
}
}
</style>
<template>
<el-select
v-model="index"
filterable
clearable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="remoteMethod"
:loading="loading">
<el-option
v-for="(item, index) in list"
:key="item.id"
:label="`${item.contactsName}`"
:value="index">
</el-option>
</el-select>
<div>
<el-select
v-model="index"
filterable
clearable
remote
reserve-keyword
:placeholder="$t('请输入关键词')"
:remote-method="remoteMethod"
:loading="loading">
<el-option
v-for="(item, index) in formattedList"
:key="item.id"
:label="`${item.label}`"
:value="index">
</el-option>
</el-select>
<!-- <el-button v-if="quickable" type="text" @click="showQuickCreate=true" class="ml-10">{{$t('快速新建')}}</el-button> -->
<!-- <quick-create v-if="showQuickCreate" @success="onQuickCreateSuccess" @close="showQuickCreate=false" :default="{type}"></quick-create> -->
</div>
</template>
<script>
import {getCustomerContactsSelect, getCustomerContacts} from '@/api/ecw/customerContacts'
import {getCustomerContactsSelect, getCustomerContactsListByCustomer} from '@/api/ecw/customerContacts'
import QuickCreateCustomer from '@/components/QuickCreateCustomer'
import Vue from 'vue'
export default {
components:{QuickCreateCustomer},
props:{
value: [String, Number]
value: [String, Number],
quickable: {
type: Boolean,
default: true
},
type: String, // 客户类别,新建时指定默认类别,也可以根据需要筛选联系人所属的客户类别
},
data(){
return {
index: null,
list:[],
loading: false,
size: 20
size: 20,
showQuickCreate: false
}
},
computed:{
formattedList(){
return this.list.map(item => {
item.label = item.contactsName
let more = []
if(item.customerName){
more.push(item.customerName)
}
if(item.phoneNew){
more.push(item.phoneNew)
}
if(item.email){
more.push(item.email)
}
if(more.length){
item.label += `(${more.join('|')})`
}
return item
})
}
},
watch:{
......@@ -38,6 +72,31 @@ export default {
},
value(val){
this.init()
},
showQuickCreate(){
if(!this.showQuickCreate)return
const QuickCreateComp = Vue.extend(QuickCreateCustomer)
const dialog = new QuickCreateComp({
propsData:{
type: this.type
},
})
dialog.$on('close', () => {
console.log('关闭拉')
this.showQuickCreate = false
document.body.removeChild(dialog.$el)
dialog.$destroy()
})
dialog.$on('success', (id) => {
this.onQuickCreateSuccess(id)
dialog.$emit('close')
})
dialog.$mount()
window.dialogComp = dialog
document.body.append(dialog.$el)
}
},
created(){
......@@ -51,7 +110,7 @@ export default {
if(index < 0){
getCustomerContactsSelect({ids: this.value}).then(res => {
if(!res.data || !res.data.length){
return this.$message.error('联系人信息获取失败')
return this.$message.error(this.$t('联系人信息获取失败'))
}
this.list.unshift(res.data[0])
this.index = 0
......@@ -67,6 +126,20 @@ export default {
getCustomerContactsSelect(params)
.then(res => this.list = res.data)
.finally(() => this.loading = false)
},
onQuickCreateSuccess(data){
this.showQuickCreate = false
this.list.unshift(data)
this.index = 0
/* getCustomerContactsListByCustomer({customerId: id}).then(res => {
if(!res.data || !res.data.length){
return this.$message.error(this.$t('联系人信息获取失败'))
}
let data = res.data[0]
data.contactsName = data.name // 字段名跟getCustomerContactsSelect对齐
this.list.unshift(data)
this.index = 0
}) */
}
}
}
......
......@@ -3,9 +3,9 @@
<el-col :span="10">
<el-card>
<div slot="header" class="header">
<el-input v-model="queryParams.searchKey" placeholder="用户名/手机/邮箱" style="width:200px" />
<el-input v-model="queryParams.searchKey" :placeholder="$t('用户名/手机/邮箱')" style="width:200px" />
<!-- <dict-selector :type="DICT_TYPE.USER_TYPE" v-model="queryParams.customerType" style="width:100px" /> -->
<el-button type="primary" @click="reLoad">搜索</el-button>
<el-button type="primary" @click="reLoad">{{$t('搜索')}}</el-button>
</div>
<div class="list">
<template v-for="item in list" >
......@@ -20,7 +20,7 @@
<el-col :span="10">
<el-card>
<div slot="header" class="header">
已选客户
{{$t('已选客户')}}
</div>
<div class="list">
<div class="item" v-for="item in choosedList" :key="item.customerContactsId">
......
......@@ -10,7 +10,7 @@
>
<el-table-column
type="index"
label="#"
label="序号"
>
</el-table-column>
<el-table-column
......@@ -59,17 +59,18 @@
title="客户跟进"
:visible.sync="customerFollow.dialogVisible"
:close-on-click-modal="false"
:before-close="customerFollowClose"
width="680px">
<el-form ref="customerFollowForm" :model="customerFollow.form" label-width="80px">
<el-row :gutter="10">
<el-col>
<el-form-item label="跟进类型" required>
<dict-selector form-type="radio" v-model="customerFollow.form.followType" :type="DICT_TYPE.CUSTOMER_FOLLOW_TYPE"></dict-selector>
<dict-selector ref="dictType" form-type="radio" v-model="customerFollow.form.followType" :type="DICT_TYPE.CUSTOMER_FOLLOW_TYPE"></dict-selector>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="跟进时间" required>
<el-date-picker v-model="customerFollow.form.followTime" type="datetime" placeholder="选择跟进时间"></el-date-picker>
<el-date-picker v-model="customerFollow.form.followTime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="选择跟进时间"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
......@@ -98,7 +99,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="跟进方式" required>
<dict-selector v-model="customerFollow.form.followMethod" :type="DICT_TYPE.CUSTOMER_FOLLOW_METHOD"></dict-selector>
<dict-selector ref="dictMethod" v-model="customerFollow.form.followMethod" :type="DICT_TYPE.CUSTOMER_FOLLOW_METHOD"></dict-selector>
</el-form-item>
</el-col>
<el-col>
......@@ -114,7 +115,7 @@
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="customerFollow.dialogVisible = false">取 消</el-button>
<el-button @click="customerFollowClose">取 消</el-button>
<el-button type="primary" @click="customerFollowSubmit">确 定</el-button>
</span>
</el-dialog>
......@@ -157,9 +158,10 @@ export default {
},
created() {
this.resetCustomerFollowForm()
// this.resetCustomerFollowForm()
if (!!this.customerId) getCustomerContactsListByCustomer({customerId: this.customerId}).then(r => {
this.customerContactsList = r.data
this.customerFollow.form.customerId = this.customerId
})
listServiceUser().then(r => {
this.serviceUserList = r.data
......@@ -172,16 +174,46 @@ export default {
if (!valid) {
return
}
if(!this.customerFollow.form.followType){
this.$modal.msgError("请选择跟进类型");
return
}
if(!this.customerFollow.form.followTime){
this.$modal.msgError("请选择跟进时间");
return
}
if(!this.customerFollow.form.contactName){
this.$modal.msgError("请选择联系人");
return
}
if(!this.customerFollow.form.followUserId){
this.$modal.msgError("请选择跟进业务");
return
}
if(!this.customerFollow.form.followMethod){
this.$modal.msgError("请选择跟进方式");
return
}
if(!this.customerFollow.form.feedback){
this.$modal.msgError("请输入客户反馈");
return
}
if(!this.customerFollow.form.result){
this.$modal.msgError("请输入处理结果");
return
}
createCustomerFollow(this.customerFollow.form).then(r => {
this.resetCustomerFollowForm()
this.customerFollowClose()
this.getCustomerFollowList()
this.customerFollow.dialogVisible = false
})
})
},
customerFollowClose(){
this.resetCustomerFollowForm()
this.customerFollow.dialogVisible = false
},
resetCustomerFollowForm() {
console.log(11)
this.customerFollow.form = {
"bizId": this.id,
"contactName": undefined,
......@@ -192,6 +224,8 @@ export default {
"followUserId": undefined,
"result": undefined
}
this.$refs.dictType.changeValue(this.customerFollow.form.followType);
this.$refs.dictMethod.changeValue(this.customerFollow.form.followMethod);
},
getCustomerFollowList() {
getCustomerFollowPage({bizId: this.id}).then(r => {
......
......@@ -5,22 +5,23 @@
title="客户跟进"
:visible.sync="customerFollow.dialogVisible"
:close-on-click-modal="false"
:before-close="customerFollowClose"
width="680px">
<el-form ref="customerFollowForm" :model="customerFollow.form" label-width="80px">
<el-form ref="customerFollowForm" :model="form" label-width="80px">
<el-row :gutter="10">
<el-col>
<el-form-item label="跟进类型" required>
<dict-selector form-type="radio" v-model="customerFollow.form.followType" :type="DICT_TYPE.CUSTOMER_FOLLOW_TYPE"></dict-selector>
<dict-selector ref="dictTag" form-type="radio" v-model="form.followType" :type="DICT_TYPE.CUSTOMER_FOLLOW_TYPE"></dict-selector>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="跟进时间" required>
<el-date-picker v-model="customerFollow.form.followTime" type="datetime" placeholder="选择跟进时间"></el-date-picker>
<el-date-picker v-model="form.followTime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="选择跟进时间"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人" required>
<el-select v-model="customerFollow.form.contactName" placeholder="请选择">
<el-select v-model="form.contactName" placeholder="请选择">
<el-option
v-for="(item, index) in customerContactsList"
:key="index"
......@@ -32,7 +33,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="跟进业务" required>
<el-select v-model="customerFollow.form.followUserId" placeholder="请选择">
<el-select v-model="form.followUserId" placeholder="请选择">
<el-option
v-for="item in serviceUserList"
:key="item.id"
......@@ -44,23 +45,23 @@
</el-col>
<el-col :span="12">
<el-form-item label="跟进方式" required>
<dict-selector v-model="customerFollow.form.followMethod" :type="DICT_TYPE.CUSTOMER_FOLLOW_METHOD"></dict-selector>
<dict-selector ref='dictMethod' v-model="form.followMethod" :type="DICT_TYPE.CUSTOMER_FOLLOW_METHOD"></dict-selector>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="客户反馈" required>
<el-input type="textarea" v-model="customerFollow.form.feedback"></el-input>
<el-input type="textarea" v-model="form.feedback"></el-input>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="处理结果" required>
<el-input type="textarea" v-model="customerFollow.form.result"></el-input>
<el-input type="textarea" v-model="form.result"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="customerFollow.dialogVisible = false">取 消</el-button>
<el-button @click="customerFollowClose">取 消</el-button>
<el-button type="primary" @click="customerFollowSubmit">确 定</el-button>
</span>
</el-dialog>
......@@ -94,17 +95,19 @@ export default {
customerFollowList: [],
serviceUserList: [],
customerContactsList: [],
customerFollow: {
customerFollow:{
dialogVisible: false,
form: {}
},
form: {}
}
},
created() {
// this.resetCustomerFollowForm()
if (!!this.customerId) getCustomerContactsListByCustomer({customerId: this.customerId}).then(r => {
this.customerContactsList = r.data
// this.$set(form, 'customerId', this.customerId)
// this.customerFollow.form.customerId = this.customerId
})
listServiceUser().then(r => {
this.serviceUserList = r.data
......@@ -112,21 +115,52 @@ export default {
},
methods: {
customerFollowSubmit() {
console.log(this.form)
this.$refs["customerFollowForm"].validate(valid => {
if (!valid) {
return
}
createCustomerFollow(this.customerFollow.form).then(r => {
this.resetCustomerFollowForm()
this.customerFollow.dialogVisible = false
if(!this.form.followType){
this.$modal.msgError("请选择跟进类型");
return
}
if(!this.form.followTime){
this.$modal.msgError("请选择跟进时间");
return
}
if(!this.form.contactName){
this.$modal.msgError("请选择联系人");
return
}
if(!this.form.followUserId){
this.$modal.msgError("请选择跟进业务");
return
}
if(!this.form.followMethod){
this.$modal.msgError("请选择跟进方式");
return
}
if(!this.form.feedback){
this.$modal.msgError("请输入客户反馈");
return
}
if(!this.form.result){
this.$modal.msgError("请输入处理结果");
return
}
this.$set(this.form, 'customerId', this.customerId)
createCustomerFollow(this.form).then(r => {
this.customerFollowClose()
})
})
},
customerFollowClose(){
this.resetCustomerFollowForm()
this.customerFollow.dialogVisible = false
},
resetCustomerFollowForm() {
this.customerFollow.form = {
"bizId":undefined,
var form = {
"bizId":this.id,
"contactName": undefined,
"feedback": undefined,
"followMethod": undefined,
......@@ -135,12 +169,15 @@ export default {
"followUserId": undefined,
"result": undefined
}
this.form = Object.assign({},form)
this.$refs.dictTag.changeValue(this.form.followType);
this.$refs.dictMethod.changeValue(this.form.followMethod);
},
},
watch:{
customerId(val){
this.customerFollow.form.bizId = val;
this.form.bizId = val;
if (!!this.customerId) getCustomerContactsListByCustomer({customerId: this.customerId}).then(r => {
this.customerContactsList = r.data
})
......
......@@ -5,7 +5,7 @@
clearable
remote
reserve-keyword
placeholder="请输入关键词"
:placeholder="$t('请输入关键词')"
:remote-method="remoteMethod"
:loading="loading">
<el-option
......
......@@ -3,9 +3,9 @@
<el-col :span="10">
<el-card>
<div slot="header" class="header">
<el-input v-model="queryParams.searchKey" placeholder="用户名/手机/邮箱" style="width:200px" />
<el-input v-model="queryParams.searchKey" :placeholder="$t('用户名/手机/邮箱')" style="width:200px" />
<dict-selector :type="DICT_TYPE.USER_TYPE" v-model="queryParams.customerType" style="width:100px" />
<el-button type="primary" @click="reLoad">搜索</el-button>
<el-button type="primary" @click="reLoad">{{$t('搜索')}}</el-button>
</div>
<div class="list">
<div class="item" v-for="item in list" :key="item.id">
......@@ -18,7 +18,7 @@
<el-col :span="10">
<el-card>
<div slot="header" class="header">
已选客户
{{$t('已选客户')}}
</div>
<div class="list">
<div class="item" v-for="item in choosedList" :key="item.id">
......@@ -94,7 +94,7 @@ export default {
},
loadNextPage(){
if(this.page >= this.pages){
return this.$message.error('已加载全部')
return this.$message.info(this.$t('已加载全部'))
}
this.queryParams.page ++
this.getList()
......
<template>
<div class="dict-selector">
<el-select v-if="formType == 'select'" v-model="valueSync" :placeholder="placeholder" clearable :multiple="multiple" :disabled="disabled">
<el-select v-if="formType == 'select'" v-model="valueSync" :placeholder="placeholder" :clearable="clearable" :multiple="multiple" :disabled="disabled" @change="val => $emit('change', val)">
<el-option v-for="dict in formattedList"
:key="dict.value" :label="dict.label" :value="dict.value"/>
:key="dict.value" :label="$l(dict, 'label')" :value="dict.value"/>
</el-select>
<el-radio-group v-if="formType == 'radio'" v-model="valueSync" :disabled="disabled">
<el-radio v-for="dict in formattedList" :label="dict.value" :checked="valueSync === dict.value" :key="dict.value">{{dict.label}}</el-radio>
<el-radio v-for="dict in formattedList" :label="dict.value" :checked="valueSync === dict.value" :key="dict.value">{{$l(dict, 'label')}}</el-radio>
</el-radio-group>
<el-checkbox-group v-if="formType == 'checkbox'" v-model="valueSync" :disabled="disabled">
<el-checkbox v-for="dict in formattedList" :label="dict.value" :key="dict.value">{{dict.label}}</el-checkbox>
<el-checkbox v-for="dict in formattedList" :label="dict.value" :key="dict.value">{{$l(dict, 'label')}}</el-checkbox>
</el-checkbox-group>
</div>
</template>
......@@ -40,10 +40,6 @@ export default {
type: [Function, String],
default: String
},
/* forceString: {
type: Boolean,
default: true
}, */
defaultable: Boolean, // 是否默认选择第一个
disabled: Boolean,
/**
......@@ -52,7 +48,8 @@ export default {
filter: {
type: Function,
default: () => true
}
},
clearable: Boolean
},
data(){
return {
......@@ -68,6 +65,7 @@ export default {
this.dictList.forEach(item => {
arr.push({
label: item.label,
labelEn: item.labelEn,
value: this.format(item.value),
cssClass: item.cssClass,
colorType: item.colorType
......@@ -78,11 +76,10 @@ export default {
},
watch:{
valueSync(val){
//this.$emit('input', this.forceString ? String(this.valueSync) : this.valueSync)
this.$emit('input', this.format(val))
this.$emit('input', val)
},
value(val){
this.setValueSync()
if(val != this.valueSync)this.setValueSync()
},
dictList(){
this.setDefault()
......@@ -91,10 +88,10 @@ export default {
created(){
this.setValueSync()
this.setDefault()
},
},
methods:{
format(val){
if(val === null || val == undefined) return val
if(val === null || val == undefined || val == '') return val
let formatter = typeof this.formatter == 'function' ? this.formatter : FORMATTERS[this.formatter]
if(!formatter){
console.warn('格式器无效', this.formatter)
......@@ -102,8 +99,13 @@ export default {
}
return formatter(val)
},
changeValue(val){
this.valueSync = val
},
setValueSync(){
if(this.value === null || this.value === undefined || this.value === '') return
if(this.value === null || this.value === undefined || this.value === ''){
return this.valueSync = this.multiple ? [] : this.value
}
if(this.multiple){
let value = []
if(typeof this.value == 'string'){
......@@ -111,19 +113,15 @@ export default {
}
this.valueSync = value.map(item => this.format(item))
}else{
this.valueSync = this.format(this.value)
this.valueSync = this.format(this.value)
}
/* if(this.forceString && this.multiple){
this.valueSync = this.value.split(',')
}else this.valueSync = this.forceString ? String(this.value) : this.value */
},
getList(){
return this.getDictDatas(this.type)
},
setDefault(){
if(!this.defaultable) return
if(this.dictList.length && (this.valueSync === null || this.valueSync == '')){
if(!this.defaultable) return
if(this.dictList.length && (this.valueSync === null || this.valueSync == undefined || this.valueSync == '')){
this.valueSync = this.multiple ? [] : this.formattedList[0].value
}
}
......@@ -134,4 +132,4 @@ export default {
.dict-selector{
display: inline-block;
}
</style>
\ No newline at end of file
</style>
......@@ -3,10 +3,10 @@
<template v-for="(dict, index) in this.getDictDatas2(type, value)">
<!-- 默认样式 -->
<span v-if="dict.colorType === 'default' || dict.colorType === '' || dict.colorType === undefined" :key="dict.value" :index="index"
:class="dict.cssClass">{{ dict.label }}</span>
:class="dict.cssClass">{{ $l(dict, 'label') }}</span>
<!-- Tag 样式 -->
<el-tag v-else :disable-transitions="true" :key="dict.value" :index="index" :type="dict.colorType" :class="dict.cssClass">
{{ dict.label }}
{{ $l(dict, 'label') }}
</el-tag>
</template>
</span>
......
......@@ -73,7 +73,7 @@ export default {
number: 0,
uploadList: [],
baseUrl: process.env.VUE_APP_BASE_API,
uploadFileUrl: process.env.VUE_APP_BASE_API + "/app-api/file/upload", // 上传的文件服务器地址
uploadFileUrl: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/org-name/up", // 上传的文件服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
......
<template>
<div class="need-know" :id="'need-know_' + keyname" v-if="detail">
<!-- <h2>{{detail.titleZh}}</h2> -->
<div class="body" ref="body" v-html="$l(detail, 'content')"></div>
</div>
</template>
<script>
import {getNeedKnowByKey, download} from '@/api/system/needKnow'
import html2canvas from 'html2canvas'
import FileSaver from 'file-saver'
import saveFie from '@/plugins/download'
export default {
props:{
keyname: String
},
data(){
return {
detail: null
}
},
created(){
getNeedKnowByKey(this.keyname).then(res => {
this.detail = res.data
})
},
methods:{
downloadPdf(){
download({id: this.detail.id}).then(res => {
this.$download.pdf(res, '入仓须知.pdf')
})
},
download(){
// 直接保存图片
let l = this.$loading()
/* document.querySelectorAll(`#need-know_${this.keyname} img`).forEach(img => {
img.setAttribute('crossOrigin', '*')
}) */
html2canvas(document.querySelector("#need-know_" + this.keyname)).then(canvas => {
canvas.toBlob((blob) => {
FileSaver.saveAs(blob, this.keyname + '.png')
})
}).finally(res => {
l.close()
});
},
}
}
</script>
<style scoped>
.body img{
max-width: 100%;
}
.need-know{
padding: 20px;
}
</style>
\ No newline at end of file
......@@ -2,9 +2,9 @@
<div>
<el-descriptions border v-if="order.orderId">
<el-descriptions-item label="唛头">{{ order.marks }}</el-descriptions-item>
<el-descriptions-item label="已到箱数">{{ order.sumNum }}</el-descriptions-item>
<el-descriptions-item label="订单状态"><dict-tag :type="DICT_TYPE.ORDER_STATUS" :value="order.status" /></el-descriptions-item>
<el-descriptions-item label="送货时间">{{ order.consigneeVO && order.consigneeVO.deliveryDate || '' }}</el-descriptions-item>
<el-descriptions-item label="已到箱数/总箱数">{{ order.sumNum }}/{{ order.costVO.totalNum }}</el-descriptions-item>
<el-descriptions-item label="订单状态"><dict-tag :type="DICT_TYPE.ORDER_STATUS" :value="order.status" :class="{red: order.status === 1, green: order.status === 5 || order.status === 2}" /></el-descriptions-item>
<el-descriptions-item label="送货时间">{{ order.deliveryDate || '' }}</el-descriptions-item>
<el-descriptions-item label="运输方式">
<dict-tag :type="DICT_TYPE.ECW_TRANSPORT_TYPE" :value="order.logisticsInfoDto.transportId"></dict-tag>
</el-descriptions-item>
......@@ -12,10 +12,10 @@
<el-descriptions-item label="目的地">{{ order.logisticsInfoDto.destTitleZh || '' }}</el-descriptions-item>
<el-descriptions-item label="发货人姓名">{{ order.consignorVO && order.consignorVO.name || ''}}</el-descriptions-item>
<el-descriptions-item label="发货人公司">{{ order.consignorVO && order.consignorVO.company || '' }}</el-descriptions-item>
<el-descriptions-item label="发货人电话">{{ order.consignorVO && order.consignorVO.phone || '' }}</el-descriptions-item>
<el-descriptions-item label="发货人电话">{{ order.consignorVO && (order.consignorVO.countryCode + order.consignorVO.phone) || '' }}</el-descriptions-item>
<el-descriptions-item label="收货人姓名">{{ order.consigneeVO && order.consigneeVO.name || ''}}</el-descriptions-item>
<el-descriptions-item label="收货人公司">{{ order.consigneeVO && order.consigneeVO.company || '' }}</el-descriptions-item>
<el-descriptions-item label="收货人电话">{{ order.consigneeVO && order.consigneeVO.phone || '' }}</el-descriptions-item>
<el-descriptions-item label="收货人电话">{{ order.consigneeVO &&(order.consigneeVO.countryCode + order.consigneeVO.phone) || '' }}</el-descriptions-item>
<el-descriptions-item label="入仓类型">{{ getDictDataLabel(DICT_TYPE.ECW_WAREHOUSING_TYPE, order.warehouseType) }}</el-descriptions-item>
<el-descriptions-item label="订单号">{{ order.orderNo }}</el-descriptions-item>
</el-descriptions>
......@@ -41,6 +41,12 @@ export default {
}
</script>
<style scoped>
<style scoped lang="scss">
@import "src/assets/styles/element-variables";
.red{
color: $--color-danger;
}
.green{
color: $--color-success;
}
</style>
......@@ -5,14 +5,15 @@
clearable
remote
reserve-keyword
placeholder="请输入商品关键词"
:placeholder="$t('请输入商品关键词')"
:disabled="disabled"
:remote-method="remoteMethod"
@focus="remoteMethod()"
:loading="loading">
<el-option
v-for="(item, index) in list"
:key="item.id"
:label="item.titleZh"
:label="item['title' + lang]"
:value="index">
</el-option>
......@@ -25,7 +26,11 @@ export default {
props:{
productType: [String, Number],
value: [String, Number],
disabled: Boolean
disabled: Boolean,
lang: {
type: String,
default: 'Zh'
}
},
data(){
return {
......@@ -36,7 +41,6 @@ export default {
},
watch:{
index(val){
let productId = val !== '' && val !== null ? this.list[val].id : null
console.log('index val', val, productId)
this.$emit('input', productId)
......@@ -45,15 +49,7 @@ export default {
},
value(val){
console.log('初始化内容', val)
/* let index = this.list.findIndex(item => item.id == val)
if(index < 0){
getProduct(val).then(res => {
this.list.unshift(res.data)
this.index = 0
})
} */
this.init()
}
},
created(){
......@@ -62,17 +58,22 @@ export default {
},
methods:{
init(){
if(!this.value) return null
if(!this.value){
this.index = null
return
}
let index = this.list.findIndex(item => item.id == this.value)
if(index < 0){
getProduct(this.value).then(res => {
this.list.unshift(res.data)
this.index = 0
})
}
}else this.index = index
},
remoteMethod(keyword){
let params = {}
let params = {
pageSize: keyword ? 100000 : 10
}
if(this.productType){
params.typeId = this.productType
}
......
<template>
<el-row class="" :gutter="10">
<el-col :span="10">
<div class="flex" :gutter="10">
<div class="flex-1">
<el-card>
<div slot="header" class="header">
<el-select v-model="queryParams.typeId" placeholder="选择类型" style="width:120px" clearable>
<el-select v-model="queryParams.typeId" :placeholder="$t('选择类型')" style="width:120px" clearable>
<el-option v-for="item in typeList" :key="item.id" :label="item.titleZh" :value="item.id" />
</el-select>
<el-select v-model="queryParams.attrId" placeholder="选择属性" style="width:120px" clearable>
<el-select v-model="queryParams.attrId" :placeholder="$t('选择属性')" style="width:120px" clearable>
<el-option v-for="item in attrList" :key="item.id" :label="item.attrName" :value="item.id" />
</el-select>
<el-input v-model="queryParams.titleZh" placeholder="产品关键字" style="width:120px" clearable />
<el-button type="primary" @click="reLoad">搜索</el-button>
<el-input v-model="queryParams.titleZh" :placeholder="$t('产品关键字')" style="width:120px" clearable />
<el-button type="primary" @click="reLoad">{{$t('搜索')}}</el-button>
</div>
<div class="list">
<div class="item" v-for="item in list" :key="item.id">
......@@ -19,11 +19,11 @@
</div>
</div>
</el-card>
</el-col>
<el-col :span="10">
<el-card>
</div>
<div class="flex-1 ml-10">
<el-card style="height:100%">
<div slot="header" class="header">
已选产品
{{$t('已选产品')}}
</div>
<div class="list">
<div class="item" v-for="(choosed) in choosedList" :key="choosed.id" :data-data="JSON.stringify(choosed)">
......@@ -32,8 +32,8 @@
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import { getProductPage } from '@/api/ecw/product'
......@@ -99,7 +99,7 @@ export default {
},
loadNextPage() {
if (this.page >= this.pages) {
return this.$message.error('已加载全部')
return this.$message.error(this.$t('已加载全部'))
}
this.queryParams.page++
this.getList()
......
<template>
<el-dialog :visible.sync="show" title="快速新建客户" :close-on-click-modal="false" class="quick-create-customer">
<el-form ref="form" :model="form" :rules="rules" label-width="100px" :validate-on-rule-change="false">
<el-form-item label="客户类别" prop="type">
<dict-selector :type="DICT_TYPE.CUSTOMER_TYPE" form-type="checkbox" multiple v-model="form.type"></dict-selector>
</el-form-item>
<el-form-item label="客户名称" prop="name">
<el-input v-model="form.name" placeholder="请输入客户名称" />
</el-form-item>
<el-form-item label="联系人" prop="customerContacts.0.name">
<el-input v-model="form.customerContacts[0].name" placeholder="请输入联系人" />
</el-form-item>
<el-form-item label="手机号" prop="customerContacts.0.phoneNew">
<el-select v-model="form.customerContacts[0].areaCode" placeholder="请选择区号" filterable class="w-200">
<el-option v-for="(item, index) in countryList"
:key="index" :label="item.nameShort + item.nameZh + '(' + item.tel + ')'" :value="item.tel" />
</el-select>
<el-input v-model="form.customerContacts[0].phoneNew" placeholder="请输入联系方式" class="w-150 ml-10"/>
</el-form-item>
<el-form-item label="客户来源" prop="source">
<el-select v-model="form.source" placeholder="请选择客户来源">
<el-option v-for="dict in getDictDatas(DICT_TYPE.CUSTOMER_SOURCE)"
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="form.createTime"
type="datetime"
value-format="timestamp"
placeholder="选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="客户经理" prop="customerService">
<el-select v-model="form.customerService" placeholder="请选择客户经理">
<el-option v-for="item in serviceUserList"
:key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="form.remarks" placeholder="请输入备注"/>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</template>
<script>
import {createCustomer} from '@/api/ecw/customer'
import {listServiceUser} from "@/api/system/user"
import { getCountryListAll } from '@/api/ecw/country'
import {getCustomerContactsSelect} from '@/api/ecw/customerContacts'
export default {
name: "quickCreateCustomer",
props:{
type: String,
},
data(){
return {
show: true,
// 表单参数
form: {
customerContacts:[{}]
},
// 表单校验
rules: {
name : [{ required: true, message: this.$t("客户名称不能为空"), trigger: "blur" }],
'customerContacts.0.phoneNew' : [{ required: true, message: this.$t("手机号不能为空"), trigger: "blur" }],
'customerContacts.0.name' : [{ required: true, message: this.$t("联系人不能为空"), trigger: "blur" }],
type : [{ required: true, message: this.$t("客户类别不能为空"), trigger: "blur" }],
createTime : [{ required: true, message: this.$t("创建时间不能为空"), trigger: "blur" }],
source : [{ required: true, message: this.$t("客户来源不能为空"), trigger: "blur" }],
customerService : [{ required: true, message: this.$t("客户经理不能为空"), trigger: "blur" }],
status : [{ required: true, message: this.$t("客户状态不能为空"), trigger: "blur" }],
founder : [{ required: true, message: this.$t("创建人不能为空"), trigger: "blur" }],
},
serviceUserList: [],
countryList: [],
}
},
watch:{
show(){
if(!this.show){
this.$emit('close')
}
}
},
created() {
if(this.type){
this.$set(this.form, 'type', this.type)
}
listServiceUser().then(r => {
this.serviceUserList = r.data
})
getCountryListAll().then(r => {
this.countryList = r.data
})
},
methods: {
open(){
this.show = true
},
/** 取消按钮 */
cancel() {
this.show = false
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
// 添加的提交
createCustomer(this.form).then(res => {
this.$modal.msgSuccess("新增成功");
return getCustomerContactsSelect({customerId: res.data})
}).then(res => {
this.$emit('success', res.data.list[0])
})
});
},
}
}
</script>
<style lang="scss">
.quick-create-customer .el-form-item{
margin-bottom: 22px;
}
</style>
<template>
<div>
<div class="filters mb-10">
运输方式
<dict-selector :type='DICT_TYPE.ECW_TRANSPORT_TYPE' v-model="transportType" placeholder="请选择运输方式" style="width:150px" />
{{$t('运输方式')}}
<dict-selector :type='DICT_TYPE.ECW_TRANSPORT_TYPE' v-model="transportType" :placeholder="$t('请选择运输方式')" style="width:150px" />
始发地
<el-select placeholder="请选择始发地" v-model="exportCity" clearable>
{{$t('始发地')}}
<el-select :placeholder="$t('请选择始发地')" v-model="exportCity" clearable>
<el-option v-for="item in exportCityList" :key="item.id" :label="item.titleZh" :value="item.id" />
</el-select>
目的地
<el-select placeholder="请选择目的地" v-model="importCity" clearable>
{{$t('目的地')}}
<el-select :placeholder="$t('请选择目的地')" v-model="importCity" clearable>
<el-option v-for="item in importCityList" :key="item.id" :label="item.titleZh" :value="item.id" />
</el-select>
出货渠道:
<el-select placeholder="请选择目渠道" v-model="channelId" clearable>
{{$t('出货渠道')}}:
<el-select :placeholder="$t('请选择目渠道')" v-model="channelId" clearable>
<el-option v-for="item in channelList" :key="item.channelId" :label="item.nameZh" :value="item.channelId" />
</el-select>
</div>
<div class="mb-10">
<el-radio-group v-model="checkAll">
<el-radio :label="true">全选</el-radio>
<el-radio :label="false">全不选</el-radio>
<el-radio :label="true">{{$t('全选')}}</el-radio>
<el-radio :label="false">{{$t('全不选')}}</el-radio>
</el-radio-group>
</div>
<el-row class="" :gutter="10">
......@@ -30,19 +30,27 @@
<el-col :span="12" :key="item.value">
<el-card class="mb-10">
<div slot="header">
{{item.label}}
<el-link type="primary" @click.native="toggleHide(item.value)" style="float:right">{{item._hide ? '展开' : '折叠'}}</el-link>
{{$l(item, 'label')}}
<el-link type="primary" @click.native="toggleHide(item.value)" style="float:right">{{item._hide ? $t('展开') : $t('折叠')}}</el-link>
</div>
<!--table需要给一个key,否则全选的时候不会自动更新渲染-->
<el-table v-if="!hideMap[item.value]" :data="item.routerList" :span-method="SpanMethod" border :key="selectedRoutes.length + item.value">
<el-table-column label="始发地" prop="startTitleZh" />
<el-table-column label="目的地" prop="destTitleZh" />
<el-table-column label="渠道" prop="startTitleZh">
<el-table-column :label="$t('始发地')" prop="startTitleZh">
<template slot-scope="{row}">
{{row.channel.nameZh}}
{{$l(row, 'startTitle')}}
</template>
</el-table-column>
<el-table-column label="操作" prop="">
<el-table-column :label="$t('目的地')" prop="destTitleZh" >
<template slot-scope="{row}">
{{$l(row, 'destTitle')}}
</template>
</el-table-column>
<el-table-column :label="$t('渠道')" prop="startTitleZh">
<template slot-scope="{row}">
{{$l(row.channel, 'name')}}
</template>
</el-table-column>
<el-table-column :label="$t('操作')" prop="">
<template slot-scope="{row}">
<el-checkbox :checked="getSelectedIndex(row) > -1" @change="toggleChecker(row, $event)"></el-checkbox>
</template>
......@@ -83,10 +91,24 @@ export default {
computed:{
importCityList(){
return this.tradeCityList.filter(item => item.type == 1)
return this.tradeCityList.filter(item => item.type == 1 || item.type == 3)
},
exportCityList(){
return this.tradeCityList.filter(item => item.type == 2)
return this.tradeCityList.filter(item => item.type == 2 || item.type == 3)
},
exportCityIds(){
let ids = []
this.exportCityList.forEach(item => {
ids.push(item.id)
})
return ids
},
importCityIds(){
let ids = []
this.importCityList.forEach(item => {
ids.push(item.id)
})
return ids
},
availChannelList(){
return this.channelList.filter(item => !this.channelId || this.channelId == item.channelId)
......@@ -116,6 +138,7 @@ export default {
let child = {
label: item.label,
labelEn: item.labelEn,
value: item.value,
_hide: false, // 是否折叠
routerList: routerList
......@@ -164,9 +187,10 @@ export default {
})
getTradeCityList().then(res => {
this.tradeCityList = res.data
// 路线需要过滤失效的进出口城市,所以在程序加载后再加载路线
this.getOpenedRouterList()
})
this.getOpenedRouterList()
if(this.value && this.value.length){
this.selectedRoutes = this.value
}
......@@ -181,9 +205,9 @@ export default {
if(this.importCity){
params.destCityId = this.importCity
}
openedRouterList(params).then(res => {
this.openedRouterList = res.data
})
openedRouterList(params).then(res => this.openedRouterList = res.data.filter(item => {
return this.exportCityIds.indexOf(item.startCityId) > -1 && this.importCityIds.indexOf(item.destCityId) > -1
}))
},
// 切换路线选择
toggleChecker(router, selected){
......@@ -197,7 +221,8 @@ export default {
if(selected){
this.selectedRoutes.push({
lineId: router.id,
channelId: router.channel.channelId
channelId: router.channel.channelId,
transportId: router.transportType
})
}else{
let index = this.getSelectedIndex(router)
......
<template>
<el-select v-model="valueSync" :multiple="multiple" :disabled="disabled">
<el-option v-for="item in optionsFormated" :key="item.value" :label="item.label" :value="item.value" />
<el-select v-model="valueSync" :multiple="multiple" :disabled="disabled" :filterable="filterable">
<el-option v-for="item in optionsFormated" :key="item.key" :label="item.label" :value="item.value" />
</el-select>
</template>
<script>
......@@ -21,6 +21,11 @@ export default {
type: String,
default: 'value'
},
keyField:{
type: String,
default: 'value'
},
filterable: Boolean,
multiple: Boolean,
clearable: Boolean,
defaultable: Boolean, // 没有值的时候是否选择第一项
......@@ -32,7 +37,8 @@ export default {
this.options.forEach((item, index) => {
arr.push({
label: typeof this.labelField == 'string' ? item[this.labelField] : (this.labelField)(item, index),
value: item[this.valueField]
value: item[this.valueField],
key: item[this.keyField]
})
})
return arr
......
......@@ -11,17 +11,17 @@
<el-option
v-for="(item, index) in list"
:key="item.id"
:label="`${item.name}(${item.number})`"
:label="$l(item, 'company') + '('+item.companyCode+')'"
:value="index">
</el-option>
</el-select>
</template>
<script>
import {getSupplier, getSupplierPage} from '@/api/ecw/supplier'
// TODO 接口暂不支持关键词搜索,待接口支持后完善
export default {
props:{
productType: [String, Number],
companyType: [String, Number],
value: [String, Number]
},
data(){
......@@ -41,6 +41,7 @@ export default {
}
},
created(){
this.remoteMethod('')
this.init()
},
methods:{
......@@ -52,14 +53,17 @@ export default {
this.list.unshift(res.data)
this.index = 0
})
}
}else this.index = index
},
remoteMethod(keyword){
let params = {}
params.searchKey = keyword
let params = {
pageSize: 500,
companyType: this.companyType
}
params.keyword = keyword
this.loading = true
getSupplierPage(params)
.then(res => this.list = res.data)
.then(res => this.list = res.data.list)
.finally(() => this.loading = false)
}
}
......
<template>
<div class="xselect">
<el-select v-model="valueSync">
<el-option v-for="(item, index) in options" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</template>
<script>
export default {
props:{
value:{
type: String,
},
options:{
type: Array,
default(){
return []
}
}
},
watch: {
valueSync(newValue) {
this.$emit('input', newValue)
}
},
data(){
return {
valueSync: []
}
},
created() {
this.$set(this, 'valueSync', this.value)
},
methods: {
}
}
</script>
let modules = {}
const files = require.context('', false, /\.vue$/);
files.keys().forEach((filename) => {
modules[filename.slice(2, -4)] = files(filename).default || files(filename)
});
export default modules
\ No newline at end of file
<template>
<el-card shadow="never">
<div slot="header" class="clearfix card-header">
<div class="card-title">{{title}}</div>
<el-button size="mini" type="primary" icon="el-icon-plus" @click="listData.push({})"></el-button>
</div>
<el-table :data="listData" border>
<el-table-column label="序号" width="90px">
<template slot-scope="scope">
{{scope.$index + 1}}
</template>
</el-table-column>
<template v-for="col in fields">
<el-table-column :label="col.label" :key="col.field">
<template slot-scope="{row}">
<component :is="col.tag || 'el-input'" v-model="row[col.field]" v-bind="col.attrs" />
</template>
</el-table-column>
</template>
<!-- <el-table-column label="职位">
<template slot-scope="{row}">
<el-input v-model="row.job" />
</template>
</el-table-column> -->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click="del(scope.$index)"></el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
<script>
/*
fields:
[
{
field: 'name',
label: '字段名'
tag: 'el-input',
attr: {}
}
]
*/
import FormComponents from './components/index.js'
export default {
components: {...FormComponents},
props:{
title: String,
fields: Array,
value: Array
},
data(){
return {
listData: []
}
},
watch:{
listData(val){
console.log('数据更新')
this.$emit('input', val)
},
value(){
this.listData = this.value
}
},
methods:{
del(index){
this.$confirm('确定删除此行?')
.then(res => {
this.listData.splice(index, 1)
})
}
}
}
</script>
<style scoped lang="scss">
.card-header{
display: flex;
.card-title{
flex: 1;
display: flex;
align-items: center;
font-size: 16px;
}
}
</style>
\ No newline at end of file
......@@ -54,5 +54,7 @@
</script>
<style>
#edui_fixedlayer{
z-index: 10005 !important;
}
</style>
......@@ -2,7 +2,7 @@
<el-select
v-model="index"
filterable
clearable
:clearable="clearable"
remote
reserve-keyword
placeholder="请选择"
......@@ -20,7 +20,8 @@ import {getCustomerContactsSelect, getCustomerContacts} from '@/api/ecw/customer
import {listSimpleUsers} from '@/api/system/user'
export default {
props:{
value: [String, Number]
value: [String, Number],
clearable: Boolean
},
data(){
return {
......@@ -36,7 +37,10 @@ export default {
this.$emit('change', val !== null ? this.list[val]: null)
},
value(val){
// this.init()
this.resetIndex()
},
list(){
this.resetIndex()
}
},
created(){
......@@ -46,6 +50,11 @@ export default {
// this.init()
},
methods:{
resetIndex(){
let index = this.list.findIndex(item => item.id == this.value)
if(index < 0) this.index = null
else this.index = index
}
/* init(){
console.log('初始化联系人选择', this.value)
if(!this.value) return
......
......@@ -5,6 +5,7 @@
:visible.sync="opened"
width="600px"
:before-close="handleClose()"
v-bind="$attrs"
>
<el-tabs v-model="activeName" type="card" @tab-click="activeWarehouse = {}">
<el-tab-pane :label="item.name" :name="'' + index" v-for="(item, index) in area" :key="index">
......@@ -62,7 +63,15 @@ export default {
default: false
},
value: Array,
orderId: Number
orderId: Number,
cityId: {
type: Number,
default: undefined
},
warehouseId: {
type: Number,
default: undefined
}
},
data() {
......@@ -81,6 +90,25 @@ export default {
visible(val) {
if (val) {
this.opened = true
getByWarehouseId({cityId: this.cityId,warehouseId: this.warehouseId }).then(r => {
const area = r.data
area.forEach(e => {
// 仓库
e.children.forEach(f => {
// 区域
f.selected = false
if(f.positionList) f.positionList.forEach(g => {
// 位置
g.children?.forEach(k => {
// 子位置
k.selected = false
})
})
})
})
this.area = area
})
} else {
}
},
......@@ -107,7 +135,7 @@ export default {
// 区域被选,清空该区域下的位置
if(warehouse.positionList) warehouse.positionList.forEach(g => {
g.children.forEach(k => {
g.children?.forEach(k => {
k.selected = false
})
})
......@@ -124,7 +152,7 @@ export default {
let hasSelected = false
parentAre.positionList.forEach(g => {
// 位置
g.children.forEach(k => {
g.children?.forEach(k => {
// 子位置
if (k.selected) hasSelected = true
})
......@@ -143,28 +171,7 @@ export default {
},
mounted() {
if (this.visible) {
this.opened = true
}
getByWarehouseId().then(r => {
const area = r.data
area.forEach(e => {
// 仓库
e.children.forEach(f => {
// 区域
f.selected = false
if(f.positionList) f.positionList.forEach(g => {
// 位置
g.children.forEach(k => {
// 子位置
k.selected = false
})
})
})
})
this.area = area
})
console.log('area dialog mounted')
},
computed: {
......@@ -180,7 +187,7 @@ export default {
else if(f.positionList) f.positionList.forEach(g => {
// 位置
if (g.selected) result.push(k.code)
g.children.forEach(k => {
g.children?.forEach(k => {
// 子位置
if (k.selected) result.push(k.code)
})
......
<template>
<div>
<div style="height:350px; overflow:hidden;">
<div class="mb-10">
<my-process-viewer
ref="processViewer"
:value="bpmnXML"
......@@ -8,12 +8,11 @@
:activityData="activityData"
:processInstanceData="processInstanceData"
:taskData="taskData"
style="height:500px; margin-top: -80px"
/>
</div>
<el-form label-position="left" label-width="100px">
<el-form-item label="抄送">
<el-select v-model="valueSync" multiple placeholder="请选择抄送人" style="width:100%">
<el-form-item :label="$t('抄送')">
<el-select v-model="valueSync" multiple :placeholder="$t('请选择抄送人')" style="width:100%">
<el-option
v-for="item in users"
:key="item.id"
......
......@@ -90,7 +90,10 @@ export default {
let xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix);
try {
// console.log(this.bpmnModeler.importXML);
let { warnings } = await this.bpmnModeler.importXML(xmlString);
let { warnings } = await this.bpmnModeler.importXML(xmlString)
// 220906 增加一个缩放,自动适应尺寸
this.bpmnModeler.get('canvas').zoom('fit-viewport');
if (warnings && warnings.length) {
warnings.forEach(warn => console.warn(warn));
}
......@@ -314,8 +317,7 @@ export default {
};
</script>
<style>
<style scoped>
/** 处理中 */
.highlight-todo.djs-connection > .djs-visual > path {
stroke: #1890ff !important;
......
......@@ -20,19 +20,40 @@
</el-select>
</el-form-item>
<el-form-item label="订单号" prop="orderId">
<el-input v-model="form.orderId" placeholder="请输入订单号" />
<el-select
v-model="form.orderId"
filterable
remote
placeholder="请输入订单号"
:remote-method="getOrderList">
<el-option
v-for="item in orderList"
:key="item.value"
:label="item.value"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="提单号" prop="ladingbillId">
<el-input v-model="form.ladingbillId" placeholder="请输入提单号" />
<el-select
v-model="form.ladingbillId"
filterable
remote
placeholder="请输入提单号"
:remote-method="getBillList">
<el-option
v-for="item in billList"
:key="item.value"
:label="item.value"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="投诉内容" prop="content">
<el-input v-model="form.content" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="处理状态" prop="status">
<el-select v-model="form.status" placeholder="请选择处理状态">
<el-option v-for="dict in getDictDatas(DICT_TYPE.CUSTOMER_COMPLAINT_STATUS)"
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
</el-select>
<span>{{ getDictDataLabel(DICT_TYPE.CUSTOMER_COMPLAINT_STATUS, 1) }}</span>
</el-form-item>
</el-form>
......@@ -90,7 +111,8 @@
import { createCustomerComplaint, updateCustomerComplaint, deleteCustomerComplaint, getCustomerComplaint, getCustomerComplaintPage, exportCustomerComplaintExcel } from "@/api/ecw/customerComplaint";
import {getCustomerSelect} from '@/api/ecw/customer'
import DictSelector from '@/components/DictSelector'
import { DICT_TYPE } from '@/utils/dict'
import { DICT_TYPE, getDictDatas, getDictDataLabel } from '@/utils/dict'
import {getBillNoSearch, getOrderNoSearch} from "@/api/ecw/order"
export default {
name: "customerComplaints",
......@@ -107,6 +129,8 @@ export default {
data() {
return {
DICT_TYPE,
getDictDatas,
getDictDataLabel,
// 遮罩层
loading: true,
// 导出遮罩层
......@@ -148,7 +172,10 @@ export default {
// 处理
handle: {
dialogVisible: false
}
},
billList: [],
orderList: []
};
},
created() {
......@@ -157,6 +184,21 @@ export default {
})
},
methods: {
getBillList(key){
getBillNoSearch({key, pageNo: 1, pageSize: 20}).then(r => {
if (r.code === 0){
this.billList = r.data.list
}
})
},
getOrderList(key){
getOrderNoSearch({key, pageNo: 1, pageSize: 20}).then(r => {
if (r.code === 0){
this.orderList = r.data.list
}
})
},
/** 查询列表 */
/** 取消按钮 */
cancel() {
......@@ -172,7 +214,7 @@ export default {
orderId: undefined,
ladingbillId: undefined,
content: undefined,
status: undefined,
status: 1,
ascertainReason: undefined,
plan: undefined,
result: undefined,
......
import Vue from 'vue'
import VueI18n from './vue-i18n/vue-i18n.common'
import {getLocale} from '@/utils/db'
Vue.use(VueI18n)
const i18n = new VueI18n({
locale: getLocale() || 'zh_CN',
formatFallbackMessages: true,
messages: {
'en_US': require('./languages/en_US.json'),
'zh_CN': require('./languages/zh_CN.json')
}
})
window.i18n = i18n
console.log({i18n})
/*
用法
$l('title') => titleZh
$l(item, 'title') => item.titleZh
$l(null, 'title') => titleZh
$l() => Zh
*/
Vue.prototype.$l = i18n.l = (object, field = '') => {
let prefix = i18n.locale.split('_')[0]
let append = prefix.charAt(0).toUpperCase() + prefix.toLowerCase().substr(1)
if(typeof object == 'string'){
return object + append
}
// 如果object是null或者字符串则返回字段名
if(!object) return field + append
return object[field + append] || object[field]
}
/* Vue.filter('$t', Vue.$i18n)
*/
// 重新console.warn来捕获未翻译的内容
/* console.wareOrig = console.warn
console.warn = (...data) => {
console.log('warn', typeof data)
console.wareOrig(data)
} */
export default i18n
\ No newline at end of file
{
"登录": "Login",
"个人中心": "User Center",
"布局设置": "Layout",
"编号": "No",
"新增": "Create",
"搜索": "Search",
"重置": "Reset",
"新建订单": "New Order"
}
\ No newline at end of file
{
"登录": "登录"
}
\ No newline at end of file
This diff is collapsed.
The MIT License (MIT)
Copyright (c) 2016 kazuya kawaguchi
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<p align="center"><img width="128px" height="112px" src="./assets/vue-i18n-logo.png" alt="Vue I18n logo"></p>
<h1 align="center">vue-i18n</h1>
<p align="center">
<a href="https://circleci.com/gh/kazupon/vue-i18n/tree/dev"><img src="https://circleci.com/gh/kazupon/vue-i18n/tree/dev.svg?style=shield" alt="Build Status"></a>
<a href="http://badge.fury.io/js/vue-i18n"><img src="https://badge.fury.io/js/vue-i18n.svg" alt="NPM version"></a>
<a href="https://discord.gg/4yCnk2m"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="vue-i18n channel on Discord"></a>
</p>
<p align="center">Internationalization plugin for Vue.js</p>
<br/>
<h3 align="center">🏅 Platinum Sponsors</h3>
<p align="center">
<a href="https://zenarchitects.co.jp/" target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/zenarchitects.png"
width="400px"
/>
</a>
</p>
<h3 align="center">✨ Special Sponsors</h3>
<p align="center">
<a
href="https://plaid.co.jp/"
target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/plaid.svg"
width="240px"
/>
</a>
</p>
<h3 align="center">🥇 Gold Sponsors</h3>
<p align="center">
<a
href="https://nuxtjs.org/"
target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/nuxt.png"
width="240px"
/>
</a>
</p>
<p align="center">
<a
href="https://rapidapi.com/"
target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/RapidAPI.svg"
width="240px"
/>
</a>
</p>
<p align="center">
<a
href="https://localazy.com/blog/how-to-localize-vuejs-app-with-vue-i18n-and-localazy?utm_source=kazupon&utm_medium=banner&utm_campaign=sponsorships_kazupon&utm_content=logo"
target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/localazy.svg"
width="240px"
/>
</a>
</p>
<p align="center">
<a
href="https://crowdin.com/teams/engineering?utm_source=vue-i18n.intlify.dev&utm_medium=referral"
target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/crowdin.svg"
width="240px"
/>
</a>
</p>
<h3 align="center">🥈 Silver Sponsors</h3>
<h3 align="center">🥉 Bronze Sponsors</h3>
<p align="center">
<a href="https://www.sendcloud.com/" target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/sendcloud.png"
width="144px"
/>
</a>
</p>
<p align="center">
<a href="https://www.vuemastery.com/" target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/vuemastery.png"
width="144px"
/>
</a>
</p>
<p align="center">
<a href="https://www.deci-bel.com/" target="_blank">
<img
src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/decibel.png"
width="144px"
/>
</a>
</p>
<br/>
## ⚠️ NOTICE
**This repository is for Vue I18n v8.x and Vue 2**
**If you want to know about how to usage for Vue I18n v9 on Vue 3, See the [this repository](https://github.com/intlify/vue-i18n-next))**
## 🙋‍♂️ About support for v8
We will follow Vue v2 maintenance lifespan
## 📔 Documentation
About Vue I18n v8.x, See [here](http://kazupon.github.io/vue-i18n/)
If you want to read Vue I18n v9 docs, See [here](https://vue-i18n.intlify.dev/)
## 📜 Changelog
Detailed changes for each release are documented in the [CHANGELOG.md](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md).
## ❗ Issues
Please make sure to read the [Issue Reporting Checklist](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
## 💪 Contribution
Please make sure to read the [Contributing Guide](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md) before making a pull request.
## ©️ License
[MIT](http://opensource.org/licenses/MIT)
declare var Intl: any;
declare type Path = string;
declare type Locale = string;
declare type MessageContext = {
list: (index: number) => mixed,
named: (key: string) => mixed,
linked: (key: string) => TranslateResult,
values: any,
path: string,
formatter: Formatter,
messages: LocaleMessages,
locale: Locale
}
declare type MessageFunction = (ctx: MessageContext) => string
declare type FallbackLocale = string | string[] | false | { [locale: string]: string[] };
declare type LocaleMessage = string | MessageFunction | LocaleMessageObject | LocaleMessageArray;
declare type LocaleMessageObject = { [key: Path]: LocaleMessage };
declare type LocaleMessageArray = Array<LocaleMessage>;
declare type LocaleMessages = { [key: Locale]: LocaleMessageObject };
// This options is the same as Intl.DateTimeFormat constructor options:
// http://www.ecma-international.org/ecma-402/2.0/#sec-intl-datetimeformat-constructor
declare type DateTimeFormatOptions = {
year?: 'numeric' | '2-digit',
month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',
day?: 'numeric' | '2-digit',
hour?: 'numeric' | '2-digit',
minute?: 'numeric' | '2-digit',
second?: 'numeric' | '2-digit',
weekday?: 'narrow' | 'short' | 'long',
hour12?: boolean,
era?: 'narrow' | 'short' | 'long',
timeZone?: string, // IANA time zone
timeZoneName?: 'short' | 'long',
localeMatcher?: 'lookup' | 'best fit',
formatMatcher?: 'basic' | 'best fit'
};
declare type DateTimeFormat = { [key: string]: DateTimeFormatOptions };
declare type DateTimeFormats = { [key: Locale]: DateTimeFormat };
// This options is the same as Intl.NumberFormat constructor options:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
declare type NumberFormatOptions = {
style?: 'decimal' | 'currency' | 'percent',
currency?: string, // ISO 4217 currency codes
currencyDisplay?: 'symbol' | 'code' | 'name',
useGrouping?: boolean,
minimumIntegerDigits?: number,
minimumFractionDigits?: number,
maximumFractionDigits?: number,
minimumSignificantDigits?: number,
maximumSignificantDigits?: number,
localeMatcher?: 'lookup' | 'best fit',
formatMatcher?: 'basic' | 'best fit'
};
declare type NumberFormat = { [key: string]: NumberFormatOptions };
declare type NumberFormats = { [key: Locale]: NumberFormat };
declare type Modifiers = { [key: string]: (str: string) => string };
declare type TranslateResult = string | LocaleMessages;
declare type DateTimeFormatResult = string;
declare type NumberFormatResult = string;
declare type MissingHandler = (locale: Locale, key: Path, vm?: any) => string | void;
declare type PostTranslationHandler = (str: string, key?: string) => string;
declare type GetChoiceIndex = (choice: number, choicesLength: number) => number
declare type ComponentInstanceCreatedListener = (newI18n: I18n, rootI18n: I18n) => void;
declare type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
declare type FormattedNumberPart = {
type: FormattedNumberPartType,
value: string,
};
// This array is the same as Intl.NumberFormat.formatToParts() return value:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/formatToParts#Return_value
declare type NumberFormatToPartsResult = Array<FormattedNumberPart>;
declare type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
declare type I18nOptions = {
locale?: Locale,
fallbackLocale?: FallbackLocale,
messages?: LocaleMessages,
dateTimeFormats?: DateTimeFormats,
datetimeFormats?: DateTimeFormats,
numberFormats?: NumberFormats,
formatter?: Formatter,
missing?: MissingHandler,
modifiers?: Modifiers,
root?: I18n, // for internal
fallbackRoot?: boolean,
fallbackRootWithEmptyString?: boolean,
formatFallbackMessages?: boolean,
sync?: boolean,
silentTranslationWarn?: boolean | RegExp,
silentFallbackWarn?: boolean | RegExp,
pluralizationRules?: PluralizationRules,
preserveDirectiveContent?: boolean,
warnHtmlInMessage?: WarnHtmlInMessageLevel,
sharedMessages?: LocaleMessage,
postTranslation?: PostTranslationHandler,
componentInstanceCreatedListener?: ComponentInstanceCreatedListener,
escapeParameterHtml?: boolean,
__VUE_I18N_BRIDGE__?: string,
};
declare type IntlAvailability = {
dateTimeFormat: boolean,
numberFormat: boolean
};
declare type PluralizationRules = {
[lang: string]: GetChoiceIndex,
}
declare interface I18n {
static install: () => void, // for Vue plugin interface
static version: string,
static availabilities: IntlAvailability,
get vm (): any, // for internal
get locale (): Locale,
set locale (locale: Locale): void,
get fallbackLocale (): FallbackLocale,
set fallbackLocale (locale: FallbackLocale): void,
get messages (): LocaleMessages,
get dateTimeFormats (): DateTimeFormats,
get numberFormats (): NumberFormats,
get availableLocales (): Locale[],
get missing (): ?MissingHandler,
set missing (handler: MissingHandler): void,
get formatter (): Formatter,
set formatter (formatter: Formatter): void,
get formatFallbackMessages (): boolean,
set formatFallbackMessages (fallback: boolean): void,
get silentTranslationWarn (): boolean | RegExp,
set silentTranslationWarn (silent: boolean | RegExp): void,
get silentFallbackWarn (): boolean | RegExp,
set silentFallbackWarn (slient: boolean | RegExp): void,
get pluralizationRules (): PluralizationRules,
set pluralizationRules (rules: PluralizationRules): void,
get preserveDirectiveContent (): boolean,
set preserveDirectiveContent (preserve: boolean): void,
get warnHtmlInMessage (): WarnHtmlInMessageLevel,
set warnHtmlInMessage (level: WarnHtmlInMessageLevel): void,
get postTranslation (): ?PostTranslationHandler,
set postTranslation (handler: PostTranslationHandler): void,
getLocaleMessage (locale: Locale): LocaleMessageObject,
setLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
mergeLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
t (key: Path, ...values: any): TranslateResult,
i (key: Path, locale: Locale, values: Object): TranslateResult,
tc (key: Path, choice?: number, ...values: any): TranslateResult,
te (key: Path, locale?: Locale): boolean,
getDateTimeFormat (locale: Locale): DateTimeFormat,
setDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
mergeDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
d (value: number | Date, ...args: any): DateTimeFormatResult,
getNumberFormat (locale: Locale): NumberFormat,
setNumberFormat (locale: Locale, format: NumberFormat): void,
mergeNumberFormat (locale: Locale, format: NumberFormat): void,
n (value: number, ...args: any): NumberFormatResult,
getChoiceIndex: GetChoiceIndex,
pluralizationRules: PluralizationRules,
preserveDirectiveContent: boolean
};
declare interface Formatter {
interpolate (message: string, values: any, path: string): (Array<any> | null)
};
declare type $npm$Vue$Dictionaly<T> = { [key: string]: T }
declare type Util = {
extend: (to: Object, from: ?Object) => Object,
hasOwn: (obj: Object, key: string) => boolean,
isPlainObject: (obj: any) => boolean,
isObject: (obj: mixed) => boolean,
}
declare type Config = {
optionMergeStrategies: $npm$Vue$Dictionaly<Function>,
silent: boolean,
productionTip: boolean,
performance: boolean,
devtools: boolean,
errorHandler: ?(err: Error, vm: Vue, info: string) => void,
ignoredElements: Array<string>,
keyCodes: $npm$Vue$Dictionaly<number>,
isReservedTag: (x?: string) => boolean,
parsePlatformTagName: (x: string) => string,
isUnknownElement: (x?: string) => boolean,
getTagNamespace: (x?: string) => string | void,
mustUseProp: (tag: string, type: ?string, name: string) => boolean,
}
declare interface Vue {
static config: Config,
static util: Util,
static version: string,
}
{
"_from": "vue-i18n@^8.27.2",
"_id": "vue-i18n@8.27.2",
"_inBundle": false,
"_integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg==",
"_location": "/vue-i18n",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "vue-i18n@^8.27.2",
"name": "vue-i18n",
"escapedName": "vue-i18n",
"rawSpec": "^8.27.2",
"saveSpec": null,
"fetchSpec": "^8.27.2"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz",
"_shasum": "b649a65ff42b7d1a482679b732902f889965a068",
"_spec": "vue-i18n@^8.27.2",
"_where": "D:\\projects\\jiedao-admin",
"author": {
"name": "kazuya kawaguchi",
"email": "kawakazu80@gmail.com"
},
"bugs": {
"url": "https://github.com/kazupon/vue-i18n/issues"
},
"bundleDependencies": false,
"changelog": {
"labels": {
"Type: Feature": ":star: New Features",
"Type: Bug": ":bug: Bug Fixes",
"Type: Security": ":lock: Security Fixes",
"Type: Performance": ":chart_with_upwards_trend: Performance Fixes",
"Type: Improvement": ":zap: Improved Features",
"Type: Breaking": ":boom: Breaking Change",
"Type: Deprecated": ":warning: Deprecated Features",
"Type: I18n": ":globe_with_meridians: Internationalization",
"Type: A11y": ":wheelchair: Accessibility",
"Type: Documentation": ":pencil: Documentation"
}
},
"deprecated": false,
"description": "Internationalization plugin for Vue.js",
"devDependencies": {
"@babel/core": "^7.1.0",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-syntax-flow": "^7.0.0",
"@babel/plugin-transform-flow-strip-types": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^3.0.0",
"@typescript-eslint/parser": "^3.0.0",
"@vue/babel-preset-app": "^4.4.1",
"@vuepress/theme-vue": "^1.9.7",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babel-plugin-istanbul": "^6.0.0",
"babel-preset-power-assert": "^3.0.0",
"buble": "^0.19.3",
"chromedriver": "^102.0.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.2",
"cross-spawn": "^7.0.3",
"eslint": "^6.8.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-flowtype": "^4.7.0",
"eslint-plugin-ie11": "^1.0.0",
"eslint-plugin-no-autofix": "^1.0.1",
"eslint-plugin-vue": "^7.14.0",
"eslint-plugin-vue-libs": "^4.0.0",
"flow-bin": "^0.38.0",
"http-server": "^0.12.3",
"intl": "^1.2.5",
"karma": "^5.0.9",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.2",
"karma-firefox-launcher": "^2.1.1",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-safari-launcher": "^1.0.0",
"karma-sauce-launcher": "^4.1.5",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.2",
"lerna-changelog": "^1.0.0",
"lerna-changelog-label-schema": "^3.0.0",
"mocha": "^7.2.0",
"mocha-loader": "^5.0.0",
"nightwatch": "^1.3.5",
"nightwatch-helpers": "^1.2.0",
"power-assert": "^1.6.0",
"rollup": "^0.66.0",
"rollup-plugin-buble": "^0.19.2",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-flow-no-whitespace": "^1.0.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-replace": "^2.0.0",
"selenium-server": "^3.141.59",
"shipjs": "^0.23.3",
"sinon": "^11.1.1",
"terser": "^3.17.0",
"typescript": "^3.9.3",
"vue": "^2.5.17",
"vue-github-button": "^1.1.2",
"vue-template-compiler": "^2.5.17",
"vuepress": "^1.8.2",
"webpack": "^4.43.0",
"webpack-cli": "^4.7.2",
"webpack-dev-middleware": "^5.0.0",
"webpack-dev-server": "^3.11.0"
},
"files": [
"dist/vue-i18n.js",
"dist/vue-i18n.min.js",
"dist/vue-i18n.common.js",
"dist/vue-i18n.esm.js",
"dist/vue-i18n.esm.browser.js",
"dist/vue-i18n.esm.browser.min.js",
"src/**/*.js",
"types/*.d.ts",
"decls",
"vetur/tags.json",
"vetur/attributes.json"
],
"homepage": "https://github.com/kazupon/vue-i18n#readme",
"keywords": [
"i18n",
"internationalization",
"plugin",
"vue",
"vue.js"
],
"license": "MIT",
"main": "dist/vue-i18n.common.js",
"module": "dist/vue-i18n.esm.js",
"name": "vue-i18n",
"repository": {
"type": "git",
"url": "git+https://github.com/kazupon/vue-i18n.git"
},
"scripts": {
"build": "node config/build.js",
"clean": "rm -rf coverage && rm -rf dist/*.js* && rm ./*.log",
"coverage": "cat ./coverage/lcov.info",
"dev": "cross-env BABEL_ENV=test webpack-dev-server --inline --hot --open --content-base ./test/unit/ --config config/webpack.dev.conf.js",
"docs:build": "cross-env NODE_ENV=production node config/version.js && cross-env NODE_ENV=production vuepress build vuepress -d docs",
"docs:clean": "rm -rf docs/**",
"docs:dev": "vuepress dev vuepress",
"flow": "flow check",
"lint": "eslint --fix src test types/**/*.ts",
"release:prepare": "shipjs prepare",
"release:trigger": "shipjs trigger",
"sauce": "npm run sauce:coolkids && npm run sauce:ie && npm run sauce:mobile",
"sauce:coolkids": "karma start config/karma.sauce.conf.js -- 0",
"sauce:ie": "karma start config/karma.sauce.conf.js -- 1",
"sauce:mobile": "karma start config/karma.sauce.conf.js -- 2",
"test": "npm run lint && npm run flow && npm run test:types && npm run test:cover && npm run test:e2e",
"test:cover": "cross-env BABEL_ENV=test karma start config/karma.cover.conf.js",
"test:e2e": "npm run build && node test/e2e/runner.js",
"test:types": "tsc -p types",
"test:unit": "cross-env BABEL_ENV=test karma start config/karma.unit.conf.js",
"test:unit:ci": "cross-env BABEL_ENV=test karma start config/karma.unit.ci.conf.js"
},
"sideEffects": false,
"types": "types/index.d.ts",
"unpkg": "dist/vue-i18n.js",
"version": "8.27.2",
"vetur": {
"tags": "vetur/tags.json",
"attributes": "vetur/attributes.json"
}
}
/* @flow */
import { warn } from '../util'
export default {
name: 'i18n',
functional: true,
props: {
tag: {
type: [String, Boolean, Object],
default: 'span'
},
path: {
type: String,
required: true
},
locale: {
type: String
},
places: {
type: [Array, Object]
}
},
render (h: Function, { data, parent, props, slots }: Object) {
const { $i18n } = parent
if (!$i18n) {
if (process.env.NODE_ENV !== 'production') {
warn('Cannot find VueI18n instance!')
}
return
}
const { path, locale, places } = props
const params = slots()
const children = $i18n.i(
path,
locale,
onlyHasDefaultPlace(params) || places
? useLegacyPlaces(params.default, places)
: params
)
const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
return tag ? h(tag, data, children) : children
}
}
function onlyHasDefaultPlace (params) {
let prop
for (prop in params) {
if (prop !== 'default') { return false }
}
return Boolean(prop)
}
function useLegacyPlaces (children, places) {
const params = places ? createParamsFromPlaces(places) : {}
if (!children) { return params }
// Filter empty text nodes
children = children.filter(child => {
return child.tag || child.text.trim() !== ''
})
const everyPlace = children.every(vnodeHasPlaceAttribute)
if (process.env.NODE_ENV !== 'production' && everyPlace) {
warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.')
}
return children.reduce(
everyPlace ? assignChildPlace : assignChildIndex,
params
)
}
function createParamsFromPlaces (places) {
if (process.env.NODE_ENV !== 'production') {
warn('`places` prop is deprecated in next major version. Please switch to Vue slots.')
}
return Array.isArray(places)
? places.reduce(assignChildIndex, {})
: Object.assign({}, places)
}
function assignChildPlace (params, child) {
if (child.data && child.data.attrs && child.data.attrs.place) {
params[child.data.attrs.place] = child
}
return params
}
function assignChildIndex (params, child, index) {
params[index] = child
return params
}
function vnodeHasPlaceAttribute (vnode) {
return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
}
/* @flow */
import { warn, isString, isObject, includes, numberFormatKeys } from '../util'
export default {
name: 'i18n-n',
functional: true,
props: {
tag: {
type: [String, Boolean, Object],
default: 'span'
},
value: {
type: Number,
required: true
},
format: {
type: [String, Object]
},
locale: {
type: String
}
},
render (h: Function, { props, parent, data }: Object) {
const i18n = parent.$i18n
if (!i18n) {
if (process.env.NODE_ENV !== 'production') {
warn('Cannot find VueI18n instance!')
}
return null
}
let key: ?string = null
let options: ?NumberFormatOptions = null
if (isString(props.format)) {
key = props.format
} else if (isObject(props.format)) {
if (props.format.key) {
key = props.format.key
}
// Filter out number format options only
options = Object.keys(props.format).reduce((acc, prop) => {
if (includes(numberFormatKeys, prop)) {
return Object.assign({}, acc, { [prop]: props.format[prop] })
}
return acc
}, null)
}
const locale: Locale = props.locale || i18n.locale
const parts: NumberFormatToPartsResult = i18n._ntp(props.value, locale, key, options)
const values = parts.map((part, index) => {
const slot: ?Function = data.scopedSlots && data.scopedSlots[part.type]
return slot ? slot({ [part.type]: part.value, index, parts }) : part.value
})
const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
return tag
? h(tag, {
attrs: data.attrs,
'class': data['class'],
staticClass: data.staticClass
}, values)
: values
}
}
/* @flow */
import { warn, isString, isPlainObject, looseEqual } from './util'
export function bind (el: any, binding: Object, vnode: any): void {
if (!assert(el, vnode)) { return }
t(el, binding, vnode)
}
export function update (el: any, binding: Object, vnode: any, oldVNode: any): void {
if (!assert(el, vnode)) { return }
const i18n: any = vnode.context.$i18n
if (localeEqual(el, vnode) &&
(looseEqual(binding.value, binding.oldValue) &&
looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
t(el, binding, vnode)
}
export function unbind (el: any, binding: Object, vnode: any, oldVNode: any): void {
const vm: any = vnode.context
if (!vm) {
warn('Vue instance does not exists in VNode context')
return
}
const i18n: any = vnode.context.$i18n || {}
if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
el.textContent = ''
}
el._vt = undefined
delete el['_vt']
el._locale = undefined
delete el['_locale']
el._localeMessage = undefined
delete el['_localeMessage']
}
function assert (el: any, vnode: any): boolean {
const vm: any = vnode.context
if (!vm) {
warn('Vue instance does not exists in VNode context')
return false
}
if (!vm.$i18n) {
warn('VueI18n instance does not exists in Vue instance')
return false
}
return true
}
function localeEqual (el: any, vnode: any): boolean {
const vm: any = vnode.context
return el._locale === vm.$i18n.locale
}
function t (el: any, binding: Object, vnode: any): void {
const value: any = binding.value
const { path, locale, args, choice } = parseValue(value)
if (!path && !locale && !args) {
warn('value type not supported')
return
}
if (!path) {
warn('`path` is required in v-t directive')
return
}
const vm: any = vnode.context
if (choice != null) {
el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args))
} else {
el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args))
}
el._locale = vm.$i18n.locale
el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale)
}
function parseValue (value: any): Object {
let path: ?string
let locale: ?Locale
let args: any
let choice: ?number
if (isString(value)) {
path = value
} else if (isPlainObject(value)) {
path = value.path
locale = value.locale
args = value.args
choice = value.choice
}
return { path, locale, args, choice }
}
function makeParams (locale: Locale, args: any): Array<any> {
const params: Array<any> = []
locale && params.push(locale)
if (args && (Array.isArray(args) || isPlainObject(args))) {
params.push(args)
}
return params
}
/* @flow */
export default function extend (Vue: any): void {
if (!Vue.prototype.hasOwnProperty('$i18n')) {
// $FlowFixMe
Object.defineProperty(Vue.prototype, '$i18n', {
get () { return this._i18n }
})
}
Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
const i18n = this.$i18n
return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
}
Vue.prototype.$tc = function (key: Path, choice?: number, ...values: any): TranslateResult {
const i18n = this.$i18n
return i18n._tc(key, i18n.locale, i18n._getMessages(), this, choice, ...values)
}
Vue.prototype.$te = function (key: Path, locale?: Locale): boolean {
const i18n = this.$i18n
return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
}
Vue.prototype.$d = function (value: number | Date, ...args: any): DateTimeFormatResult {
return this.$i18n.d(value, ...args)
}
Vue.prototype.$n = function (value: number, ...args: any): NumberFormatResult {
return this.$i18n.n(value, ...args)
}
}
/* @flow */
import { warn, isObject } from './util'
export default class BaseFormatter {
_caches: { [key: string]: Array<Token> }
constructor () {
this._caches = Object.create(null)
}
interpolate (message: string, values: any): Array<any> {
if (!values) {
return [message]
}
let tokens: Array<Token> = this._caches[message]
if (!tokens) {
tokens = parse(message)
this._caches[message] = tokens
}
return compile(tokens, values)
}
}
type Token = {
type: 'text' | 'named' | 'list' | 'unknown',
value: string
}
const RE_TOKEN_LIST_VALUE: RegExp = /^(?:\d)+/
const RE_TOKEN_NAMED_VALUE: RegExp = /^(?:\w)+/
export function parse (format: string): Array<Token> {
const tokens: Array<Token> = []
let position: number = 0
let text: string = ''
while (position < format.length) {
let char: string = format[position++]
if (char === '{') {
if (text) {
tokens.push({ type: 'text', value: text })
}
text = ''
let sub: string = ''
char = format[position++]
while (char !== undefined && char !== '}') {
sub += char
char = format[position++]
}
const isClosed = char === '}'
const type = RE_TOKEN_LIST_VALUE.test(sub)
? 'list'
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
? 'named'
: 'unknown'
tokens.push({ value: sub, type })
} else if (char === '%') {
// when found rails i18n syntax, skip text capture
if (format[(position)] !== '{') {
text += char
}
} else {
text += char
}
}
text && tokens.push({ type: 'text', value: text })
return tokens
}
export function compile (tokens: Array<Token>, values: Object | Array<any>): Array<any> {
const compiled: Array<any> = []
let index: number = 0
const mode: string = Array.isArray(values)
? 'list'
: isObject(values)
? 'named'
: 'unknown'
if (mode === 'unknown') { return compiled }
while (index < tokens.length) {
const token: Token = tokens[index]
switch (token.type) {
case 'text':
compiled.push(token.value)
break
case 'list':
compiled.push(values[parseInt(token.value, 10)])
break
case 'named':
if (mode === 'named') {
compiled.push((values: any)[token.value])
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
}
}
break
case 'unknown':
if (process.env.NODE_ENV !== 'production') {
warn(`Detect 'unknown' type of token!`)
}
break
}
index++
}
return compiled
}
This diff is collapsed.
import { warn } from './util'
import extend from './extend'
import defineMixin from './mixin'
import interpolationComponent from './components/interpolation'
import numberComponent from './components/number'
import { bind, update, unbind } from './directive'
export let Vue
export function install (_Vue, options = { bridge: false }) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
warn('already installed.')
return
}
install.installed = true
Vue = _Vue
const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && version < 2) {
warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
return
}
extend(Vue)
Vue.mixin(defineMixin(options.bridge))
Vue.directive('t', { bind, update, unbind })
Vue.component(interpolationComponent.name, interpolationComponent)
Vue.component(numberComponent.name, numberComponent)
// use simple mergeStrategies to prevent i18n instance lose '__proto__'
const strats = Vue.config.optionMergeStrategies
strats.i18n = function (parentVal, childVal) {
return childVal === undefined
? parentVal
: childVal
}
}
/* @flow */
import VueI18n from './index'
import { isPlainObject, warn, error, merge } from './util'
/**
* Mixin
*
* If `bridge` mode, empty mixin is returned,
* else regulary mixin implementation is returned.
*/
export default function defineMixin (bridge: boolean = false) {
function mounted (): void {
if (this !== this.$root && this.$options.__INTLIFY_META__ && this.$el) {
this.$el.setAttribute('data-intlify', this.$options.__INTLIFY_META__)
}
}
return bridge
? { mounted } // delegate `vue-i18n-bridge` mixin implementation
: { // regulary
beforeCreate (): void {
const options: any = this.$options
options.i18n = options.i18n || ((options.__i18nBridge || options.__i18n) ? {} : null)
if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
if ((options.__i18nBridge || options.__i18n)) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
const __i18n = options.__i18nBridge || options.__i18n
__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
Object.keys(localeMessages).forEach((locale: Locale) => {
options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
})
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
error(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
this._i18n = options.i18n
this._i18nWatcher = this._i18n.watchI18nData()
} else if (isPlainObject(options.i18n)) {
const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
? this.$root.$i18n
: null
// component local i18n
if (rootI18n) {
options.i18n.root = this.$root
options.i18n.formatter = rootI18n.formatter
options.i18n.fallbackLocale = rootI18n.fallbackLocale
options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
options.i18n.pluralizationRules = rootI18n.pluralizationRules
options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
}
// init locale messages via custom blocks
if ((options.__i18nBridge || options.__i18n)) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
const __i18n = options.__i18nBridge || options.__i18n
__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
options.i18n.messages = localeMessages
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
const { sharedMessages } = options.i18n
if (sharedMessages && isPlainObject(sharedMessages)) {
options.i18n.messages = merge(options.i18n.messages, sharedMessages)
}
this._i18n = new VueI18n(options.i18n)
this._i18nWatcher = this._i18n.watchI18nData()
if (options.i18n.sync === undefined || !!options.i18n.sync) {
this._localeWatcher = this.$i18n.watchLocale()
}
if (rootI18n) {
rootI18n.onComponentInstanceCreated(this._i18n)
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
// root i18n
this._i18n = this.$root.$i18n
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
// parent i18n
this._i18n = options.parent.$i18n
}
},
beforeMount (): void {
const options: any = this.$options
options.i18n = options.i18n || ((options.__i18nBridge || options.__i18n) ? {} : null)
if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (isPlainObject(options.i18n)) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
}
},
mounted,
beforeDestroy (): void {
if (!this._i18n) { return }
const self = this
this.$nextTick(() => {
if (self._subscribing) {
self._i18n.unsubscribeDataChanging(self)
delete self._subscribing
}
if (self._i18nWatcher) {
self._i18nWatcher()
self._i18n.destroyVM()
delete self._i18nWatcher
}
if (self._localeWatcher) {
self._localeWatcher()
delete self._localeWatcher
}
})
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"i18n/path" : {
"description": "[required]\nKeypath of the locale message",
"type": "string"
},
"i18n/locale" : {
"description": "[optional]\nLocale to be used in this translation",
"type": "string"
},
"i18n/tag" : {
"description": "[optional]\nWhich tag to render, default is \"span\"",
"type": "string"
},
"i18n/places": {
"description": "[optional after v8.14]\nWill be removed in the next major version, use the slot syntax instead\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#slots-syntax-usage",
"type": "array|object"
},
"i18n-n/value" : {
"description": "[required]\nNumber to be used in formatting",
"type": "number"
},
"i18n-n/format": {
"description": "[optional]\nNumber format name or object with explicit format options",
"type": "string|object"
},
"i18n-n/locale" : {
"description": "[optional]\nLocale to be used in this translation",
"type": "string"
},
"i18n-n/tag" : {
"description": "[optional]\nWhich tag to render, default is `span`",
"type": "string"
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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