Compare commits
No commits in common. "b0741d4ddb7f09a590962576c4837ff129286b46" and "5b38710ddfd9755042527e6e0b836ef7e923ee31" have entirely different histories.
b0741d4ddb
...
5b38710ddf
|
@ -4,7 +4,7 @@ ENV = 'production'
|
||||||
# base api url
|
# base api url
|
||||||
# VITE_BASE_API_URL = 'https://nest-api.buqiyuan.site'
|
# VITE_BASE_API_URL = 'https://nest-api.buqiyuan.site'
|
||||||
# VITE_BASE_API_URL = 'http://123.249.107.55'
|
# VITE_BASE_API_URL = 'http://123.249.107.55'
|
||||||
VITE_BASE_API_URL = 'http://192.168.60.213:3001'
|
VITE_BASE_API_URL = 'http://144.123.43.138:3001'
|
||||||
|
|
||||||
# 公共基础路径, 所有资源的路径都将据此配置重写。
|
# 公共基础路径, 所有资源的路径都将据此配置重写。
|
||||||
VITE_BASE_URL = /api
|
VITE_BASE_URL = /api
|
||||||
|
|
|
@ -9,7 +9,7 @@ COPY ./ $PROJECT_DIR
|
||||||
# 若网络不通,可以使用淘宝源
|
# 若网络不通,可以使用淘宝源
|
||||||
# RUN pnpm config set registry https://registry.npmmirror.com
|
# RUN pnpm config set registry https://registry.npmmirror.com
|
||||||
# 若不存在安装pnpm
|
# 若不存在安装pnpm
|
||||||
RUN npm install -g pnpm@8.10.2
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
# 构建项目
|
# 构建项目
|
||||||
# 安装生成依赖
|
# 安装生成依赖
|
||||||
|
|
|
@ -34,7 +34,7 @@ http {
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 3001;
|
listen 3001;
|
||||||
server_name localhost;
|
server_name 144.123.43.138;
|
||||||
absolute_redirect off; #取消绝对路径的重定向
|
absolute_redirect off; #取消绝对路径的重定向
|
||||||
sendfile on;
|
sendfile on;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { request, type RequestOptions } from '@/utils/request';
|
|
||||||
|
|
||||||
/** 获取公司列表 GET /api/domain */
|
|
||||||
export async function domainList(params: API.DomainParams, options?: RequestOptions) {
|
|
||||||
return request<{
|
|
||||||
items?: API.DomainEntity[];
|
|
||||||
meta?: {
|
|
||||||
itemCount?: number;
|
|
||||||
totalItems?: number;
|
|
||||||
itemsPerPage?: number;
|
|
||||||
totalPages?: number;
|
|
||||||
currentPage?: number;
|
|
||||||
};
|
|
||||||
}>('/api/domain', {
|
|
||||||
method: 'GET',
|
|
||||||
params: {
|
|
||||||
// page has a default value: 1
|
|
||||||
page: '1',
|
|
||||||
// pageSize has a default value: 10
|
|
||||||
pageSize: '10',
|
|
||||||
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -35,11 +35,9 @@ import * as vehicleUsage from './vehicleUsage';
|
||||||
import * as saleQuotationGroup from './saleQuotationGroup';
|
import * as saleQuotationGroup from './saleQuotationGroup';
|
||||||
import * as saleQuotationComponent from './saleQuotationComponent';
|
import * as saleQuotationComponent from './saleQuotationComponent';
|
||||||
import * as saleQuotationTemplate from './saleQuotationTemplate';
|
import * as saleQuotationTemplate from './saleQuotationTemplate';
|
||||||
import * as saleQuotation from './saleQuotation';
|
|
||||||
import * as domain from './domain';
|
|
||||||
export default {
|
export default {
|
||||||
auth,
|
auth,
|
||||||
domain,
|
|
||||||
account,
|
account,
|
||||||
captcha,
|
captcha,
|
||||||
authEmail,
|
authEmail,
|
||||||
|
@ -72,5 +70,4 @@ export default {
|
||||||
saleQuotationGroup,
|
saleQuotationGroup,
|
||||||
saleQuotationComponent,
|
saleQuotationComponent,
|
||||||
saleQuotationTemplate,
|
saleQuotationTemplate,
|
||||||
saleQuotation,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
import { request, type RequestOptions } from '@/utils/request';
|
import { request, type RequestOptions } from '@/utils/request';
|
||||||
|
|
||||||
/** 导出出入库记录 GET /api/materials-inventory/export*/
|
|
||||||
export async function materialsInoutExport(
|
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: API.MaterialsInoutExportParams,
|
|
||||||
options?: RequestOptions,
|
|
||||||
) {
|
|
||||||
const { ...queryParams } = params;
|
|
||||||
return request(`/api/materials-in-out/export`, {
|
|
||||||
method: 'GET',
|
|
||||||
params: { ...queryParams },
|
|
||||||
...(options || { responseType: 'blob', isReturnResult: false }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取原材料出入库记录列表 GET /api/materials-in-out */
|
/** 获取原材料出入库记录列表 GET /api/materials-in-out */
|
||||||
export async function materialsInOutList(
|
export async function materialsInOutList(
|
||||||
params: API.MaterialsInOutListParams,
|
params: API.MaterialsInOutListParams,
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { request, type RequestOptions } from '@/utils/request';
|
|
||||||
const baseApi = '/api/sale_quotation/sale_quotation';
|
|
||||||
/** 导出原材料盘点表 GET /api/sale_quotation/export*/
|
|
||||||
export async function exportSaleQuotation(id: number, options?: RequestOptions) {
|
|
||||||
return request(`${baseApi}/export/${id}`, {
|
|
||||||
method: 'GET',
|
|
||||||
...(options || { responseType: 'blob', isReturnResult: false }),
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -21,8 +21,6 @@ declare namespace API {
|
||||||
remark: string;
|
remark: string;
|
||||||
/** 头像 */
|
/** 头像 */
|
||||||
avatar: string;
|
avatar: string;
|
||||||
/** 所属域 */
|
|
||||||
domain: DomainType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type AccountMenus = {
|
type AccountMenus = {
|
||||||
|
@ -1215,13 +1213,12 @@ declare namespace API {
|
||||||
status: number;
|
status: number;
|
||||||
roles: RoleEntity[];
|
roles: RoleEntity[];
|
||||||
dept: DeptEntity;
|
dept: DeptEntity;
|
||||||
domain: DomainType;
|
|
||||||
accessTokens: AccessTokenEntity[];
|
accessTokens: AccessTokenEntity[];
|
||||||
id: number;
|
id: number;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
type DomainType = number;
|
|
||||||
type UserListParams = {
|
type UserListParams = {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
|
@ -1382,9 +1379,8 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type MaterialsInventoryExportParams = {
|
type MaterialsInventoryExportParams = {
|
||||||
time: string[];
|
time: string;
|
||||||
filename:string;
|
projectId: number;
|
||||||
projectId?: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type MaterialsInventoryInfoParams = {
|
type MaterialsInventoryInfoParams = {
|
||||||
|
@ -1812,11 +1808,6 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Materials In out history
|
// Materials In out history
|
||||||
type MaterialsInoutExportParams = {
|
|
||||||
time: string[];
|
|
||||||
filename:string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MaterialsInOutUpdateParams = {
|
type MaterialsInOutUpdateParams = {
|
||||||
id: number;
|
id: number;
|
||||||
fileIds?: number[];
|
fileIds?: number[];
|
||||||
|
@ -2024,18 +2015,4 @@ declare namespace API {
|
||||||
type SaleQuotationTemplateDeleteParams = {
|
type SaleQuotationTemplateDeleteParams = {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DomainEntity = {
|
|
||||||
title: string;
|
|
||||||
id: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type DomainParams = {
|
|
||||||
page?: number;
|
|
||||||
pageSize?: number;
|
|
||||||
title?: string;
|
|
||||||
field?: string;
|
|
||||||
order?: 'ASC' | 'DESC';
|
|
||||||
_t?: number;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,11 @@ export const useExportExcelModal = () => {
|
||||||
modalProps: {
|
modalProps: {
|
||||||
title: t('component.excel.exportModalTitle'),
|
title: t('component.excel.exportModalTitle'),
|
||||||
onFinish: async (values) => {
|
onFinish: async (values) => {
|
||||||
const { filename, bookType, time } = values;
|
const { filename, bookType } = values;
|
||||||
|
|
||||||
onOk({
|
onOk({
|
||||||
filename: bookType ? `${filename.split('.').shift()}.${bookType}` : filename,
|
filename: `${filename.split('.').shift()}.${bookType}`,
|
||||||
bookType,
|
bookType,
|
||||||
time,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,12 +12,7 @@ export const USER_INFO_KEY = 'USER__INFO__';
|
||||||
|
|
||||||
// role info key
|
// role info key
|
||||||
export const ROLES_KEY = 'ROLES__KEY__';
|
export const ROLES_KEY = 'ROLES__KEY__';
|
||||||
|
|
||||||
/** 是否锁屏 */
|
/** 是否锁屏 */
|
||||||
export const IS_LOCKSCREEN = 'IS_LOCKSCREEN';
|
export const IS_LOCKSCREEN = 'IS_LOCKSCREEN';
|
||||||
|
|
||||||
/** 标签页 */
|
/** 标签页 */
|
||||||
export const TABS_ROUTES = 'TABS_ROUTES';
|
export const TABS_ROUTES = 'TABS_ROUTES';
|
||||||
|
|
||||||
/** 域 */
|
|
||||||
export const DOMAIN_KEY = 'DOMAIN__';
|
|
|
@ -1,51 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
公司: <a-select ref="select"
|
|
||||||
v-if="options.length"
|
|
||||||
:disabled="!$auth('system:domain:change')"
|
|
||||||
v-model:value="userStore.domain"
|
|
||||||
style="min-width: 100px;"
|
|
||||||
placeholder="请选择"
|
|
||||||
@change="onChange"
|
|
||||||
:dropdownStyle="{ 'textOverflow': 'ellipsis', 'min-width': 'fit-content' }">
|
|
||||||
<a-select-option :value="item.value"
|
|
||||||
v-for="(item, index) in options"
|
|
||||||
:key="index">{{ item.label }}</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang='ts'>
|
|
||||||
import Api from '@/api';
|
|
||||||
import { useUserStore } from '@/store/modules/user';
|
|
||||||
import type { SelectValue } from 'ant-design-vue/es/select';
|
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'DomianPicker'
|
|
||||||
})
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const options = ref<{ label: string, value: number }[]>([]);
|
|
||||||
let domains = ref<API.DomainEntity[]>([]);
|
|
||||||
const onChange = (value: SelectValue) => {
|
|
||||||
userStore.changeDomain(value)
|
|
||||||
};
|
|
||||||
onMounted(() => {
|
|
||||||
Api.domain.domainList({}).then((res) => {
|
|
||||||
if (res) {
|
|
||||||
domains.value = res.items ?? [];
|
|
||||||
options.value = domains.value.map((item) => {
|
|
||||||
return {
|
|
||||||
label: item.title,
|
|
||||||
value: item.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang='less' scoped></style>
|
|
|
@ -1,4 +1,3 @@
|
||||||
export { default as Search } from './search/index.vue';
|
export { default as Search } from './search/index.vue';
|
||||||
export { default as FullScreen } from './fullscreen/index.vue';
|
export { default as FullScreen } from './fullscreen/index.vue';
|
||||||
export { default as ProjectSetting } from './setting/index.vue';
|
export { default as ProjectSetting } from './setting/index.vue';
|
||||||
export { default as DomianPicker } from './domianPicker/index.vue';
|
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<Layout.Header :style="headerStyle"
|
<Layout.Header :style="headerStyle" class="layout-header">
|
||||||
class="layout-header">
|
|
||||||
<Space :size="20">
|
<Space :size="20">
|
||||||
<slot>
|
<slot>
|
||||||
<Space :size="20">
|
<Space :size="20">
|
||||||
<span class="menu-fold"
|
<span class="menu-fold" @click="() => emit('update:collapsed', !collapsed)">
|
||||||
@click="() => emit('update:collapsed', !collapsed)">
|
|
||||||
<component :is="collapsed ? MenuUnfoldOutlined : MenuFoldOutlined" />
|
<component :is="collapsed ? MenuUnfoldOutlined : MenuFoldOutlined" />
|
||||||
</span>
|
</span>
|
||||||
<Breadcrumb>
|
<Breadcrumb>
|
||||||
<template v-for="(routeItem, rotueIndex) in menus"
|
<template v-for="(routeItem, rotueIndex) in menus" :key="routeItem?.name">
|
||||||
:key="routeItem?.name">
|
|
||||||
<Breadcrumb.Item>
|
<Breadcrumb.Item>
|
||||||
<TitleI18n :title="routeItem?.meta?.title" />
|
<TitleI18n :title="routeItem?.meta?.title" />
|
||||||
<template v-if="routeItem?.children?.length"
|
<template v-if="routeItem?.children?.length" #overlay>
|
||||||
#overlay>
|
|
||||||
<Menu :selected-keys="getSelectKeys(rotueIndex)">
|
<Menu :selected-keys="getSelectKeys(rotueIndex)">
|
||||||
<template v-for="childItem in routeItem?.children"
|
<template v-for="childItem in routeItem?.children" :key="childItem.name">
|
||||||
:key="childItem.name">
|
<Menu.Item
|
||||||
<Menu.Item v-if="!childItem.meta?.hideInMenu && !childItem.meta?.hideInBreadcrumb"
|
v-if="!childItem.meta?.hideInMenu && !childItem.meta?.hideInBreadcrumb"
|
||||||
:key="childItem.name"
|
:key="childItem.name"
|
||||||
@click="clickMenuItem(childItem)">
|
@click="clickMenuItem(childItem)"
|
||||||
|
>
|
||||||
<TitleI18n :title="childItem.meta?.title" />
|
<TitleI18n :title="childItem.meta?.title" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,17 +30,14 @@
|
||||||
</slot>
|
</slot>
|
||||||
</Space>
|
</Space>
|
||||||
<Space :size="20">
|
<Space :size="20">
|
||||||
<DomianPicker />
|
|
||||||
<Search />
|
<Search />
|
||||||
<Tooltip :title="$t('layout.header.tooltipLock')"
|
<Tooltip :title="$t('layout.header.tooltipLock')" placement="bottom">
|
||||||
placement="bottom">
|
|
||||||
<LockOutlined @click="lockscreenStore.setLock(true)" />
|
<LockOutlined @click="lockscreenStore.setLock(true)" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<FullScreen />
|
<FullScreen />
|
||||||
<!-- <LocalePicker /> -->
|
<!-- <LocalePicker /> -->
|
||||||
<Dropdown placement="bottomRight">
|
<Dropdown placement="bottomRight">
|
||||||
<Avatar :src="userInfo.avatar"
|
<Avatar :src="userInfo.avatar" :alt="userInfo.username">{{ userInfo.username }}</Avatar>
|
||||||
:alt="userInfo.username">{{ userInfo.username }}</Avatar>
|
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item @click="$router.push({ name: 'account-about' })">
|
<Menu.Item @click="$router.push({ name: 'account-about' })">
|
||||||
|
@ -67,16 +61,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, type CSSProperties } from 'vue';
|
import { computed, type CSSProperties } from 'vue';
|
||||||
import { useRouter, useRoute, type RouteRecordRaw } from 'vue-router';
|
import { useRouter, useRoute, type RouteRecordRaw } from 'vue-router';
|
||||||
import {
|
import {
|
||||||
QuestionCircleOutlined,
|
QuestionCircleOutlined,
|
||||||
MenuFoldOutlined,
|
MenuFoldOutlined,
|
||||||
MenuUnfoldOutlined,
|
MenuUnfoldOutlined,
|
||||||
PoweroffOutlined,
|
PoweroffOutlined,
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import {
|
import {
|
||||||
Layout,
|
Layout,
|
||||||
Modal,
|
Modal,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
|
@ -86,40 +80,40 @@ import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
type MenuTheme,
|
type MenuTheme,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import { Search, FullScreen, ProjectSetting, DomianPicker } from './components/';
|
import { Search, FullScreen, ProjectSetting } from './components/';
|
||||||
import { LocalePicker } from '@/components/basic/locale-picker';
|
import { LocalePicker } from '@/components/basic/locale-picker';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { useLockscreenStore } from '@/store/modules/lockscreen';
|
import { useLockscreenStore } from '@/store/modules/lockscreen';
|
||||||
import { TitleI18n } from '@/components/basic/title-i18n';
|
import { TitleI18n } from '@/components/basic/title-i18n';
|
||||||
import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
|
import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
collapsed: {
|
collapsed: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
type: String as PropType<MenuTheme>,
|
type: String as PropType<MenuTheme>,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['update:collapsed']);
|
const emit = defineEmits(['update:collapsed']);
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const layoutSettingStore = useLayoutSettingStore();
|
const layoutSettingStore = useLayoutSettingStore();
|
||||||
const lockscreenStore = useLockscreenStore();
|
const lockscreenStore = useLockscreenStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const userInfo = computed(() => userStore.userInfo);
|
const userInfo = computed(() => userStore.userInfo);
|
||||||
const headerStyle = computed<CSSProperties>(() => {
|
const headerStyle = computed<CSSProperties>(() => {
|
||||||
const { navTheme, layout } = layoutSettingStore.layoutSetting;
|
const { navTheme, layout } = layoutSettingStore.layoutSetting;
|
||||||
const isDark = navTheme === 'dark' && layout === 'topmenu';
|
const isDark = navTheme === 'dark' && layout === 'topmenu';
|
||||||
return {
|
return {
|
||||||
backgroundColor: navTheme === 'realDark' || isDark ? '' : 'rgba(255, 255, 255, 0.85)',
|
backgroundColor: navTheme === 'realDark' || isDark ? '' : 'rgba(255, 255, 255, 0.85)',
|
||||||
color: isDark ? 'rgba(255, 255, 255, 0.85)' : '',
|
color: isDark ? 'rgba(255, 255, 255, 0.85)' : '',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const menus = computed(() => {
|
const menus = computed(() => {
|
||||||
if (route.meta?.namePath) {
|
if (route.meta?.namePath) {
|
||||||
let children = userStore.menus;
|
let children = userStore.menus;
|
||||||
const paths = route.meta?.namePath?.map((item) => {
|
const paths = route.meta?.namePath?.map((item) => {
|
||||||
|
@ -139,13 +133,13 @@ const menus = computed(() => {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return route.matched;
|
return route.matched;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getSelectKeys = (rotueIndex: number) => {
|
const getSelectKeys = (rotueIndex: number) => {
|
||||||
return [menus.value[rotueIndex + 1]?.name] as string[];
|
return [menus.value[rotueIndex + 1]?.name] as string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const findLastChild = (route?: RouteRecordRaw) => {
|
const findLastChild = (route?: RouteRecordRaw) => {
|
||||||
if (typeof route?.redirect === 'object') {
|
if (typeof route?.redirect === 'object') {
|
||||||
const redirectValues = Object.values(route.redirect);
|
const redirectValues = Object.values(route.redirect);
|
||||||
if (route?.children?.length) {
|
if (route?.children?.length) {
|
||||||
|
@ -165,11 +159,11 @@ const findLastChild = (route?: RouteRecordRaw) => {
|
||||||
return route?.redirect;
|
return route?.redirect;
|
||||||
}
|
}
|
||||||
return route;
|
return route;
|
||||||
};
|
};
|
||||||
const getRouteByName = (name: string) => router.getRoutes().find((n) => n.name === name);
|
const getRouteByName = (name: string) => router.getRoutes().find((n) => n.name === name);
|
||||||
|
|
||||||
// 点击菜单
|
// 点击菜单
|
||||||
const clickMenuItem = (menuItem: RouteRecordRaw) => {
|
const clickMenuItem = (menuItem: RouteRecordRaw) => {
|
||||||
const lastChild = findLastChild(menuItem);
|
const lastChild = findLastChild(menuItem);
|
||||||
console.log('lastChild', menuItem, lastChild);
|
console.log('lastChild', menuItem, lastChild);
|
||||||
|
|
||||||
|
@ -180,10 +174,10 @@ const clickMenuItem = (menuItem: RouteRecordRaw) => {
|
||||||
} else {
|
} else {
|
||||||
router.push({ name: lastChild?.name });
|
router.push({ name: lastChild?.name });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
const doLogout = () => {
|
const doLogout = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '您确定要退出登录吗?',
|
title: '您确定要退出登录吗?',
|
||||||
icon: <QuestionCircleOutlined />,
|
icon: <QuestionCircleOutlined />,
|
||||||
|
@ -196,11 +190,11 @@ const doLogout = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.layout-header {
|
.layout-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
@ -213,5 +207,5 @@ const doLogout = () => {
|
||||||
* {
|
* {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useDictStore } from './dict';
|
||||||
import { useRouter, type RouteRecordRaw, useRoute } from 'vue-router';
|
import { useRouter, type RouteRecordRaw, useRoute } from 'vue-router';
|
||||||
import { store } from '@/store';
|
import { store } from '@/store';
|
||||||
import Api from '@/api/';
|
import Api from '@/api/';
|
||||||
import { ACCESS_TOKEN_KEY, DOMAIN_KEY } from '@/enums/cacheEnum';
|
import { ACCESS_TOKEN_KEY } from '@/enums/cacheEnum';
|
||||||
import { Storage } from '@/utils/Storage';
|
import { Storage } from '@/utils/Storage';
|
||||||
import { resetRouter } from '@/router';
|
import { resetRouter } from '@/router';
|
||||||
import { generateDynamicRoutes } from '@/router/helper/routeHelper';
|
import { generateDynamicRoutes } from '@/router/helper/routeHelper';
|
||||||
|
@ -21,12 +21,12 @@ export type MessageEvent = {
|
||||||
export const useUserStore = defineStore('user', () => {
|
export const useUserStore = defineStore('user', () => {
|
||||||
let eventSource: EventSource | null = null;
|
let eventSource: EventSource | null = null;
|
||||||
const token = ref(Storage.get(ACCESS_TOKEN_KEY, null));
|
const token = ref(Storage.get(ACCESS_TOKEN_KEY, null));
|
||||||
const name = ref('admin');
|
const name = ref('amdin');
|
||||||
const perms = ref<string[]>([]);
|
const perms = ref<string[]>([]);
|
||||||
const menus = ref<RouteRecordRaw[]>([]);
|
const menus = ref<RouteRecordRaw[]>([]);
|
||||||
const userInfo = ref<Partial<API.UserEntity>>({});
|
const userInfo = ref<Partial<API.UserEntity>>({});
|
||||||
const serverConnected = ref(true);
|
const serverConnected = ref(true);
|
||||||
const domain = ref<API.DomainType>(Storage.get(DOMAIN_KEY, null));
|
|
||||||
watch(serverConnected, (val) => {
|
watch(serverConnected, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
initServerMsgListener();
|
initServerMsgListener();
|
||||||
|
@ -87,7 +87,6 @@ export const useUserStore = defineStore('user', () => {
|
||||||
// const ex = 7 * 24 * 60 * 60 * 1000;
|
// const ex = 7 * 24 * 60 * 60 * 1000;
|
||||||
Storage.set(ACCESS_TOKEN_KEY, token.value);
|
Storage.set(ACCESS_TOKEN_KEY, token.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 登录 */
|
/** 登录 */
|
||||||
const login = async (params: API.LoginDto) => {
|
const login = async (params: API.LoginDto) => {
|
||||||
try {
|
try {
|
||||||
|
@ -98,7 +97,6 @@ export const useUserStore = defineStore('user', () => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 解锁屏幕 */
|
/** 解锁屏幕 */
|
||||||
const unlock = async (params: API.LoginDto) => {
|
const unlock = async (params: API.LoginDto) => {
|
||||||
try {
|
try {
|
||||||
|
@ -108,17 +106,6 @@ export const useUserStore = defineStore('user', () => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 切换domain */
|
|
||||||
const changeDomain = (value) => {
|
|
||||||
domain.value = value;
|
|
||||||
Storage.set(DOMAIN_KEY, value);
|
|
||||||
setTimeout(() => {
|
|
||||||
// 刷新页面
|
|
||||||
window.location.reload();
|
|
||||||
}, 200);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 登录成功之后, 获取用户信息以及生成权限路由 */
|
/** 登录成功之后, 获取用户信息以及生成权限路由 */
|
||||||
const afterLogin = async () => {
|
const afterLogin = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -126,12 +113,9 @@ export const useUserStore = defineStore('user', () => {
|
||||||
useDictStore();
|
useDictStore();
|
||||||
// const wsStore = useWsStore();
|
// const wsStore = useWsStore();
|
||||||
const userInfoData = await accountProfile();
|
const userInfoData = await accountProfile();
|
||||||
|
|
||||||
userInfo.value = userInfoData;
|
userInfo.value = userInfoData;
|
||||||
|
|
||||||
if (!Storage.get(DOMAIN_KEY)) {
|
|
||||||
domain.value = userInfoData.domain;
|
|
||||||
Storage.set(DOMAIN_KEY, domain.value);
|
|
||||||
}
|
|
||||||
await fetchPermsAndMenus();
|
await fetchPermsAndMenus();
|
||||||
initServerMsgListener();
|
initServerMsgListener();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -174,8 +158,6 @@ export const useUserStore = defineStore('user', () => {
|
||||||
perms,
|
perms,
|
||||||
menus,
|
menus,
|
||||||
userInfo,
|
userInfo,
|
||||||
domain,
|
|
||||||
changeDomain,
|
|
||||||
login,
|
login,
|
||||||
unlock,
|
unlock,
|
||||||
afterLogin,
|
afterLogin,
|
||||||
|
|
|
@ -123,8 +123,6 @@ export function request<T = any>(config: RequestOptions): Promise<BaseResponse<T
|
||||||
export async function request(_url: string | RequestOptions, _config: RequestOptions = {}) {
|
export async function request(_url: string | RequestOptions, _config: RequestOptions = {}) {
|
||||||
const url = isString(_url) ? _url : _url.url;
|
const url = isString(_url) ? _url : _url.url;
|
||||||
const config = isString(_url) ? _config : _url;
|
const config = isString(_url) ? _config : _url;
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 兼容 from data 文件上传的情况
|
// 兼容 from data 文件上传的情况
|
||||||
const { requestType, isReturnResult = true, ...rest } = config;
|
const { requestType, isReturnResult = true, ...rest } = config;
|
||||||
|
@ -139,7 +137,6 @@ export async function request(_url: string | RequestOptions, _config: RequestOpt
|
||||||
headers: {
|
headers: {
|
||||||
...rest.headers,
|
...rest.headers,
|
||||||
...(requestType === 'form' ? { 'Content-Type': 'multipart/form-data' } : {}),
|
...(requestType === 'form' ? { 'Content-Type': 'multipart/form-data' } : {}),
|
||||||
'sk-domain':userStore.domain
|
|
||||||
},
|
},
|
||||||
})) as AxiosResponse<BaseResponse>;
|
})) as AxiosResponse<BaseResponse>;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</div>
|
</div>
|
||||||
<a-form layout="horizontal" :model="state.formInline" @submit.prevent="handleSubmit">
|
<a-form layout="horizontal" :model="state.formInline" @submit.prevent="handleSubmit">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-input v-model:value="state.formInline.username" size="large" placeholder="用户名">
|
<a-input v-model:value="state.formInline.username" size="large" placeholder="admin">
|
||||||
<template #prefix><user-outlined type="user" /></template>
|
<template #prefix><user-outlined type="user" /></template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
v-model:value="state.formInline.password"
|
v-model:value="state.formInline.password"
|
||||||
size="large"
|
size="large"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="密码"
|
placeholder="huaxin123"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
>
|
>
|
||||||
<template #prefix><lock-outlined type="user" /></template>
|
<template #prefix><lock-outlined type="user" /></template>
|
||||||
|
@ -61,8 +61,8 @@
|
||||||
loading: false,
|
loading: false,
|
||||||
captcha: '',
|
captcha: '',
|
||||||
formInline: {
|
formInline: {
|
||||||
username: '',
|
username: 'admin',
|
||||||
password: '',
|
password: 'huaxin123',
|
||||||
verifyCode: '',
|
verifyCode: '',
|
||||||
captchaId: '',
|
captchaId: '',
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,37 +21,36 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup
|
||||||
import { useTable } from '@/components/core/dynamic-table';
|
lang="tsx">
|
||||||
import {
|
import { useTable } from '@/components/core/dynamic-table';
|
||||||
|
import {
|
||||||
baseColumns,
|
baseColumns,
|
||||||
type TableColumnItem,
|
type TableColumnItem,
|
||||||
type TableListItem,
|
type TableListItem,
|
||||||
} from './columns';
|
} from './columns';
|
||||||
import Api from '@/api/';
|
import Api from '@/api/';
|
||||||
import { onMounted, ref, type FunctionalComponent } from 'vue';
|
import { onMounted, ref, type FunctionalComponent } from 'vue';
|
||||||
import { useFormModal, useModal } from '@/hooks/useModal';
|
import { useFormModal, useModal } from '@/hooks/useModal';
|
||||||
import { Button, message } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
import { formSchemas } from './formSchemas';
|
import { formSchemas } from './formSchemas';
|
||||||
import AttachmentManage from '@/components/business/attachment-manage/index.vue';
|
import AttachmentManage from '@/components/business/attachment-manage/index.vue';
|
||||||
import AttachmentUpload from '@/components/business/attachment-upload/index.vue';
|
import AttachmentUpload from '@/components/business/attachment-upload/index.vue';
|
||||||
import { useExportExcelModal, jsonToSheetXlsx } from '@/components/basic/excel';
|
import { useExportExcelModal, jsonToSheetXlsx } from '@/components/basic/excel';
|
||||||
import { MaterialsInOutEnum } from '@/enums/materialsInventoryEnum';
|
import { MaterialsInOutEnum } from '@/enums/materialsInventoryEnum';
|
||||||
import { formatToDate } from '@/utils/dateUtil';
|
import { formatToDate } from '@/utils/dateUtil';
|
||||||
import dayjs from 'dayjs';
|
defineOptions({
|
||||||
import fileDownload from 'js-file-download';
|
|
||||||
defineOptions({
|
|
||||||
name: 'MaterialsInOut',
|
name: 'MaterialsInOut',
|
||||||
});
|
});
|
||||||
|
|
||||||
const [DynamicTable, dynamicTableInstance] = useTable({ formProps: { autoSubmitOnEnter: true } });
|
const [DynamicTable, dynamicTableInstance] = useTable({ formProps: { autoSubmitOnEnter: true } });
|
||||||
const [showModal] = useFormModal();
|
const [showModal] = useFormModal();
|
||||||
const exportExcelModal = useExportExcelModal();
|
const exportExcelModal = useExportExcelModal();
|
||||||
const [fnModal] = useModal();
|
const [fnModal] = useModal();
|
||||||
const isUploadPopupVisiable = ref(false);
|
const isUploadPopupVisiable = ref(false);
|
||||||
|
|
||||||
let columns = ref<TableColumnItem[]>();
|
let columns = ref<TableColumnItem[]>();
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
columns.value = [
|
columns.value = [
|
||||||
...baseColumns,
|
...baseColumns,
|
||||||
{
|
{
|
||||||
|
@ -99,85 +98,72 @@ onMounted(() => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
|
||||||
|
|
||||||
const openExportModal = async () => {
|
|
||||||
const queryModel = dynamicTableInstance.queryFormRef?.formModel;
|
|
||||||
if(!queryModel?.time){
|
|
||||||
message.warning('请选择时间范围')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const timeRange = (queryModel?.time ?? []).map(item => dayjs(item).format('YYYY-MM-DD'));
|
|
||||||
const response = await Api.materialsInOut.materialsInoutExport({
|
|
||||||
time: timeRange ?? [], filename: `${timeRange[0]}-${timeRange[1]}`
|
|
||||||
});
|
});
|
||||||
fileDownload(response, `${timeRange[0]}-${timeRange[1]}.xls`);
|
|
||||||
// exportExcelModal.openModal({
|
const openExportModal = () => {
|
||||||
// formSchemas: [
|
exportExcelModal.openModal({
|
||||||
// {
|
formSchemas: [
|
||||||
// field: 'time',
|
{
|
||||||
// component: 'RangePicker',
|
field: 'time',
|
||||||
// label: '时间范围',
|
component: 'RangePicker',
|
||||||
// rules: [{ required: true }],
|
label:'时间范围',
|
||||||
// },
|
rules: [{ required: true }],
|
||||||
// ],
|
},
|
||||||
// onOk: async ({ filename, bookType, time }) => {
|
],
|
||||||
// const response = await Api.materialsInOut.materialsInoutExport({
|
onOk: ({ filename, bookType }) => {
|
||||||
// time: (time ?? []).map(item => dayjs(item).format('YYYY-MM-DD')), filename
|
const tableData: TableListItem[] = dynamicTableInstance.tableData;
|
||||||
// });
|
let exportData: any[] = []
|
||||||
// fileDownload(response, `${filename}.xls`);
|
for (let item of tableData) {
|
||||||
// const tableData: TableListItem[] = dynamicTableInstance.tableData;
|
exportData.push({
|
||||||
// let exportData: any[] = []
|
projectName: item.project?.name,
|
||||||
// for (let item of tableData) {
|
inOrOut: item.inOrOut === MaterialsInOutEnum.In ? '入库' : '出库',
|
||||||
// exportData.push({
|
inventoryInOutNumber: item.inventoryInOutNumber,
|
||||||
// projectName: item.project?.name,
|
time: formatToDate(item.time),
|
||||||
// inOrOut: item.inOrOut === MaterialsInOutEnum.In ? '入库' : '出库',
|
company: item.product?.company?.name,
|
||||||
// inventoryInOutNumber: item.inventoryInOutNumber,
|
productName: item.product?.name,
|
||||||
// time: formatToDate(item.time),
|
productSpecification: item.product?.productSpecification,
|
||||||
// company: item.product?.company?.name,
|
unit: item.product?.unit?.label,
|
||||||
// productName: item.product?.name,
|
quantity: item.quantity,
|
||||||
// productSpecification: item.product?.productSpecification,
|
unitPrice: parseFloat(item.unitPrice),
|
||||||
// unit: item.product?.unit?.label,
|
amount: parseFloat(item.amount),
|
||||||
// quantity: item.quantity,
|
agent: item.agent,
|
||||||
// unitPrice: parseFloat(item.unitPrice),
|
issuanceNumber: item.issuanceNumber,
|
||||||
// amount: parseFloat(item.amount),
|
remark: item.remark
|
||||||
// agent: item.agent,
|
})
|
||||||
// issuanceNumber: item.issuanceNumber,
|
}
|
||||||
// remark: item.remark
|
jsonToSheetXlsx({
|
||||||
// })
|
data: exportData,
|
||||||
// }
|
header: {
|
||||||
// jsonToSheetXlsx({
|
inOrOut: '出/入库',
|
||||||
// data: exportData,
|
inventoryInOutNumber: '出入库单号',
|
||||||
// header: {
|
time: '时间',
|
||||||
// inOrOut: '出/入库',
|
projectName: '项目',
|
||||||
// inventoryInOutNumber: '出入库单号',
|
company: '公司',
|
||||||
// time: '时间',
|
productName: '产品名',
|
||||||
// projectName: '项目',
|
productSpecification: "产品规格",
|
||||||
// company: '公司',
|
unit: '单位',
|
||||||
// productName: '产品名',
|
quantity: '数量',
|
||||||
// productSpecification: "产品规格",
|
unitPrice: '单价',
|
||||||
// unit: '单位',
|
amount: '金额',
|
||||||
// quantity: '数量',
|
agent: '经办人',
|
||||||
// unitPrice: '单价',
|
issuanceNumber: '领料单号',
|
||||||
// amount: '金额',
|
remark: '备注'
|
||||||
// agent: '经办人',
|
},
|
||||||
// issuanceNumber: '领料单号',
|
filename,
|
||||||
// remark: '备注'
|
write2excelOpts: {
|
||||||
// },
|
bookType,
|
||||||
// filename,
|
},
|
||||||
// write2excelOpts:
|
json2sheetOpts: {
|
||||||
// { bookType: 'xls' },
|
// 指定顺序
|
||||||
// json2sheetOpts: {
|
header: [
|
||||||
// // 指定顺序
|
'inOrOut', 'inventoryInOutNumber', 'time', 'projectName', 'company', 'productName', 'productSpecification', 'unit', 'quantity',
|
||||||
// header: [
|
'unitPrice', 'amount', 'agent', 'issuanceNumber', 'remark'],
|
||||||
// 'inOrOut', 'inventoryInOutNumber', 'time', 'projectName', 'company', 'productName', 'productSpecification', 'unit', 'quantity',
|
},
|
||||||
// 'unitPrice', 'amount', 'agent', 'issuanceNumber', 'remark'],
|
});
|
||||||
// },
|
},
|
||||||
// });
|
});
|
||||||
// },
|
};
|
||||||
// });
|
const openAttachmentUploadModal = async (record: TableListItem) => {
|
||||||
};
|
|
||||||
const openAttachmentUploadModal = async (record: TableListItem) => {
|
|
||||||
isUploadPopupVisiable.value = true;
|
isUploadPopupVisiable.value = true;
|
||||||
fnModal.show({
|
fnModal.show({
|
||||||
width: 800,
|
width: 800,
|
||||||
|
@ -198,26 +184,26 @@ const openAttachmentUploadModal = async (record: TableListItem) => {
|
||||||
open: isUploadPopupVisiable.value,
|
open: isUploadPopupVisiable.value,
|
||||||
footer: null,
|
footer: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleUploadClose = (hasSuccess: boolean) => {
|
const handleUploadClose = (hasSuccess: boolean) => {
|
||||||
fnModal.hide();
|
fnModal.hide();
|
||||||
isUploadPopupVisiable.value = false;
|
isUploadPopupVisiable.value = false;
|
||||||
};
|
};
|
||||||
const afterUploadCallback = async (
|
const afterUploadCallback = async (
|
||||||
files: { filename: { path: string; id: number } }[],
|
files: { filename: { path: string; id: number } }[],
|
||||||
id: number,
|
id: number,
|
||||||
) => {
|
) => {
|
||||||
await Api.materialsInOut.materialsInOutUpdate(
|
await Api.materialsInOut.materialsInOutUpdate(
|
||||||
{ id },
|
{ id },
|
||||||
{ fileIds: files.map((item) => item.filename.id) },
|
{ fileIds: files.map((item) => item.filename.id) },
|
||||||
);
|
);
|
||||||
dynamicTableInstance?.reload();
|
dynamicTableInstance?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 打开新增/编辑弹窗
|
* @description 打开新增/编辑弹窗
|
||||||
*/
|
*/
|
||||||
const openEditModal = async (record: Partial<TableListItem>) => {
|
const openEditModal = async (record: Partial<TableListItem>) => {
|
||||||
const [formRef] = await showModal({
|
const [formRef] = await showModal({
|
||||||
modalProps: {
|
modalProps: {
|
||||||
title: `${record.id ? '编辑' : '新增'}出入库记录`,
|
title: `${record.id ? '编辑' : '新增'}出入库记录`,
|
||||||
|
@ -251,13 +237,13 @@ const openEditModal = async (record: Partial<TableListItem>) => {
|
||||||
...info,
|
...info,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const delRowConfirm = async (record) => {
|
const delRowConfirm = async (record) => {
|
||||||
await Api.materialsInOut.materialsInOutDelete({ id: record });
|
await Api.materialsInOut.materialsInOutDelete({ id: record });
|
||||||
dynamicTableInstance?.reload();
|
dynamicTableInstance?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
const FilesRender: FunctionalComponent<TableListItem> = (materialsInOut: TableListItem) => {
|
const FilesRender: FunctionalComponent<TableListItem> = (materialsInOut: TableListItem) => {
|
||||||
const [fnModal] = useModal();
|
const [fnModal] = useModal();
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -269,9 +255,9 @@ const FilesRender: FunctionalComponent<TableListItem> = (materialsInOut: TableLi
|
||||||
{materialsInOut.files?.length || 0}
|
{materialsInOut.files?.length || 0}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openFilesManageModal = (fnModal, tableData: TableListItem) => {
|
const openFilesManageModal = (fnModal, tableData: TableListItem) => {
|
||||||
const fileIds = tableData.files?.map((item) => item.id) || [];
|
const fileIds = tableData.files?.map((item) => item.id) || [];
|
||||||
fnModal.show({
|
fnModal.show({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
|
@ -287,11 +273,12 @@ const openFilesManageModal = (fnModal, tableData: TableListItem) => {
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
footer: null,
|
footer: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const unlinkAttachments = async (id: number, unlinkIds: number[]) => {
|
const unlinkAttachments = async (id: number, unlinkIds: number[]) => {
|
||||||
await Api.materialsInOut.unlinkAttachments({ id }, { fileIds: unlinkIds });
|
await Api.materialsInOut.unlinkAttachments({ id }, { fileIds: unlinkIds });
|
||||||
dynamicTableInstance?.reload();
|
dynamicTableInstance?.reload();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less"
|
||||||
|
scoped></style>
|
||||||
|
|
|
@ -18,26 +18,25 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup
|
||||||
import { useTable } from '@/components/core/dynamic-table';
|
lang="tsx">
|
||||||
import { baseColumns, type TableColumnItem, type TableListItem } from './columns';
|
import { useTable } from '@/components/core/dynamic-table';
|
||||||
import Api from '@/api/';
|
import { baseColumns, type TableColumnItem, type TableListItem } from './columns';
|
||||||
import { onMounted, ref, unref } from 'vue';
|
import Api from '@/api/';
|
||||||
import { useFormModal } from '@/hooks/useModal';
|
import { onMounted, ref, unref } from 'vue';
|
||||||
import { exportSchemas } from './exportSchema';
|
import { useFormModal } from '@/hooks/useModal';
|
||||||
import dayjs from 'dayjs';
|
import { exportSchemas } from './exportSchema';
|
||||||
import fileDownload from 'js-file-download';
|
import dayjs from 'dayjs';
|
||||||
import { message } from 'ant-design-vue';
|
import fileDownload from 'js-file-download';
|
||||||
import { useExportExcelModal } from '@/components/basic/excel';
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'MaterialsInventory',
|
name: 'MaterialsInventory',
|
||||||
});
|
});
|
||||||
const [DynamicTable, dynamicTableInstance] = useTable();
|
const [DynamicTable, dynamicTableInstance] = useTable();
|
||||||
const [showExportModal] = useFormModal();
|
const [showExportModal] = useFormModal();
|
||||||
const exportExcelModal = useExportExcelModal();
|
let columns = ref<TableColumnItem[]>();
|
||||||
let columns = ref<TableColumnItem[]>();
|
onMounted(() => {
|
||||||
onMounted(() => {
|
|
||||||
columns.value = [
|
columns.value = [
|
||||||
...baseColumns,
|
...baseColumns,
|
||||||
|
|
||||||
|
@ -72,56 +71,41 @@ onMounted(() => {
|
||||||
// ],
|
// ],
|
||||||
// },
|
// },
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
const exportMI = async () => {
|
const exportMI = async () => {
|
||||||
const { time } = unref<{ time: string; projectId: number }>(
|
const { time } = unref<{ time: string; projectId: number }>(
|
||||||
dynamicTableInstance?.queryFormRef?.formModel as { time: string; projectId: number },
|
dynamicTableInstance?.queryFormRef?.formModel as { time: string; projectId: number },
|
||||||
);
|
);
|
||||||
exportExcelModal.openModal({
|
|
||||||
formSchemas: [
|
const [formRef] = await showExportModal({
|
||||||
{
|
modalProps: {
|
||||||
field: 'time',
|
title: `导出条件选择`,
|
||||||
component: 'RangePicker',
|
width: '50%',
|
||||||
label: '时间范围',
|
okText: '导出',
|
||||||
rules: [{ required: true }],
|
onFinish: async (values) => {
|
||||||
|
const response = await Api.materialsInventory.materialsInventoryExport(values);
|
||||||
|
const { time } = values;
|
||||||
|
fileDownload(response, `${dayjs(time).format('YYYY.MM.盘点表')}.xls`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
formProps: {
|
||||||
|
labelWidth: 100,
|
||||||
|
schemas: exportSchemas,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
onOk: async ({ filename, bookType, time }) => {
|
|
||||||
const response = await Api.materialsInventory.materialsInventoryExport({
|
|
||||||
time: (time ?? []).map(item => dayjs(item).format('YYYY-MM-DD')), filename
|
|
||||||
});
|
});
|
||||||
fileDownload(response, `${filename}.xls`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// const [formRef] = await showExportModal({
|
|
||||||
// modalProps: {
|
|
||||||
// title: `导出条件选择`,
|
|
||||||
// width: '50%',
|
|
||||||
// okText: '导出',
|
|
||||||
// onFinish: async (values) => {
|
|
||||||
// const response = await Api.materialsInventory.materialsInventoryExport(values);
|
|
||||||
// const { time } = values;
|
|
||||||
// fileDownload(response, `${dayjs(time).format('YYYY.MM.盘点表')}.xls`);
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// formProps: {
|
|
||||||
// labelWidth: 100,
|
|
||||||
// schemas: exportSchemas,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// auto fill export time fields
|
// auto fill export time fields
|
||||||
// if (time) {
|
if (time) {
|
||||||
// formRef?.setFieldsValue({
|
formRef?.setFieldsValue({
|
||||||
// time,
|
time,
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 打开新增/编辑弹窗
|
* @description 打开新增/编辑弹窗
|
||||||
*/
|
*/
|
||||||
const openEditModal = async (record: Partial<TableListItem>) => {
|
const openEditModal = async (record: Partial<TableListItem>) => {
|
||||||
message.warning(
|
message.warning(
|
||||||
<div>
|
<div>
|
||||||
暂不支持编辑功能,等待后期需求确认
|
暂不支持编辑功能,等待后期需求确认
|
||||||
|
@ -158,14 +142,15 @@ const openEditModal = async (record: Partial<TableListItem>) => {
|
||||||
// ...info,
|
// ...info,
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
const delRowConfirm = async (record) => {
|
const delRowConfirm = async (record) => {
|
||||||
await Api.contract.contractDelete({ id: record });
|
await Api.contract.contractDelete({ id: record });
|
||||||
dynamicTableInstance?.reload();
|
dynamicTableInstance?.reload();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less"
|
||||||
|
scoped></style>
|
||||||
import dayjs from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem
|
import dayjs from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem
|
||||||
} from '../in-out/columns'; import { exportSchemas } from '../in-out/exportSchema'; import dayjs
|
} from '../in-out/columns'; import { exportSchemas } from '../in-out/exportSchema'; import dayjs
|
||||||
from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem } from
|
from 'dayjs'; import fileDownload from 'js-file-download'; import type { TableQueryItem } from
|
||||||
|
|
|
@ -26,7 +26,6 @@ import { useFormModal, useModal } from '@/hooks/useModal';
|
||||||
import { formSchemas } from './formSchemas';
|
import { formSchemas } from './formSchemas';
|
||||||
|
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import fileDownload from 'js-file-download';
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'SaleQuotationTemplate',
|
name: 'SaleQuotationTemplate',
|
||||||
});
|
});
|
||||||
|
@ -47,7 +46,6 @@ onMounted(() => {
|
||||||
dataIndex: 'ACTION',
|
dataIndex: 'ACTION',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
actions: ({ record }) => [
|
actions: ({ record }) => [
|
||||||
|
|
||||||
{
|
{
|
||||||
icon: 'ant-design:edit-outlined',
|
icon: 'ant-design:edit-outlined',
|
||||||
tooltip: '编辑',
|
tooltip: '编辑',
|
||||||
|
@ -68,25 +66,14 @@ onMounted(() => {
|
||||||
onConfirm: () => delRowConfirm(record.id),
|
onConfirm: () => delRowConfirm(record.id),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'ant-design:file-excel-outlined',
|
|
||||||
tooltip: '导出',
|
|
||||||
auth: {
|
|
||||||
perm: 'sale_quotation:sale_quotation:export',
|
|
||||||
effect: 'disable',
|
|
||||||
},
|
|
||||||
onClick: () => onExport(record),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const onExport = async (record:TableListItem) => {
|
|
||||||
const response = await Api.saleQuotation.exportSaleQuotation(record.id);
|
|
||||||
fileDownload(response, `${record.name}.xls`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 打开新增/编辑弹窗
|
* @description 打开新增/编辑弹窗
|
||||||
|
|
Loading…
Reference in New Issue