20260805173201
This commit is contained in:
1 parent
7c9761a4fc
commit
bca59a2755
7 files changed
+805
-24
No files matched your search
@@ -1,7 +1,30 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import zhCN from "antdv-next/locale/zh_CN";
|
import zhCN from "antdv-next/locale/zh_CN";
|
||||||
|
|
||||||
const themeConfig = {};
|
const themeConfig = {
|
||||||
|
token: {
|
||||||
|
controlHeight: 28,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Splitter: {
|
||||||
|
splitBarSize: 1,
|
||||||
|
},
|
||||||
|
Button: {
|
||||||
|
contentFontSize: 13,
|
||||||
|
paddingInline: 10,
|
||||||
|
},
|
||||||
|
Form: {
|
||||||
|
labelFontSize: 13,
|
||||||
|
verticalLabelMargin: "0 0 2px",
|
||||||
|
itemMarginBottom: 8,
|
||||||
|
},
|
||||||
|
Collapse: {
|
||||||
|
headerBg: "#ffffff",
|
||||||
|
contentBg: "#ffffff",
|
||||||
|
borderlessContentBg: "#ffffff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
const timePickerLocale = {
|
const timePickerLocale = {
|
||||||
...zhCN.TimePicker,
|
...zhCN.TimePicker,
|
||||||
placeholder: "",
|
placeholder: "",
|
||||||
@@ -45,3 +68,11 @@ const locale = {
|
|||||||
</a-app>
|
</a-app>
|
||||||
</a-config-provider>
|
</a-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 全局:按钮内图标跟随 contentFontSize(13px),覆盖 Lucide 的固定 size */
|
||||||
|
.ant-btn svg {
|
||||||
|
width: 1em !important;
|
||||||
|
height: 1em !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -138,7 +138,7 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
:aria-label="appStore.t('common.search', '搜索')"
|
:aria-label="appStore.t('common.search', '搜索')"
|
||||||
@click="handleQuickSearch"
|
@click="handleQuickSearch"
|
||||||
>
|
>
|
||||||
<Search :size="16" />
|
<Search />
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space-compact>
|
</a-space-compact>
|
||||||
|
|
||||||
@@ -152,7 +152,6 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
>
|
>
|
||||||
<a-button
|
<a-button
|
||||||
shape="circle"
|
shape="circle"
|
||||||
class="toolbar-icon-button"
|
|
||||||
:class="{ 'toolbar-icon-button--active': advancedOpen }"
|
:class="{ 'toolbar-icon-button--active': advancedOpen }"
|
||||||
:aria-label="
|
:aria-label="
|
||||||
advancedOpen
|
advancedOpen
|
||||||
@@ -161,7 +160,7 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
"
|
"
|
||||||
@click="toggleAdvancedSearch"
|
@click="toggleAdvancedSearch"
|
||||||
>
|
>
|
||||||
<Search :size="16" />
|
<Search />
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
@@ -172,17 +171,14 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
:trigger="['click']"
|
:trigger="['click']"
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
>
|
>
|
||||||
<span class="more-trigger">
|
|
||||||
<a-tooltip :title="appStore.t('common.more', '更多')">
|
<a-tooltip :title="appStore.t('common.more', '更多')">
|
||||||
<a-button
|
<a-button
|
||||||
shape="circle"
|
shape="circle"
|
||||||
class="toolbar-icon-button"
|
|
||||||
:aria-label="appStore.t('common.more', '更多')"
|
:aria-label="appStore.t('common.more', '更多')"
|
||||||
>
|
>
|
||||||
<Ellipsis :size="17" />
|
<Ellipsis />
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</span>
|
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -211,8 +207,8 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
class="query-more-toggle"
|
class="query-more-toggle"
|
||||||
@click="advancedMoreOpen = !advancedMoreOpen"
|
@click="advancedMoreOpen = !advancedMoreOpen"
|
||||||
>
|
>
|
||||||
<ChevronUp v-if="advancedMoreOpen" :size="15" />
|
<ChevronUp v-if="advancedMoreOpen" />
|
||||||
<ChevronDown v-else :size="15" />
|
<ChevronDown v-else />
|
||||||
{{
|
{{
|
||||||
advancedMoreOpen
|
advancedMoreOpen
|
||||||
? appStore.t("common.collapseConditions", "收起条件")
|
? appStore.t("common.collapseConditions", "收起条件")
|
||||||
@@ -223,11 +219,11 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
|
|
||||||
<div class="query-actions">
|
<div class="query-actions">
|
||||||
<a-button type="primary" :loading="loading" @click="handleAdvancedSearch">
|
<a-button type="primary" :loading="loading" @click="handleAdvancedSearch">
|
||||||
<Search :size="15" />
|
<Search />
|
||||||
{{ appStore.t("common.search", "查询") }}
|
{{ appStore.t("common.search", "查询") }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="text" :disabled="loading" @click="handleAdvancedReset">
|
<a-button type="text" :disabled="loading" @click="handleAdvancedReset">
|
||||||
<RotateCcw :size="15" />
|
<RotateCcw />
|
||||||
{{ appStore.t("common.reset", "重置") }}
|
{{ appStore.t("common.reset", "重置") }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -294,14 +290,6 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-icon-button {
|
.toolbar-icon-button {
|
||||||
display: inline-flex;
|
|
||||||
width: 34px;
|
|
||||||
min-width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
border-color: #91caff;
|
border-color: #91caff;
|
||||||
background: #e6f4ff;
|
background: #e6f4ff;
|
||||||
@@ -311,8 +299,6 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true });
|
|||||||
|
|
||||||
.more-trigger {
|
.more-trigger {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.query-panel {
|
.query-panel {
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ const routes = [
|
|||||||
moduleId: "v_b_othercompany",
|
moduleId: "v_b_othercompany",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "base/othercompany/detail",
|
||||||
|
name: "base-othercompany-detail",
|
||||||
|
component: () => import("@/views/base/othercompany/detail.vue"),
|
||||||
|
meta: {
|
||||||
|
title: "合作伙伴详情",
|
||||||
|
section: "基础数据",
|
||||||
|
menuKey: "/base/othercompany",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "base/contact",
|
path: "base/contact",
|
||||||
name: "base-contact",
|
name: "base-contact",
|
||||||
@@ -36,6 +46,16 @@ const routes = [
|
|||||||
moduleId: "v_b_contact",
|
moduleId: "v_b_contact",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "base/contact/detail",
|
||||||
|
name: "base-contact-detail",
|
||||||
|
component: () => import("@/views/base/contact/detail.vue"),
|
||||||
|
meta: {
|
||||||
|
title: "联系人详情",
|
||||||
|
section: "基础数据",
|
||||||
|
menuKey: "/base/contact",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "base/otherdata",
|
path: "base/otherdata",
|
||||||
name: "base-otherdata",
|
name: "base-otherdata",
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { ArrowLeft } from "@lucide/vue";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const isCreate = computed(() => route.query.mode === "create");
|
||||||
|
const recordId = computed(() => route.query.id || "");
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
router.push({ name: "base-contact" });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="contact-detail">
|
||||||
|
<div class="detail-header">
|
||||||
|
<a-button type="text" @click="goBack">
|
||||||
|
<ArrowLeft :size="16" />返回
|
||||||
|
</a-button>
|
||||||
|
<h2 class="detail-title">{{ isCreate ? "新增联系人" : "编辑联系人" }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="detail-body">
|
||||||
|
<a-empty description="详细内容待实现" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.contact-detail {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--fms-surface);
|
||||||
|
border: 1px solid var(--fms-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid var(--fms-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-body {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,10 +1,82 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { message, Modal } from "antdv-next";
|
||||||
|
import { Plus, Trash2 } from "@lucide/vue";
|
||||||
import FmsModuleListPage from "@/components/fms-module-list/FmsModuleListPage.vue";
|
import FmsModuleListPage from "@/components/fms-module-list/FmsModuleListPage.vue";
|
||||||
|
import { usePermissionStore } from "@/stores/permissions";
|
||||||
|
|
||||||
|
const CONTACT_MODULE_CODE = "v_b_contact";
|
||||||
|
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
|
const canCreateRow = computed(() => permissionStore.canPower(CONTACT_MODULE_CODE, "create"));
|
||||||
|
const canDeleteRow = computed(() => permissionStore.canPower(CONTACT_MODULE_CODE, "delete"));
|
||||||
|
|
||||||
|
const moduleListRef = ref(null);
|
||||||
|
const selectedRowKeys = ref([]);
|
||||||
|
const dirtyCount = ref(0);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const rowSelection = computed(() => ({
|
||||||
|
selectedRowKeys: selectedRowKeys.value,
|
||||||
|
onChange: (keys) => {
|
||||||
|
selectedRowKeys.value = keys;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function goCreate() {
|
||||||
|
if (canCreateRow.value) {
|
||||||
|
router.push({ name: "base-contact-detail", query: { mode: "create" } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmBatchDelete() {
|
||||||
|
if (!canDeleteRow.value || !selectedRowKeys.value.length) {
|
||||||
|
message.warning("请先选择要删除的记录");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Modal.confirm({
|
||||||
|
title: `确定删除选中的 ${selectedRowKeys.value.length} 条记录?`,
|
||||||
|
content: "此操作不可恢复",
|
||||||
|
okText: "删除",
|
||||||
|
cancelText: "取消",
|
||||||
|
okButtonProps: { danger: true },
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await moduleListRef.value?.deleteSelected?.(selectedRowKeys.value);
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
dirtyCount.value = 0;
|
||||||
|
} finally {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="contact-page">
|
<div class="contact-page">
|
||||||
<FmsModuleListPage data-code="v_b_contact" />
|
<FmsModuleListPage
|
||||||
|
ref="moduleListRef"
|
||||||
|
data-code="v_b_contact"
|
||||||
|
:row-selection="rowSelection"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<a-space>
|
||||||
|
<a-button v-if="canCreateRow" type="primary" @click="goCreate">
|
||||||
|
<Plus :size="15" />新增
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
v-if="canDeleteRow"
|
||||||
|
danger
|
||||||
|
:disabled="!selectedRowKeys.length"
|
||||||
|
@click="confirmBatchDelete"
|
||||||
|
>
|
||||||
|
<Trash2 :size="15" />批量删除
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</FmsModuleListPage>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,537 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { Save, RotateCcw, Trash2 } from "@lucide/vue";
|
||||||
|
|
||||||
|
const activeTab = ref("basic");
|
||||||
|
|
||||||
|
const tabItems = [
|
||||||
|
{ key: "basic", label: "基本信息" },
|
||||||
|
{ key: "contact", label: "联系信息" },
|
||||||
|
{ key: "finance", label: "财务信息" },
|
||||||
|
{ key: "business", label: "业务信息" },
|
||||||
|
{ key: "attach", label: "附件" },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!--
|
||||||
|
IDEA 沉浸风 Demo
|
||||||
|
核心思路:
|
||||||
|
- 背景冷灰,无圆角无阴影,全贴边
|
||||||
|
- 工具栏极窄,纯功能
|
||||||
|
- 表单极致紧凑,冷色系
|
||||||
|
-->
|
||||||
|
<div class="idea-detail">
|
||||||
|
<!-- 顶部工具栏:36px,纯功能 -->
|
||||||
|
<div class="idea-toolbar">
|
||||||
|
<span class="idea-toolbar-title">合作伙伴详情</span>
|
||||||
|
<div class="idea-toolbar-actions">
|
||||||
|
<a-button>
|
||||||
|
<RotateCcw :size="15" />重置
|
||||||
|
</a-button>
|
||||||
|
<a-button danger>
|
||||||
|
<Trash2 :size="15" />删除
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary">
|
||||||
|
<Save :size="15" />保存
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab:极小高度,贴边 -->
|
||||||
|
<div class="idea-tabs">
|
||||||
|
<a-tabs v-model:active-key="activeTab" :items="tabItems" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表单内容区 -->
|
||||||
|
<div class="idea-body">
|
||||||
|
<!-- ========== Tab: 基本信息 ========== -->
|
||||||
|
<div v-show="activeTab === 'basic'" class="idea-form">
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">基本信息</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="合作伙伴编码">
|
||||||
|
<a-input placeholder="自动生成" disabled />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="合作伙伴名称" required>
|
||||||
|
<a-input placeholder="请输入名称" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="简称">
|
||||||
|
<a-input placeholder="请输入简称" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="合作伙伴类型">
|
||||||
|
<a-select placeholder="请选择类型" allow-clear>
|
||||||
|
<a-select-option value="1">客户</a-select-option>
|
||||||
|
<a-select-option value="2">供应商</a-select-option>
|
||||||
|
<a-select-option value="3">代理商</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="客户级别">
|
||||||
|
<a-select placeholder="请选择级别" allow-clear>
|
||||||
|
<a-select-option value="A">A级</a-select-option>
|
||||||
|
<a-select-option value="B">B级</a-select-option>
|
||||||
|
<a-select-option value="C">C级</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="客户来源">
|
||||||
|
<a-select placeholder="请选择来源" allow-clear>
|
||||||
|
<a-select-option value="1">线上推广</a-select-option>
|
||||||
|
<a-select-option value="2">线下展会</a-select-option>
|
||||||
|
<a-select-option value="3">客户介绍</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">区域信息</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="国家">
|
||||||
|
<a-select placeholder="请选择国家" allow-clear>
|
||||||
|
<a-select-option value="CN">中国</a-select-option>
|
||||||
|
<a-select-option value="US">美国</a-select-option>
|
||||||
|
<a-select-option value="JP">日本</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="省份">
|
||||||
|
<a-input placeholder="请输入省份" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="城市">
|
||||||
|
<a-input placeholder="请输入城市" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">状态设置</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="是否启用">
|
||||||
|
<a-switch checked-children="启用" un-checked-children="停用" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="排序号">
|
||||||
|
<a-input-number placeholder="请输入排序号" :min="0" :style="{ width: '100%' }" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== Tab: 联系信息 ========== -->
|
||||||
|
<div v-show="activeTab === 'contact'" class="idea-form">
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">主要联系人</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="联系人姓名">
|
||||||
|
<a-input placeholder="请输入姓名" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="职位">
|
||||||
|
<a-input placeholder="请输入职位" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="手机号码">
|
||||||
|
<a-input placeholder="请输入手机号码" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="电子邮箱">
|
||||||
|
<a-input placeholder="请输入邮箱" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">地址信息</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="16">
|
||||||
|
<a-form-item label="详细地址">
|
||||||
|
<a-textarea placeholder="请输入详细地址" :rows="2" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8">
|
||||||
|
<a-form-item label="邮政编码">
|
||||||
|
<a-input placeholder="请输入邮政编码" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== Tab: 财务信息 ========== -->
|
||||||
|
<div v-show="activeTab === 'finance'" class="idea-form">
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">结算信息</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="结算币种">
|
||||||
|
<a-select placeholder="请选择币种" allow-clear>
|
||||||
|
<a-select-option value="CNY">人民币 (CNY)</a-select-option>
|
||||||
|
<a-select-option value="USD">美元 (USD)</a-select-option>
|
||||||
|
<a-select-option value="EUR">欧元 (EUR)</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="结算方式">
|
||||||
|
<a-select placeholder="请选择结算方式" allow-clear>
|
||||||
|
<a-select-option value="1">月结</a-select-option>
|
||||||
|
<a-select-option value="2">票结</a-select-option>
|
||||||
|
<a-select-option value="3">预付</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="付款条款">
|
||||||
|
<a-select placeholder="请选择付款条款" allow-clear>
|
||||||
|
<a-select-option value="1">预付</a-select-option>
|
||||||
|
<a-select-option value="2">到付</a-select-option>
|
||||||
|
<a-select-option value="3">月结30天</a-select-option>
|
||||||
|
<a-select-option value="4">月结60天</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">银行账户</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="开户银行">
|
||||||
|
<a-input placeholder="请输入开户银行" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="银行账号">
|
||||||
|
<a-input placeholder="请输入银行账号" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="账户名称">
|
||||||
|
<a-input placeholder="请输入账户名称" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="税号">
|
||||||
|
<a-input placeholder="请输入税号" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== Tab: 业务信息 ========== -->
|
||||||
|
<div v-show="activeTab === 'business'" class="idea-form">
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">业务范围</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="主营业务">
|
||||||
|
<a-select placeholder="请选择主营业务" mode="multiple" allow-clear>
|
||||||
|
<a-select-option value="1">海运</a-select-option>
|
||||||
|
<a-select-option value="2">空运</a-select-option>
|
||||||
|
<a-select-option value="3">陆运</a-select-option>
|
||||||
|
<a-select-option value="4">报关</a-select-option>
|
||||||
|
<a-select-option value="5">仓储</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="合作状态">
|
||||||
|
<a-select placeholder="请选择状态" allow-clear>
|
||||||
|
<a-select-option value="1">合作中</a-select-option>
|
||||||
|
<a-select-option value="2">暂停</a-select-option>
|
||||||
|
<a-select-option value="3">终止</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="idea-section">
|
||||||
|
<div class="idea-section-label">备注信息</div>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-row :gutter="12">
|
||||||
|
<a-col :span="16">
|
||||||
|
<a-form-item label="备注">
|
||||||
|
<a-textarea placeholder="请输入备注信息" :rows="3" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== Tab: 附件 ========== -->
|
||||||
|
<div v-show="activeTab === 'attach'" class="idea-form">
|
||||||
|
<a-empty description="暂无附件" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/*
|
||||||
|
* Modern IDE 风格 v3
|
||||||
|
* 参考:IDEA 2024 New UI / Linear / Vercel
|
||||||
|
* 关键词:柔和、圆角、透明度、微妙阴影、过渡动画
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ═══ 颜色令牌 ═══
|
||||||
|
$bg-root: #f1f3f5; // 根背景 — 暖灰偏冷
|
||||||
|
$bg-toolbar: #ffffff; // 工具栏白
|
||||||
|
$bg-tab: #f8f9fb; // Tab 区
|
||||||
|
$bg-card: #ffffff; // 表单卡片
|
||||||
|
$border: #e2e5e9; // 边框
|
||||||
|
$border-light: #eceff3; // 淡边框
|
||||||
|
$text: #111418; // 主文字
|
||||||
|
$text-secondary: #5e6470; // 副文字
|
||||||
|
$text-muted: #9098a5; // 淡文字
|
||||||
|
$primary: #1a56db; // 主色
|
||||||
|
$primary-soft: rgba(26, 86, 219, 0.06); // focus 光晕
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// 根容器
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
.idea-detail {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
background: $bg-root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// 工具栏
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
.idea-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 40px;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.idea-toolbar-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $text-secondary;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idea-toolbar-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// Tab 栏
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
.idea-tabs {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: $bg-tab;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-bottom: 1px solid $border-light;
|
||||||
|
|
||||||
|
:deep(.ant-tabs-nav) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-tab) {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: $text-muted;
|
||||||
|
border-radius: 0;
|
||||||
|
transition: color 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-tabs-tab-active .ant-tabs-tab-btn {
|
||||||
|
color: $text;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-ink-bar) {
|
||||||
|
background: $primary;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-content-holder) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// 内容区
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
.idea-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 24px;
|
||||||
|
background: $bg-root;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar { width: 6px; }
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 3px;
|
||||||
|
&:hover { background: rgba(0, 0, 0, 0.2); }
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track { background: transparent; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单卡片
|
||||||
|
.idea-form {
|
||||||
|
max-width: 840px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: $bg-card;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 32px 40px;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(0, 0, 0, 0.04),
|
||||||
|
0 1px 2px rgba(0, 0, 0, 0.03),
|
||||||
|
0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// Section
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
.idea-section {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.idea-section-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid $border-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
// 表单控件 — 现代圆角、柔和边框
|
||||||
|
// ═══════════════════════════════════════════
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-form-item-label) {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-secondary;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框 / 选择器 — 6px 圆角,现代感
|
||||||
|
:deep(.ant-input),
|
||||||
|
:deep(.ant-input-affix-wrapper),
|
||||||
|
:deep(.ant-select-selector),
|
||||||
|
:deep(.ant-input-number) {
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-color: $border;
|
||||||
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: darken($border, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-number-input) {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-selection-item) {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus — 蓝色光晕
|
||||||
|
:deep(.ant-input:focus),
|
||||||
|
:deep(.ant-input-affix-wrapper-focused),
|
||||||
|
:deep(.ant-select-focused .ant-select-selector),
|
||||||
|
:deep(.ant-input-number-focused) {
|
||||||
|
border-color: $primary;
|
||||||
|
box-shadow: 0 0 0 3px $primary-soft;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disabled 态更柔和
|
||||||
|
:deep(.ant-input-disabled),
|
||||||
|
:deep(.ant-select-disabled .ant-select-selector) {
|
||||||
|
background: #f8f9fb;
|
||||||
|
color: $text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch 微调
|
||||||
|
:deep(.ant-switch) {
|
||||||
|
&.ant-switch-checked {
|
||||||
|
background: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,14 +6,35 @@ import FmsModuleListPage from "@/components/fms-module-list/FmsModuleListPage.vu
|
|||||||
import FmsTree from "@/components/FmsTree.vue";
|
import FmsTree from "@/components/FmsTree.vue";
|
||||||
import { escapeSqlText } from "@/components/fms-module-list/moduleListUtils";
|
import { escapeSqlText } from "@/components/fms-module-list/moduleListUtils";
|
||||||
import { loadDataApi, nextIdApi, pageDataApi, saveObjectApi } from "@/services/api";
|
import { loadDataApi, nextIdApi, pageDataApi, saveObjectApi } from "@/services/api";
|
||||||
|
import { usePermissionStore } from "@/stores/permissions";
|
||||||
import { buildTree, sortTree } from "@/utils/tree";
|
import { buildTree, sortTree } from "@/utils/tree";
|
||||||
|
|
||||||
|
const OTHERCOMPANY_MODULE_CODE = "v_b_othercompany";
|
||||||
const ALL_CATEGORIES_KEY = "__fms_tree_root__";
|
const ALL_CATEGORIES_KEY = "__fms_tree_root__";
|
||||||
const categories = ref([]);
|
const categories = ref([]);
|
||||||
const categoryLoading = ref(false);
|
const categoryLoading = ref(false);
|
||||||
const selectedCategoryKey = ref(ALL_CATEGORIES_KEY);
|
const selectedCategoryKey = ref(ALL_CATEGORIES_KEY);
|
||||||
const expandedCategoryKeys = ref([ALL_CATEGORIES_KEY]);
|
const expandedCategoryKeys = ref([ALL_CATEGORIES_KEY]);
|
||||||
|
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
|
const canCreateRow = computed(() => permissionStore.canPower(OTHERCOMPANY_MODULE_CODE, "create"));
|
||||||
|
const canUpdateRow = computed(() => permissionStore.canPower(OTHERCOMPANY_MODULE_CODE, "update"));
|
||||||
|
const canDeleteRow = computed(() => permissionStore.canPower(OTHERCOMPANY_MODULE_CODE, "delete"));
|
||||||
|
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const moduleListRef = ref(null);
|
||||||
|
const selectedRowKeys = ref([]);
|
||||||
|
const dirtyCount = ref(0);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const rowSelection = computed(() => ({
|
||||||
|
selectedRowKeys: selectedRowKeys.value,
|
||||||
|
onChange: (keys) => {
|
||||||
|
selectedRowKeys.value = keys;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const categoryById = computed(
|
const categoryById = computed(
|
||||||
() => new Map(categories.value.map((item) => [String(item.b_id), item])),
|
() => new Map(categories.value.map((item) => [String(item.b_id), item])),
|
||||||
);
|
);
|
||||||
@@ -368,6 +389,36 @@ async function confirmDeleteCategory(node) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 新增 / 批量删除 ──
|
||||||
|
function goCreate() {
|
||||||
|
if (canCreateRow.value) {
|
||||||
|
router.push({ name: "base-othercompany-detail", query: { mode: "create" } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmBatchDelete() {
|
||||||
|
if (!canDeleteRow.value || !selectedRowKeys.value.length) {
|
||||||
|
message.warning("请先选择要删除的记录");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Modal.confirm({
|
||||||
|
title: `确定删除选中的 ${selectedRowKeys.value.length} 条记录?`,
|
||||||
|
content: "此操作不可恢复",
|
||||||
|
okText: "删除",
|
||||||
|
cancelText: "取消",
|
||||||
|
okButtonProps: { danger: true },
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await moduleListRef.value?.deleteSelected?.(selectedRowKeys.value);
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
dirtyCount.value = 0;
|
||||||
|
} finally {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadCategories();
|
loadCategories();
|
||||||
});
|
});
|
||||||
@@ -396,10 +447,28 @@ onMounted(() => {
|
|||||||
<a-splitter-panel :min="520">
|
<a-splitter-panel :min="520">
|
||||||
<main class="partner-panel">
|
<main class="partner-panel">
|
||||||
<FmsModuleListPage
|
<FmsModuleListPage
|
||||||
|
ref="moduleListRef"
|
||||||
data-code="v_b_othercompany"
|
data-code="v_b_othercompany"
|
||||||
:fixed-search-condition="categoryFilterCondition"
|
:fixed-search-condition="categoryFilterCondition"
|
||||||
:column-extensions="columnExtensions"
|
:column-extensions="columnExtensions"
|
||||||
/>
|
:row-selection="rowSelection"
|
||||||
|
>
|
||||||
|
<template #actions>
|
||||||
|
<a-space>
|
||||||
|
<a-button v-if="canCreateRow" type="primary" @click="goCreate">
|
||||||
|
<Plus :size="15" />新增
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
v-if="canDeleteRow"
|
||||||
|
danger
|
||||||
|
:disabled="!selectedRowKeys.length"
|
||||||
|
@click="confirmBatchDelete"
|
||||||
|
>
|
||||||
|
<Trash2 :size="15" />批量删除
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</FmsModuleListPage>
|
||||||
</main>
|
</main>
|
||||||
</a-splitter-panel>
|
</a-splitter-panel>
|
||||||
</a-splitter>
|
</a-splitter>
|
||||||
|
|||||||
Reference in new issue
Block a user