diff --git a/apps/admin-web/src/lib/storeCreate.ts b/apps/admin-web/src/lib/storeCreate.ts
index cc68ce3..c7a363e 100644
--- a/apps/admin-web/src/lib/storeCreate.ts
+++ b/apps/admin-web/src/lib/storeCreate.ts
@@ -14,6 +14,7 @@ export type StoreCreateForm = {
latitude?: number | null;
longitude?: number | null;
intro?: string;
+ benefitUsageRule?: string;
openTime?: string;
closeTime?: string;
openTime2?: string;
@@ -48,6 +49,7 @@ export function validateStoreCreateStep1(
| 'phone'
| 'address'
| 'intro'
+ | 'benefitUsageRule'
| 'openTime'
| 'closeTime'
| 'openTime2'
@@ -88,6 +90,9 @@ export function validateStoreCreateStep1(
const len = form.intro.trim().length;
if (len < 2 || len > 500) return '门店简介须为 2~500 字';
}
+ if (form.benefitUsageRule?.trim() && form.benefitUsageRule.trim().length > 1000) {
+ return '好客权益券使用规则最多 1000 字';
+ }
return null;
}
diff --git a/apps/admin-web/src/pages/StoresPage.tsx b/apps/admin-web/src/pages/StoresPage.tsx
index 697951f..50823c1 100644
--- a/apps/admin-web/src/pages/StoresPage.tsx
+++ b/apps/admin-web/src/pages/StoresPage.tsx
@@ -504,6 +504,7 @@ export default function StoresPage() {
}
: {}),
intro: values.intro?.trim() || undefined,
+ benefitUsageRule: values.benefitUsageRule?.trim() || undefined,
openTime: values.openTime?.trim() || '10:00',
closeTime: values.closeTime?.trim() || '22:00',
...(values.openTime2?.trim() && values.closeTime2?.trim()
@@ -585,6 +586,7 @@ export default function StoresPage() {
name: d.name,
phone: d.phone,
intro: d.intro,
+ benefitUsageRule: d.benefitUsageRule,
coverUrl: d.coverUrl,
address: d.address,
district: d.district,
@@ -688,6 +690,7 @@ export default function StoresPage() {
phone: v.phone,
coverUrl: v.coverUrl,
intro: v.intro,
+ benefitUsageRule: v.benefitUsageRule ?? null,
district: v.district,
address: v.address,
avgPrice: v.avgPrice,
@@ -797,7 +800,14 @@ export default function StoresPage() {
-
+
+
+
+
@@ -1031,6 +1041,13 @@ export default function StoresPage() {
+
+
+
diff --git a/apps/h5-partner/src/lib/storeDraft.ts b/apps/h5-partner/src/lib/storeDraft.ts
index 899f880..f3d5f89 100644
--- a/apps/h5-partner/src/lib/storeDraft.ts
+++ b/apps/h5-partner/src/lib/storeDraft.ts
@@ -22,6 +22,8 @@ export type StoreDraftForm = {
categoryParentId: string;
categoryId: string;
intro: string;
+ /** 好客权益券使用规则 */
+ benefitUsageRule: string;
coverUrl: string;
envPhotoUrls: string[];
contractUrl: string;
@@ -61,6 +63,7 @@ export const defaultStoreForm = (): StoreDraftForm => ({
categoryParentId: '',
categoryId: '',
intro: '',
+ benefitUsageRule: '',
coverUrl: '',
envPhotoUrls: ['', '', ''],
contractUrl: '',
@@ -155,6 +158,7 @@ export function validateStoreStep1(
| 'avgPrice'
| 'categoryId'
| 'intro'
+ | 'benefitUsageRule'
>,
): string | null {
if (!form.regionCodes || form.regionCodes.length < 3) return '请选择省 / 市 / 区县';
@@ -185,10 +189,13 @@ export function validateStoreStep1(
if (Number.isNaN(n) || n < 0) return '人均费用须为非负数字';
}
if (!form.categoryId.trim()) return '请选择店铺类型';
- if (form.intro.trim()) {
- const len = form.intro.trim().length;
- if (len < 2 || len > 500) return '门店简介须为 2~500 字';
- }
+ if (form.intro.trim()) {
+ const len = form.intro.trim().length;
+ if (len < 2 || len > 500) return '门店简介须为 2~500 字';
+ }
+ if (form.benefitUsageRule.trim().length > 1000) {
+ return '好客权益券使用规则最多 1000 字';
+ }
return null;
}
diff --git a/apps/h5-partner/src/pages/StoreCreatePage.tsx b/apps/h5-partner/src/pages/StoreCreatePage.tsx
index b639ffd..64d4cdc 100644
--- a/apps/h5-partner/src/pages/StoreCreatePage.tsx
+++ b/apps/h5-partner/src/pages/StoreCreatePage.tsx
@@ -536,6 +536,7 @@ export default function StoreCreatePage() {
categoryId: form.categoryId.trim(),
intro: form.intro.trim() || undefined,
+ benefitUsageRule: form.benefitUsageRule.trim() || undefined,
coverUrl: form.coverUrl.trim() || undefined,
@@ -936,6 +937,26 @@ export default function StoreCreatePage() {
+
+
diff --git a/apps/h5-partner/src/pages/StoreDetailPage.tsx b/apps/h5-partner/src/pages/StoreDetailPage.tsx
index 5477446..8e83366 100644
--- a/apps/h5-partner/src/pages/StoreDetailPage.tsx
+++ b/apps/h5-partner/src/pages/StoreDetailPage.tsx
@@ -45,6 +45,7 @@ export default function StoreDetailPage() {
phone: '',
address: '',
intro: '',
+ benefitUsageRule: '',
latitude: '',
longitude: '',
});
@@ -66,6 +67,7 @@ export default function StoreDetailPage() {
phone: String(data.phone || ''),
address: String(data.address || ''),
intro: String(data.intro || ''),
+ benefitUsageRule: String(data.benefitUsageRule || ''),
latitude: data.latitude != null && data.latitude !== '' ? String(data.latitude) : '',
longitude: data.longitude != null && data.longitude !== '' ? String(data.longitude) : '',
});
@@ -162,6 +164,7 @@ export default function StoreDetailPage() {
phone: form.phone.trim(),
address: form.address.trim(),
intro: form.intro.trim(),
+ benefitUsageRule: form.benefitUsageRule.trim() || null,
...(form.latitude.trim() && form.longitude.trim()
? {
latitude: Number(form.latitude),
@@ -396,6 +399,20 @@ export default function StoreDetailPage() {
{form.intro.length} / 500
+
diff --git a/apps/mini-user/src/pages/store-detail/index.tsx b/apps/mini-user/src/pages/store-detail/index.tsx
index 789b6a5..3c0efec 100644
--- a/apps/mini-user/src/pages/store-detail/index.tsx
+++ b/apps/mini-user/src/pages/store-detail/index.tsx
@@ -29,6 +29,7 @@ type Store = {
district?: string;
phone?: string;
intro?: string | null;
+ benefitUsageRule?: string | null;
coverUrl?: string | null;
carouselUrls?: string[] | null;
media?: StoreMedia[] | null;
@@ -173,6 +174,7 @@ export default function StoreDetailPage() {
]);
const intro = store.intro?.trim() || '';
+ const benefitRule = store.benefitUsageRule?.trim() || '';
function previewEnv(index: number) {
if (!envPhotos.length) return;
@@ -248,6 +250,13 @@ export default function StoreDetailPage() {
) : null}
+ {benefitRule ? (
+
+ 好客权益券使用规则
+ {benefitRule}
+
+ ) : null}
+
{envPhotos.length > 0 ? (
店内环境
diff --git a/server/dukang-api/prisma/schema.prisma b/server/dukang-api/prisma/schema.prisma
index 0721a49..8db886b 100644
--- a/server/dukang-api/prisma/schema.prisma
+++ b/server/dukang-api/prisma/schema.prisma
@@ -1025,6 +1025,8 @@ model Store {
latitude Decimal? @db.Decimal(10, 7)
longitude Decimal? @db.Decimal(10, 7)
intro String? @db.Text
+ /** 好客权益券使用规则(C 端门店详情展示) */
+ benefitUsageRule String? @map("benefit_usage_rule") @db.Text
coverResourceId BigInt? @map("cover_resource_id") @db.UnsignedBigInt
avgPrice Decimal? @map("avg_price") @db.Decimal(10, 2)
rating Decimal? @db.Decimal(3, 2)
diff --git a/server/dukang-api/src/modules/ops/admin-stores.service.ts b/server/dukang-api/src/modules/ops/admin-stores.service.ts
index e9d3e8d..394c91f 100644
--- a/server/dukang-api/src/modules/ops/admin-stores.service.ts
+++ b/server/dukang-api/src/modules/ops/admin-stores.service.ts
@@ -214,6 +214,9 @@ export class AdminStoresService {
...(dto.name !== undefined ? { name: dto.name } : {}),
...(dto.phone !== undefined ? { phone: dto.phone } : {}),
...(dto.intro !== undefined ? { intro: dto.intro } : {}),
+ ...(dto.benefitUsageRule !== undefined
+ ? { benefitUsageRule: String(dto.benefitUsageRule).trim() || null }
+ : {}),
...(dto.address !== undefined ? { address: dto.address } : {}),
...(dto.district !== undefined ? { district: dto.district } : {}),
...(dto.settlementRate !== undefined ? { settlementRate: dto.settlementRate } : {}),
@@ -305,6 +308,15 @@ export class AdminStoresService {
]);
if (!hoursCheck.ok) throw new BadRequestException(hoursCheck.message);
+ const intro = dto.intro?.trim() || null;
+ if (intro && (intro.length < 2 || intro.length > 500)) {
+ throw new BadRequestException('门店简介须为 2~500 字');
+ }
+ const benefitUsageRule = dto.benefitUsageRule?.trim() || null;
+ if (benefitUsageRule && benefitUsageRule.length > 1000) {
+ throw new BadRequestException('好客权益券使用规则最多 1000 字');
+ }
+
const store = await this.prisma.store.create({
data: {
cityId: city.id,
@@ -317,7 +329,8 @@ export class AdminStoresService {
cityName: dto.city ?? city.name,
district: dto.district ?? '',
address: dto.address,
- intro: dto.intro ?? null,
+ intro,
+ benefitUsageRule,
avgPrice: dto.avgPrice ?? null,
openTime,
closeTime,
diff --git a/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts b/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts
index c3e63c7..b620bf2 100644
--- a/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts
+++ b/server/dukang-api/src/modules/ops/dto/admin-mutate.dto.ts
@@ -69,6 +69,10 @@ export class CreateStoreDto {
@IsString()
intro?: string;
+ @IsOptional()
+ @IsString()
+ benefitUsageRule?: string;
+
@IsOptional()
@IsString()
coverUrl?: string;
@@ -138,6 +142,10 @@ export class UpdateStoreDto {
@IsString()
intro?: string;
+ @IsOptional()
+ @IsString()
+ benefitUsageRule?: string;
+
@IsOptional()
@IsString()
coverUrl?: string;
diff --git a/server/dukang-api/src/modules/store/store.service.ts b/server/dukang-api/src/modules/store/store.service.ts
index c909460..8782968 100644
--- a/server/dukang-api/src/modules/store/store.service.ts
+++ b/server/dukang-api/src/modules/store/store.service.ts
@@ -304,6 +304,11 @@ export class StoreService {
if (introRaw && (introRaw.length < 2 || introRaw.length > 500)) {
throw new BadRequestException('门店简介须为 2~500 字');
}
+ const benefitUsageRuleRaw =
+ body.benefitUsageRule != null ? String(body.benefitUsageRule).trim() : '';
+ if (benefitUsageRuleRaw.length > 1000) {
+ throw new BadRequestException('好客权益券使用规则最多 1000 字');
+ }
const latitude = parseOptionalCoord(body.latitude, 'lat');
const longitude = parseOptionalCoord(body.longitude, 'lng');
@@ -323,6 +328,7 @@ export class StoreService {
district: String(body.district ?? ''),
address: String(body.address),
intro: introRaw || null,
+ benefitUsageRule: benefitUsageRuleRaw || null,
avgPrice: avgPriceRaw,
openTime,
closeTime,
@@ -518,6 +524,8 @@ export class StoreService {
const phone = body.phone !== undefined ? String(body.phone).trim() : undefined;
const address = body.address !== undefined ? String(body.address).trim() : undefined;
const introRaw = body.intro !== undefined ? String(body.intro).trim() : undefined;
+ const benefitUsageRuleRaw =
+ body.benefitUsageRule !== undefined ? String(body.benefitUsageRule).trim() : undefined;
const latitude =
body.latitude !== undefined ? parseOptionalCoord(body.latitude, 'lat') : undefined;
const longitude =
@@ -531,6 +539,9 @@ export class StoreService {
if (introRaw && (introRaw.length < 2 || introRaw.length > 500)) {
throw new BadRequestException('门店简介须为 2~500 字');
}
+ if (benefitUsageRuleRaw !== undefined && benefitUsageRuleRaw.length > 1000) {
+ throw new BadRequestException('好客权益券使用规则最多 1000 字');
+ }
if (
(latitude !== undefined || longitude !== undefined) &&
(latitude == null || longitude == null)
@@ -552,6 +563,9 @@ export class StoreService {
: {}),
...(hasCoordsUpdate ? { latitude, longitude } : {}),
...(introRaw !== undefined ? { intro: introRaw || null } : {}),
+ ...(benefitUsageRuleRaw !== undefined
+ ? { benefitUsageRule: benefitUsageRuleRaw || null }
+ : {}),
...(resubmitAudit
? {
auditStatus: 'PENDING' as const,