| | |
| | | "userPhone": "用户电话", |
| | | "role": "角色", |
| | | "accountStatus": "账号状态", |
| | | "userNamePlaceholder": "请输入用户姓名", |
| | | "userPhonePlaceholder": "请输入用户电话", |
| | | "rolePlaceholder": "请选择角色", |
| | | "accountStatusPlaceholder": "请选择状态" |
| | | "userNamePlaceholder": "请输入", |
| | | "userPhonePlaceholder": "请输入", |
| | | "rolePlaceholder": "请选择", |
| | | "accountStatusPlaceholder": "请选择" |
| | | }, |
| | | "table": { |
| | | "index": "序号", |
| | |
| | | "search": { |
| | | "userName": "用户名称", |
| | | "userPhone": "用户电话", |
| | | "enterUserName": "请输入用户名称", |
| | | "enterUserPhone": "请输入用户电话" |
| | | "enterUserName": "请输入", |
| | | "enterUserPhone": "请输入" |
| | | } |
| | | } |
| | | }, |
| | |
| | | "role": "所属角色" |
| | | }, |
| | | "placeholder": { |
| | | "userName": "请输入用户姓名", |
| | | "userName": "请输入", |
| | | "number": "系统自动生成", |
| | | "loginAccount": "请输入登录账号", |
| | | "phoneNumber": "请输入联系电话", |
| | | "initialPassword": "请输入初始密码", |
| | | "role": "请选择角色" |
| | | "loginAccount": "请输入", |
| | | "phoneNumber": "请输入", |
| | | "initialPassword": "请输入", |
| | | "role": "请选择" |
| | | }, |
| | | "validation": { |
| | | "userNameRequired": "请输入用户姓名", |
| | |
| | | } |
| | | |
| | | :deep(.n-card__content) { |
| | | padding: 24px; |
| | | padding:16px 24px; |
| | | } |
| | | |
| | | .section-header { |
| | |
| | | <script setup lang="ts"> |
| | | <script setup lang="tsx"> |
| | | import { useBoolean } from '@/hooks' |
| | | import { addOpenCity, editOpenCity, getRegionCascader } from '@/service/api/operations' |
| | | |
| | |
| | | const { |
| | | modalName = '', |
| | | } = defineProps<Props>() |
| | | |
| | | const emit = defineEmits<{ |
| | | success: [] |
| | | open: [] |
| | | close: [] |
| | | }>() |
| | | |
| | | const isRoleSelectOpen = ref(false) |
| | | |
| | | const dialog = useDialog() |
| | | const { bool: modalVisible, setTrue: showModal, setFalse: hiddenModal } = useBoolean(false) |
| | |
| | | |
| | | <template> |
| | | <n-modal |
| | | v-model:show="modalVisible" :mask-closable="false" preset="card" title="开通城市" class="w-400px" |
| | | v-model:show="modalVisible" |
| | | :segmented="{ |
| | | content: true, |
| | | action: true, |
| | | }" |
| | | :content-style="{ |
| | | padding: '16px 24px 0px 24px', |
| | | }" |
| | | :mask-closable="false" preset="card" title="开通城市" class="w-400px table-modal" |
| | | > |
| | | <n-form |
| | | ref="formRef" :rules="rules" :model="formModel" :disabled="modalType === 'view'" |
| | |
| | | > |
| | | <n-form-item label="开通城市" path="pca"> |
| | | <n-cascader |
| | | v-model:value="formModel.pca" |
| | | :options="pcaOptions" |
| | | value-field="code" |
| | | label-field="name" |
| | | check-strategy="all" |
| | | @update:value="handlePcaChange" |
| | | /> |
| | | v-model:value="formModel.pca" :options="pcaOptions" value-field="code" label-field="name" |
| | | check-strategy="all" @update:value="handlePcaChange" |
| | | @update:show="isRoleSelectOpen = $event" |
| | | > |
| | | <template #arrow> |
| | | <img |
| | | src="/src/assets/element-img/select-down.png" |
| | | class="arrow-icon" |
| | | :class="{ 'arrow-icon--open': isRoleSelectOpen }" |
| | | style="width: 16px;height: 16px;" |
| | | alt="arrow" |
| | | > |
| | | </template> |
| | | </n-cascader> |
| | | </n-form-item> |
| | | <n-form-item label="启用禁用状态" path="status" required> |
| | | <n-form-item label="启用禁用状态" path="status" required label-placement="left"> |
| | | <n-switch v-model:value="formModel.status" :checked-value="1" :unchecked-value="0" /> |
| | | </n-form-item> |
| | | </n-form> |
| | |
| | | </template> |
| | | </n-modal> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | :deep(.table-modal .n-card__content) { |
| | | padding: 16px 24px 0 24px !important; |
| | | } |
| | | </style> |
| | |
| | | |
| | | const dialog = useDialog() |
| | | const message = useMessage() |
| | | const isRoleSelectOpen = ref(false) |
| | | |
| | | const initialModel = { |
| | | cityName: '', |
| | |
| | | key: 'createTime', |
| | | ellipsis: true, |
| | | resizable: true, |
| | | width: 280, |
| | | }, |
| | | { |
| | | title: '开通城市', |
| | | key: 'city', |
| | | resizable: true, |
| | | width: 280, |
| | | render: (row) => { |
| | | if (row.provinceCode === row.cityCode) { |
| | | return `${row.provinceName || ''}` |
| | |
| | | { |
| | | title: '状态', |
| | | key: 'status', |
| | | width: 80, |
| | | resizable: true, |
| | | render: (row) => { |
| | | return row.status === 1 ? '启用' : '禁用' |
| | | return ( |
| | | <NTag |
| | | round |
| | | bordered={false} |
| | | style={{ |
| | | borderRadius: '4px', |
| | | border: 'none', |
| | | color: row.status === 1 ? '#0BB52D' : '#666666', |
| | | backgroundColor: row.status === 1 ? '#DCF5DD' : 'rgba(23, 31, 38, 0.05)', |
| | | }} |
| | | > |
| | | {row.status === 1 ? '启用' : '禁用'} |
| | | </NTag> |
| | | ) |
| | | }, |
| | | }, |
| | | { |
| | |
| | | unchecked-value={0} |
| | | v-slots={{ |
| | | checked: () => '启用', |
| | | unchecked: () => '禁用' |
| | | unchecked: () => '禁用', |
| | | }} |
| | | onUpdate:value={() => handleChangeStatus(row)} |
| | | > |
| | |
| | | { |
| | | label: '城市', |
| | | path: 'cityName', |
| | | render: () => <n-input v-model:value={model.value.cityName} placeholder="请输入城市名称" />, |
| | | render: () => <n-input v-model:value={model.value.cityName} placeholder="请输入" />, |
| | | }, |
| | | { |
| | | label: '状态', |
| | | path: 'status', |
| | | render: () => <n-select v-model:value={model.value.status} options={options} placeholder="请选择状态" clearable />, |
| | | render: () => ( |
| | | <n-select |
| | | v-model:value={model.value.status} |
| | | options={options} |
| | | placeholder="请选择" |
| | | onUpdate:show={val => isRoleSelectOpen.value = val} |
| | | clearable |
| | | > |
| | | {{ |
| | | arrow: () => ( |
| | | <img |
| | | src="/src/assets/element-img/select-down.png" |
| | | class={`arrow-icon ${isRoleSelectOpen.value ? 'arrow-icon--open' : ''}`} |
| | | style={{ width: '16px', height: '16px' }} |
| | | alt="arrow" |
| | | /> |
| | | ), |
| | | }} |
| | | </n-select> |
| | | ), |
| | | }, |
| | | ]) |
| | | |
| | |
| | | }, |
| | | onNegativeClick: () => { |
| | | row.status = row.status === 1 ? 0 : 1 |
| | | } |
| | | }, |
| | | }) |
| | | } |
| | | |
| | |
| | | <template #header> |
| | | <n-flex v-permission="4011" justify="flex-end"> |
| | | <NButton type="primary" secondary @click="modalRef.openModal('add')"> |
| | | 新增城市 |
| | | 新增 |
| | | </NButton> |
| | | </n-flex> |
| | | </template> |
| | | <div class="flex-1 flex flex-col h-full"> |
| | | <n-data-table class="flex-1" :columns="columns" :data="listData" :loading="loading" flex-height |
| | | :bordered="false" :header-height="18" :row-height="18" /> |
| | | <Pagination :count="count" :page="pageNum" :page-size="pageSize" class="robotaxi-pagination mt-12px" |
| | | @change="changePage" /> |
| | | <n-data-table |
| | | class="flex-1" :columns="columns" :data="listData" :loading="loading" flex-height |
| | | :bordered="false" :scroll-x="1020" :header-height="18" :row-height="18" |
| | | /> |
| | | <Pagination |
| | | :count="count" :page="pageNum" :page-size="pageSize" class="robotaxi-pagination mt-12px" |
| | | @change="changePage" |
| | | /> |
| | | </div> |
| | | |
| | | <TableModal ref="modalRef" modal-name="开通城市" @success="handleSearch" /> |
| | |
| | | width: 180, |
| | | resizable: true, |
| | | render: (row) => { |
| | | return row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-' |
| | | return row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-' |
| | | }, |
| | | }, |
| | | { |
| | |
| | | width: 180, |
| | | resizable: true, |
| | | render: (row) => { |
| | | return row.applyTime ? dayjs(row.applyTime).format("YYYY/MM/DD HH:mm:ss") : "-"; |
| | | return row.applyTime ? dayjs(row.applyTime).format("YYYY/MM/DD HH:mm") : "-"; |
| | | } |
| | | }, |
| | | { |
| | |
| | | width: 160, |
| | | resizable: true, |
| | | render: (row) => { |
| | | return row.auditTime ? dayjs(row.auditTime).format("YYYY/MM/DD HH:mm:ss") : "-"; |
| | | return row.auditTime ? dayjs(row.auditTime).format("YYYY/MM/DD HH:mm") : "-"; |
| | | } |
| | | }, |
| | | { |
| | |
| | | minWidth: 220, |
| | | ellipsis: true, |
| | | resizable: true, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') || '-'}</span>, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm') || '-'}</span>, |
| | | }, |
| | | { |
| | | title: t('accountManagement.table.remark'), |
| | |
| | | width: 180, |
| | | ellipsis: true, |
| | | resizable: true, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') || '-'}</span>, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm') || '-'}</span>, |
| | | }, |
| | | { |
| | | title: t('permissionGroup.table.remark'), |
| | |
| | | width: 180, |
| | | ellipsis: true, |
| | | resizable: true, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') || '-'}</span>, |
| | | render: row => <span>{dayjs(row.createTime).format('YYYY/MM/DD HH:mm') || '-'}</span>, |
| | | }, |
| | | { |
| | | title: t('roleManagement.table.remark'), |
| | |
| | | width: 180, |
| | | align: 'left', |
| | | resizable: true, |
| | | render: row => row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-', |
| | | render: row => row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-', |
| | | }, |
| | | { |
| | | title: '操作', |
| | |
| | | import BatchSendModal from './BatchSendModal.vue' |
| | | import Pagination from '@/components/common/Pagination.vue' |
| | | import { deleteCouponById, fetchCouponList, sendCoupon } from '@/service/api/coupon' |
| | | import dayjs from 'dayjs' |
| | | |
| | | const router = useRouter() |
| | | const message = useMessage() |
| | |
| | | |
| | | const columns = computed<DataTableColumns<any>>(() => [ |
| | | { title: '序号', key: 'id', width: 80, align: 'center', resizable: true, render: (_, index) => (currentPage.value - 1) * pageSize.value + index + 1 }, |
| | | { title: '添加时间', key: 'createTime', width: 180, ellipsis: true, resizable: true }, |
| | | { title: '添加时间', key: 'createTime', width: 180, ellipsis: true, resizable: true, render: row => row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-' }, |
| | | { title: '优惠券名称', key: 'couponName', width: 400, ellipsis: true, resizable: true }, |
| | | { |
| | | title: '优惠券类型', |
| | |
| | | :show="show" |
| | | :mask-closable="false" |
| | | preset="card" |
| | | :title="mode === 'add' ? '添加广告' : mode === 'edit' ? '编辑广告' : '查看广告'" |
| | | :title="mode === 'add' ? '新增广告' : mode === 'edit' ? '编辑广告' : '广告详情'" |
| | | class="banner-modal" |
| | | style="width: 400px;" |
| | | :auto-focus="false" |
| | |
| | | import { deleteBanner, fetchBannerPageList, updateBanner } from '@/service/api/banner' |
| | | import type { Banner } from '@/service/api/banner' |
| | | import { useBoolean } from '@/hooks' |
| | | import dayjs from 'dayjs' |
| | | |
| | | const message = useMessage() |
| | | const dialog = useDialog() |
| | |
| | | key: 'bannerTitle', |
| | | width: 150, |
| | | }, |
| | | { |
| | | title: '排序', |
| | | key: 'sort', |
| | | width: 80, |
| | | render: row => row.sort ?? '-', |
| | | }, |
| | | // { |
| | | // title: '排序', |
| | | // key: 'sort', |
| | | // width: 80, |
| | | // render: row => row.sort ?? '-', |
| | | // }, |
| | | { |
| | | title: '显示时间', |
| | | key: 'time', |
| | | width: 240, |
| | | width: 420, |
| | | render: (row) => { |
| | | return `${row.startTime} 至 ${row.endTime}` |
| | | }, |
| | |
| | | ) |
| | | }, |
| | | }, |
| | | { |
| | | title: '跳转类型', |
| | | key: 'jumpType', |
| | | width: 120, |
| | | render: (row) => { |
| | | const map: Record<number, string> = { |
| | | 1: '小程序内页面', |
| | | 2: '小程序地址', |
| | | 3: '网页地址', |
| | | } |
| | | return map[row.jumpType] || '未知' |
| | | }, |
| | | }, |
| | | // { |
| | | // title: '跳转类型', |
| | | // key: 'jumpType', |
| | | // width: 120, |
| | | // render: (row) => { |
| | | // const map: Record<number, string> = { |
| | | // 1: '小程序内页面', |
| | | // 2: '小程序地址', |
| | | // 3: '网页地址', |
| | | // } |
| | | // return map[row.jumpType] || '未知' |
| | | // }, |
| | | // }, |
| | | { |
| | | title: '跳转地址', |
| | | key: 'jumpTarget', |
| | |
| | | title: '创建时间', |
| | | key: 'createTime', |
| | | width: 180, |
| | | render: row => row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-', |
| | | }, |
| | | { |
| | | title: '操作', |
| | |
| | | |
| | | .tab-item:hover { |
| | | color: #0068FF; |
| | | border-color: #0068FF; |
| | | /* border-color: #0068FF; */ |
| | | } |
| | | |
| | | .active-tab { |
| | |
| | | } |
| | | } |
| | | |
| | | function handleCancel() { |
| | | |
| | | } |
| | | |
| | | async function loadContent(tabKey: string) { |
| | | try { |
| | | loading.value = true |
| | |
| | | </div> |
| | | |
| | | <div v-permission="30211" class="footer flex justify-end " style="background-color: white; padding: 16px 24px; border-radius: 8px; box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);"> |
| | | <n-button style="padding: 8px 24px; border-radius: 4px; font-size: 14px;margin-right: 12px;" @click="handleCancel"> |
| | | 取消 |
| | | </n-button> |
| | | <n-button type="primary" style="padding: 8px 24px; border-radius: 4px; font-size: 14px;" @click="handleSave"> |
| | | 保存 |
| | | </n-button> |
| | |
| | | type="textarea" |
| | | placeholder="请输入手机号,多个账号请换行输入" |
| | | :maxlength="10000" |
| | | show-count |
| | | style="height: 80px;" |
| | | :autosize="{ |
| | | minRows: 1, |
| | |
| | | { |
| | | label: '邀请码', |
| | | path: 'invitationCode', |
| | | render: () => <n-input v-model:value={model.value.invitationCode} placeholder="请输入邀请码" clearable />, |
| | | render: () => <n-input v-model:value={model.value.invitationCode} placeholder="请输入" clearable />, |
| | | }, |
| | | { |
| | | label: '绑定账号', |
| | | path: 'bindAccount', |
| | | render: () => <n-input v-model:value={model.value.bindAccount} placeholder="请输入绑定账号" clearable />, |
| | | render: () => <n-input v-model:value={model.value.bindAccount} placeholder="请输入" clearable />, |
| | | }, |
| | | ]) |
| | | |
| | |
| | | resizable: true, |
| | | render: row => ( |
| | | <span> |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-'} |
| | | {' '} |
| | | </span> |
| | | ), |
| | |
| | | resizable: true, |
| | | render: row => ( |
| | | <span> |
| | | {row.bindTime ? dayjs(row.bindTime).format('YYYY/MM/DD HH:mm:ss') : '-'} |
| | | {row.bindTime ? dayjs(row.bindTime).format('YYYY/MM/DD HH:mm') : '-'} |
| | | {' '} |
| | | </span> |
| | | ), |
| | |
| | | width: 140, |
| | | fixed: 'right', |
| | | render: row => ( |
| | | <div class="flex justify-center"> |
| | | <div class="flex justify-start"> |
| | | <NButton |
| | | text |
| | | type="primary" |
| | |
| | | strong |
| | | @click="handleGenerate" |
| | | > |
| | | 新增邀请码 |
| | | 生成邀请码 |
| | | </NButton> |
| | | </n-flex> |
| | | </n-flex> |
| | |
| | | require-mark-placement="left" |
| | | > |
| | | <!-- 新增模式:多行输入 --> |
| | | <NFormItem v-if="mode === 'add'" label="白名单账号" path="phones"> |
| | | <NFormItem v-if="mode === 'add'" label="邀请手机号" path="phones"> |
| | | <NInput |
| | | v-model:value="formModel.phones" |
| | | type="textarea" |
| | |
| | | </NFormItem> |
| | | |
| | | <!-- 编辑模式:单行输入 --> |
| | | <NFormItem v-if="mode === 'edit'" label="白名单账号" path="account"> |
| | | <NFormItem v-if="mode === 'edit'" label="邀请手机号" path="account"> |
| | | <NInput |
| | | v-model:value="formModel.account" |
| | | placeholder="请输入手机号" |
| | |
| | | { |
| | | label: '白名单账号', |
| | | path: 'account', |
| | | render: () => <n-input v-model:value={model.value.account} placeholder="请输入白名单账号" />, |
| | | render: () => <n-input v-model:value={model.value.account} placeholder="请输入" />, |
| | | }, |
| | | { |
| | | label: '来源', |
| | |
| | | v-model:value={model.value.whitelistSource} |
| | | options={sourceOptions} |
| | | clearable |
| | | placeholder="请选择来源" |
| | | placeholder="请选择" |
| | | onUpdate:show={(value: boolean) => isSourceSelectOpen.value = value} |
| | | > |
| | | {{ |
| | |
| | | v-model:value={model.value.status} |
| | | options={statusOptions} |
| | | clearable |
| | | placeholder="请选择冻结状态" |
| | | placeholder="请选择" |
| | | onUpdate:show={(value: boolean) => isStatusSelectOpen.value = value} |
| | | |
| | | > |
| | |
| | | resizable: true, |
| | | render: row => ( |
| | | <span> |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-'} |
| | | {' '} |
| | | </span> |
| | | ), |
| | |
| | | render: (row) => { |
| | | const isNormal = row.status === 1 || row.status === true |
| | | return ( |
| | | <div class="flex justify-center gap-3"> |
| | | <div class="flex justify-start gap-3"> |
| | | <span |
| | | v-permission="30125" |
| | | style={{ color: isNormal ? '#0068FF' : '#ccc', cursor: isNormal ? 'pointer' : 'not-allowed' }} |
| | |
| | | strong |
| | | @click="handleAdd" |
| | | > |
| | | 新增白名单 |
| | | 新增 |
| | | </NButton> |
| | | </n-flex> |
| | | </n-flex> |
| | |
| | | { |
| | | label: '操作人', |
| | | path: 'operationName', |
| | | render: () => <n-input v-model:value={model.value.operationName} placeholder="请输入操作人" />, |
| | | render: () => <n-input v-model:value={model.value.operationName} placeholder="请输入" />, |
| | | }, |
| | | { |
| | | label: '操作类型', |
| | |
| | | v-model:value={model.value.operationType} |
| | | options={operationTypeOptions} |
| | | clearable |
| | | placeholder="请选择操作类型" |
| | | placeholder="请选择" |
| | | onUpdate:show={(value: boolean) => isOperationTypeSelectOpen.value = value} |
| | | > |
| | | {{ |
| | |
| | | resizable: true, |
| | | render: row => ( |
| | | <span> |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} |
| | | {row.createTime ? dayjs(row.createTime).format('YYYY/MM/DD HH:mm') : '-'} |
| | | {' '} |
| | | </span> |
| | | ), |