This commit is contained in:
2025-11-29 23:40:29 +08:00
parent bfa83f42a8
commit 51ffefbe2f
95 changed files with 9692 additions and 1322 deletions

View File

@@ -33,6 +33,7 @@
"@jeesite/core": "workspace:*",
"@jeesite/dbm": "workspace:*",
"@jeesite/dfm": "workspace:*",
"@jeesite/erp": "workspace:^",
"@jeesite/test": "workspace:*",
"@jeesite/types": "workspace:*",
"@jeesite/vite": "workspace:*",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -68,5 +68,10 @@ export const bizListItemImportData = (
params,
);
export const bizListItemSflow = (params?: BizListItem | any) =>
defHttp.get<BizListItem>({ url: adminPath + '/biz/listItem/sflow', params });
export const bizListItemDelete = (params?: BizListItem | any) =>
defHttp.get<BizListItem>({ url: adminPath + '/biz/listItem/delete', params });

View File

@@ -32,6 +32,9 @@ export interface BizProjectInfo extends BasicModel<BizProjectInfo> {
export const bizProjectInfoList = (params?: BizProjectInfo | any) =>
defHttp.get<BizProjectInfo>({ url: adminPath + '/biz/projectInfo/list', params });
export const bizProjectInfoListAll = (params?: BizProjectInfo | any) =>
defHttp.get<BizProjectInfo[]>({ url: adminPath + '/biz/projectInfo/listAll', params });
export const bizProjectInfoListData = (params?: BizProjectInfo | any) =>
defHttp.post<Page<BizProjectInfo>>({ url: adminPath + '/biz/projectInfo/listData', params });

View File

@@ -50,25 +50,15 @@
maxlength: 512,
},
required: true,
colProps: { md: 24, lg: 24 },
},
{
label: t('是否删除'),
field: 'titleDelete',
component: 'Select',
componentProps: {
dictType: 'title_delete',
allowClear: true,
},
},
{
label: t('发送时间'),
label: t('到期时间'),
field: 'datetime',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD',
showTime: false,
},
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('所属类型'),
@@ -81,32 +71,17 @@
required: true,
},
{
label: t('是否关闭'),
field: 'clickClose',
component: 'Select',
label: t('通知人员'),
field: 'loginUser',
fieldLabel: 'userName',
component: 'ListSelect',
componentProps: {
dictType: 'click_close',
allowClear: true,
selectType: 'userSelect',
},
required: true,
},
{
label: t('待办状态'),
field: 'extra',
component: 'Input',
componentProps: {
maxlength: 64,
},
},
{
label: t('颜色编码'),
field: 'color',
component: 'Input',
componentProps: {
maxlength: 32,
},
},
{
label: t('描述信息'),
label: t('内容信息'),
field: 'description',
component: 'InputTextArea',
required: true,

View File

@@ -18,11 +18,14 @@
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
</a-button>
</template>
<template #firstColumn="{ record }">
<a @click="handleForm({ id: record.id })" :title="record.createTime">
{{ record.createTime }}
<template #slotBizKey="{ record }">
<a @click="handleForm({ id: record.id })" :title="record.title">
{{ record.title }}
</a>
</template>
<template #slotBizAvatar="{ record }">
<img :src="record.avatar" style="width: 20px; height: 20px; object-fit: cover; border-radius: 50%; display: inline-block; vertical-align: middle;" />
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
@@ -92,12 +95,17 @@
allowClear: true,
},
},
{
label: t('待办状态'),
field: 'extra',
component: 'Input',
},
{
label: t('是否已读'),
field: 'readFlag',
component: 'Select',
componentProps: {
dictType: 'read_flag',
dictType: 'is_open',
allowClear: true,
},
},
@@ -106,15 +114,10 @@
field: 'clickClose',
component: 'Select',
componentProps: {
dictType: 'click_close',
dictType: 'is_open',
allowClear: true,
},
},
{
label: t('待办状态'),
field: 'extra',
component: 'Input',
},
],
};
@@ -126,7 +129,6 @@
sorter: true,
width: 180,
align: 'left',
slot: 'firstColumn',
},
{
title: t('头像图标'),
@@ -135,6 +137,7 @@
sorter: true,
width: 130,
align: 'left',
slot: 'slotBizAvatar',
},
{
title: t('通知标题'),
@@ -143,6 +146,7 @@
sorter: true,
width: 200,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('是否删除'),
@@ -151,10 +155,10 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'title_delete',
dictType: 'is_open',
},
{
title: t('发送时间'),
title: t('到期时间'),
dataIndex: 'datetime',
key: 'a.datetime',
sorter: true,
@@ -177,16 +181,24 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'read_flag',
dictType: 'is_open',
},
{
title: t('描述信息'),
title: t('内容信息'),
dataIndex: 'description',
key: 'a.description',
sorter: true,
width: 225,
align: 'left',
},
{
title: t('接收用户'),
dataIndex: 'userName',
key: 'a.user_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('是否关闭'),
dataIndex: 'clickClose',
@@ -194,7 +206,7 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'click_close',
dictType: 'is_open',
},
{
title: t('待办状态'),
@@ -241,6 +253,7 @@
confirm: handleDelete.bind(this, record),
},
auth: 'biz:listItem:edit',
ifShow: record.clickClose == false
},
],
};

View File

@@ -61,7 +61,7 @@
},
},
{
label: t('项目区域'),
label: t('区域名称'),
field: 'areaCode',
fieldLabel: 'provinceName',
component: 'ListSelect',
@@ -81,7 +81,7 @@
required: true,
},
{
label: t('需求人员'),
label: t('需求用户'),
field: 'employeeId',
fieldLabel: 'employeeName',
component: 'ListSelect',

View File

@@ -89,7 +89,7 @@
component: 'Input',
},
{
label: t('项目区域'),
label: t('区域名称'),
field: 'areaCode',
fieldLabel: 'provinceName',
component: 'ListSelect',
@@ -107,7 +107,7 @@
},
},
{
label: t('需求人员'),
label: t('需求用户'),
field: 'employeeId',
fieldLabel: 'employeeName',
component: 'ListSelect',
@@ -172,14 +172,46 @@
width: 130,
align: 'left',
},
{
title: t('项目区域'),
dataIndex: 'areaCode',
key: 'a.area_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('需求用户'),
dataIndex: 'employeeName',
key: 'b.employee_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('项目编码'),
dataIndex: 'projectCode',
key: 'c.project_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('项目名称'),
dataIndex: 'projectName',
key: 'c.project_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('区域编号'),
dataIndex: 'areaCode',
key: 'a.area_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('项目名称'),
dataIndex: 'provinceName',
key: 'd.province_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('需求描述'),
dataIndex: 'requirementDescription',
@@ -242,6 +274,7 @@
const actionColumn: BasicColumn<BizProjectRequirements> = {
width: 160,
align: 'center',
actions: (record: BizProjectRequirements) => [
{
icon: 'i-clarity:note-edit-line',
@@ -258,6 +291,7 @@
confirm: handleDelete.bind(this, record),
},
auth: 'biz:projectRequirements:edit',
ifShow: record.requirementsStatus == 'PDC'
},
],
};

View File

@@ -1,226 +0,0 @@
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
import { bizProjectRequirementsListData } from '@jeesite/biz/api/biz/projectRequirements';
const { t } = useI18n('biz.projectRequirements');
const modalProps = {
title: t('需求信息选择'),
};
const searchForm: FormProps<BizProjectRequirements> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('记录日期起'),
field: 'createTime_gte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('记录日期止'),
field: 'createTime_lte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('需求名称'),
field: 'requirementName',
component: 'Input',
},
{
label: t('需求编号'),
field: 'requirementCode',
component: 'Input',
},
{
label: t('项目区域'),
field: 'areaCode',
component: 'Input',
},
{
label: t('需求描述'),
field: 'requirementDescription',
component: 'Input',
},
{
label: t('优先级'),
field: 'priority',
component: 'Select',
componentProps: {
dictType: '',
allowClear: true,
},
},
{
label: t('项目ID'),
field: 'projectId',
component: 'Select',
componentProps: {
dictType: '',
allowClear: true,
},
},
{
label: t('用户ID'),
field: 'employeeId',
component: 'Select',
componentProps: {
dictType: '',
allowClear: true,
},
},
{
label: t('需求备注'),
field: 'remark',
component: 'Input',
},
{
label: t('状态'),
field: 'requirementsStatus',
component: 'Select',
componentProps: {
dictType: '',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<BizProjectRequirements>[] = [
{
title: t('记录日期'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 230,
align: 'left',
slot: 'firstColumn',
},
{
title: t('需求名称'),
dataIndex: 'requirementName',
key: 'a.requirement_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('需求编号'),
dataIndex: 'requirementCode',
key: 'a.requirement_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('项目区域'),
dataIndex: 'areaCode',
key: 'a.area_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('需求描述'),
dataIndex: 'requirementDescription',
key: 'a.requirement_description',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('开始时间'),
dataIndex: 'startTime',
key: 'a.start_time',
sorter: true,
width: 130,
align: 'center',
},
{
title: t('结束时间'),
dataIndex: 'endTime',
key: 'a.end_time',
sorter: true,
width: 130,
align: 'center',
},
{
title: t('优先级'),
dataIndex: 'priority',
key: 'a.priority',
sorter: true,
width: 130,
align: 'left',
dictType: '',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 130,
align: 'center',
},
{
title: t('项目ID'),
dataIndex: 'projectId',
key: 'a.project_id',
sorter: true,
width: 130,
align: 'left',
dictType: '',
},
{
title: t('用户ID'),
dataIndex: 'employeeId',
key: 'a.employee_id',
sorter: true,
width: 130,
align: 'left',
dictType: '',
},
{
title: t('需求备注'),
dataIndex: 'remark',
key: 'a.remark',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('状态'),
dataIndex: 'requirementsStatus',
key: 'a.requirements_status',
sorter: true,
width: 130,
align: 'left',
dictType: '',
},
];
const tableProps: BasicTableProps = {
api: bizProjectRequirementsListData,
beforeFetch: (params) => {
params['isAll'] = true;
return params;
},
columns: tableColumns,
formConfig: searchForm,
rowKey: 'requirementId',
};
export default {
modalProps,
tableProps,
itemCode: 'requirementId',
itemName: 'requirementId',
isShowCode: false,
};

View File

@@ -63,7 +63,7 @@
colProps: { md: 24, lg: 24 },
},
{
label: t('图标类名'),
label: t('图标地址'),
field: 'iconClass',
component: 'Input',
componentProps: {
@@ -112,7 +112,7 @@
field: 'isEnabled',
component: 'Select',
componentProps: {
dictType: 'is_enabled',
dictType: 'ustatus',
allowClear: true,
},
required: true,

View File

@@ -15,9 +15,9 @@
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
</a-button>
</template>
<template #firstColumn="{ record }">
<a @click="handleForm({ id: record.id })" :title="record.createTime">
{{ record.createTime }}
<template #slotBizKey="{ record }">
<a @click="handleForm({ id: record.id })" :title="record.systemName">
{{ record.systemName }}
</a>
</template>
</BasicTable>
@@ -85,26 +85,26 @@
sorter: true,
width: 180,
align: 'left',
slot: 'firstColumn',
},
{
title: t('系统名称'),
dataIndex: 'systemName',
key: 'a.system_name',
sorter: true,
width: 225,
width: 200,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('首页地址'),
dataIndex: 'homepageUrl',
key: 'a.homepage_url',
sorter: true,
width: 200,
width: 225,
align: 'left',
},
{
title: t('图标类名'),
title: t('图标地址'),
dataIndex: 'iconClass',
key: 'a.icon_class',
sorter: true,
@@ -150,7 +150,7 @@
sorter: true,
width: 130,
align: 'center',
dictType: 'is_enabled',
dictType: 'ustatus',
},
{
title: t('更新时间'),

View File

@@ -0,0 +1,123 @@
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
import { ErpAccount, erpAccountListData } from '@jeesite/erp/api/erp/account';
const { t } = useI18n('erp.account');
const modalProps = {
title: t('账户信息选择'),
};
const searchForm: FormProps<ErpAccount> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('账户名称'),
field: 'accountName',
component: 'Input',
},
{
label: t('账户类型'),
field: 'accountType',
component: 'Input',
},
{
label: t('是否激活'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpAccount>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('账户名称'),
dataIndex: 'accountName',
key: 'a.account_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('账户类型'),
dataIndex: 'accountType',
key: 'a.account_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'account_type'
},
{
title: t('账户卡号'),
dataIndex: 'accountCode',
key: 'a.account_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('初始余额'),
dataIndex: 'initialBalance',
key: 'a.initial_balance',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('当前余额'),
dataIndex: 'currentBalance',
key: 'a.current_balance',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('是否激活'),
dataIndex: 'isActive',
key: 'a.is_active',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_active',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const tableProps: BasicTableProps = {
api: erpAccountListData,
beforeFetch: (params) => {
params['isAll'] = true;
return params;
},
columns: tableColumns,
formConfig: searchForm,
rowKey: 'accountId',
};
export default {
modalProps,
tableProps,
itemCode: 'accountId',
itemName: 'accountName',
isShowCode: true,
};

View File

@@ -0,0 +1,120 @@
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
import { ErpCategory, erpCategoryListData } from '@jeesite/erp/api/erp/category';
const { t } = useI18n('erp.category');
const modalProps = {
title: t('分类信息选择'),
};
const searchForm: FormProps<ErpCategory> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('分类名称'),
field: 'categoryName',
component: 'Input',
},
{
label: t('分类类型'),
field: 'categoryType',
component: 'Select',
componentProps: {
dictType: 'category_type',
allowClear: true,
},
},
{
label: t('是否启用'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpCategory>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('分类名称'),
dataIndex: 'categoryName',
key: 'a.category_name',
sorter: true,
width: 230,
align: 'left',
},
{
title: t('分类类型'),
dataIndex: 'categoryType',
key: 'a.category_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'category_type',
},
{
title: t('父级分类'),
dataIndex: 'parentId',
key: 'a.parent_id',
sorter: true,
width: 130,
align: 'left',
dictType: 'parent_type',
},
{
title: t('排序序号'),
dataIndex: 'sortOrder',
key: 'a.sort_order',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('是否启用'),
dataIndex: 'isActive',
key: 'a.is_active',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_active',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const tableProps: BasicTableProps = {
api: erpCategoryListData,
beforeFetch: (params) => {
params['isAll'] = true;
return params;
},
columns: tableColumns,
formConfig: searchForm,
rowKey: 'categoryId',
};
export default {
modalProps,
tableProps,
itemCode: 'categoryId',
itemName: 'categoryName',
isShowCode: false,
};

View File

@@ -0,0 +1,128 @@
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
import { ErpTransactionFlow, erpTransactionFlowListData } from '@jeesite/erp/api/erp/transactionFlow';
const { t } = useI18n('erp.transactionFlow');
const modalProps = {
title: t('明细信息选择'),
};
const searchForm: FormProps<ErpTransactionFlow> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('交易名称'),
field: 'flowName',
component: 'Input',
},
{
label: t('交易类型'),
field: 'transactionType',
component: 'Select',
componentProps: {
dictType: 'transaction_type',
allowClear: true,
},
},
{
label: t('是否记账'),
field: 'isFinish',
component: 'Select',
componentProps: {
dictType: 'is_finish',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpTransactionFlow>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
slot: 'firstColumn',
},
{
title: t('交易名称'),
dataIndex: 'flowName',
key: 'a.flow_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易类型'),
dataIndex: 'transactionType',
key: 'a.transaction_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'transaction_type',
},
{
title: t('交易金额'),
dataIndex: 'amount',
key: 'a.amount',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('交易时间'),
dataIndex: 'transactionTime',
key: 'a.transaction_time',
sorter: true,
width: 180,
align: 'center',
},
{
title: t('交易备注'),
dataIndex: 'remark',
key: 'a.remark',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('是否记账'),
dataIndex: 'isFinish',
key: 'a.is_finish',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_finish',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const tableProps: BasicTableProps = {
api: erpTransactionFlowListData,
beforeFetch: (params) => {
params['isAll'] = true;
return params;
},
columns: tableColumns,
formConfig: searchForm,
rowKey: 'flowId',
};
export default {
modalProps,
tableProps,
itemCode: 'flowId',
itemName: 'flowName',
isShowCode: true,
};

View File

@@ -1,196 +0,0 @@
export interface ListItem {
id: string;
avatar: string;
// 通知的标题内容
title: string;
// 是否在标题上显示删除线
titleDelete?: boolean;
datetime?: string;
type: string;
read?: boolean;
description: string;
clickClose?: boolean;
extra?: string;
color?: string;
}
export interface TabItem {
key: string;
name: string;
count?: number;
btnHref?: string;
btnText?: string;
list: ListItem[];
unreadlist?: ListItem[];
}
export const tabListData: TabItem[] = [
{
key: '1',
name: '通知',
list: [
{
id: '000000001',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: '你收到了 10 份新周报',
description: '',
datetime: '2022-08-09',
type: '1',
},
{
id: '000000002',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
title: '你推荐的果汁已通过第三轮面试',
description: '',
datetime: '2022-08-08',
type: '1',
},
{
id: '000000003',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
title: '这种模板可以区分多种通知类型',
description: '',
datetime: '2022-08-07',
// read: true,
type: '1',
},
{
id: '000000004',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000005',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title:
'标题可以设置自动显示省略号本例中标题行数已设为1行如果内容超过1行将自动截断并支持tooltip显示完整标题。',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000006',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000009',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
{
id: '000000010',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
description: '',
datetime: '2022-08-07',
type: '1',
},
],
},
{
key: '2',
name: '消息',
list: [
{
id: '000000006',
avatar: 'ant-design:message-outlined',
title: '彩虹 评论了你',
description: '描述信息描述信息描述信息',
datetime: '2022-08-07',
type: '2',
clickClose: true,
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '果汁 回复了你',
description: '这种模板用于提醒谁与你发生了互动',
datetime: '2022-08-07',
type: '2',
clickClose: true,
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '标题',
description:
'请将鼠标移动到此处以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2超过2行的描述内容将被省略并且可以通过tooltip查看完整内容',
datetime: '2022-08-07',
type: '2',
clickClose: true,
},
],
},
{
key: '3',
name: '待办',
list: [
{
id: '000000009',
avatar: '',
title: '任务名称',
description: '任务需要在 2022-01-12 20:00 前启动',
datetime: '',
extra: '未开始',
color: '',
type: '3',
},
{
id: '000000010',
avatar: '',
title: '第三方紧急代码变更',
description: '彩虹 需在 2022-01-07 前完成代码变更任务',
datetime: '',
extra: '马上到期',
color: 'red',
type: '3',
},
{
id: '000000011',
avatar: '',
title: '信息安全考试',
description: '指派竹尔于 2022-01-09 前完成更新并发布',
datetime: '',
extra: '已耗时 8 天',
color: 'gold',
type: '3',
},
{
id: '000000012',
avatar: '',
title: 'ABCD 版本发布',
description: '指派竹尔于 2022-01-09 前完成更新并发布',
datetime: '',
extra: '进行中',
color: 'blue',
type: '3',
},
],
},
];

View File

@@ -13,7 +13,8 @@
<span v-if="item.list.length !== 0">({{ item.list.length }})</span>
</template>
<!-- 绑定title-click事件的通知列表中标题是可点击-->
<NoticeList :list="item.list" @title-click="onNoticeClick" />
<NoticeList :list="item.list" v-if="item.key === '3'" @title-click="onNoticeClick" />
<NoticeList :list="item.list" v-else />
</TabPane>
</template>
</Tabs>
@@ -28,7 +29,7 @@
import NoticeList from './NoticeList.vue';
import { useDesign } from '@jeesite/core/hooks/web/useDesign';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { tabListDataAll, TabItem, BizListItem } from '@jeesite/biz/api/biz/listItem';
import { tabListDataAll, bizListItemSflow, TabItem, BizListItem } from '@jeesite/biz/api/biz/listItem';
export default defineComponent({
components: { Popover, BellOutlined, Tabs, TabPane: Tabs.TabPane, Badge, NoticeList },
@@ -53,10 +54,11 @@
}
return count;
});
function onNoticeClick(record: BizListItem) {
createMessage.success('你点击了' + record.title);
getDataList()
async function onNoticeClick(record: BizListItem) {
const res = await bizListItemSflow(record);
createMessage.success(res.message);
getDataList()
}
onMounted(() => {

View File

@@ -121,168 +121,6 @@ export const groupItems: GroupItem[] = [
group: '前端组',
date: '2021-09-01',
},
{
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
}, {
title: 'Vue',
icon: 'i-ion:logo-vue',
color: '#3fb27f',
desc: '现在的你决定将来的你。',
group: '前端组',
date: '2021-09-01',
},
{
title: 'Html5',
icon: 'i-ion:logo-html5',

View File

@@ -3,19 +3,37 @@
<template #extra>
<a-button type="link" size="small">更多</a-button>
</template>
<!-- 滚动容器 + 网格布局确保一行3个 -->
<div class="scroll-container">
<template v-for="item in items" :key="item">
<CardGrid class="!w-full">
<span class="flex">
<Icon :icon="item.icon" :color="item.color" size="30" />
<span class="ml-4 text-lg">{{ item.title }}</span>
</span>
<div class="text-secondary mt-2 h-10 flex">{{ item.desc }}</div>
<div class="text-secondary flex justify-between">
<span>{{ item.group }}</span>
<span>{{ item.date }}</span>
<template v-for="item in listData" :key="item">
<CardGrid class="!w-full rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow duration-200 border border-gray-100">
<div class="flex items-center mb-3">
<Icon icon="i-ion:layers-outline" color="#00bfff" size="25" />
<span class="ml-2 text-lg font-medium text-gray-800">{{ item.projectName }}</span>
</div>
<div class="text-gray-600 mt-1 mb-4 h-12 flex items-center overflow-auto text-sm pr-2">
{{ item.projectDesc }}
</div>
<div class="bg-blue-50 rounded-md p-3 border-b-2 border-blue-200">
<div class="text-gray-600 flex justify-between mb-2 text-sm">
<span class="flex items-center">
<i class="ri-calendar-start-line mr-1 text-blue-400"></i>
开始时间: {{ item.startDate }}
</span>
<span class="flex items-center">
<i class="ri-code-line mr-1 text-blue-400"></i>
项目编码: {{ item.projectCode }}
</span>
</div>
<div class="text-gray-600 flex justify-between text-sm">
<span class="flex items-center">
<i class="ri-calendar-end-line mr-1 text-blue-400"></i>
结束时间: {{ item.endDate }}
</span>
<span class="flex items-center">
<i class="ri-user-line mr-1 text-blue-400"></i>
项目经理: {{ item.employeeName }}
</span>
</div>
</div>
</CardGrid>
</template>
@@ -23,17 +41,34 @@
</Card>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, onMounted, ref } from 'vue';
import { Card } from 'ant-design-vue';
import { Icon } from '@jeesite/core/components/Icon';
import { groupItems } from './Data';
import { BizProjectInfo, bizProjectInfoListAll } from '@jeesite/biz/api/biz/projectInfo';
export default defineComponent({
components: { Card, CardGrid: Card.Grid, Icon },
setup() {
return { items: groupItems };
},
} as any);
components: { Card, CardGrid: Card.Grid, Icon },
setup() {
const listData = ref();
const getDataList = async () => {
try {
const params = { projectStatus: '2' };
const result = await bizProjectInfoListAll(params);
listData.value = result || [];
} catch (error) {
listData.value = []; // 异常时置空列表,显示空状态
}
}
onMounted(() => {
getDataList()
});
return {
listData,
};
},
});
</script>
<style scoped>
@@ -46,7 +81,7 @@
/* 关键网格布局一行3个 */
display: grid;
grid-template-columns: repeat(3, 1fr); /* 强制一行3列 */
grid-template-columns: repeat(2, 1fr); /* 强制一行3列 */
gap: 16px; /* 卡片间距,可按需调整 */
}

View File

@@ -6,7 +6,6 @@
<Select
:showSearch="false"
:options="[
{ label: '使用手机号码找回您的密码', value: 'mobile' },
{ label: '使用电子邮箱找回您的密码', value: 'email' },
{ label: '使用保密问题找回您的密码', value: 'question' },
]"

View File

@@ -20,12 +20,6 @@
<div class="-enter-x mt-10 text-white font-medium">
<span class="mt-4 inline-block text-3xl"></span>
</div>
<div class="-enter-x text-md mt-5 text-white font-normal dark:text-gray-500">
JeeSite 是一个专业的平台是一个让你使用放心的平台<br />
前端基于 Vue3ViteTypeScriptAnt-Design-VueVben Admin<br />
后台基于 Spring BootApache MyBatis 最先进最经典的技术栈<br />
精致的 UI规范的代码书写匠心著作封装细节专注业务快速开发<br />
</div>
</div>
</div>
<div class="h-full w-full flex overflow-auto py-5 lg:my-0 lg:h-auto lg:w-11/24 lg:py-0">
@@ -35,9 +29,6 @@
>
<LoginForm @demo-mode="demoMode = $event" />
<ForgetPasswordForm :demoMode="demoMode" />
<RegisterForm :demoMode="demoMode" />
<MobileForm :demoMode="demoMode" />
<QrCodeForm :demoMode="demoMode" />
</div>
</div>
</div>
@@ -50,37 +41,10 @@
import { AppLocalePicker, AppDarkModeToggle } from '@jeesite/core/components/Application';
import LoginForm from './LoginForm.vue';
import ForgetPasswordForm from './ForgetPasswordForm.vue';
import RegisterForm from './RegisterForm.vue';
import MobileForm from './MobileForm.vue';
import QrCodeForm from './QrCodeForm.vue';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { useDesign } from '@jeesite/core/hooks/web/useDesign';
import { useLocaleStore } from '@jeesite/core/store/modules/locale';
/* import { onMounted } from 'vue';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
const { createConfirm } = useMessage();
onMounted(() => {
if (!import.meta.env.DEV) {
createConfirm({
content: [
'<div onclick="window.open(\'https://gitee.com/thinkgem/jeesite-vue\')">',
'进入 <strong style="color: #FF0036;">JeeSite Vue</strong> 源码仓库页面,',
'点右上角 <strong style="color: #FF0036;">Star</strong> 加星关注',
'</div>',
].join(''),
width: 480,
iconType: 'info',
maskClosable: false,
cancelText: '我已 Star',
okText: '带我去 Star',
onOk: () => {
window.open('https://gitee.com/thinkgem/jeesite-vue');
},
});
}
}); */
defineProps({
sessionTimeout: {
type: Boolean,

View File

@@ -66,40 +66,7 @@
<Button type="primary" size="large" block @click="handleLogin" :loading="loading">
{{ t('sys.login.loginButton') }}
</Button>
<!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
{{ t('sys.login.registerButton') }}
</Button> -->
</FormItem>
<ARow class="enter-x md:pl-3">
<ACol :md="7" :xs="24">
<Button block @click="setLoginState(LoginStateEnum.MOBILE)">
{{ t('sys.login.mobileSignInFormTitle') }}
</Button>
</ACol>
<ACol :md="8" :xs="24" class="xs:mx-0 !my-2 md:mx-2 !md:my-0">
<Button block @click="setLoginState(LoginStateEnum.QR_CODE)">
{{ t('sys.login.qrSignInFormTitle') }}
</Button>
</ACol>
<ACol :md="7" :xs="24">
<Button block @click="setLoginState(LoginStateEnum.REGISTER)">
{{ t('sys.login.registerButton') }}
</Button>
</ACol>
</ARow>
<Divider class="enter-x">{{ t('sys.login.otherSignIn') }}</Divider>
<div class="enter-x flex justify-evenly" :class="`${prefixCls}-sign-in-way`">
<Icon icon="i-simple-icons:gitee" color="#d81e06" size="28" @click="handleOauth2" />
<Icon icon="i-ant-design:qq-circle-filled" color="#2178e3" size="32" @click="handleOauth2" />
<Icon icon="i-ant-design:wechat-filled" color="#2eb60d" size="32" @click="handleOauth2" />
<Icon icon="i-ant-design:github-filled" color="#2c2c2c" size="32" @click="handleOauth2" />
<a href="https://gitee.com/thinkgem/jeesite-client" target="_blank">
<Icon icon="i-ant-design:windows-filled" size="32" style="vertical-align: middle" />
<span class="pl-1" style="vertical-align: middle"> {{ t('客户端下载') }}</span>
</a>
</div>
</Form>
</template>
<script lang="ts" setup>

View File

@@ -0,0 +1,22 @@
- 官方网站:<https://jeesite.com>
- 使用文档:<https://jeesite.com/docs>
- 后端代码:<https://gitee.com/thinkgem/jeesite5>
- 前端代码:<https://gitee.com/thinkgem/jeesite-vue>
------
<div align="center">
如果你喜欢 JeeSite请给她一个 ⭐️ Star您的支持将是我们前行的动力。
</div>
------
- 问题反馈:<https://gitee.com/thinkgem/jeesite-vue/issues> [【新手必读】](https://gitee.com/thinkgem/jeesite5/issues/I18ARR)
- 需求收集:<https://gitee.com/thinkgem/jeesite-vue/issues/new>
- QQ 群:`127515876``209330483``223507718``709534275``730390092``1373527``183903863(外包)`
- 微信群:添加客服微信 <http://s.jeesite.com> 邀请您进群
- 关注微信公众号,了解最新动态:
<p style="padding-left:40px">
<img alt="JeeSite微信公众号" src="https://jeesite.com/assets/images/mp.png" width="220" height="220">
</p>

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
*/
import { defHttp } from '@jeesite/core/utils/http/axios';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { BasicModel, Page } from '@jeesite/core/api/model/baseModel';
import { UploadApiResult } from '@jeesite/core/api/sys/upload';
import { UploadFileParams } from '@jeesite/types/axios';
import { AxiosProgressEvent } from 'axios';
const { ctxPath, adminPath } = useGlobSetting();
export interface ErpAccount extends BasicModel<ErpAccount> {
createTime?: string; // 记录时间
accountId?: string; // 账户标识
accountName: string; // 账户名称
accountType: string; // 账户类型
accountCode: string; // 账户卡号
initialBalance: number; // 初始余额
currentBalance: number; // 当前余额
isActive: string; // 是否激活
updateTime?: string; // 更新时间
ftenantId?: string; // 租户id
fflowId?: string; // 流程id
fflowTaskId?: string; // 流程任务主键
fflowState?: number; // 流程任务状态
}
export const erpAccountList = (params?: ErpAccount | any) =>
defHttp.get<ErpAccount>({ url: adminPath + '/erp/account/list', params });
export const erpAccountListData = (params?: ErpAccount | any) =>
defHttp.post<Page<ErpAccount>>({ url: adminPath + '/erp/account/listData', params });
export const erpAccountForm = (params?: ErpAccount | any) =>
defHttp.get<ErpAccount>({ url: adminPath + '/erp/account/form', params });
export const erpAccountSave = (params?: any, data?: ErpAccount | any) =>
defHttp.postJson<ErpAccount>({ url: adminPath + '/erp/account/save', params, data });
export const erpAccountImportData = (
params: UploadFileParams,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void,
) =>
defHttp.uploadFile<UploadApiResult>(
{
url: ctxPath + adminPath + '/erp/account/importData',
onUploadProgress,
},
params,
);
export const erpAccountDelete = (params?: ErpAccount | any) =>
defHttp.get<ErpAccount>({ url: adminPath + '/erp/account/delete', params });

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
*/
import { defHttp } from '@jeesite/core/utils/http/axios';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { BasicModel, Page } from '@jeesite/core/api/model/baseModel';
import { UploadApiResult } from '@jeesite/core/api/sys/upload';
import { UploadFileParams } from '@jeesite/types/axios';
import { AxiosProgressEvent } from 'axios';
const { ctxPath, adminPath } = useGlobSetting();
export interface ErpCategory extends BasicModel<ErpCategory> {
createTime: string; // 记录时间
categoryId: string; // 分类标识
categoryName: string; // 分类名称
categoryType: string; // 分类类型
parentId?: string; // 父级分类
sortOrder: string; // 排序序号
isActive: string; // 是否启用
updateTime?: string; // 更新时间
ftenantId: string; // 租户id
fflowId?: string; // 流程id
fflowTaskId?: string; // 流程任务主键
fflowState?: number; // 流程任务状态
}
export const erpCategoryList = (params?: ErpCategory | any) =>
defHttp.get<ErpCategory>({ url: adminPath + '/erp/category/list', params });
export const erpCategoryListAll = (params?: ErpCategory | any) =>
defHttp.get<ErpCategory[]>({ url: adminPath + '/erp/category/listAll', params });
export const erpCategoryListData = (params?: ErpCategory | any) =>
defHttp.post<Page<ErpCategory>>({ url: adminPath + '/erp/category/listData', params });
export const erpCategoryForm = (params?: ErpCategory | any) =>
defHttp.get<ErpCategory>({ url: adminPath + '/erp/category/form', params });
export const erpCategorySave = (params?: any, data?: ErpCategory | any) =>
defHttp.postJson<ErpCategory>({ url: adminPath + '/erp/category/save', params, data });
export const erpCategoryImportData = (
params: UploadFileParams,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void,
) =>
defHttp.uploadFile<UploadApiResult>(
{
url: ctxPath + adminPath + '/erp/category/importData',
onUploadProgress,
},
params,
);
export const erpCategoryDelete = (params?: ErpCategory | any) =>
defHttp.get<ErpCategory>({ url: adminPath + '/erp/category/delete', params });

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
*/
import { defHttp } from '@jeesite/core/utils/http/axios';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { BasicModel, Page } from '@jeesite/core/api/model/baseModel';
import { UploadApiResult } from '@jeesite/core/api/sys/upload';
import { UploadFileParams } from '@jeesite/types/axios';
import { AxiosProgressEvent } from 'axios';
const { ctxPath, adminPath } = useGlobSetting();
export interface ErpExpense extends BasicModel<ErpExpense> {
createTime?: string; // 记录时间
expenseId?: string; // 支出ID
zflowId: string; // 关联流水ID
accountId: string; // 支出账户ID
categoryId: string; // 支出分类ID
amount: number; // 交易金额
updateTime?: string; // 更新时间
ftenantId?: string; // 租户id
fflowId?: string; // 流程id
fflowTaskId?: string; // 流程任务主键
fflowState?: number; // 流程任务状态
}
export const erpExpenseList = (params?: ErpExpense | any) =>
defHttp.get<ErpExpense>({ url: adminPath + '/erp/expense/list', params });
export const erpExpenseListData = (params?: ErpExpense | any) =>
defHttp.post<Page<ErpExpense>>({ url: adminPath + '/erp/expense/listData', params });
export const erpExpenseForm = (params?: ErpExpense | any) =>
defHttp.get<ErpExpense>({ url: adminPath + '/erp/expense/form', params });
export const erpExpenseSave = (params?: any, data?: ErpExpense | any) =>
defHttp.postJson<ErpExpense>({ url: adminPath + '/erp/expense/save', params, data });
export const erpExpenseImportData = (
params: UploadFileParams,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void,
) =>
defHttp.uploadFile<UploadApiResult>(
{
url: ctxPath + adminPath + '/erp/expense/importData',
onUploadProgress,
},
params,
);
export const erpExpenseDelete = (params?: ErpExpense | any) =>
defHttp.get<ErpExpense>({ url: adminPath + '/erp/expense/delete', params });

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
*/
import { defHttp } from '@jeesite/core/utils/http/axios';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { BasicModel, Page } from '@jeesite/core/api/model/baseModel';
import { UploadApiResult } from '@jeesite/core/api/sys/upload';
import { UploadFileParams } from '@jeesite/types/axios';
import { AxiosProgressEvent } from 'axios';
const { ctxPath, adminPath } = useGlobSetting();
export interface ErpIncome extends BasicModel<ErpIncome> {
createTime?: string; // 记录时间
incomeId?: string; // 收入ID
sflowId: string; // 关联流水ID
accountId: string; // 收入账户ID
categoryId: string; // 收入分类ID
amount: number; // 交易金额(正数)
updateTime?: string; // 更新时间
ftenantId?: string; // 租户id
fflowId?: string; // 流程id
fflowTaskId?: string; // 流程任务主键
fflowState?: number; // 流程任务状态
}
export const erpIncomeList = (params?: ErpIncome | any) =>
defHttp.get<ErpIncome>({ url: adminPath + '/erp/income/list', params });
export const erpIncomeListData = (params?: ErpIncome | any) =>
defHttp.post<Page<ErpIncome>>({ url: adminPath + '/erp/income/listData', params });
export const erpIncomeForm = (params?: ErpIncome | any) =>
defHttp.get<ErpIncome>({ url: adminPath + '/erp/income/form', params });
export const erpIncomeSave = (params?: any, data?: ErpIncome | any) =>
defHttp.postJson<ErpIncome>({ url: adminPath + '/erp/income/save', params, data });
export const erpIncomeImportData = (
params: UploadFileParams,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void,
) =>
defHttp.uploadFile<UploadApiResult>(
{
url: ctxPath + adminPath + '/erp/income/importData',
onUploadProgress,
},
params,
);
export const erpIncomeDelete = (params?: ErpIncome | any) =>
defHttp.get<ErpIncome>({ url: adminPath + '/erp/income/delete', params });

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
*/
import { defHttp } from '@jeesite/core/utils/http/axios';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { BasicModel, Page } from '@jeesite/core/api/model/baseModel';
import { UploadApiResult } from '@jeesite/core/api/sys/upload';
import { UploadFileParams } from '@jeesite/types/axios';
import { AxiosProgressEvent } from 'axios';
const { ctxPath, adminPath } = useGlobSetting();
export interface ErpTransactionFlow extends BasicModel<ErpTransactionFlow> {
createTime?: string; // 记录时间
flowId?: string; // 流水编号
flowName: string; // 交易名称
transactionType: string; // 交易类型
amount: number; // 交易金额
transactionTime?: string; // 交易时间
accountId: string; // 交易账户
categoryId: string; // 交易分类
remark?: string; // 交易备注
isFinish?: string; // 是否记账
updateTime?: string; // 更新时间
ftenantId?: string; // 租户id
fflowId?: string; // 流程id
fflowTaskId?: string; // 流程任务主键
fflowState?: number; // 流程任务状态
}
export const erpTransactionFlowList = (params?: ErpTransactionFlow | any) =>
defHttp.get<ErpTransactionFlow>({ url: adminPath + '/erp/transactionFlow/list', params });
export const erpTransactionFlowListData = (params?: ErpTransactionFlow | any) =>
defHttp.post<Page<ErpTransactionFlow>>({ url: adminPath + '/erp/transactionFlow/listData', params });
export const erpTransactionFlowForm = (params?: ErpTransactionFlow | any) =>
defHttp.get<ErpTransactionFlow>({ url: adminPath + '/erp/transactionFlow/form', params });
export const erpTransactionFlowSave = (params?: any, data?: ErpTransactionFlow | any) =>
defHttp.postJson<ErpTransactionFlow>({ url: adminPath + '/erp/transactionFlow/save', params, data });
export const erpTransactionFlowImportData = (
params: UploadFileParams,
onUploadProgress: (progressEvent: AxiosProgressEvent) => void,
) =>
defHttp.uploadFile<UploadApiResult>(
{
url: ctxPath + adminPath + '/erp/transactionFlow/importData',
onUploadProgress,
},
params,
);
export const erpTransactionFlowDelete = (params?: ErpTransactionFlow | any) =>
defHttp.get<ErpTransactionFlow>({ url: adminPath + '/erp/transactionFlow/delete', params });
export const erpTransactionFlowFinish = (params?: ErpTransactionFlow | any) =>
defHttp.get<ErpTransactionFlow>({ url: adminPath + '/erp/transactionFlow/finish', params });

View File

@@ -0,0 +1,30 @@
{
"name": "@jeesite/erp",
"version": "5.14.0",
"private": true,
"type": "module",
"scripts": {
"type:check": "vue-tsc --noEmit --skipLibCheck",
"uninstall": "rimraf node_modules",
"update": "ncu -u"
},
"dependencies": {
"qs": "6.14.0"
},
"devDependencies": {
"@types/qs": "6.9.18"
},
"homepage": "https://jeesite.com",
"repository": {
"type": "git",
"url": "https://gitee.com/thinkgem/jeesite-vue.git"
},
"bugs": {
"url": "https://gitee.com/thinkgem/jeesite-vue/issues"
},
"author": {
"name": "ThinkGem",
"email": "thinkgem@163.com",
"url": "https://gitee.com/thinkgem"
}
}

View File

@@ -0,0 +1,20 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@jeesite/erp/*": ["./*"]
}
},
"include": [
"./**/*.ts",
"./**/*.tsx",
"./**/*.vue"
],
"exclude": [
"node_modules",
"vite.config.ts",
"_lib",
"dist"
]
}

View File

@@ -0,0 +1,143 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicDrawer
v-bind="$attrs"
:showFooter="true"
:okAuth="'erp:account:edit'"
@register="registerDrawer"
@ok="handleSubmit"
width="40%"
>
<template #title>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup name="ViewsErpAccountForm">
import { ref, unref, computed } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
import { ErpAccount, erpAccountSave, erpAccountForm } from '@jeesite/erp/api/erp/account';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.account');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpAccount>({} as ErpAccount);
const getTitle = computed(() => ({
icon: meta.icon || 'i-ant-design:book-outlined',
value: record.value.isNewRecord ? t('新增账户信息') : t('编辑账户信息'),
}));
const inputFormSchemas: FormSchema<ErpAccount>[] = [
{
label: t('账户名称'),
field: 'accountName',
component: 'Input',
componentProps: {
maxlength: 100,
},
required: true,
colProps: { md: 24, lg: 24 },
},
{
label: t('账户卡号'),
field: 'accountCode',
component: 'Input',
componentProps: {
maxlength: 32,
},
required: true,
colProps: { md: 24, lg: 24 },
},
{
label: t('初始余额'),
field: 'initialBalance',
component: 'InputNumber',
componentProps: {
maxlength: 10,
},
required: true,
},
{
label: t('当前余额'),
field: 'currentBalance',
component: 'InputNumber',
componentProps: {
maxlength: 10,
},
required: true,
},
{
label: t('账户类型'),
field: 'accountType',
component: 'Select',
componentProps: {
dictType: 'account_type',
allowClear: true,
},
required: true,
},
{
label: t('是否激活'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
required: true,
},
];
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm<ErpAccount>({
labelWidth: 120,
schemas: inputFormSchemas,
baseColProps: { md: 24, lg: 12 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
await resetFields();
const res = await erpAccountForm(data);
record.value = (res.erpAccount || {}) as ErpAccount;
record.value.__t = new Date().getTime();
await setFieldsValue(record.value);
setDrawerProps({ loading: false });
});
async function handleSubmit() {
try {
const data = await validate();
setDrawerProps({ confirmLoading: true });
const params: any = {
isNewRecord: record.value.isNewRecord,
accountId: record.value.accountId || data.accountId,
};
// console.log('submit', params, data, record);
const res = await erpAccountSave(params, data);
showMessage(res.message);
setTimeout(closeDrawer);
emit('success', data);
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,103 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicModal
v-bind="$attrs"
:title="t('导入账户信息')"
:okText="t('导入')"
@register="registerModal"
@ok="handleSubmit"
:minHeight="120"
:width="400"
>
<Upload accept=".xls,.xlsx" :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button> <Icon icon="ant-design:upload-outlined" /> {{ t('选择文件') }} </a-button>
<span class="ml-4">{{ uploadInfo }}</span>
</Upload>
<div class="ml-4 mt-4">
{{ t('提示仅允许导入“xls”或“xlsx”格式文件') }}
</div>
<div class="mt-4">
<a-button @click="handleDownloadTemplate()" type="text">
<Icon icon="i-fa:file-excel-o" />
{{ t('下载模板') }}
</a-button>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Upload } from 'ant-design-vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { erpAccountImportData } from '@jeesite/erp/api/erp/account';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.account');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref<FileType[]>([]);
const uploadInfo = ref('');
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
const handleRemove = () => {
fileList.value = [];
};
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
fileList.value = [];
uploadInfo.value = '';
});
async function handleDownloadTemplate() {
const { ctxAdminPath } = useGlobSetting();
downloadByUrl({ url: ctxAdminPath + '/erp/account/importTemplate' });
}
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍候') + ' ' + complete + '%...';
} else {
uploadInfo.value = '';
}
}
async function handleSubmit() {
try {
if (fileList.value.length == 0) {
showMessage(t('请选择要导入的数据文件'));
return;
}
setModalProps({ confirmLoading: true });
const params = {
file: fileList.value[0],
};
const { data } = await erpAccountImportData(params, onUploadProgress);
showMessageModal({ content: data.message });
setTimeout(closeModal);
emit('success');
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,234 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<div>
<BasicTable @register="registerTable">
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<template #toolbar>
<a-button type="default" :loading="loading" @click="handleExport()">
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
<a-button type="primary" @click="handleForm({})" v-auth="'erp:account:edit'">
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
</a-button>
</template>
<template #slotBizKey="{ record }">
<a @click="handleForm({ accountId: record.accountId })" :title="record.accountName">
{{ record.accountName }}
</a>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup name="ViewsErpAccountList">
import { onMounted, ref, unref } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { ErpAccount, erpAccountList } from '@jeesite/erp/api/erp/account';
import { erpAccountDelete, erpAccountListData } from '@jeesite/erp/api/erp/account';
import { useDrawer } from '@jeesite/core/components/Drawer';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import InputForm from './form.vue';
import FormImport from './formImport.vue';
const { t } = useI18n('erp.account');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpAccount>({} as ErpAccount);
const getTitle = {
icon: meta.icon || 'i-ant-design:book-outlined',
value: meta.title || t('账户信息管理'),
};
const loading = ref(false);
const searchForm: FormProps<ErpAccount> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('账户名称'),
field: 'accountName',
component: 'Input',
},
{
label: t('账户类型'),
field: 'accountType',
component: 'Select',
componentProps: {
dictType: 'account_type',
allowClear: true,
},
},
{
label: t('是否激活'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpAccount>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('账户名称'),
dataIndex: 'accountName',
key: 'a.account_name',
sorter: true,
width: 130,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('账户类型'),
dataIndex: 'accountType',
key: 'a.account_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'account_type',
},
{
title: t('账户卡号'),
dataIndex: 'accountCode',
key: 'a.account_code',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('初始余额'),
dataIndex: 'initialBalance',
key: 'a.initial_balance',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('当前余额'),
dataIndex: 'currentBalance',
key: 'a.current_balance',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('是否激活'),
dataIndex: 'isActive',
key: 'a.is_active',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_active',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const actionColumn: BasicColumn<ErpAccount> = {
width: 160,
align: 'center',
actions: (record: ErpAccount) => [
{
icon: 'i-clarity:note-edit-line',
title: t('编辑'),
onClick: handleForm.bind(this, { accountId: record.accountId }),
auth: 'erp:account:edit',
},
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除账户?'),
confirm: handleDelete.bind(this, record),
},
auth: 'erp:account:edit',
ifShow: record.isActive == '0'
},
],
};
const [registerTable, { reload, getForm }] = useTable<ErpAccount>({
api: erpAccountListData,
beforeFetch: (params) => {
return params;
},
columns: tableColumns,
actionColumn: actionColumn,
formConfig: searchForm,
showTableSetting: true,
useSearchForm: true,
canResize: true,
});
onMounted(async () => {
const res = await erpAccountList();
record.value = (res.erpAccount || {}) as ErpAccount;
await getForm().setFieldsValue(record.value);
});
const [registerDrawer, { openDrawer }] = useDrawer();
function handleForm(record: Recordable) {
openDrawer(true, record);
}
async function handleExport() {
loading.value = true;
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/erp/account/exportData',
params: getForm().getFieldsValue(),
});
loading.value = false;
}
const [registerImportModal, { openModal: importModal }] = useModal();
function handleImport() {
importModal(true, {});
}
async function handleDelete(record: Recordable) {
const params = { accountId: record.accountId };
const res = await erpAccountDelete(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });
}
</script>

View File

@@ -0,0 +1,142 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicDrawer
v-bind="$attrs"
:showFooter="true"
:okAuth="'erp:category:edit'"
@register="registerDrawer"
@ok="handleSubmit"
width="40%"
>
<template #title>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup name="ViewsErpCategoryForm">
import { ref, unref, computed } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
import { ErpCategory, erpCategorySave, erpCategoryForm } from '@jeesite/erp/api/erp/category';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.category');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpCategory>({} as ErpCategory);
const getTitle = computed(() => ({
icon: meta.icon || 'i-ant-design:book-outlined',
value: record.value.isNewRecord ? t('新增分类信息') : t('编辑分类信息'),
}));
const inputFormSchemas: FormSchema<ErpCategory>[] = [
{
label: t('记录时间'),
field: 'createTime',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
required: true,
},
{
label: t('分类名称'),
field: 'categoryName',
component: 'Input',
componentProps: {
maxlength: 50,
},
required: true,
},
{
label: t('分类类型'),
field: 'categoryType',
component: 'Select',
componentProps: {
dictType: 'category_type',
allowClear: true,
},
required: true,
},
{
label: t('父级分类'),
field: 'parentId',
component: 'Select',
componentProps: {
dictType: 'parent_type',
allowClear: true,
},
},
{
label: t('排序序号'),
field: 'sortOrder',
component: 'Input',
componentProps: {
maxlength: 32,
},
required: true,
},
{
label: t('是否启用'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
required: true,
},
];
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm<ErpCategory>({
labelWidth: 120,
schemas: inputFormSchemas,
baseColProps: { md: 24, lg: 12 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
await resetFields();
const res = await erpCategoryForm(data);
record.value = (res.erpCategory || {}) as ErpCategory;
record.value.__t = new Date().getTime();
await setFieldsValue(record.value);
setDrawerProps({ loading: false });
});
async function handleSubmit() {
try {
const data = await validate();
setDrawerProps({ confirmLoading: true });
const params: any = {
isNewRecord: record.value.isNewRecord,
categoryId: record.value.categoryId || data.categoryId,
};
// console.log('submit', params, data, record);
const res = await erpCategorySave(params, data);
showMessage(res.message);
setTimeout(closeDrawer);
emit('success', data);
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,103 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicModal
v-bind="$attrs"
:title="t('导入分类信息')"
:okText="t('导入')"
@register="registerModal"
@ok="handleSubmit"
:minHeight="120"
:width="400"
>
<Upload accept=".xls,.xlsx" :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button> <Icon icon="ant-design:upload-outlined" /> {{ t('选择文件') }} </a-button>
<span class="ml-4">{{ uploadInfo }}</span>
</Upload>
<div class="ml-4 mt-4">
{{ t('提示仅允许导入“xls”或“xlsx”格式文件') }}
</div>
<div class="mt-4">
<a-button @click="handleDownloadTemplate()" type="text">
<Icon icon="i-fa:file-excel-o" />
{{ t('下载模板') }}
</a-button>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Upload } from 'ant-design-vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { erpCategoryImportData } from '@jeesite/erp/api/erp/category';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.category');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref<FileType[]>([]);
const uploadInfo = ref('');
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
const handleRemove = () => {
fileList.value = [];
};
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
fileList.value = [];
uploadInfo.value = '';
});
async function handleDownloadTemplate() {
const { ctxAdminPath } = useGlobSetting();
downloadByUrl({ url: ctxAdminPath + '/erp/category/importTemplate' });
}
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍候') + ' ' + complete + '%...';
} else {
uploadInfo.value = '';
}
}
async function handleSubmit() {
try {
if (fileList.value.length == 0) {
showMessage(t('请选择要导入的数据文件'));
return;
}
setModalProps({ confirmLoading: true });
const params = {
file: fileList.value[0],
};
const { data } = await erpCategoryImportData(params, onUploadProgress);
showMessageModal({ content: data.message });
setTimeout(closeModal);
emit('success');
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,227 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<div>
<BasicTable @register="registerTable">
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<template #toolbar>
<a-button type="default" :loading="loading" @click="handleExport()">
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
<a-button type="primary" @click="handleForm({})" v-auth="'erp:category:edit'">
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
</a-button>
</template>
<template #slotBizKey="{ record }">
<a @click="handleForm({ categoryId: record.categoryId })" :title="record.categoryName">
{{ record.categoryName }}
</a>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup name="ViewsErpCategoryList">
import { onMounted, ref, unref } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { ErpCategory, erpCategoryList } from '@jeesite/erp/api/erp/category';
import { erpCategoryDelete, erpCategoryListData } from '@jeesite/erp/api/erp/category';
import { useDrawer } from '@jeesite/core/components/Drawer';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import InputForm from './form.vue';
import FormImport from './formImport.vue';
const { t } = useI18n('erp.category');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpCategory>({} as ErpCategory);
const getTitle = {
icon: meta.icon || 'i-ant-design:book-outlined',
value: meta.title || t('分类信息管理'),
};
const loading = ref(false);
const searchForm: FormProps<ErpCategory> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('分类名称'),
field: 'categoryName',
component: 'Input',
},
{
label: t('分类类型'),
field: 'categoryType',
component: 'Select',
componentProps: {
dictType: 'category_type',
allowClear: true,
},
},
{
label: t('是否启用'),
field: 'isActive',
component: 'Select',
componentProps: {
dictType: 'is_active',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpCategory>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('分类名称'),
dataIndex: 'categoryName',
key: 'a.category_name',
sorter: true,
width: 200,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('分类类型'),
dataIndex: 'categoryType',
key: 'a.category_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'category_type',
},
{
title: t('父级分类'),
dataIndex: 'parentId',
key: 'a.parent_id',
sorter: true,
width: 130,
align: 'left',
dictType: 'parent_type',
},
{
title: t('排序序号'),
dataIndex: 'sortOrder',
key: 'a.sort_order',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('是否启用'),
dataIndex: 'isActive',
key: 'a.is_active',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_active',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 130,
align: 'center',
},
];
const actionColumn: BasicColumn<ErpCategory> = {
width: 160,
align: 'center',
actions: (record: ErpCategory) => [
{
icon: 'i-clarity:note-edit-line',
title: t('编辑'),
onClick: handleForm.bind(this, { categoryId: record.categoryId }),
auth: 'erp:category:edit',
},
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除分类信息?'),
confirm: handleDelete.bind(this, record),
},
auth: 'erp:category:edit',
ifShow: record.isActive == '0'
},
],
};
const [registerTable, { reload, getForm }] = useTable<ErpCategory>({
api: erpCategoryListData,
beforeFetch: (params) => {
return params;
},
columns: tableColumns,
actionColumn: actionColumn,
formConfig: searchForm,
showTableSetting: true,
useSearchForm: true,
canResize: true,
});
onMounted(async () => {
const res = await erpCategoryList();
record.value = (res.erpCategory || {}) as ErpCategory;
await getForm().setFieldsValue(record.value);
});
const [registerDrawer, { openDrawer }] = useDrawer();
function handleForm(record: Recordable) {
openDrawer(true, record);
}
async function handleExport() {
loading.value = true;
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/erp/category/exportData',
params: getForm().getFieldsValue(),
});
loading.value = false;
}
const [registerImportModal, { openModal: importModal }] = useModal();
function handleImport() {
importModal(true, {});
}
async function handleDelete(record: Recordable) {
const params = { categoryId: record.categoryId };
const res = await erpCategoryDelete(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });
}
</script>

View File

@@ -0,0 +1,103 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicModal
v-bind="$attrs"
:title="t('导入支出信息')"
:okText="t('导入')"
@register="registerModal"
@ok="handleSubmit"
:minHeight="120"
:width="400"
>
<Upload accept=".xls,.xlsx" :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button> <Icon icon="ant-design:upload-outlined" /> {{ t('选择文件') }} </a-button>
<span class="ml-4">{{ uploadInfo }}</span>
</Upload>
<div class="ml-4 mt-4">
{{ t('提示仅允许导入“xls”或“xlsx”格式文件') }}
</div>
<div class="mt-4">
<a-button @click="handleDownloadTemplate()" type="text">
<Icon icon="i-fa:file-excel-o" />
{{ t('下载模板') }}
</a-button>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Upload } from 'ant-design-vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { erpExpenseImportData } from '@jeesite/erp/api/erp/expense';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.expense');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref<FileType[]>([]);
const uploadInfo = ref('');
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
const handleRemove = () => {
fileList.value = [];
};
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
fileList.value = [];
uploadInfo.value = '';
});
async function handleDownloadTemplate() {
const { ctxAdminPath } = useGlobSetting();
downloadByUrl({ url: ctxAdminPath + '/erp/expense/importTemplate' });
}
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍候') + ' ' + complete + '%...';
} else {
uploadInfo.value = '';
}
}
async function handleSubmit() {
try {
if (fileList.value.length == 0) {
showMessage(t('请选择要导入的数据文件'));
return;
}
setModalProps({ confirmLoading: true });
const params = {
file: fileList.value[0],
};
const { data } = await erpExpenseImportData(params, onUploadProgress);
showMessageModal({ content: data.message });
setTimeout(closeModal);
emit('success');
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,213 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<div>
<BasicTable @register="registerTable">
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<template #toolbar>
<a-button type="default" :loading="loading" @click="handleExport()">
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup name="ViewsErpExpenseList">
import { onMounted, ref, unref } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { ErpExpense, erpExpenseList } from '@jeesite/erp/api/erp/expense';
import { erpExpenseDelete, erpExpenseListData } from '@jeesite/erp/api/erp/expense';
import { useDrawer } from '@jeesite/core/components/Drawer';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import FormImport from './formImport.vue';
const { t } = useI18n('erp.expense');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpExpense>({} as ErpExpense);
const getTitle = {
icon: meta.icon || 'i-ant-design:book-outlined',
value: meta.title || t('支出信息管理'),
};
const loading = ref(false);
const searchForm: FormProps<ErpExpense> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('记录时间起'),
field: 'createTime_gte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('记录时间止'),
field: 'createTime_lte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('交易分类'),
field: 'categoryId',
fieldLabel: 'categoryName',
component: 'ListSelect',
componentProps: {
selectType: 'erpCategorySelect',
},
},
],
};
const tableColumns: BasicColumn<ErpExpense>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('交易账号'),
dataIndex: 'accountName',
key: 'b.account_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('父级分类'),
dataIndex: 'parentId',
key: 'c.parent_id',
sorter: true,
width: 130,
align: 'left',
dictType: 'parent_type',
},
{
title: t('分类名称'),
dataIndex: 'categoryName',
key: 'c.category_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易名称'),
dataIndex: 'flowName',
key: 'd.flow_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易金额'),
dataIndex: 'amount',
key: 'a.amount',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const actionColumn: BasicColumn<ErpExpense> = {
width: 160,
align: 'center',
actions: (record: ErpExpense) => [
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除支出信息?'),
confirm: handleDelete.bind(this, record),
},
auth: 'erp:expense:edit',
ifShow: record.isFinish == '0'
},
],
};
const [registerTable, { reload, getForm }] = useTable<ErpExpense>({
api: erpExpenseListData,
beforeFetch: (params) => {
return params;
},
columns: tableColumns,
actionColumn: actionColumn,
formConfig: searchForm,
showTableSetting: true,
useSearchForm: true,
canResize: true,
});
onMounted(async () => {
const res = await erpExpenseList();
record.value = (res.erpExpense || {}) as ErpExpense;
await getForm().setFieldsValue(record.value);
});
const [registerDrawer, { openDrawer }] = useDrawer();
function handleForm(record: Recordable) {
openDrawer(true, record);
}
async function handleExport() {
loading.value = true;
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/erp/expense/exportData',
params: getForm().getFieldsValue(),
});
loading.value = false;
}
const [registerImportModal, { openModal: importModal }] = useModal();
function handleImport() {
importModal(true, {});
}
async function handleDelete(record: Recordable) {
const params = { expenseId: record.expenseId };
const res = await erpExpenseDelete(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });
}
</script>

View File

@@ -0,0 +1,103 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicModal
v-bind="$attrs"
:title="t('导入收入信息')"
:okText="t('导入')"
@register="registerModal"
@ok="handleSubmit"
:minHeight="120"
:width="400"
>
<Upload accept=".xls,.xlsx" :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button> <Icon icon="ant-design:upload-outlined" /> {{ t('选择文件') }} </a-button>
<span class="ml-4">{{ uploadInfo }}</span>
</Upload>
<div class="ml-4 mt-4">
{{ t('提示仅允许导入“xls”或“xlsx”格式文件') }}
</div>
<div class="mt-4">
<a-button @click="handleDownloadTemplate()" type="text">
<Icon icon="i-fa:file-excel-o" />
{{ t('下载模板') }}
</a-button>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Upload } from 'ant-design-vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { erpIncomeImportData } from '@jeesite/erp/api/erp/income';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.income');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref<FileType[]>([]);
const uploadInfo = ref('');
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
const handleRemove = () => {
fileList.value = [];
};
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
fileList.value = [];
uploadInfo.value = '';
});
async function handleDownloadTemplate() {
const { ctxAdminPath } = useGlobSetting();
downloadByUrl({ url: ctxAdminPath + '/erp/income/importTemplate' });
}
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍候') + ' ' + complete + '%...';
} else {
uploadInfo.value = '';
}
}
async function handleSubmit() {
try {
if (fileList.value.length == 0) {
showMessage(t('请选择要导入的数据文件'));
return;
}
setModalProps({ confirmLoading: true });
const params = {
file: fileList.value[0],
};
const { data } = await erpIncomeImportData(params, onUploadProgress);
showMessageModal({ content: data.message });
setTimeout(closeModal);
emit('success');
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,213 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<div>
<BasicTable @register="registerTable">
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<template #toolbar>
<a-button type="default" :loading="loading" @click="handleExport()">
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup name="ViewsErpIncomeList">
import { onMounted, ref, unref } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { ErpIncome, erpIncomeList } from '@jeesite/erp/api/erp/income';
import { erpIncomeDelete, erpIncomeListData } from '@jeesite/erp/api/erp/income';
import { useDrawer } from '@jeesite/core/components/Drawer';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import FormImport from './formImport.vue';
const { t } = useI18n('erp.income');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpIncome>({} as ErpIncome);
const getTitle = {
icon: meta.icon || 'i-ant-design:book-outlined',
value: meta.title || t('收入信息管理'),
};
const loading = ref(false);
const searchForm: FormProps<ErpIncome> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('记录时间起'),
field: 'createTime_gte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('记录时间止'),
field: 'createTime_lte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('交易分类'),
field: 'categoryId',
fieldLabel: 'categoryName',
component: 'ListSelect',
componentProps: {
selectType: 'erpCategorySelect',
},
},
],
};
const tableColumns: BasicColumn<ErpIncome>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('交易账号'),
dataIndex: 'accountName',
key: 'b.account_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('父级分类'),
dataIndex: 'parentId',
key: 'c.parent_id',
sorter: true,
width: 130,
align: 'left',
dictType: 'parent_type',
},
{
title: t('分类名称'),
dataIndex: 'categoryName',
key: 'c.category_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易名称'),
dataIndex: 'flowName',
key: 'd.flow_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易金额'),
dataIndex: 'amount',
key: 'a.amount',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const actionColumn: BasicColumn<ErpIncome> = {
width: 160,
align: 'center',
actions: (record: ErpIncome) => [
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除收入信息?'),
confirm: handleDelete.bind(this, record),
},
auth: 'erp:income:edit',
ifShow: record.isFinish == '0'
},
],
};
const [registerTable, { reload, getForm }] = useTable<ErpIncome>({
api: erpIncomeListData,
beforeFetch: (params) => {
return params;
},
columns: tableColumns,
actionColumn: actionColumn,
formConfig: searchForm,
showTableSetting: true,
useSearchForm: true,
canResize: true,
});
onMounted(async () => {
const res = await erpIncomeList();
record.value = (res.erpIncome || {}) as ErpIncome;
await getForm().setFieldsValue(record.value);
});
const [registerDrawer, { openDrawer }] = useDrawer();
function handleForm(record: Recordable) {
openDrawer(true, record);
}
async function handleExport() {
loading.value = true;
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/erp/income/exportData',
params: getForm().getFieldsValue(),
});
loading.value = false;
}
const [registerImportModal, { openModal: importModal }] = useModal();
function handleImport() {
importModal(true, {});
}
async function handleDelete(record: Recordable) {
const params = { incomeId: record.incomeId };
const res = await erpIncomeDelete(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });
}
</script>

View File

@@ -0,0 +1,153 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicDrawer
v-bind="$attrs"
:showFooter="true"
:okAuth="'erp:transactionFlow:edit'"
@register="registerDrawer"
@ok="handleSubmit"
width="70%"
>
<template #title>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup name="ViewsErpTransactionFlowForm">
import { ref, unref, computed } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
import { ErpCategory, erpCategoryListAll } from '@jeesite/erp/api/erp/category';
import { ErpTransactionFlow, erpTransactionFlowSave, erpTransactionFlowForm } from '@jeesite/erp/api/erp/transactionFlow';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.transactionFlow');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpTransactionFlow>({} as ErpTransactionFlow);
const categoryParams = ref<Recordable>({ categoryType: '' });
const getTitle = computed(() => ({
icon: meta.icon || 'i-ant-design:book-outlined',
value: record.value.isNewRecord ? t('新增明细信息') : t('编辑明细信息'),
}));
const inputFormSchemas: FormSchema<ErpTransactionFlow>[] = [
{
label: t('交易名称'),
field: 'flowName',
component: 'Input',
componentProps: {
maxlength: 32,
},
required: true,
colProps: { md: 24, lg: 24 },
},
{
label: t('交易类型'),
field: 'transactionType',
component: 'Select',
componentProps: {
dictType: 'transaction_type',
allowClear: true,
immediate: true,
onChange:(value: string) => {
categoryParams.value.categoryType = value
},
},
required: true,
},
{
label: t('交易分类'),
field: 'categoryId',
component: 'Select',
componentProps: {
api: erpCategoryListAll,
params: categoryParams.value,
fieldNames: { label: 'categoryName', value: 'categoryId' },
allowClear: true,
immediate: true,
},
required: true,
},
{
label: t('交易账户'),
field: 'accountId',
fieldLabel: 'accountName',
component: 'ListSelect',
componentProps: {
selectType: 'erpAccountSelect',
},
required: true,
},
{
label: t('交易金额'),
field: 'amount',
component: 'InputNumber',
componentProps: {
maxlength: 10,
},
required: true,
},
{
label: t('交易备注'),
field: 'remark',
component: 'InputTextArea',
componentProps: {
maxlength: 500,
},
colProps: { md: 24, lg: 24 },
},
];
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm<ErpTransactionFlow>({
labelWidth: 120,
schemas: inputFormSchemas,
baseColProps: { md: 24, lg: 12 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
await resetFields();
const res = await erpTransactionFlowForm(data);
record.value = (res.erpTransactionFlow || {}) as ErpTransactionFlow;
record.value.__t = new Date().getTime();
await setFieldsValue(record.value);
setDrawerProps({ loading: false });
});
async function handleSubmit() {
try {
const data = await validate();
setDrawerProps({ confirmLoading: true });
const params: any = {
isNewRecord: record.value.isNewRecord,
flowId: record.value.flowId || data.flowId,
};
// console.log('submit', params, data, record);
const res = await erpTransactionFlowSave(params, data);
showMessage(res.message);
setTimeout(closeDrawer);
emit('success', data);
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,103 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<BasicModal
v-bind="$attrs"
:title="t('导入明细信息')"
:okText="t('导入')"
@register="registerModal"
@ok="handleSubmit"
:minHeight="120"
:width="400"
>
<Upload accept=".xls,.xlsx" :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button> <Icon icon="ant-design:upload-outlined" /> {{ t('选择文件') }} </a-button>
<span class="ml-4">{{ uploadInfo }}</span>
</Upload>
<div class="ml-4 mt-4">
{{ t('提示仅允许导入“xls”或“xlsx”格式文件') }}
</div>
<div class="mt-4">
<a-button @click="handleDownloadTemplate()" type="text">
<Icon icon="i-fa:file-excel-o" />
{{ t('下载模板') }}
</a-button>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { Upload } from 'ant-design-vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { erpTransactionFlowImportData } from '@jeesite/erp/api/erp/transactionFlow';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('erp.transactionFlow');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref<FileType[]>([]);
const uploadInfo = ref('');
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
const handleRemove = () => {
fileList.value = [];
};
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
fileList.value = [];
uploadInfo.value = '';
});
async function handleDownloadTemplate() {
const { ctxAdminPath } = useGlobSetting();
downloadByUrl({ url: ctxAdminPath + '/erp/transactionFlow/importTemplate' });
}
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍候') + ' ' + complete + '%...';
} else {
uploadInfo.value = '';
}
}
async function handleSubmit() {
try {
if (fileList.value.length == 0) {
showMessage(t('请选择要导入的数据文件'));
return;
}
setModalProps({ confirmLoading: true });
const params = {
file: fileList.value[0],
};
const { data } = await erpTransactionFlowImportData(params, onUploadProgress);
showMessageModal({ content: data.message });
setTimeout(closeModal);
emit('success');
} catch (error: any) {
if (error && error.errorFields) {
showMessage(error.message || t('common.validateError'));
}
console.log('error', error);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@@ -0,0 +1,310 @@
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author gaoxq
-->
<template>
<div>
<BasicTable @register="registerTable">
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<template #toolbar>
<a-button type="default" :loading="loading" @click="handleExport()">
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
<a-button type="primary" @click="handleForm({})" v-auth="'erp:transactionFlow:edit'">
<Icon icon="i-fluent:add-12-filled" /> {{ t('新增') }}
</a-button>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup name="ViewsErpTransactionFlowList">
import { onMounted, ref, unref } from 'vue';
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { router } from '@jeesite/core/router';
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { ErpTransactionFlow, erpTransactionFlowList } from '@jeesite/erp/api/erp/transactionFlow';
import { erpTransactionFlowDelete, erpTransactionFlowFinish, erpTransactionFlowListData } from '@jeesite/erp/api/erp/transactionFlow';
import { useDrawer } from '@jeesite/core/components/Drawer';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import InputForm from './form.vue';
import FormImport from './formImport.vue';
const { t } = useI18n('erp.transactionFlow');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<ErpTransactionFlow>({} as ErpTransactionFlow);
const getTitle = {
icon: meta.icon || 'i-ant-design:book-outlined',
value: meta.title || t('明细信息管理'),
};
const loading = ref(false);
const searchForm: FormProps<ErpTransactionFlow> = {
baseColProps: { md: 8, lg: 6 },
labelWidth: 90,
schemas: [
{
label: t('记录时间起'),
field: 'createTime_gte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('记录时间止'),
field: 'createTime_lte',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('交易名称'),
field: 'flowName',
component: 'Input',
},
{
label: t('交易类型'),
field: 'transactionType',
component: 'Select',
componentProps: {
dictType: 'transaction_type',
allowClear: true,
},
},
{
label: t('交易账户'),
field: 'accountId',
fieldLabel: 'accountName',
component: 'ListSelect',
componentProps: {
selectType: 'erpAccountSelect',
},
},
{
label: t('交易分类'),
field: 'categoryId',
fieldLabel: 'categoryName',
component: 'ListSelect',
componentProps: {
selectType: 'erpCategorySelect',
},
},
{
label: t('是否记账'),
field: 'isFinish',
component: 'Select',
componentProps: {
dictType: 'is_finish',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<ErpTransactionFlow>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
},
{
title: t('交易名称'),
dataIndex: 'flowName',
key: 'a.flow_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('交易类型'),
dataIndex: 'transactionType',
key: 'a.transaction_type',
sorter: true,
width: 130,
align: 'left',
dictType: 'transaction_type',
},
{
title: t('账户名称'),
dataIndex: 'accountName',
key: 'b.account_name',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('父级分类'),
dataIndex: 'parentId',
key: 'c.parent_id',
sorter: true,
width: 130,
align: 'right',
dictType: 'parent_type',
},
{
title: t('分类名称'),
dataIndex: 'categoryName',
key: 'c.category_name',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('交易金额'),
dataIndex: 'amount',
key: 'a.amount',
sorter: true,
width: 130,
align: 'right',
},
{
title: t('交易时间'),
dataIndex: 'transactionTime',
key: 'a.transaction_time',
sorter: true,
width: 180,
align: 'center',
},
{
title: t('交易备注'),
dataIndex: 'remark',
key: 'a.remark',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('是否记账'),
dataIndex: 'isFinish',
key: 'a.is_finish',
sorter: true,
width: 130,
align: 'left',
dictType: 'is_finish',
},
{
title: t('更新时间'),
dataIndex: 'updateTime',
key: 'a.update_time',
sorter: true,
width: 180,
align: 'center',
},
];
const actionColumn: BasicColumn<ErpTransactionFlow> = {
width: 160,
align: 'center',
actions: (record: ErpTransactionFlow) => [
{
icon: 'i-clarity:note-edit-line',
title: t('编辑'),
onClick: handleForm.bind(this, { flowId: record.flowId }),
auth: 'erp:transactionFlow:edit',
ifShow: record.isFinish == '0'
},
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
title: t('删除'),
popConfirm: {
title: t('是否确认删除明细信息?'),
confirm: handleDelete.bind(this, record),
},
auth: 'erp:transactionFlow:edit',
ifShow: record.isFinish == '0'
},
{
icon: 'simple-line-icons:check',
color: 'success',
title: t('记账'),
popConfirm: {
title: t('是否确认记账本条明细?'),
confirm: handleFinish.bind(this, record),
},
auth: 'erp:transactionFlow:edit',
ifShow: record.isFinish == '0'
},
],
};
const [registerTable, { reload, getForm }] = useTable<ErpTransactionFlow>({
api: erpTransactionFlowListData,
beforeFetch: (params) => {
return params;
},
columns: tableColumns,
actionColumn: actionColumn,
formConfig: searchForm,
showTableSetting: true,
useSearchForm: true,
canResize: true,
});
onMounted(async () => {
const res = await erpTransactionFlowList();
record.value = (res.erpTransactionFlow || {}) as ErpTransactionFlow;
await getForm().setFieldsValue(record.value);
});
const [registerDrawer, { openDrawer }] = useDrawer();
function handleForm(record: Recordable) {
openDrawer(true, record);
}
async function handleExport() {
loading.value = true;
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/erp/transactionFlow/exportData',
params: getForm().getFieldsValue(),
});
loading.value = false;
}
const [registerImportModal, { openModal: importModal }] = useModal();
function handleImport() {
importModal(true, {});
}
async function handleDelete(record: Recordable) {
const params = { flowId: record.flowId };
const res = await erpTransactionFlowDelete(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleFinish(record: Recordable) {
const params = { flowId: record.flowId };
const res = await erpTransactionFlowFinish(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });
}
</script>

15
web-vue/pnpm-lock.yaml generated
View File

@@ -35,6 +35,9 @@ importers:
'@jeesite/dfm':
specifier: workspace:*
version: link:packages/dfm
'@jeesite/erp':
specifier: workspace:^
version: link:packages/erp
'@jeesite/test':
specifier: workspace:*
version: link:packages/test
@@ -380,6 +383,16 @@ importers:
specifier: 3.2.4
version: 3.2.4(@types/node@24.7.2)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)(yaml@2.8.1)
packages/erp:
dependencies:
qs:
specifier: 6.14.0
version: 6.14.0
devDependencies:
'@types/qs':
specifier: 6.9.18
version: 6.9.18
packages/test: {}
packages/tests:
@@ -523,7 +536,7 @@ packages:
'@ant-design/icons-vue@7.0.1':
resolution: {integrity: sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==}
peerDependencies:
vue: '>=3.0.3'
vue: ^3.5.17
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 53 KiB