物品规则ui优化
This commit is contained in:
@@ -1,31 +1,22 @@
|
|||||||
import {
|
import {
|
||||||
CheckOutlined,
|
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
FormOutlined,
|
FormOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
|
||||||
Drawer,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Radio,
|
Radio,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
Tabs,
|
||||||
@@ -33,66 +24,26 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkProductRule,
|
deleteAdminWorkProductRule,
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
fetchAdminWorkCategories,
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
fetchAdminWorkProductRules,
|
||||||
fetchAdminWorkerLevels,
|
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
saveAdminWorkProductRule,
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type { CollectField, WorkProductRule } from '@/types/worker-platform'
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import {
|
|
||||||
ADMIN_DEFAULT_PAGE_SIZE,
|
|
||||||
buildAdminTablePagination,
|
|
||||||
} from '@/utils/admin-pagination'
|
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
import { formatMoney } from './shared'
|
import { formatMoney } from './shared'
|
||||||
|
|
||||||
export default function ProductRulesPanel() {
|
export default function ProductRulesPanel() {
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
|
|
||||||
const [editingRule, setEditingRule] = useState<WorkProductRule | null>(null)
|
const [editingRule, setEditingRule] = useState<WorkProductRule | null>(null)
|
||||||
|
const [keyword, setKeyword] = useState('')
|
||||||
|
const [categoryId, setCategoryId] = useState<number | undefined>()
|
||||||
|
|
||||||
const rulesQuery = useQuery({
|
const rulesQuery = useQuery({
|
||||||
queryKey: ['admin-worker-platform-product-rules'],
|
queryKey: ['admin-worker-platform-product-rules'],
|
||||||
queryFn: () => fetchAdminWorkProductRules(),
|
queryFn: () => fetchAdminWorkProductRules(),
|
||||||
@@ -102,6 +53,57 @@ export default function ProductRulesPanel() {
|
|||||||
queryFn: () => fetchAdminWorkCategories(),
|
queryFn: () => fetchAdminWorkCategories(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const allRules = rulesQuery.data?.data.items || []
|
||||||
|
|
||||||
|
const filteredRules = allRules.filter((rule) => {
|
||||||
|
if (categoryId && Number(rule.categoryId || 0) !== categoryId) return false
|
||||||
|
const keywordText = keyword.trim().toLowerCase()
|
||||||
|
if (!keywordText) return true
|
||||||
|
return [
|
||||||
|
rule.ruleKey,
|
||||||
|
rule.productName,
|
||||||
|
rule.skuCode,
|
||||||
|
rule.provider,
|
||||||
|
rule.shopId,
|
||||||
|
rule.categoryName,
|
||||||
|
].some((value) => String(value || '').toLowerCase().includes(keywordText))
|
||||||
|
})
|
||||||
|
|
||||||
|
function resetRuleForm() {
|
||||||
|
setEditingRule(null)
|
||||||
|
form.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
function editRule(rule: WorkProductRule) {
|
||||||
|
setEditingRule(rule)
|
||||||
|
form.setFieldsValue({
|
||||||
|
ruleKey: rule.ruleKey,
|
||||||
|
provider: rule.provider,
|
||||||
|
platform: rule.platform,
|
||||||
|
shopId: rule.shopId,
|
||||||
|
skuCode: rule.skuCode,
|
||||||
|
productName: rule.productName,
|
||||||
|
matchType: rule.matchType,
|
||||||
|
categoryId: rule.categoryId || undefined,
|
||||||
|
pricingMode: rule.unitPriceFen > 0 ? 'unit' : 'fixed',
|
||||||
|
rewardAmount: rule.rewardAmount / 100,
|
||||||
|
unitPrice: rule.unitPriceFen / 100,
|
||||||
|
requiredDepositAmount: rule.requiredDepositAmount / 100,
|
||||||
|
depositThresholdAmount: rule.depositThresholdAmount / 100,
|
||||||
|
sharingEnabled: rule.sharing?.enabled || false,
|
||||||
|
sharingTotalQuantity: rule.sharing?.totalQuantity || 1,
|
||||||
|
sharingUnitReward: (rule.sharing?.unitReward || 0) / 100,
|
||||||
|
sharingTotalAmount:
|
||||||
|
((rule.sharing?.totalQuantity || 1) * (rule.sharing?.unitReward || 0)) / 100,
|
||||||
|
timeoutMinutes: rule.timeoutMinutes || 0,
|
||||||
|
timeoutPolicy: rule.timeoutPolicy || 'reopen',
|
||||||
|
fieldsText: formatRuleFields(rule.requirement?.fields || []),
|
||||||
|
sortOrder: rule.sortOrder,
|
||||||
|
enabled: rule.enabled,
|
||||||
|
autoCreate: rule.autoCreate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function saveRule(values: {
|
async function saveRule(values: {
|
||||||
ruleId?: number
|
ruleId?: number
|
||||||
ruleKey: string
|
ruleKey: string
|
||||||
@@ -151,39 +153,41 @@ export default function ProductRulesPanel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetRuleForm() {
|
async function toggleRuleEnabled(rule: WorkProductRule, enabled: boolean) {
|
||||||
setEditingRule(null)
|
try {
|
||||||
form.resetFields()
|
await saveAdminWorkProductRule({
|
||||||
}
|
ruleId: rule.ruleId,
|
||||||
|
ruleKey: rule.ruleKey,
|
||||||
function editRule(rule: WorkProductRule) {
|
provider: rule.provider,
|
||||||
setEditingRule(rule)
|
platform: rule.platform,
|
||||||
form.setFieldsValue({
|
shopId: rule.shopId,
|
||||||
ruleKey: rule.ruleKey,
|
skuCode: rule.skuCode,
|
||||||
provider: rule.provider,
|
productName: rule.productName,
|
||||||
platform: rule.platform,
|
matchType: rule.matchType,
|
||||||
shopId: rule.shopId,
|
categoryId: rule.categoryId || undefined,
|
||||||
skuCode: rule.skuCode,
|
rewardAmount: rule.rewardAmount / 100,
|
||||||
productName: rule.productName,
|
unitPrice: rule.unitPriceFen / 100,
|
||||||
matchType: rule.matchType,
|
requiredDepositAmount: rule.requiredDepositAmount / 100,
|
||||||
categoryId: rule.categoryId || undefined,
|
depositThresholdAmount: rule.depositThresholdAmount / 100,
|
||||||
pricingMode: rule.unitPriceFen > 0 ? 'unit' : 'fixed',
|
sharingEnabled: rule.sharing?.enabled || false,
|
||||||
rewardAmount: rule.rewardAmount / 100,
|
sharingTotalQuantity: rule.sharing?.totalQuantity || 1,
|
||||||
unitPrice: rule.unitPriceFen / 100,
|
sharingUnitReward: (rule.sharing?.unitReward || 0) / 100,
|
||||||
requiredDepositAmount: rule.requiredDepositAmount / 100,
|
sharingTotalAmount:
|
||||||
depositThresholdAmount: rule.depositThresholdAmount / 100,
|
((rule.sharing?.totalQuantity || 1) * (rule.sharing?.unitReward || 0)) / 100,
|
||||||
sharingEnabled: rule.sharing?.enabled || false,
|
timeoutMinutes: rule.timeoutMinutes || 0,
|
||||||
sharingTotalQuantity: rule.sharing?.totalQuantity || 1,
|
timeoutPolicy: rule.timeoutPolicy || 'reopen',
|
||||||
sharingUnitReward: (rule.sharing?.unitReward || 0) / 100,
|
fieldsText: formatRuleFields(rule.requirement?.fields || []),
|
||||||
sharingTotalAmount:
|
sortOrder: rule.sortOrder,
|
||||||
((rule.sharing?.totalQuantity || 1) * (rule.sharing?.unitReward || 0)) / 100,
|
enabled,
|
||||||
timeoutMinutes: rule.timeoutMinutes || 0,
|
autoCreate: rule.autoCreate,
|
||||||
timeoutPolicy: rule.timeoutPolicy || 'reopen',
|
})
|
||||||
fieldsText: formatRuleFields(rule.requirement?.fields || []),
|
message.success(`规则「${rule.ruleKey}」已${enabled ? '启用' : '停用'}`)
|
||||||
sortOrder: rule.sortOrder,
|
await queryClient.invalidateQueries({
|
||||||
enabled: rule.enabled,
|
queryKey: ['admin-worker-platform-product-rules'],
|
||||||
autoCreate: rule.autoCreate,
|
})
|
||||||
})
|
} catch (error) {
|
||||||
|
message.error(error instanceof Error ? error.message : '修改状态失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeRule(rule: WorkProductRule) {
|
async function removeRule(rule: WorkProductRule) {
|
||||||
@@ -201,23 +205,6 @@ export default function ProductRulesPanel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [keyword, setKeyword] = useState('')
|
|
||||||
const [categoryId, setCategoryId] = useState<number | undefined>()
|
|
||||||
|
|
||||||
const filteredRules = (rulesQuery.data?.data.items || []).filter((rule) => {
|
|
||||||
if (categoryId && Number(rule.categoryId || 0) !== categoryId) return false
|
|
||||||
const keywordText = keyword.trim().toLowerCase()
|
|
||||||
if (!keywordText) return true
|
|
||||||
return [
|
|
||||||
rule.ruleKey,
|
|
||||||
rule.productName,
|
|
||||||
rule.skuCode,
|
|
||||||
rule.provider,
|
|
||||||
rule.shopId,
|
|
||||||
rule.categoryName,
|
|
||||||
].some((value) => String(value || '').toLowerCase().includes(keywordText))
|
|
||||||
})
|
|
||||||
|
|
||||||
function syncSharingRuleForm(next: {
|
function syncSharingRuleForm(next: {
|
||||||
sharingTotalQuantity?: number
|
sharingTotalQuantity?: number
|
||||||
sharingUnitReward?: number
|
sharingUnitReward?: number
|
||||||
@@ -244,45 +231,82 @@ export default function ProductRulesPanel() {
|
|||||||
|
|
||||||
const columns: TableColumnsType<WorkProductRule> = [
|
const columns: TableColumnsType<WorkProductRule> = [
|
||||||
{
|
{
|
||||||
title: '规则',
|
title: '规则 / 商品',
|
||||||
minWidth: 260,
|
key: 'rule',
|
||||||
|
width: '24%',
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<div className="cell-stack">
|
<div className="cell-stack">
|
||||||
<Typography.Text strong>
|
<Typography.Text strong title={row.productName || row.skuCode}>
|
||||||
{row.productName || row.skuCode}
|
{row.productName || row.skuCode || row.ruleKey}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<Typography.Text type="secondary">{row.ruleKey}</Typography.Text>
|
<Space size={4} wrap style={{ marginTop: 2 }}>
|
||||||
|
<Tag color="blue" style={{ margin: 0, fontSize: 11, lineHeight: '18px' }}>
|
||||||
|
{row.ruleKey}
|
||||||
|
</Tag>
|
||||||
|
{row.provider ? (
|
||||||
|
<Typography.Text type="secondary" style={{ fontSize: 11 }}>
|
||||||
|
{row.provider}
|
||||||
|
</Typography.Text>
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '店铺',
|
title: '平台 / 店铺',
|
||||||
width: 120,
|
key: 'platformShop',
|
||||||
|
width: '13%',
|
||||||
render: (_, row) => {
|
render: (_, row) => {
|
||||||
const shopId = String(row.shopId || '')
|
const shopId = String(row.shopId || '')
|
||||||
return shopId ? (
|
return (
|
||||||
<Tag color="geekblue">{shopId}</Tag>
|
<div className="cell-stack">
|
||||||
) : (
|
<Typography.Text style={{ fontSize: 12 }}>
|
||||||
<Tag>通配</Tag>
|
{row.platform || 'kuaishou'}
|
||||||
|
</Typography.Text>
|
||||||
|
{shopId ? (
|
||||||
|
<Tag color="geekblue" style={{ margin: 0, fontSize: 11, lineHeight: '18px' }}>
|
||||||
|
{shopId}
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag style={{ margin: 0, fontSize: 11, lineHeight: '18px' }}>通配店铺</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'SKU',
|
title: 'SKU',
|
||||||
dataIndex: 'skuCode',
|
dataIndex: 'skuCode',
|
||||||
width: 180,
|
width: '11%',
|
||||||
render: (value) => String(value || '-'),
|
render: (value) => (
|
||||||
|
<Typography.Text code style={{ fontSize: 12 }}>
|
||||||
|
{String(value || '-')}
|
||||||
|
</Typography.Text>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分类',
|
||||||
|
dataIndex: 'categoryName',
|
||||||
|
width: '11%',
|
||||||
|
render: (value) =>
|
||||||
|
value ? (
|
||||||
|
<Tag color="cyan" style={{ margin: 0 }}>{value}</Tag>
|
||||||
|
) : (
|
||||||
|
<Typography.Text type="secondary">-</Typography.Text>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{ title: '分类', width: 140, render: (_, row) => row.categoryName || '-' },
|
|
||||||
{
|
{
|
||||||
title: '接单金额',
|
title: '接单金额',
|
||||||
width: 150,
|
key: 'reward',
|
||||||
|
width: '13%',
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<div className="cell-stack">
|
<div className="cell-stack">
|
||||||
<span>{formatMoney(row.rewardAmount)}</span>
|
<Typography.Text strong style={{ color: '#3f8600', fontSize: 13 }}>
|
||||||
|
{formatMoney(row.rewardAmount)}
|
||||||
|
</Typography.Text>
|
||||||
{row.unitPriceFen > 0 ? (
|
{row.unitPriceFen > 0 ? (
|
||||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
<Typography.Text type="secondary" style={{ fontSize: 11 }}>
|
||||||
按数量计价:{formatMoney(row.unitPriceFen)} × 数量
|
按件: {formatMoney(row.unitPriceFen)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -290,36 +314,56 @@ export default function ProductRulesPanel() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '押金',
|
title: '押金',
|
||||||
width: 120,
|
key: 'deposit',
|
||||||
render: (_, row) => formatMoney(row.requiredDepositAmount),
|
width: '9%',
|
||||||
|
render: (_, row) => (
|
||||||
|
<Typography.Text type={row.requiredDepositAmount > 0 ? undefined : 'secondary'}>
|
||||||
|
{formatMoney(row.requiredDepositAmount)}
|
||||||
|
</Typography.Text>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '匹配',
|
title: '匹配',
|
||||||
width: 130,
|
dataIndex: 'matchType',
|
||||||
render: (_, row) => (row.matchType === 'exact' ? '精确' : '包含'),
|
width: '7%',
|
||||||
|
render: (value) => (
|
||||||
|
<Tag color={value === 'exact' ? 'blue' : 'orange'} style={{ margin: 0 }}>
|
||||||
|
{value === 'exact' ? '精确' : '包含'}
|
||||||
|
</Tag>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
width: 150,
|
key: 'status',
|
||||||
|
width: '6%',
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<Space>
|
<Space direction="vertical" size={2}>
|
||||||
<Tag color={row.enabled ? 'green' : 'default'}>
|
<Switch
|
||||||
{row.enabled ? '启用' : '停用'}
|
size="small"
|
||||||
</Tag>
|
checked={row.enabled}
|
||||||
{row.autoCreate ? <Tag color="blue">自动创建</Tag> : null}
|
checkedChildren="启用"
|
||||||
{row.sharing?.enabled ? (
|
unCheckedChildren="停用"
|
||||||
<Tag color="purple">
|
onChange={(checked) => toggleRuleEnabled(row, checked)}
|
||||||
拼单 {formatMoney(row.sharing.unitReward)}/份
|
/>
|
||||||
</Tag>
|
<Space size={2} wrap>
|
||||||
) : null}
|
{row.autoCreate ? (
|
||||||
|
<Tag color="blue" style={{ fontSize: 10, margin: 0, padding: '0 4px' }}>
|
||||||
|
自动
|
||||||
|
</Tag>
|
||||||
|
) : null}
|
||||||
|
{row.sharing?.enabled ? (
|
||||||
|
<Tag color="purple" style={{ fontSize: 10, margin: 0, padding: '0 4px' }}>
|
||||||
|
拼单
|
||||||
|
</Tag>
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
width: 104,
|
width: '6%',
|
||||||
fixed: 'right',
|
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<Space size={0} onClick={(event) => event.stopPropagation()}>
|
<Space size={0} onClick={(event) => event.stopPropagation()}>
|
||||||
<Button
|
<Button
|
||||||
@@ -331,7 +375,7 @@ export default function ProductRulesPanel() {
|
|||||||
/>
|
/>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={`删除规则“${row.productName || row.ruleKey}”?`}
|
title={`删除规则“${row.productName || row.ruleKey}”?`}
|
||||||
description="删除后不会影响已创建的工单。"
|
description="删除后不会影响已创建工单。"
|
||||||
okText="删除"
|
okText="删除"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
okButtonProps={{ danger: true }}
|
okButtonProps={{ danger: true }}
|
||||||
@@ -353,13 +397,19 @@ export default function ProductRulesPanel() {
|
|||||||
return (
|
return (
|
||||||
<section className="platform-panel-stack">
|
<section className="platform-panel-stack">
|
||||||
<div className="product-rules-layout">
|
<div className="product-rules-layout">
|
||||||
|
{/* Left Form Card - 30% Width Proportional Split */}
|
||||||
<Card
|
<Card
|
||||||
className="product-rules-form-card"
|
className="product-rules-form-card"
|
||||||
title={editingRule ? `编辑物品规则 · ${editingRule.ruleKey}` : '新建物品规则'}
|
title={
|
||||||
|
<Space size={6}>
|
||||||
|
<FormOutlined style={{ color: '#1677ff' }} />
|
||||||
|
<span>{editingRule ? `编辑规则 · ${editingRule.ruleKey}` : '新建物品规则'}</span>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space size={4}>
|
||||||
{editingRule ? (
|
{editingRule ? (
|
||||||
<Button type="link" onClick={resetRuleForm}>
|
<Button type="link" size="small" onClick={resetRuleForm}>
|
||||||
取消编辑
|
取消编辑
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -378,7 +428,7 @@ export default function ProductRulesPanel() {
|
|||||||
id="product-rule-form"
|
id="product-rule-form"
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
className="worker-rule-form"
|
className="worker-rule-form-30"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
platform: 'kuaishou',
|
platform: 'kuaishou',
|
||||||
matchType: 'contains',
|
matchType: 'contains',
|
||||||
@@ -396,7 +446,7 @@ export default function ProductRulesPanel() {
|
|||||||
}}
|
}}
|
||||||
onFinish={saveRule}
|
onFinish={saveRule}
|
||||||
>
|
>
|
||||||
<div className="worker-rule-grid">
|
<div className="rule-form-grid-2col">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="规则标识"
|
label="规则标识"
|
||||||
name="ruleKey"
|
name="ruleKey"
|
||||||
@@ -407,11 +457,9 @@ export default function ProductRulesPanel() {
|
|||||||
const key = String(value || '').trim()
|
const key = String(value || '').trim()
|
||||||
if (
|
if (
|
||||||
!editingRule &&
|
!editingRule &&
|
||||||
(rulesQuery.data?.data.items || []).some(
|
allRules.some((rule) => rule.ruleKey === key)
|
||||||
(rule) => rule.ruleKey === key,
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return Promise.reject(new Error('规则标识已存在,请更换'))
|
return Promise.reject(new Error('标识已存在'))
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
},
|
},
|
||||||
@@ -420,21 +468,23 @@ export default function ProductRulesPanel() {
|
|||||||
>
|
>
|
||||||
<Input placeholder="skin-training" disabled={Boolean(editingRule)} />
|
<Input placeholder="skin-training" disabled={Boolean(editingRule)} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="来源" name="provider">
|
<Form.Item label="来源" name="provider">
|
||||||
<Input placeholder="留空通配,如 91kaquan" />
|
<Input placeholder="如 91kaquan" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="平台" name="platform">
|
<Form.Item label="平台" name="platform">
|
||||||
<Input placeholder="kuaishou" />
|
<Input placeholder="kuaishou" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="店铺" name="shopId">
|
<Form.Item label="店铺" name="shopId">
|
||||||
<Input placeholder="留空通配" />
|
<Input placeholder="留空通配" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="SKU" name="skuCode">
|
<Form.Item label="SKU" name="skuCode">
|
||||||
<Input placeholder="优先精确匹配" />
|
<Input placeholder="优先精确匹配" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="商品名" name="productName">
|
|
||||||
<Input placeholder="用于包含/精确匹配" />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="匹配方式" name="matchType">
|
<Form.Item label="匹配方式" name="matchType">
|
||||||
<Select
|
<Select
|
||||||
options={[
|
options={[
|
||||||
@@ -443,31 +493,35 @@ export default function ProductRulesPanel() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="分类" name="categoryId">
|
|
||||||
|
<Form.Item label="商品名称" name="productName" className="span-2">
|
||||||
|
<Input placeholder="用于包含/精确匹配商品" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item label="所属分类" name="categoryId">
|
||||||
<Select
|
<Select
|
||||||
allowClear
|
allowClear
|
||||||
|
placeholder="选择分类"
|
||||||
loading={categoriesQuery.isLoading}
|
loading={categoriesQuery.isLoading}
|
||||||
options={(categoriesQuery.data?.data.items || []).map(
|
options={(categoriesQuery.data?.data.items || []).map((item) => ({
|
||||||
(item) => ({
|
value: item.categoryId,
|
||||||
value: item.categoryId,
|
label: item.name,
|
||||||
label: item.name,
|
}))}
|
||||||
}),
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
label="计价方式"
|
<Form.Item label="计价方式" name="pricingMode">
|
||||||
name="pricingMode"
|
|
||||||
tooltip="按数量计价时,接单总价 = 单价 × 商品名称文字中的规格数量(如「指挥官秘钥15个」→ 15)"
|
|
||||||
>
|
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
|
optionType="button"
|
||||||
|
buttonStyle="solid"
|
||||||
className="full-width"
|
className="full-width"
|
||||||
options={[
|
options={[
|
||||||
{ value: 'fixed', label: '固定金额' },
|
{ value: 'fixed', label: '固定金额' },
|
||||||
{ value: 'unit', label: '按数量 × 单价' },
|
{ value: 'unit', label: '按件计价' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item noStyle shouldUpdate>
|
<Form.Item noStyle shouldUpdate>
|
||||||
{({ getFieldValue }) =>
|
{({ getFieldValue }) =>
|
||||||
getFieldValue('pricingMode') === 'unit' ? (
|
getFieldValue('pricingMode') === 'unit' ? (
|
||||||
@@ -475,182 +529,144 @@ export default function ProductRulesPanel() {
|
|||||||
label="单价"
|
label="单价"
|
||||||
name="unitPrice"
|
name="unitPrice"
|
||||||
rules={[{ required: true, message: '请填写单价' }]}
|
rules={[{ required: true, message: '请填写单价' }]}
|
||||||
extra="接单总价 = 单价 × 商品名称文字中的数量"
|
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0.01} step={1} addonAfter="元" className="full-width" />
|
||||||
min={0.01}
|
|
||||||
step={1}
|
|
||||||
addonAfter="元"
|
|
||||||
className="full-width"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : (
|
) : (
|
||||||
<Form.Item
|
<Form.Item label="接单金额" name="rewardAmount">
|
||||||
label="接单金额"
|
<InputNumber min={0} step={1} addonAfter="元" className="full-width" />
|
||||||
name="rewardAmount"
|
|
||||||
extra="可填 0,但接单金额为 0 的工单不能发布到大厅"
|
|
||||||
>
|
|
||||||
<InputNumber
|
|
||||||
min={0}
|
|
||||||
step={1}
|
|
||||||
addonAfter="元"
|
|
||||||
className="full-width"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="押金阈值" name="depositThresholdAmount">
|
|
||||||
<InputNumber
|
|
||||||
min={0}
|
|
||||||
step={10}
|
|
||||||
addonAfter="元"
|
|
||||||
className="full-width"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="固定押金" name="requiredDepositAmount">
|
|
||||||
<InputNumber
|
|
||||||
min={0}
|
|
||||||
step={10}
|
|
||||||
addonAfter="元"
|
|
||||||
className="full-width"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="排序" name="sortOrder">
|
<Form.Item label="排序" name="sortOrder">
|
||||||
<InputNumber min={0} max={9999} className="full-width" />
|
<InputNumber min={0} max={9999} className="full-width" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="启用" name="enabled" valuePropName="checked">
|
|
||||||
<Switch />
|
<Form.Item label="押金阈值" name="depositThresholdAmount">
|
||||||
|
<InputNumber min={0} step={10} addonAfter="元" className="full-width" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
label="自动创建"
|
<Form.Item label="固定押金" name="requiredDepositAmount">
|
||||||
name="autoCreate"
|
<InputNumber min={0} step={10} addonAfter="元" className="full-width" />
|
||||||
valuePropName="checked"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
label="启用拼单"
|
<Form.Item label="任务时限" name="timeoutMinutes">
|
||||||
name="sharingEnabled"
|
<InputNumber min={0} step={5} addonAfter="分钟" className="full-width" />
|
||||||
valuePropName="checked"
|
|
||||||
tooltip="开启后按下方总数量与单价生成拼单工单"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
label="默认任务时限"
|
<Form.Item label="超时策略" name="timeoutPolicy">
|
||||||
name="timeoutMinutes"
|
|
||||||
tooltip="自动创建的工单继承该时限,打手抢单后开始计时;0 表示不限时"
|
|
||||||
>
|
|
||||||
<InputNumber min={0} step={5} addonAfter="分钟" />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label="默认超时策略"
|
|
||||||
name="timeoutPolicy"
|
|
||||||
tooltip="reopen:释放押金退回大厅;cancel_release:取消退押金;cancel_deduct:取消扣押金"
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
options={[
|
options={[
|
||||||
{ value: 'reopen', label: '释放押金退回大厅' },
|
{ value: 'reopen', label: '释放押金退回大厅' },
|
||||||
{ value: 'cancel_release', label: '取消订单并退还押金' },
|
{ value: 'cancel_release', label: '取消订单退押金' },
|
||||||
{ value: 'cancel_deduct', label: '取消订单并扣除押金' },
|
{ value: 'cancel_deduct', label: '取消订单扣押金' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="form-switches-strip">
|
||||||
|
<Form.Item label="启用" name="enabled" valuePropName="checked">
|
||||||
|
<Switch size="small" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="自动创建" name="autoCreate" valuePropName="checked">
|
||||||
|
<Switch size="small" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="启用拼单" name="sharingEnabled" valuePropName="checked">
|
||||||
|
<Switch size="small" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Form.Item noStyle shouldUpdate>
|
<Form.Item noStyle shouldUpdate>
|
||||||
{({ getFieldValue }) =>
|
{({ getFieldValue }) =>
|
||||||
getFieldValue('sharingEnabled') ? (
|
getFieldValue('sharingEnabled') ? (
|
||||||
<Space size={16} wrap style={{ marginBottom: 16 }}>
|
<div className="sharing-box-inline">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="拼单总数量"
|
label="拼单数量"
|
||||||
name="sharingTotalQuantity"
|
name="sharingTotalQuantity"
|
||||||
rules={[{ required: true, message: '请填写总数量' }]}
|
rules={[{ required: true, message: '必填' }]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
min={1}
|
min={1}
|
||||||
max={100000}
|
max={100000}
|
||||||
addonAfter="份"
|
addonAfter="份"
|
||||||
|
className="full-width"
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
syncSharingRuleForm({
|
syncSharingRuleForm({ sharingTotalQuantity: Number(value) || 0 })
|
||||||
sharingTotalQuantity: Number(value) || 0,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="拼单单价"
|
label="拼单单价"
|
||||||
name="sharingUnitReward"
|
name="sharingUnitReward"
|
||||||
rules={[{ required: true, message: '请填写单价' }]}
|
rules={[{ required: true, message: '必填' }]}
|
||||||
tooltip="每个数量份对应的报酬,修改后总价自动重算"
|
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
min={0.01}
|
min={0.01}
|
||||||
step={1}
|
step={1}
|
||||||
addonAfter="元"
|
addonAfter="元"
|
||||||
|
className="full-width"
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
syncSharingRuleForm({
|
syncSharingRuleForm({ sharingUnitReward: Number(value) || 0 })
|
||||||
sharingUnitReward: Number(value) || 0,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="拼单总价"
|
label="拼单总价"
|
||||||
name="sharingTotalAmount"
|
name="sharingTotalAmount"
|
||||||
rules={[{ required: true, message: '请填写总价' }]}
|
rules={[{ required: true, message: '必填' }]}
|
||||||
tooltip="总价 = 单价 × 数量,修改总价会自动反推数量"
|
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
min={0.01}
|
min={0.01}
|
||||||
step={1}
|
step={1}
|
||||||
addonAfter="元"
|
addonAfter="元"
|
||||||
|
className="full-width"
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
syncSharingRuleForm({
|
syncSharingRuleForm({ sharingTotalAmount: Number(value) || 0 })
|
||||||
sharingTotalAmount: Number(value) || 0,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Space>
|
</div>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* 资料字段: 默认展开 4 行全部清晰可见,无内嵌滚动条 */}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="资料字段"
|
label="资料字段"
|
||||||
name="fieldsText"
|
name="fieldsText"
|
||||||
extra="每行一个字段:key:名称,下拉项用 # 分隔(如 system:系统#安卓,苹果)"
|
style={{ marginBottom: 0 }}
|
||||||
|
extra="格式:key:名称#选项1,选项2"
|
||||||
>
|
>
|
||||||
<Input.TextArea rows={2} />
|
<Input.TextArea
|
||||||
|
rows={4}
|
||||||
|
placeholder="gameId:游戏编号 gameNickname:游戏昵称 system:系统#安卓,苹果 serverZone:区服#QQ区,微信区"
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Right Table Card - 60% Width, Zero Horizontal Scrollbar */}
|
||||||
<Card
|
<Card
|
||||||
className="product-rules-list-card"
|
className="product-rules-list-card"
|
||||||
title={
|
title={
|
||||||
<div className="product-rules-list-heading">
|
<Space align="center" size={10}>
|
||||||
<span>物品规则</span>
|
<Typography.Text strong style={{ fontSize: 15 }}>
|
||||||
<Tabs
|
物品规则列表
|
||||||
className="product-rules-category-tabs"
|
</Typography.Text>
|
||||||
size="small"
|
<Tag color="blue" style={{ margin: 0 }}>
|
||||||
activeKey={categoryId ? String(categoryId) : 'all'}
|
{filteredRules.length} 条规则
|
||||||
onChange={(key) => setCategoryId(key === 'all' ? undefined : Number(key))}
|
</Tag>
|
||||||
items={[
|
</Space>
|
||||||
{ key: 'all', label: '全部' },
|
|
||||||
...(categoriesQuery.data?.data.items || []).map((item) => ({
|
|
||||||
key: String(item.categoryId),
|
|
||||||
label: item.name,
|
|
||||||
})),
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space size={8} wrap>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
allowClear
|
allowClear
|
||||||
placeholder="搜索规则标识/商品/SKU/店铺"
|
placeholder="搜索规则/商品/SKU/店铺"
|
||||||
style={{ width: 240 }}
|
style={{ width: 200 }}
|
||||||
value={keyword}
|
value={keyword}
|
||||||
onChange={(event) => setKeyword(event.target.value)}
|
onChange={(event) => setKeyword(event.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -661,23 +677,49 @@ export default function ProductRulesPanel() {
|
|||||||
>
|
>
|
||||||
刷新
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={resetRuleForm}
|
||||||
|
>
|
||||||
|
新建规则
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
>
|
>
|
||||||
|
{/* Category Tabs Bar */}
|
||||||
|
<div className="product-rules-category-tabs-bar">
|
||||||
|
<Tabs
|
||||||
|
activeKey={categoryId ? String(categoryId) : 'all'}
|
||||||
|
onChange={(key) => setCategoryId(key === 'all' ? undefined : Number(key))}
|
||||||
|
items={[
|
||||||
|
{ key: 'all', label: `全部 (${allRules.length})` },
|
||||||
|
...(categoriesQuery.data?.data.items || []).map((item) => {
|
||||||
|
const count = allRules.filter(
|
||||||
|
(r) => Number(r.categoryId || 0) === item.categoryId,
|
||||||
|
).length
|
||||||
|
return {
|
||||||
|
key: String(item.categoryId),
|
||||||
|
label: `${item.name}${count ? ` (${count})` : ''}`,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Table<WorkProductRule>
|
<Table<WorkProductRule>
|
||||||
rowKey="ruleId"
|
rowKey="ruleId"
|
||||||
loading={rulesQuery.isLoading}
|
loading={rulesQuery.isLoading}
|
||||||
dataSource={filteredRules}
|
dataSource={filteredRules}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
scroll={{ x: 1000, y: 'calc(100vh - 300px)' }}
|
|
||||||
rowClassName={(row) =>
|
rowClassName={(row) =>
|
||||||
editingRule?.ruleId === row.ruleId ? 'product-rule-row-active' : ''
|
editingRule?.ruleId === row.ruleId ? 'product-rule-row-active' : ''
|
||||||
}
|
}
|
||||||
onRow={(row) => ({
|
onRow={(row) => ({
|
||||||
onClick: () => editRule(row),
|
onClick: () => editRule(row),
|
||||||
title: '点击快速编辑',
|
title: '点击编辑此规则',
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -689,9 +731,10 @@ export default function ProductRulesPanel() {
|
|||||||
function formatRuleFields(fields: CollectField[]) {
|
function formatRuleFields(fields: CollectField[]) {
|
||||||
return fields
|
return fields
|
||||||
.map((field) => {
|
.map((field) => {
|
||||||
const options = Array.isArray(field.options) && field.options.length > 0
|
const options =
|
||||||
? `#${field.options.join(',')}`
|
Array.isArray(field.options) && field.options.length > 0
|
||||||
: ''
|
? `#${field.options.join(',')}`
|
||||||
|
: ''
|
||||||
return `${field.key}:${field.label}${options}`
|
return `${field.key}:${field.label}${options}`
|
||||||
})
|
})
|
||||||
.join('\n')
|
.join('\n')
|
||||||
|
|||||||
@@ -2496,89 +2496,120 @@ select {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 物品规则:左侧编辑表单 + 右侧可滚动列表 */
|
/* 物品规则:3:7 比例响应式双栏 (左侧 30% + 右侧 70%) */
|
||||||
.product-rules-layout {
|
.product-rules-layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-form-card {
|
.product-rules-form-card {
|
||||||
width: 560px;
|
flex: 0 0 calc(30% - 8px);
|
||||||
flex-shrink: 0;
|
width: calc(30% - 8px);
|
||||||
|
min-width: 360px;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 左侧表单一屏展示,不出现滚动条 */
|
/* 左侧表单彻底消除滚动条,紧凑舒适排版 */
|
||||||
.product-rules-form-card .ant-card-body {
|
.product-rules-form-card .ant-card-body {
|
||||||
|
padding: 12px 14px;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-form-card .worker-rule-form .ant-form-item {
|
.worker-rule-form-30 .rule-form-grid-2col {
|
||||||
margin-bottom: 14px;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-form-card .worker-rule-form .ant-form-item-label {
|
.worker-rule-form-30 .rule-form-grid-2col .span-2 {
|
||||||
padding-bottom: 2px;
|
grid-column: span 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-form-card .worker-rule-form .ant-input-textarea textarea {
|
.worker-rule-form-30 .ant-form-item {
|
||||||
min-height: 56px !important;
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .ant-form-item-label {
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .ant-form-item-label > label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #374151;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .form-switches-strip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
background: #f9fafb;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .form-switches-strip .ant-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .sharing-box-inline {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px dashed #cbd5e1;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-rule-form-30 .sharing-box-inline .ant-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-list-card {
|
.product-rules-list-card {
|
||||||
flex: 1;
|
flex: 0 0 calc(70% - 8px);
|
||||||
|
width: calc(70% - 8px);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
border-radius: 8px;
|
||||||
|
|
||||||
.product-rules-list-heading {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 20px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-rules-category-tabs {
|
|
||||||
min-width: 0;
|
|
||||||
transform: translateY(-6px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-rules-category-tabs .ant-tabs-nav {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-rules-category-tabs .ant-tabs-content-holder {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-list-card .ant-card-body {
|
.product-rules-list-card .ant-card-body {
|
||||||
max-height: calc(100vh - 150px);
|
padding: 12px 16px;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-list-card .ant-table-wrapper {
|
.product-rules-category-tabs-bar {
|
||||||
max-height: calc(100vh - 230px);
|
margin-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-rules-category-tabs-bar .ant-tabs-nav {
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rule-row-active > td {
|
.product-rule-row-active > td {
|
||||||
background: #e6f4ff !important;
|
background: #e6f4ff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1080px) {
|
||||||
.product-rules-layout {
|
.product-rules-layout {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-rules-form-card {
|
.product-rules-form-card,
|
||||||
|
.product-rules-list-card {
|
||||||
|
flex: 1 1 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.worker-rule-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
gap: 0 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.worker-page-head {
|
.worker-page-head {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|||||||
Reference in New Issue
Block a user