refactor: 四端完成 Options API → script setup + vuex → pinia 迁移

- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup>
- 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录)
- util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入
- 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md)
- 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API
- 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
This commit is contained in:
lifenlong
2026-10-13 07:06:59 +08:00
parent 870bacdd8c
commit 88fc1b0b2a
674 changed files with 71220 additions and 69943 deletions

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -90,74 +90,74 @@
</div>
</template>
<script>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { getUserRecharge } from "@/api/member";
export default {
name: "recharge",
data() {
return {
loading: true,
searchForm: {
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
},
selectDate: null,
data: [],
total: 0,
};
},
methods: {
rechargeWayText(way) {
if (way === "ALIPAY") return "支付宝";
if (way === "WECHAT") return "微信";
if (way === "BANK_TRANSFER") return "线下转账";
return "";
},
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getDataList();
},
changePageSize(v) {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getDataList();
},
selectDateRange(v) {
if (v && v.length === 2) {
this.searchForm.startDate = v[0];
this.searchForm.endDate = v[1];
} else {
this.searchForm.startDate = "";
this.searchForm.endDate = "";
}
},
getDataList() {
this.loading = true;
getUserRecharge(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
},
mounted() {
this.init();
},
};
defineOptions({ name: "recharge" });
// 模板 el-form 的 ref(原 ref="searchForm",与 data 同名会互相覆盖,改名为 searchFormRef)
const searchFormRef = ref(null);
const table = ref(null);
const loading = ref(true);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
});
const selectDate = ref(null);
const data = ref([]);
const total = ref(0);
function rechargeWayText(way) {
if (way === "ALIPAY") return "支付宝";
if (way === "WECHAT") return "微信";
if (way === "BANK_TRANSFER") return "线下转账";
return "";
}
function init() {
getDataList();
}
function changePage(v) {
searchForm.pageNumber = v;
getDataList();
}
function changePageSize(v) {
searchForm.pageNumber = 1;
searchForm.pageSize = v;
getDataList();
}
function handleSearch() {
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
getDataList();
}
function selectDateRange(v) {
if (v && v.length === 2) {
searchForm.startDate = v[0];
searchForm.endDate = v[1];
} else {
searchForm.startDate = "";
searchForm.endDate = "";
}
}
function getDataList() {
loading.value = true;
getUserRecharge(searchForm).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
onMounted(() => {
init();
});
</script>

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -85,75 +85,75 @@
</div>
</template>
<script>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { getUserWallet } from "@/api/member";
export default {
name: "walletLog",
data() {
return {
loading: true,
searchForm: {
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
},
selectDate: null,
data: [],
total: 0,
};
},
methods: {
serviceTypeText(type) {
if (type === "WALLET_WITHDRAWAL") return "余额提现";
if (type === "WALLET_PAY") return "余额支付";
if (type === "WALLET_REFUND") return "余额退款";
if (type === "WALLET_RECHARGE") return "余额充值";
return "佣金提成";
},
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getDataList();
},
changePageSize(v) {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getDataList();
},
selectDateRange(v) {
if (v && v.length === 2) {
this.searchForm.startDate = v[0];
this.searchForm.endDate = v[1];
} else {
this.searchForm.startDate = "";
this.searchForm.endDate = "";
}
},
getDataList() {
this.loading = true;
getUserWallet(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
},
mounted() {
this.init();
},
};
defineOptions({ name: "walletLog" });
// 模板 el-form 的 ref(原 ref="searchForm",与 data 同名会互相覆盖,改名为 searchFormRef)
const searchFormRef = ref(null);
const table = ref(null);
const loading = ref(true);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
});
const selectDate = ref(null);
const data = ref([]);
const total = ref(0);
function serviceTypeText(type) {
if (type === "WALLET_WITHDRAWAL") return "余额提现";
if (type === "WALLET_PAY") return "余额支付";
if (type === "WALLET_REFUND") return "余额退款";
if (type === "WALLET_RECHARGE") return "余额充值";
return "佣金提成";
}
function init() {
getDataList();
}
function changePage(v) {
searchForm.pageNumber = v;
getDataList();
}
function changePageSize(v) {
searchForm.pageNumber = 1;
searchForm.pageSize = v;
getDataList();
}
function handleSearch() {
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
getDataList();
}
function selectDateRange(v) {
if (v && v.length === 2) {
searchForm.startDate = v[0];
searchForm.endDate = v[1];
} else {
searchForm.startDate = "";
searchForm.endDate = "";
}
}
function getDataList() {
loading.value = true;
getUserWallet(searchForm).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
onMounted(() => {
init();
});
</script>

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -169,168 +169,169 @@
</div>
</template>
<script>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { getUserWithdrawApply, withdrawApply } from "@/api/member";
import { ElMessage } from "element-plus";
export default {
name: "withdrawApply",
data() {
return {
modalTitle: "",
loading: true,
audit: "",
roleModalVisible: false,
queryModalVisible: false,
searchForm: {
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
applyStatus: "",
},
selectDate: null,
submitLoading: false,
selectList: [],
selectCount: 0,
showList: {},
data: [],
total: 0,
};
},
methods: {
paramTypeFilter(val) {
if (val === "APPLY") return "申请中";
if (val === "VIA_AUDITING") return "审核通过(提现成功)";
if (val === "WAIT_USER_CONFIRM") return "用户确认";
if (val === "FAIL_AUDITING") return "审核拒绝";
if (val === "SUCCESS") return "提现成功";
if (val === "ERROR") return "提现失败";
return "未知状态";
},
applyStatusText(status) {
if (status === "APPLY") return "申请中";
if (status === "VIA_AUDITING") return "审核通过";
if (status === "WAIT_USER_CONFIRM") return "用户确认";
if (status === "SUCCESS") return "提现成功";
if (status === "ERROR") return "提现失败";
return "审核拒绝";
},
applyStatusTagType(status) {
if (status === "APPLY") return "warning";
if (status === "VIA_AUDITING") return "success";
if (status === "WAIT_USER_CONFIRM") return "warning";
if (status === "SUCCESS") return "primary";
if (status === "ERROR") return "primary";
return "danger";
},
openAudit(row) {
this.showList = { ...row };
this.audit = "";
this.roleModalVisible = true;
},
openQuery(row) {
this.showList = { ...row };
this.modalTitle = "查看";
this.queryModalVisible = true;
},
submitRole(res) {
const params = {};
params.applyId = this.showList.id;
params.result = res;
params.remark = this.audit;
if (res === false && params.remark === "") {
ElMessage.error("审核备注不能为空");
return;
defineOptions({ name: "withdrawApply" });
// 模板 el-form 的 ref(原 ref="searchForm",与 data 同名会互相覆盖,改名为 searchFormRef)
const searchFormRef = ref(null);
// 模板 el-table 的 ref
const table = ref(null);
const modalTitle = ref("");
const loading = ref(true);
const audit = ref("");
const roleModalVisible = ref(false);
const queryModalVisible = ref(false);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
startDate: "",
endDate: "",
memberName: "",
applyStatus: "",
});
const selectDate = ref(null);
const submitLoading = ref(false);
const selectList = ref([]);
const selectCount = ref(0);
const showList = ref({});
const data = ref([]);
const total = ref(0);
function paramTypeFilter(val) {
if (val === "APPLY") return "申请中";
if (val === "VIA_AUDITING") return "审核通过(提现成功)";
if (val === "WAIT_USER_CONFIRM") return "用户确认";
if (val === "FAIL_AUDITING") return "审核拒绝";
if (val === "SUCCESS") return "提现成功";
if (val === "ERROR") return "提现失败";
return "未知状态";
}
function applyStatusText(status) {
if (status === "APPLY") return "申请中";
if (status === "VIA_AUDITING") return "审核通过";
if (status === "WAIT_USER_CONFIRM") return "用户确认";
if (status === "SUCCESS") return "提现成功";
if (status === "ERROR") return "提现失败";
return "审核拒绝";
}
function applyStatusTagType(status) {
if (status === "APPLY") return "warning";
if (status === "VIA_AUDITING") return "success";
if (status === "WAIT_USER_CONFIRM") return "warning";
if (status === "SUCCESS") return "primary";
if (status === "ERROR") return "primary";
return "danger";
}
function openAudit(row) {
showList.value = { ...row };
audit.value = "";
roleModalVisible.value = true;
}
function openQuery(row) {
showList.value = { ...row };
modalTitle.value = "查看";
queryModalVisible.value = true;
}
function submitRole(res) {
const params = {};
params.applyId = showList.value.id;
params.result = res;
params.remark = audit.value;
if (res === false && params.remark === "") {
ElMessage.error("审核备注不能为空");
return;
}
submitLoading.value = true;
withdrawApply(params)
.then((result) => {
const success = result === true || (result && result.success === true);
if (success) {
ElMessage.success("操作成功");
roleModalVisible.value = false;
queryModalVisible.value = false;
audit.value = "";
showList.value = {};
getDataList();
}
this.submitLoading = true;
withdrawApply(params)
.then((result) => {
const success = result === true || (result && result.success === true);
if (success) {
ElMessage.success("操作成功");
this.roleModalVisible = false;
this.queryModalVisible = false;
this.audit = "";
this.showList = {};
this.getDataList();
}
})
.finally(() => {
this.submitLoading = false;
});
},
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getDataList();
},
handleReset() {
this.$refs.searchForm.resetFields();
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.selectDate = null;
this.searchForm.startDate = "";
this.searchForm.endDate = "";
this.searchForm.memberName = "";
this.getDataList();
},
changeSort(e) {
this.searchForm.sort = e.prop || e.key;
this.searchForm.order = e.order === "ascending" ? "asc" : e.order === "descending" ? "desc" : "";
if (!e.order) {
this.searchForm.order = "";
}
this.getDataList();
},
clearSelectAll() {
if (this.$refs.table) {
this.$refs.table.clearSelection();
}
},
changeSelect(e) {
this.selectList = e;
this.selectCount = e.length;
},
selectDateRange(v) {
if (v && v.length === 2) {
this.searchForm.startDate = v[0];
this.searchForm.endDate = v[1];
} else {
this.searchForm.startDate = "";
this.searchForm.endDate = "";
}
},
getDataList() {
this.loading = true;
getUserWithdrawApply(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
},
mounted() {
this.init();
},
};
})
.finally(() => {
submitLoading.value = false;
});
}
function init() {
getDataList();
}
function changePage(v) {
searchForm.pageNumber = v;
getDataList();
clearSelectAll();
}
function changePageSize(v) {
searchForm.pageSize = v;
getDataList();
}
function handleSearch() {
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
getDataList();
}
function handleReset() {
searchFormRef.value.resetFields();
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
selectDate.value = null;
searchForm.startDate = "";
searchForm.endDate = "";
searchForm.memberName = "";
getDataList();
}
function changeSort(e) {
searchForm.sort = e.prop || e.key;
searchForm.order = e.order === "ascending" ? "asc" : e.order === "descending" ? "desc" : "";
if (!e.order) {
searchForm.order = "";
}
getDataList();
}
function clearSelectAll() {
if (table.value) {
table.value.clearSelection();
}
}
function changeSelect(e) {
selectList.value = e;
selectCount.value = e.length;
}
function selectDateRange(v) {
if (v && v.length === 2) {
searchForm.startDate = v[0];
searchForm.endDate = v[1];
} else {
searchForm.startDate = "";
searchForm.endDate = "";
}
}
function getDataList() {
loading.value = true;
getUserWithdrawApply(searchForm).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
onMounted(() => {
init();
});
</script>
<style lang="scss" scoped>
.ops a {

View File

@@ -343,7 +343,8 @@
</div>
</template>
<script>
<script setup>
import { ref, computed, nextTick, onMounted } from "vue";
import * as API_Member from "@/api/member.js";
import { getPlatformCoupon } from "@/api/promotion";
import { formatPromotionCouponValidityHtml } from "@/utils/promotions";
@@ -351,6 +352,8 @@ import couponTemplate from "@/views/promotions/coupon/coupon.vue";
import uploadPicInput from "@/components/lili/upload-pic-input.vue";
import { ElMessage, ElMessageBox } from "element-plus";
defineOptions({ name: "memberBenefit" });
const GIFT_POINT = "GIFT_POINT";
const COUPON_PACKAGE = "COUPON_PACKAGE";
@@ -368,496 +371,490 @@ const buildDefaultForm = () => ({
couponPackageRows: [],
});
export default {
name: "memberBenefit",
components: {
uploadPicInput,
couponTemplate,
},
data() {
return {
benefitTypeOptions: [],
loading: false,
total: 0,
searchForm: {
pageNumber: 1,
pageSize: 20,
// 模板 ref(couponPicker 为优惠券选择组件,addForm/editForm 为表单)
const couponPicker = ref(null);
const addForm = ref(null);
const editForm = ref(null);
// 动态 ref 映射表(原 this.$refs[refName])
const formRefs = { addForm, editForm };
const benefitTypeOptions = ref([]);
const loading = ref(false);
const total = ref(0);
const searchForm = ref({
pageNumber: 1,
pageSize: 20,
});
const data = ref([]);
const addFlag = ref(false);
const editFlag = ref(false);
const submitAddLoading = ref(false);
const submitEditLoading = ref(false);
const formAdd = ref(buildDefaultForm());
const formEdit = ref(buildDefaultForm());
const couponPickerVisible = ref(false);
const couponPickerWhich = ref("add");
// 动态表单映射表(原 this[formKey])
const formMap = { formAdd, formEdit };
const rulesAdd = computed(() => buildFormRules("add"));
const rulesEdit = computed(() => buildFormRules("edit"));
const couponPickerSelectedList = computed(() => {
const form = couponPickerWhich.value === "add" ? formAdd.value : formEdit.value;
return (form.couponPackageRows || []).map((r) => ({
id: r.couponId,
couponName: r.couponName || "",
}));
});
function benefitTypeLabel(v) {
if (!v) return "-";
const opt = benefitTypeOptions.value.find((o) => o.value === v);
return opt ? opt.description : v;
}
function touchFormField(refName, field) {
nextTick(() => {
const ref = formRefs[refName]?.value;
if (ref && typeof ref.validateField === "function") {
// validateField rejects on failure; catch to avoid dev-server [object Object] overlay
ref.validateField(field, () => {});
}
});
}
function onCouponQuantityChange(which, index, val) {
const formKey = which === "add" ? "formAdd" : "formEdit";
const refName = which === "add" ? "addForm" : "editForm";
formMap[formKey].value.couponPackageRows[index].quantity = val;
touchFormField(refName, "couponPackageRows");
}
function buildFormRules(which) {
const formKey = which === "add" ? "formAdd" : "formEdit";
return {
benefitType: [{ required: true, message: "请选择权益类型", trigger: "change" }],
benefitName: [{ required: true, message: "请输入权益名称", trigger: "blur" }],
benefitLogo: [{ required: true, message: "请配置权益LOGO", trigger: "change" }],
benefitSort: [{ required: true, type: "number", message: "请输入排序", trigger: "change" }],
benefitState: [{ required: true, message: "请选择启用状态", trigger: "change" }],
giftPoint: [
{
validator: (rule, value, callback) => {
const form = formMap[formKey].value;
validateGiftPoint(form, value, callback);
},
trigger: ["change", "blur"],
},
data: [],
addFlag: false,
editFlag: false,
submitAddLoading: false,
submitEditLoading: false,
formAdd: buildDefaultForm(),
formEdit: buildDefaultForm(),
couponPickerVisible: false,
couponPickerWhich: "add",
};
},
computed: {
rulesAdd() {
return this.buildFormRules("add");
},
rulesEdit() {
return this.buildFormRules("edit");
},
couponPickerSelectedList() {
const form = this.couponPickerWhich === "add" ? this.formAdd : this.formEdit;
return (form.couponPackageRows || []).map((r) => ({
id: r.couponId,
couponName: r.couponName || "",
],
couponPackageRows: [
{
validator: (rule, value, callback) => {
const form = formMap[formKey].value;
validateCouponPackage(form, callback);
},
trigger: "change",
},
],
};
}
function validateGiftPoint(form, value, callback) {
if (form.benefitType !== GIFT_POINT) return callback();
if (value === null || value === undefined || value === "") {
return callback(new Error("请输入赠送积分"));
}
const n = Number(value);
if (Number.isNaN(n) || n < 0 || n > 99999) {
return callback(new Error("赠送积分范围为 0-99999"));
}
callback();
}
function validateCouponPackage(form, callback) {
if (form.benefitType !== COUPON_PACKAGE) return callback();
const rows = form.couponPackageRows || [];
if (!rows.length) {
return callback(new Error("请添加至少一张优惠券"));
}
for (let i = 0; i < rows.length; i++) {
const q = Number(rows[i].quantity);
if (Number.isNaN(q) || q < 1 || q > 10) {
return callback(new Error("每张券赠送张数需在 1~10 之间"));
}
}
callback();
}
function formatCouponFace(row) {
if (!row) return "-";
if (row.price !== undefined && row.price !== null && row.price !== "") {
return `¥${row.price}`;
}
if (row.couponDiscount !== undefined && row.couponDiscount !== null && row.couponDiscount !== "") {
return `${row.couponDiscount}折`;
}
return "-";
}
function formatCouponValidity(row) {
return formatPromotionCouponValidityHtml(row);
}
function buildCouponDisplayRow(detail, quantity) {
const qty = Math.min(10, Math.max(1, Number(quantity) || 1));
return {
couponId: detail.id,
quantity: qty,
couponName: detail.couponName || "",
faceValueLabel: formatCouponFace(detail),
validRange: formatCouponValidity(detail),
};
}
function buildBenefitConfigString(slice) {
const { benefitType, giftPoint, couponPackageRows } = slice;
if (benefitType === GIFT_POINT) {
return JSON.stringify({ giftPoint: Number(giftPoint) });
}
if (benefitType === COUPON_PACKAGE) {
const coupons = (couponPackageRows || []).map((r) => ({
couponId: String(r.couponId),
quantity: Math.min(10, Math.max(1, Number(r.quantity) || 1)),
}));
return JSON.stringify({ coupons });
}
return "";
}
function parseGiftPointFromConfig(benefitType, benefitConfigStr) {
if (benefitType !== GIFT_POINT || !benefitConfigStr) return null;
try {
const o = JSON.parse(benefitConfigStr);
if (o && typeof o.giftPoint !== "undefined") {
const n = Number(o.giftPoint);
return Number.isNaN(n) ? null : n;
}
} catch (e) {
/* ignore */
}
return null;
}
function onAddBenefitTypeChange(val) {
if (val !== GIFT_POINT) {
formAdd.value.giftPoint = null;
}
if (val !== COUPON_PACKAGE) {
formAdd.value.couponPackageRows = [];
}
if (addForm.value && val !== GIFT_POINT) {
touchFormField("addForm", "giftPoint");
}
if (addForm.value && val !== COUPON_PACKAGE) {
touchFormField("addForm", "couponPackageRows");
}
}
function onEditBenefitTypeChange(val) {
if (val !== GIFT_POINT) {
formEdit.value.giftPoint = null;
}
if (val !== COUPON_PACKAGE) {
formEdit.value.couponPackageRows = [];
}
if (editForm.value && val !== GIFT_POINT) {
touchFormField("editForm", "giftPoint");
}
if (editForm.value && val !== COUPON_PACKAGE) {
touchFormField("editForm", "couponPackageRows");
}
}
function parseCouponsFromConfig(str) {
if (!str) return [];
try {
const o = JSON.parse(str);
if (o && Array.isArray(o.coupons)) {
return o.coupons.map((c) => ({
couponId: c.couponId,
quantity: c.quantity,
}));
},
},
methods: {
benefitTypeLabel(v) {
if (!v) return "-";
const opt = this.benefitTypeOptions.find((o) => o.value === v);
return opt ? opt.description : v;
},
touchFormField(refName, field) {
this.$nextTick(() => {
const ref = this.$refs[refName];
if (ref && typeof ref.validateField === "function") {
// validateField rejects on failure; catch to avoid dev-server [object Object] overlay
ref.validateField(field, () => {});
}
}
} catch (e) {
/* ignore */
}
return [];
}
function normalizeCouponFaceFromDetail(item) {
let face = formatCouponFace(item);
if (face !== "-") return face;
const raw = item.faceValueText;
if (raw == null || raw === "") return "-";
return String(raw)
.replace(/^减免现金\s*/, "")
.replace(/^减免\s*/, "")
.trim() || "-";
}
function mapCouponItemsToPackageRows(items) {
if (!Array.isArray(items)) return [];
return items.map((item) => {
const face = normalizeCouponFaceFromDetail(item);
const validHtml = item.validityText
? String(item.validityText).replace(/\n/g, "<br/>")
: "-";
return {
couponId: item.couponId,
quantity: Math.min(10, Math.max(1, Number(item.quantity) || 1)),
couponName: item.couponName || "",
faceValueLabel: face,
validRange: validHtml,
};
});
}
async function hydrateCouponRowsForEdit(snippets) {
const rows = [];
for (const s of snippets) {
const cid = s.couponId;
const qty = s.quantity;
try {
const res = await getPlatformCoupon(cid);
if (res && res.success && res.result) {
rows.push(buildCouponDisplayRow(res.result, qty));
} else {
rows.push({
couponId: cid,
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
couponName: String(cid),
faceValueLabel: "-",
validRange: "-",
});
}
} catch (e) {
rows.push({
couponId: cid,
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
couponName: String(cid),
faceValueLabel: "-",
validRange: "-",
});
},
onCouponQuantityChange(which, index, val) {
const formKey = which === "add" ? "formAdd" : "formEdit";
const refName = which === "add" ? "addForm" : "editForm";
this[formKey].couponPackageRows[index].quantity = val;
this.touchFormField(refName, "couponPackageRows");
},
buildFormRules(which) {
const formKey = which === "add" ? "formAdd" : "formEdit";
return {
benefitType: [{ required: true, message: "请选择权益类型", trigger: "change" }],
benefitName: [{ required: true, message: "请输入权益名称", trigger: "blur" }],
benefitLogo: [{ required: true, message: "请配置权益LOGO", trigger: "change" }],
benefitSort: [{ required: true, type: "number", message: "请输入排序", trigger: "change" }],
benefitState: [{ required: true, message: "请选择启用状态", trigger: "change" }],
giftPoint: [
{
validator: (rule, value, callback) => {
const form = this[formKey];
this.validateGiftPoint(form, value, callback);
},
trigger: ["change", "blur"],
},
],
couponPackageRows: [
{
validator: (rule, value, callback) => {
const form = this[formKey];
this.validateCouponPackage(form, callback);
},
trigger: "change",
},
],
}
}
formEdit.value.couponPackageRows = rows;
}
function handleCouponPickerClose() {
couponPickerVisible.value = false;
}
function openCouponPicker(which) {
couponPickerWhich.value = which;
couponPickerVisible.value = true;
}
function confirmCouponPicker() {
const list = couponPicker.value?.getSelection?.() || [];
if (!list.length) {
ElMessage.warning("请至少选择一张优惠券");
return;
}
onCouponTemplateSelected(list);
couponPickerVisible.value = false;
}
function onCouponTemplateSelected(selectedRows) {
const which = couponPickerWhich.value;
const form = which === "add" ? formAdd.value : formEdit.value;
const refName = which === "add" ? "addForm" : "editForm";
const list = selectedRows || [];
const rows = list.map((row) => {
const existing = (form.couponPackageRows || []).find((r) => String(r.couponId) === String(row.id));
const qty = existing ? existing.quantity : 1;
return buildCouponDisplayRow(row, qty);
});
form.couponPackageRows = rows;
touchFormField(refName, "couponPackageRows");
}
function removeCouponRow(which, index) {
const form = which === "add" ? formAdd.value : formEdit.value;
const refName = which === "add" ? "addForm" : "editForm";
form.couponPackageRows.splice(index, 1);
touchFormField(refName, "couponPackageRows");
}
function init() {
loadBenefitTypes();
getData();
}
function loadBenefitTypes() {
API_Member.getMemberBenefitTypes().then((res) => {
if (res && res.success && Array.isArray(res.result)) {
benefitTypeOptions.value = res.result;
} else {
benefitTypeOptions.value = [];
}
});
}
function changePage(page) {
searchForm.value.pageNumber = page;
getData();
}
function changePageSize(size) {
searchForm.value.pageSize = size;
searchForm.value.pageNumber = 1;
getData();
}
function getData() {
loading.value = true;
const params = { ...searchForm.value };
API_Member.getMemberBenefitByPage(params).then((res) => {
loading.value = false;
if (res && res.success && res.result) {
data.value = Array.isArray(res.result.records) ? res.result.records : [];
total.value = Number(res.result.total) || 0;
} else {
data.value = [];
total.value = 0;
}
});
}
function openAdd() {
addFlag.value = true;
submitAddLoading.value = false;
nextTick(() => {
if (addForm.value) addForm.value.resetFields();
formAdd.value = buildDefaultForm();
});
}
function submitAdd() {
if (!addForm.value) {
ElMessage.warning("表单未就绪,请稍后重试");
return;
}
addForm.value.validate((valid) => {
if (!valid) return;
submitAddLoading.value = true;
const { giftPoint, couponPackageRows, ...rest } = formAdd.value;
const payload = {
...rest,
benefitConfig: buildBenefitConfigString({
benefitType: formAdd.value.benefitType,
giftPoint,
couponPackageRows,
}),
};
API_Member.addMemberBenefit(payload).then((res) => {
submitAddLoading.value = false;
if (res && res.success) {
ElMessage.success("添加成功");
addFlag.value = false;
getData();
} else if (res && res.message) {
ElMessage.error(res.message);
} else {
ElMessage.error("添加失败");
}
}).catch(() => {
submitAddLoading.value = false;
ElMessage.error("网络异常,请稍后重试");
});
});
}
function openEdit(row) {
editFlag.value = true;
submitEditLoading.value = false;
nextTick(() => {
if (editForm.value) editForm.value.resetFields();
});
API_Member.getMemberBenefit(row.id).then((res) => {
if (res && res.success && res.result) {
const raw = res.result;
const detail = raw.benefit != null ? raw.benefit : raw;
const couponItems = raw.couponItems;
const bt = detail.benefitType || "";
const parsed = parseGiftPointFromConfig(bt, detail.benefitConfig || "");
const couponSnippets = parseCouponsFromConfig(detail.benefitConfig || "");
let couponRows = [];
if (bt === COUPON_PACKAGE && Array.isArray(couponItems) && couponItems.length) {
couponRows = mapCouponItemsToPackageRows(couponItems);
}
formEdit.value = {
id: detail.id || row.id || "",
benefitName: detail.benefitName || "",
benefitCode: detail.benefitCode || "",
benefitType: bt,
benefitLogo: detail.benefitLogo || "",
benefitDesc: detail.benefitDesc || "",
benefitSort: Number(detail.benefitSort) > 0 ? Number(detail.benefitSort) : 1,
benefitState: detail.benefitState || "OPEN",
benefitConfig: detail.benefitConfig || "",
giftPoint: bt === GIFT_POINT ? (parsed !== null ? parsed : null) : null,
couponPackageRows: couponRows,
};
},
validateGiftPoint(form, value, callback) {
if (form.benefitType !== GIFT_POINT) return callback();
if (value === null || value === undefined || value === "") {
return callback(new Error("请输入赠送积分"));
if (bt === COUPON_PACKAGE && couponRows.length === 0 && couponSnippets.length) {
hydrateCouponRowsForEdit(couponSnippets);
}
const n = Number(value);
if (Number.isNaN(n) || n < 0 || n > 99999) {
return callback(new Error("赠送积分范围为 0-99999"));
}
});
}
function submitEdit() {
if (!editForm.value) {
ElMessage.warning("表单未就绪,请稍后重试");
return;
}
editForm.value.validate((valid) => {
if (!valid) return;
submitEditLoading.value = true;
const { id, giftPoint, couponPackageRows, ...rest } = formEdit.value;
const payload = {
...rest,
benefitConfig: buildBenefitConfigString({
benefitType: formEdit.value.benefitType,
giftPoint,
couponPackageRows,
}),
};
API_Member.updateMemberBenefit(id, payload).then((res) => {
submitEditLoading.value = false;
if (res && res.success) {
ElMessage.success("修改成功");
editFlag.value = false;
getData();
} else if (res && res.message) {
ElMessage.error(res.message);
} else {
ElMessage.error("修改失败");
}
callback();
},
validateCouponPackage(form, callback) {
if (form.benefitType !== COUPON_PACKAGE) return callback();
const rows = form.couponPackageRows || [];
if (!rows.length) {
return callback(new Error("请添加至少一张优惠券"));
}
for (let i = 0; i < rows.length; i++) {
const q = Number(rows[i].quantity);
if (Number.isNaN(q) || q < 1 || q > 10) {
return callback(new Error("每张券赠送张数需在 1~10 之间"));
}
}
callback();
},
formatCouponFace(row) {
if (!row) return "-";
if (row.price !== undefined && row.price !== null && row.price !== "") {
return `¥${row.price}`;
}
if (row.couponDiscount !== undefined && row.couponDiscount !== null && row.couponDiscount !== "") {
return `${row.couponDiscount}折`;
}
return "-";
},
formatCouponValidity(row) {
return formatPromotionCouponValidityHtml(row);
},
buildCouponDisplayRow(detail, quantity) {
const qty = Math.min(10, Math.max(1, Number(quantity) || 1));
return {
couponId: detail.id,
quantity: qty,
couponName: detail.couponName || "",
faceValueLabel: this.formatCouponFace(detail),
validRange: this.formatCouponValidity(detail),
};
},
buildBenefitConfigString(slice) {
const { benefitType, giftPoint, couponPackageRows } = slice;
if (benefitType === GIFT_POINT) {
return JSON.stringify({ giftPoint: Number(giftPoint) });
}
if (benefitType === COUPON_PACKAGE) {
const coupons = (couponPackageRows || []).map((r) => ({
couponId: String(r.couponId),
quantity: Math.min(10, Math.max(1, Number(r.quantity) || 1)),
}));
return JSON.stringify({ coupons });
}
return "";
},
parseGiftPointFromConfig(benefitType, benefitConfigStr) {
if (benefitType !== GIFT_POINT || !benefitConfigStr) return null;
try {
const o = JSON.parse(benefitConfigStr);
if (o && typeof o.giftPoint !== "undefined") {
const n = Number(o.giftPoint);
return Number.isNaN(n) ? null : n;
}
} catch (e) {
/* ignore */
}
return null;
},
onAddBenefitTypeChange(val) {
if (val !== GIFT_POINT) {
this.formAdd.giftPoint = null;
}
if (val !== COUPON_PACKAGE) {
this.formAdd.couponPackageRows = [];
}
if (this.$refs.addForm && val !== GIFT_POINT) {
this.touchFormField("addForm", "giftPoint");
}
if (this.$refs.addForm && val !== COUPON_PACKAGE) {
this.touchFormField("addForm", "couponPackageRows");
}
},
onEditBenefitTypeChange(val) {
if (val !== GIFT_POINT) {
this.formEdit.giftPoint = null;
}
if (val !== COUPON_PACKAGE) {
this.formEdit.couponPackageRows = [];
}
if (this.$refs.editForm && val !== GIFT_POINT) {
this.touchFormField("editForm", "giftPoint");
}
if (this.$refs.editForm && val !== COUPON_PACKAGE) {
this.touchFormField("editForm", "couponPackageRows");
}
},
parseCouponsFromConfig(str) {
if (!str) return [];
try {
const o = JSON.parse(str);
if (o && Array.isArray(o.coupons)) {
return o.coupons.map((c) => ({
couponId: c.couponId,
quantity: c.quantity,
}));
}
} catch (e) {
/* ignore */
}
return [];
},
normalizeCouponFaceFromDetail(item) {
let face = this.formatCouponFace(item);
if (face !== "-") return face;
const raw = item.faceValueText;
if (raw == null || raw === "") return "-";
return String(raw)
.replace(/^减免现金\s*/, "")
.replace(/^减免\s*/, "")
.trim() || "-";
},
mapCouponItemsToPackageRows(items) {
if (!Array.isArray(items)) return [];
return items.map((item) => {
const face = this.normalizeCouponFaceFromDetail(item);
const validHtml = item.validityText
? String(item.validityText).replace(/\n/g, "<br/>")
: "-";
return {
couponId: item.couponId,
quantity: Math.min(10, Math.max(1, Number(item.quantity) || 1)),
couponName: item.couponName || "",
faceValueLabel: face,
validRange: validHtml,
};
});
},
async hydrateCouponRowsForEdit(snippets) {
const rows = [];
for (const s of snippets) {
const cid = s.couponId;
const qty = s.quantity;
try {
const res = await getPlatformCoupon(cid);
if (res && res.success && res.result) {
rows.push(this.buildCouponDisplayRow(res.result, qty));
} else {
rows.push({
couponId: cid,
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
couponName: String(cid),
faceValueLabel: "-",
validRange: "-",
});
}
} catch (e) {
rows.push({
couponId: cid,
quantity: Math.min(10, Math.max(1, Number(qty) || 1)),
couponName: String(cid),
faceValueLabel: "-",
validRange: "-",
});
}
}
this.formEdit.couponPackageRows = rows;
},
handleCouponPickerClose() {
this.couponPickerVisible = false;
},
openCouponPicker(which) {
this.couponPickerWhich = which;
this.couponPickerVisible = true;
},
confirmCouponPicker() {
const list = this.$refs.couponPicker?.getSelection?.() || [];
if (!list.length) {
ElMessage.warning("请至少选择一张优惠券");
return;
}
this.onCouponTemplateSelected(list);
this.couponPickerVisible = false;
},
onCouponTemplateSelected(selectedRows) {
const which = this.couponPickerWhich;
const form = which === "add" ? this.formAdd : this.formEdit;
const refName = which === "add" ? "addForm" : "editForm";
const list = selectedRows || [];
const rows = list.map((row) => {
const existing = (form.couponPackageRows || []).find((r) => String(r.couponId) === String(row.id));
const qty = existing ? existing.quantity : 1;
return this.buildCouponDisplayRow(row, qty);
});
form.couponPackageRows = rows;
this.touchFormField(refName, "couponPackageRows");
},
removeCouponRow(which, index) {
const form = which === "add" ? this.formAdd : this.formEdit;
const refName = which === "add" ? "addForm" : "editForm";
form.couponPackageRows.splice(index, 1);
this.touchFormField(refName, "couponPackageRows");
},
init() {
this.loadBenefitTypes();
this.getData();
},
loadBenefitTypes() {
API_Member.getMemberBenefitTypes().then((res) => {
if (res && res.success && Array.isArray(res.result)) {
this.benefitTypeOptions = res.result;
}).catch(() => {
submitEditLoading.value = false;
ElMessage.error("网络异常,请稍后重试");
});
});
}
function onBenefitStateSwitch(row, checked) {
const nextState = checked ? "OPEN" : "CLOSE";
const prevState = row.benefitState;
if (nextState === prevState) return;
const text = checked ? "开启" : "关闭";
ElMessageBox.confirm(`确定${text}该客户权益?`, "提示", { type: "warning" }).then(() => {
row._benefitStateLoading = true;
return API_Member.updateMemberBenefitState(row.id, nextState)
.then((res) => {
row._benefitStateLoading = false;
if (res && res.success) {
ElMessage.success(`${text}成功`);
row.benefitState = nextState;
} else {
this.benefitTypeOptions = [];
getData();
}
})
.catch(() => {
row._benefitStateLoading = false;
});
},
changePage(page) {
this.searchForm.pageNumber = page;
this.getData();
},
changePageSize(size) {
this.searchForm.pageSize = size;
this.searchForm.pageNumber = 1;
this.getData();
},
getData() {
this.loading = true;
const params = { ...this.searchForm };
API_Member.getMemberBenefitByPage(params).then((res) => {
this.loading = false;
if (res && res.success && res.result) {
this.data = Array.isArray(res.result.records) ? res.result.records : [];
this.total = Number(res.result.total) || 0;
} else {
this.data = [];
this.total = 0;
}
});
},
openAdd() {
this.addFlag = true;
this.submitAddLoading = false;
this.$nextTick(() => {
if (this.$refs.addForm) this.$refs.addForm.resetFields();
this.formAdd = buildDefaultForm();
});
},
submitAdd() {
if (!this.$refs.addForm) {
ElMessage.warning("表单未就绪,请稍后重试");
return;
}).catch(() => {});
}
function remove(row) {
ElMessageBox.confirm("确定删除该客户权益?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberBenefit(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
this.$refs.addForm.validate((valid) => {
if (!valid) return;
this.submitAddLoading = true;
const { giftPoint, couponPackageRows, ...rest } = this.formAdd;
const payload = {
...rest,
benefitConfig: this.buildBenefitConfigString({
benefitType: this.formAdd.benefitType,
giftPoint,
couponPackageRows,
}),
};
API_Member.addMemberBenefit(payload).then((res) => {
this.submitAddLoading = false;
if (res && res.success) {
ElMessage.success("添加成功");
this.addFlag = false;
this.getData();
} else if (res && res.message) {
ElMessage.error(res.message);
} else {
ElMessage.error("添加失败");
}
}).catch(() => {
this.submitAddLoading = false;
ElMessage.error("网络异常,请稍后重试");
});
});
},
openEdit(row) {
this.editFlag = true;
this.submitEditLoading = false;
this.$nextTick(() => {
if (this.$refs.editForm) this.$refs.editForm.resetFields();
});
API_Member.getMemberBenefit(row.id).then((res) => {
if (res && res.success && res.result) {
const raw = res.result;
const detail = raw.benefit != null ? raw.benefit : raw;
const couponItems = raw.couponItems;
const bt = detail.benefitType || "";
const parsed = this.parseGiftPointFromConfig(bt, detail.benefitConfig || "");
const couponSnippets = this.parseCouponsFromConfig(detail.benefitConfig || "");
});
}).catch(() => {});
}
let couponRows = [];
if (bt === COUPON_PACKAGE && Array.isArray(couponItems) && couponItems.length) {
couponRows = this.mapCouponItemsToPackageRows(couponItems);
}
this.formEdit = {
id: detail.id || row.id || "",
benefitName: detail.benefitName || "",
benefitCode: detail.benefitCode || "",
benefitType: bt,
benefitLogo: detail.benefitLogo || "",
benefitDesc: detail.benefitDesc || "",
benefitSort: Number(detail.benefitSort) > 0 ? Number(detail.benefitSort) : 1,
benefitState: detail.benefitState || "OPEN",
benefitConfig: detail.benefitConfig || "",
giftPoint: bt === GIFT_POINT ? (parsed !== null ? parsed : null) : null,
couponPackageRows: couponRows,
};
if (bt === COUPON_PACKAGE && couponRows.length === 0 && couponSnippets.length) {
this.hydrateCouponRowsForEdit(couponSnippets);
}
}
});
},
submitEdit() {
if (!this.$refs.editForm) {
ElMessage.warning("表单未就绪,请稍后重试");
return;
}
this.$refs.editForm.validate((valid) => {
if (!valid) return;
this.submitEditLoading = true;
const { id, giftPoint, couponPackageRows, ...rest } = this.formEdit;
const payload = {
...rest,
benefitConfig: this.buildBenefitConfigString({
benefitType: this.formEdit.benefitType,
giftPoint,
couponPackageRows,
}),
};
API_Member.updateMemberBenefit(id, payload).then((res) => {
this.submitEditLoading = false;
if (res && res.success) {
ElMessage.success("修改成功");
this.editFlag = false;
this.getData();
} else if (res && res.message) {
ElMessage.error(res.message);
} else {
ElMessage.error("修改失败");
}
}).catch(() => {
this.submitEditLoading = false;
ElMessage.error("网络异常,请稍后重试");
});
});
},
onBenefitStateSwitch(row, checked) {
const nextState = checked ? "OPEN" : "CLOSE";
const prevState = row.benefitState;
if (nextState === prevState) return;
const text = checked ? "开启" : "关闭";
ElMessageBox.confirm(`确定${text}该客户权益?`, "提示", { type: "warning" }).then(() => {
row._benefitStateLoading = true;
return API_Member.updateMemberBenefitState(row.id, nextState)
.then((res) => {
row._benefitStateLoading = false;
if (res && res.success) {
ElMessage.success(`${text}成功`);
row.benefitState = nextState;
} else {
this.getData();
}
})
.catch(() => {
row._benefitStateLoading = false;
});
}).catch(() => {});
},
remove(row) {
ElMessageBox.confirm("确定删除该客户权益?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberBenefit(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
this.getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
});
}).catch(() => {});
},
},
mounted() {
this.init();
},
};
onMounted(() => {
init();
});
</script>
<style lang="scss" scoped>

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="90px"
@@ -78,7 +78,8 @@
</div>
</template>
<script>
<script setup>
import { onMounted, reactive, ref } from "vue";
import * as API_Member from "@/api/member";
const RULE_OPTIONS = [
@@ -95,79 +96,76 @@ const RULE_OPTIONS = [
{ value: "SHARE_BUY", label: "分享购买" },
];
export default {
name: "memberGradeExperienceLog",
data() {
return {
loading: false,
total: 0,
data: [],
ruleOptions: RULE_OPTIONS,
searchForm: {
pageNumber: 1,
pageSize: 20,
memberMobile: "",
ruleKey: "",
},
};
},
mounted() {
this.init();
},
methods: {
formatExperienceValue(row) {
const v = row.value ?? row.variableExperience ?? row.experience ?? row.variableValue;
return v == null ? "-" : v;
},
formatMaxValue(row) {
const v = row.maxValue ?? row.maxExperience ?? row.limitValue;
return v == null ? "-" : v;
},
findRuleName(ruleKey) {
const hit = this.ruleOptions.find((item) => item.value === ruleKey);
return hit ? hit.label : "";
},
init() {
this.getData();
},
buildParams() {
const params = {
pageNumber: this.searchForm.pageNumber,
pageSize: this.searchForm.pageSize,
};
if (this.searchForm.memberMobile) params.mobile = this.searchForm.memberMobile;
if (this.searchForm.ruleKey) params.ruleKey = this.searchForm.ruleKey;
return params;
},
getData() {
this.loading = true;
API_Member.getMemberExperienceByPage(this.buildParams())
.then((res) => {
if (res && res.success && res.result) {
this.data = res.result.records || [];
this.total = res.result.total || 0;
} else {
this.data = [];
this.total = 0;
}
})
.finally(() => {
this.loading = false;
});
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.getData();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getData();
},
changePageSize(v) {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = v;
this.getData();
},
},
};
defineOptions({ name: "memberGradeExperienceLog" });
const searchFormRef = ref(null);
const loading = ref(false);
const total = ref(0);
const data = ref([]);
const ruleOptions = RULE_OPTIONS;
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
memberMobile: "",
ruleKey: "",
});
onMounted(() => {
init();
});
function formatExperienceValue(row) {
const v = row.value ?? row.variableExperience ?? row.experience ?? row.variableValue;
return v == null ? "-" : v;
}
function formatMaxValue(row) {
const v = row.maxValue ?? row.maxExperience ?? row.limitValue;
return v == null ? "-" : v;
}
function findRuleName(ruleKey) {
const hit = ruleOptions.find((item) => item.value === ruleKey);
return hit ? hit.label : "";
}
function init() {
getData();
}
function buildParams() {
const params = {
pageNumber: searchForm.pageNumber,
pageSize: searchForm.pageSize,
};
if (searchForm.memberMobile) params.mobile = searchForm.memberMobile;
if (searchForm.ruleKey) params.ruleKey = searchForm.ruleKey;
return params;
}
function getData() {
loading.value = true;
API_Member.getMemberExperienceByPage(buildParams())
.then((res) => {
if (res && res.success && res.result) {
data.value = res.result.records || [];
total.value = res.result.total || 0;
} else {
data.value = [];
total.value = 0;
}
})
.finally(() => {
loading.value = false;
});
}
function handleSearch() {
searchForm.pageNumber = 1;
getData();
}
function changePage(v) {
searchForm.pageNumber = v;
getData();
}
function changePageSize(v) {
searchForm.pageNumber = 1;
searchForm.pageSize = v;
getData();
}
</script>

View File

@@ -237,10 +237,13 @@
</div>
</template>
<script>
<script setup>
import { ref, onMounted } from "vue";
import { getSetting, setSetting } from "@/api/index";
import { ElMessage } from "element-plus";
defineOptions({ name: "memberGradeExperienceSetting" });
const RULE_OPTIONS = [
{ ruleKey: "CONSUME", ruleName: "消费" },
{ ruleKey: "REGISTER", ruleName: "注册" },
@@ -268,176 +271,169 @@ const defaultForm = () => ({
description: "",
});
export default {
name: "memberGradeExperienceSetting",
data() {
return {
loading: false,
submitLoading: false,
form: defaultForm(),
const loading = ref(false);
const submitLoading = ref(false);
const form = ref(defaultForm());
function formatInputValue(v) {
return v == null ? "" : String(v);
}
function getRawInputValue(v) {
return v && v.target ? v.target.value : v;
}
function updateRuleEnabled(index, enabled) {
const item = form.value.items[index] || {};
form.value.items[index] = {
...item,
enabled: !!enabled,
};
}
function updateRuleValue(index, v) {
const raw = getRawInputValue(v);
const next = Number(raw);
const item = form.value.items[index] || {};
form.value.items[index] = {
...item,
value: Number.isFinite(next) ? next : null,
};
}
function commitRuleValue(index) {
const item = form.value.items[index] || {};
const next = Number(item.value);
let value = 1;
if (Number.isFinite(next)) {
if (next < 1) value = 1;
else if (next > 100) value = 100;
else value = Math.floor(next);
}
form.value.items[index] = {
...item,
value,
};
}
function updateRuleMaxValue(index, v) {
const raw = getRawInputValue(v);
const item = form.value.items[index] || {};
if (raw == null || raw === "") {
form.value.items[index] = {
...item,
maxValue: null,
};
},
mounted() {
this.loadData();
},
methods: {
formatInputValue(v) {
return v == null ? "" : String(v);
},
getRawInputValue(v) {
return v && v.target ? v.target.value : v;
},
updateRuleEnabled(index, enabled) {
const item = this.form.items[index] || {};
this.form.items[index] = {
...item,
enabled: !!enabled,
};
},
updateRuleValue(index, v) {
const raw = this.getRawInputValue(v);
const next = Number(raw);
const item = this.form.items[index] || {};
this.form.items[index] = {
...item,
value: Number.isFinite(next) ? next : null,
};
},
commitRuleValue(index) {
const item = this.form.items[index] || {};
const next = Number(item.value);
let value = 1;
if (Number.isFinite(next)) {
if (next < 1) value = 1;
else if (next > 100) value = 100;
else value = Math.floor(next);
}
this.form.items[index] = {
...item,
value,
};
},
updateRuleMaxValue(index, v) {
const raw = this.getRawInputValue(v);
const item = this.form.items[index] || {};
if (raw == null || raw === "") {
this.form.items[index] = {
...item,
maxValue: null,
};
return;
}
const next = Number(raw);
this.form.items[index] = {
...item,
maxValue: Number.isFinite(next) ? next : null,
};
},
commitRuleMaxValue(index) {
const item = this.form.items[index] || {};
if (item.maxValue == null || item.maxValue === "") {
this.form.items[index] = {
...item,
maxValue: null,
};
return;
}
const next = Number(item.maxValue);
this.form.items[index] = {
...item,
maxValue: Number.isFinite(next) && next >= 1 ? Math.floor(next) : null,
};
},
normalizeConfig(val) {
if (!val) return {};
if (typeof val === "string") {
try {
return JSON.parse(val);
} catch (e) {
return {};
}
}
if (typeof val === "object") return val;
return;
}
const next = Number(raw);
form.value.items[index] = {
...item,
maxValue: Number.isFinite(next) ? next : null,
};
}
function commitRuleMaxValue(index) {
const item = form.value.items[index] || {};
if (item.maxValue == null || item.maxValue === "") {
form.value.items[index] = {
...item,
maxValue: null,
};
return;
}
const next = Number(item.maxValue);
form.value.items[index] = {
...item,
maxValue: Number.isFinite(next) && next >= 1 ? Math.floor(next) : null,
};
}
function normalizeConfig(val) {
if (!val) return {};
if (typeof val === "string") {
try {
return JSON.parse(val);
} catch (e) {
return {};
},
normalizeItems(items) {
const map = {};
if (Array.isArray(items)) {
items.forEach((item) => {
if (!item || !item.ruleKey) return;
map[item.ruleKey] = item;
});
}
return RULE_OPTIONS.map((rule) => {
const hit = map[rule.ruleKey] || {};
return {
ruleKey: rule.ruleKey,
ruleName: hit.ruleName || rule.ruleName,
enabled: !!hit.enabled,
value: Number(hit.value) > 0 ? Number(hit.value) : 1,
maxValue: hit.maxValue == null || hit.maxValue === "" ? null : Number(hit.maxValue),
}
}
if (typeof val === "object") return val;
return {};
}
function normalizeItems(items) {
const map = {};
if (Array.isArray(items)) {
items.forEach((item) => {
if (!item || !item.ruleKey) return;
map[item.ruleKey] = item;
});
}
return RULE_OPTIONS.map((rule) => {
const hit = map[rule.ruleKey] || {};
return {
ruleKey: rule.ruleKey,
ruleName: hit.ruleName || rule.ruleName,
enabled: !!hit.enabled,
value: Number(hit.value) > 0 ? Number(hit.value) : 1,
maxValue: hit.maxValue == null || hit.maxValue === "" ? null : Number(hit.maxValue),
};
});
}
function loadData() {
loading.value = true;
getSetting("EXPERIENCE_SETTING")
.then((res) => {
if (res && res.success) {
const cfg = normalizeConfig(res.result);
form.value = {
items: normalizeItems(cfg.items),
description: cfg.description || "",
};
});
},
loadData() {
this.loading = true;
getSetting("EXPERIENCE_SETTING")
.then((res) => {
if (res && res.success) {
const cfg = this.normalizeConfig(res.result);
this.form = {
items: this.normalizeItems(cfg.items),
description: cfg.description || "",
};
} else {
this.form = defaultForm();
}
})
.finally(() => {
this.loading = false;
});
},
validateForm() {
const invalid = this.form.items.find((item) => {
const v = Number(item.value);
if (!Number.isInteger(v) || v < 1 || v > 100) return true;
if (item.maxValue != null && item.maxValue !== "") {
const m = Number(item.maxValue);
if (!Number.isInteger(m) || m < 1) return true;
}
return false;
});
if (invalid) {
ElMessage.error("请检查经验值配置,经验值范围为1-100,限额需为正整数");
return false;
} else {
form.value = defaultForm();
}
return true;
},
submit() {
if (!this.validateForm()) return;
const payload = {
items: this.form.items.map((item) => ({
ruleKey: item.ruleKey,
ruleName: item.ruleName,
enabled: !!item.enabled,
value: Number(item.value),
maxValue: item.maxValue == null || item.maxValue === "" ? null : Number(item.maxValue),
})),
description: this.form.description || "",
};
this.submitLoading = true;
setSetting("EXPERIENCE_SETTING", payload)
.then((res) => {
if (res && res.success) {
ElMessage.success("保存成功");
}
})
.finally(() => {
this.submitLoading = false;
});
},
},
};
})
.finally(() => {
loading.value = false;
});
}
function validateForm() {
const invalid = form.value.items.find((item) => {
const v = Number(item.value);
if (!Number.isInteger(v) || v < 1 || v > 100) return true;
if (item.maxValue != null && item.maxValue !== "") {
const m = Number(item.maxValue);
if (!Number.isInteger(m) || m < 1) return true;
}
return false;
});
if (invalid) {
ElMessage.error("请检查经验值配置,经验值范围为1-100,限额需为正整数");
return false;
}
return true;
}
function submit() {
if (!validateForm()) return;
const payload = {
items: form.value.items.map((item) => ({
ruleKey: item.ruleKey,
ruleName: item.ruleName,
enabled: !!item.enabled,
value: Number(item.value),
maxValue: item.maxValue == null || item.maxValue === "" ? null : Number(item.maxValue),
})),
description: form.value.description || "",
};
submitLoading.value = true;
setSetting("EXPERIENCE_SETTING", payload)
.then((res) => {
if (res && res.success) {
ElMessage.success("保存成功");
}
})
.finally(() => {
submitLoading.value = false;
});
}
onMounted(() => {
loadData();
});
</script>
<style scoped lang="scss">

View File

@@ -178,11 +178,14 @@
</div>
</template>
<script>
<script setup>
import { ref, nextTick, onMounted } from "vue";
import * as API_Member from "@/api/member.js";
import uploadPicInput from "@/components/lili/upload-pic-input";
import { ElMessage, ElMessageBox } from "element-plus";
defineOptions({ name: "memberGrade" });
const buildDefaultForm = () => ({
id: "",
gradeName: "",
@@ -209,254 +212,248 @@ function syncOrderedBenefitIds(prevOrder, selected) {
return out;
}
export default {
name: "memberGrade",
components: {
uploadPicInput,
},
data() {
return {
loading: true,
data: [],
addFlag: false,
editFlag: false,
submitAddLoading: false,
submitEditLoading: false,
formAdd: buildDefaultForm(),
formEdit: buildDefaultForm(),
addBenefitOrder: [],
editBenefitOrder: [],
benefitOptions: [],
benefitTypeOptions: [],
benefitOptionsLoading: false,
editDetailLoading: false,
rules: {
gradeName: [{ required: true, message: "请输入等级名称", trigger: "blur" }],
gradeImage: [{ required: true, message: "请上传等级图标", trigger: "change" }],
requiredExperience: [{ required: true, type: "number", message: "请输入所需经验值", trigger: "change" }],
gradeSort: [{ required: true, type: "number", message: "请输入等级排序", trigger: "change" }],
gradeState: [{ required: true, message: "请选择等级开关", trigger: "change" }],
},
};
},
methods: {
benefitOptionLabel(b) {
if (!b) return "";
const name = b.benefitName || String(b.id);
const opt = this.benefitTypeOptions.find((o) => o.value === b.benefitType);
const typeText = opt ? opt.description : b.benefitType || "";
return typeText ? `${name}(${typeText})` : name;
},
onAddBenefitIdsChange(val) {
this.addBenefitOrder = syncOrderedBenefitIds(this.addBenefitOrder, val);
},
onEditBenefitIdsChange(val) {
this.editBenefitOrder = syncOrderedBenefitIds(this.editBenefitOrder, val);
},
loadBenefitTypes() {
API_Member.getMemberBenefitTypes().then((res) => {
if (res && res.success && Array.isArray(res.result)) {
this.benefitTypeOptions = res.result;
} else {
this.benefitTypeOptions = [];
}
});
},
loadBenefitOptions() {
this.benefitOptionsLoading = true;
const pageSize = 500;
const fetchPage = (pageNumber) =>
API_Member.getMemberBenefitByPage({ pageNumber, pageSize, sort: "benefitSort", order: "asc" });
return fetchPage(1)
.then((res) => {
if (!(res && res.success && res.result)) {
this.benefitOptions = [];
return;
}
const records = Array.isArray(res.result.records) ? res.result.records : [];
const total = Number(res.result.total) || records.length;
let all = records.slice();
if (total > pageSize) {
const pages = Math.ceil(total / pageSize);
const rest = [];
for (let p = 2; p <= pages; p++) {
rest.push(fetchPage(p));
}
return Promise.all(rest).then((results) => {
results.forEach((r) => {
if (r && r.success && r.result && Array.isArray(r.result.records)) {
all = all.concat(r.result.records);
}
});
this.benefitOptions = all;
});
}
this.benefitOptions = all;
})
.catch(() => {
this.benefitOptions = [];
})
.finally(() => {
this.benefitOptionsLoading = false;
});
},
parseBenefitIdsFromString(str) {
return String(str || "")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
},
fillEditFormFromGrade(grade, benefitsOrderedIds) {
this.formEdit = {
id: grade.id || "",
gradeName: grade.gradeName || "",
isDefault: grade.isDefault === true,
gradeImage: grade.gradeImage || "",
gradeBackground: grade.gradeBackground || "",
gradeFontColor: grade.gradeFontColor || "",
requiredExperience: Number(grade.requiredExperience) > 0 ? Number(grade.requiredExperience) : 1,
gradeSort: Number(grade.gradeSort) > 0 ? Number(grade.gradeSort) : 1,
gradeState: grade.gradeState || "OPEN",
benefitIds: grade.benefitIds || "",
};
this.editBenefitOrder = (benefitsOrderedIds || []).map((id) => String(id));
},
init() {
this.getData();
this.loadBenefitTypes();
this.loadBenefitOptions();
},
getData() {
this.loading = true;
API_Member.getMemberGradeByPage().then((res) => {
this.loading = false;
if (res && res.success) {
this.data = Array.isArray(res.result) ? res.result : [];
}
});
},
openAdd() {
this.addFlag = true;
this.submitAddLoading = false;
if (!this.benefitOptions.length && !this.benefitOptionsLoading) {
this.loadBenefitOptions();
// 模板 el-form 的 ref(ref="addForm" / ref="editForm")
const addForm = ref(null);
const editForm = ref(null);
const loading = ref(true);
const data = ref([]);
const addFlag = ref(false);
const editFlag = ref(false);
const submitAddLoading = ref(false);
const submitEditLoading = ref(false);
const formAdd = ref(buildDefaultForm());
const formEdit = ref(buildDefaultForm());
const addBenefitOrder = ref([]);
const editBenefitOrder = ref([]);
const benefitOptions = ref([]);
const benefitTypeOptions = ref([]);
const benefitOptionsLoading = ref(false);
const editDetailLoading = ref(false);
const rules = ref({
gradeName: [{ required: true, message: "请输入等级名称", trigger: "blur" }],
gradeImage: [{ required: true, message: "请上传等级图标", trigger: "change" }],
requiredExperience: [{ required: true, type: "number", message: "请输入所需经验值", trigger: "change" }],
gradeSort: [{ required: true, type: "number", message: "请输入等级排序", trigger: "change" }],
gradeState: [{ required: true, message: "请选择等级开关", trigger: "change" }],
});
function benefitOptionLabel(b) {
if (!b) return "";
const name = b.benefitName || String(b.id);
const opt = benefitTypeOptions.value.find((o) => o.value === b.benefitType);
const typeText = opt ? opt.description : b.benefitType || "";
return typeText ? `${name}(${typeText})` : name;
}
function onAddBenefitIdsChange(val) {
addBenefitOrder.value = syncOrderedBenefitIds(addBenefitOrder.value, val);
}
function onEditBenefitIdsChange(val) {
editBenefitOrder.value = syncOrderedBenefitIds(editBenefitOrder.value, val);
}
function loadBenefitTypes() {
API_Member.getMemberBenefitTypes().then((res) => {
if (res && res.success && Array.isArray(res.result)) {
benefitTypeOptions.value = res.result;
} else {
benefitTypeOptions.value = [];
}
});
}
function loadBenefitOptions() {
benefitOptionsLoading.value = true;
const pageSize = 500;
const fetchPage = (pageNumber) =>
API_Member.getMemberBenefitByPage({ pageNumber, pageSize, sort: "benefitSort", order: "asc" });
return fetchPage(1)
.then((res) => {
if (!(res && res.success && res.result)) {
benefitOptions.value = [];
return;
}
this.$nextTick(() => {
if (this.$refs.addForm) this.$refs.addForm.resetFields();
this.formAdd = buildDefaultForm();
this.addBenefitOrder = [];
});
},
submitAdd() {
this.$refs.addForm.validate((valid) => {
if (!valid) return;
this.submitAddLoading = true;
const { benefitIds: _omit, ...rest } = this.formAdd;
const payload = {
...rest,
benefitIds: (this.addBenefitOrder || []).join(","),
};
API_Member.addMemberGrade(payload).then((res) => {
this.submitAddLoading = false;
if (res && res.success) {
ElMessage.success("添加成功");
this.addFlag = false;
this.getData();
}
});
});
},
openEdit(row) {
this.editFlag = true;
this.submitEditLoading = false;
this.editDetailLoading = true;
if (!this.benefitOptions.length && !this.benefitOptionsLoading) {
this.loadBenefitOptions();
}
this.$nextTick(() => {
if (this.$refs.editForm) this.$refs.editForm.resetFields();
});
API_Member.getMemberGrade(row.id)
.then((res) => {
this.editDetailLoading = false;
if (res && res.success && res.result) {
const raw = res.result;
const grade = raw.grade != null ? raw.grade : raw;
const benefits = Array.isArray(raw.benefits) ? raw.benefits : [];
const orderedIds = benefits.length
? benefits.map((b) => b.id).filter((id) => id != null && id !== "")
: String(grade.benefitIds || "")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
this.fillEditFormFromGrade(grade, orderedIds);
} else {
this.fillEditFormFromGrade(row, this.parseBenefitIdsFromString(row.benefitIds));
}
})
.catch(() => {
this.editDetailLoading = false;
this.fillEditFormFromGrade(row, this.parseBenefitIdsFromString(row.benefitIds));
});
},
submitEdit() {
this.$refs.editForm.validate((valid) => {
if (!valid) return;
this.submitEditLoading = true;
const { id, benefitIds: _omit, ...rest } = this.formEdit;
const payload = {
...rest,
benefitIds: (this.editBenefitOrder || []).join(","),
};
API_Member.updateMemberGrade(id, payload).then((res) => {
this.submitEditLoading = false;
if (res && res.success) {
ElMessage.success("修改成功");
this.editFlag = false;
this.getData();
}
});
});
},
onGradeStateSwitch(row, checked) {
const nextState = checked ? "OPEN" : "CLOSE";
const prevState = row.gradeState;
if (nextState === prevState) return;
const text = checked ? "开启" : "关闭";
ElMessageBox.confirm(`确定${text}该客户等级?`, "提示", { type: "warning" }).then(() => {
row._gradeStateLoading = true;
return API_Member.updateMemberGradeState(row.id, nextState)
.then((res) => {
row._gradeStateLoading = false;
if (res && res.success) {
ElMessage.success(`${text}成功`);
row.gradeState = nextState;
} else {
this.getData();
const records = Array.isArray(res.result.records) ? res.result.records : [];
const total = Number(res.result.total) || records.length;
let all = records.slice();
if (total > pageSize) {
const pages = Math.ceil(total / pageSize);
const rest = [];
for (let p = 2; p <= pages; p++) {
rest.push(fetchPage(p));
}
return Promise.all(rest).then((results) => {
results.forEach((r) => {
if (r && r.success && r.result && Array.isArray(r.result.records)) {
all = all.concat(r.result.records);
}
})
.catch(() => {
row._gradeStateLoading = false;
});
}).catch(() => {});
},
remove(row) {
ElMessageBox.confirm("确定删除该客户等级?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberGrade(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
this.getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
benefitOptions.value = all;
});
}).catch(() => {});
},
},
mounted() {
this.init();
},
};
}
benefitOptions.value = all;
})
.catch(() => {
benefitOptions.value = [];
})
.finally(() => {
benefitOptionsLoading.value = false;
});
}
function parseBenefitIdsFromString(str) {
return String(str || "")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
}
function fillEditFormFromGrade(grade, benefitsOrderedIds) {
formEdit.value = {
id: grade.id || "",
gradeName: grade.gradeName || "",
isDefault: grade.isDefault === true,
gradeImage: grade.gradeImage || "",
gradeBackground: grade.gradeBackground || "",
gradeFontColor: grade.gradeFontColor || "",
requiredExperience: Number(grade.requiredExperience) > 0 ? Number(grade.requiredExperience) : 1,
gradeSort: Number(grade.gradeSort) > 0 ? Number(grade.gradeSort) : 1,
gradeState: grade.gradeState || "OPEN",
benefitIds: grade.benefitIds || "",
};
editBenefitOrder.value = (benefitsOrderedIds || []).map((id) => String(id));
}
function init() {
getData();
loadBenefitTypes();
loadBenefitOptions();
}
function getData() {
loading.value = true;
API_Member.getMemberGradeByPage().then((res) => {
loading.value = false;
if (res && res.success) {
data.value = Array.isArray(res.result) ? res.result : [];
}
});
}
function openAdd() {
addFlag.value = true;
submitAddLoading.value = false;
if (!benefitOptions.value.length && !benefitOptionsLoading.value) {
loadBenefitOptions();
}
nextTick(() => {
if (addForm.value) addForm.value.resetFields();
formAdd.value = buildDefaultForm();
addBenefitOrder.value = [];
});
}
function submitAdd() {
addForm.value.validate((valid) => {
if (!valid) return;
submitAddLoading.value = true;
const { benefitIds: _omit, ...rest } = formAdd.value;
const payload = {
...rest,
benefitIds: (addBenefitOrder.value || []).join(","),
};
API_Member.addMemberGrade(payload).then((res) => {
submitAddLoading.value = false;
if (res && res.success) {
ElMessage.success("添加成功");
addFlag.value = false;
getData();
}
});
});
}
function openEdit(row) {
editFlag.value = true;
submitEditLoading.value = false;
editDetailLoading.value = true;
if (!benefitOptions.value.length && !benefitOptionsLoading.value) {
loadBenefitOptions();
}
nextTick(() => {
if (editForm.value) editForm.value.resetFields();
});
API_Member.getMemberGrade(row.id)
.then((res) => {
editDetailLoading.value = false;
if (res && res.success && res.result) {
const raw = res.result;
const grade = raw.grade != null ? raw.grade : raw;
const benefits = Array.isArray(raw.benefits) ? raw.benefits : [];
const orderedIds = benefits.length
? benefits.map((b) => b.id).filter((id) => id != null && id !== "")
: String(grade.benefitIds || "")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
fillEditFormFromGrade(grade, orderedIds);
} else {
fillEditFormFromGrade(row, parseBenefitIdsFromString(row.benefitIds));
}
})
.catch(() => {
editDetailLoading.value = false;
fillEditFormFromGrade(row, parseBenefitIdsFromString(row.benefitIds));
});
}
function submitEdit() {
editForm.value.validate((valid) => {
if (!valid) return;
submitEditLoading.value = true;
const { id, benefitIds: _omit, ...rest } = formEdit.value;
const payload = {
...rest,
benefitIds: (editBenefitOrder.value || []).join(","),
};
API_Member.updateMemberGrade(id, payload).then((res) => {
submitEditLoading.value = false;
if (res && res.success) {
ElMessage.success("修改成功");
editFlag.value = false;
getData();
}
});
});
}
function onGradeStateSwitch(row, checked) {
const nextState = checked ? "OPEN" : "CLOSE";
const prevState = row.gradeState;
if (nextState === prevState) return;
const text = checked ? "开启" : "关闭";
ElMessageBox.confirm(`确定${text}该客户等级?`, "提示", { type: "warning" }).then(() => {
row._gradeStateLoading = true;
return API_Member.updateMemberGradeState(row.id, nextState)
.then((res) => {
row._gradeStateLoading = false;
if (res && res.success) {
ElMessage.success(`${text}成功`);
row.gradeState = nextState;
} else {
getData();
}
})
.catch(() => {
row._gradeStateLoading = false;
});
}).catch(() => {});
}
function remove(row) {
ElMessageBox.confirm("确定删除该客户等级?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberGrade(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
});
}).catch(() => {});
}
onMounted(() => {
init();
});
</script>
<style scoped>
.ops a {

View File

@@ -70,137 +70,136 @@
</div>
</template>
<script>
<script setup>
import { nextTick, onMounted, reactive, ref } from "vue";
import * as API_Member from "@/api/member.js";
import { ElMessage, ElMessageBox } from "element-plus";
export default {
name: "memberGroup",
data() {
return {
loading: true,
searchForm: {
pageNumber: 1,
pageSize: 20,
},
data: [],
total: 0,
addFlag: false,
editFlag: false,
submitAddLoading: false,
submitEditLoading: false,
formAdd: {
groupName: "",
description: "",
},
formEdit: {
id: "",
groupName: "",
description: "",
},
rulesAdd: {
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
},
rulesEdit: {
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
},
};
},
methods: {
init() {
this.getData();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getData();
},
changePageSize(v) {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = v;
this.getData();
},
getData() {
this.loading = true;
API_Member.getMemberGroupByPage(this.searchForm).then((res) => {
this.loading = false;
if (res && res.success && res.result) {
this.data = res.result.records || [];
this.total = res.result.total || 0;
}
});
},
openAdd() {
this.addFlag = true;
this.$nextTick(() => {
if (this.$refs.addForm) this.$refs.addForm.resetFields();
this.formAdd = { groupName: "", description: "" };
});
},
submitAdd() {
this.$refs.addForm.validate((valid) => {
if (!valid) return;
this.submitAddLoading = true;
API_Member.addMemberGroup(this.formAdd).then((res) => {
this.submitAddLoading = false;
if (res && res.success) {
ElMessage.success("添加成功");
this.addFlag = false;
this.getData();
}
});
});
},
openEdit(row) {
this.editFlag = true;
this.submitEditLoading = false;
API_Member.getMemberGroup(row.id).then((res) => {
if (res && res.success && res.result) {
this.formEdit = {
id: res.result.id,
groupName: res.result.groupName || "",
description: res.result.description || "",
};
} else {
this.formEdit = {
id: row.id,
groupName: row.groupName || "",
description: row.description || "",
};
}
});
},
submitEdit() {
this.$refs.editForm.validate((valid) => {
if (!valid) return;
this.submitEditLoading = true;
const { id, groupName, description } = this.formEdit;
API_Member.updateMemberGroup(id, { groupName, description }).then((res) => {
this.submitEditLoading = false;
if (res && res.success) {
ElMessage.success("修改成功");
this.editFlag = false;
this.getData();
}
});
});
},
remove(row) {
ElMessageBox.confirm("确定删除该分组?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberGroup(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
this.getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
});
}).catch(() => {});
},
},
mounted() {
this.init();
},
};
defineOptions({ name: "memberGroup" });
const addForm = ref(null);
const editForm = ref(null);
const loading = ref(true);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
});
const data = ref([]);
const total = ref(0);
const addFlag = ref(false);
const editFlag = ref(false);
const submitAddLoading = ref(false);
const submitEditLoading = ref(false);
const formAdd = ref({
groupName: "",
description: "",
});
const formEdit = ref({
id: "",
groupName: "",
description: "",
});
const rulesAdd = reactive({
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
});
const rulesEdit = reactive({
groupName: [{ required: true, message: "请输入分组名称", trigger: "blur" }],
});
function init() {
getData();
}
function changePage(v) {
searchForm.pageNumber = v;
getData();
}
function changePageSize(v) {
searchForm.pageNumber = 1;
searchForm.pageSize = v;
getData();
}
function getData() {
loading.value = true;
API_Member.getMemberGroupByPage(searchForm).then((res) => {
loading.value = false;
if (res && res.success && res.result) {
data.value = res.result.records || [];
total.value = res.result.total || 0;
}
});
}
function openAdd() {
addFlag.value = true;
nextTick(() => {
if (addForm.value) addForm.value.resetFields();
formAdd.value = { groupName: "", description: "" };
});
}
function submitAdd() {
addForm.value.validate((valid) => {
if (!valid) return;
submitAddLoading.value = true;
API_Member.addMemberGroup(formAdd.value).then((res) => {
submitAddLoading.value = false;
if (res && res.success) {
ElMessage.success("添加成功");
addFlag.value = false;
getData();
}
});
});
}
function openEdit(row) {
editFlag.value = true;
submitEditLoading.value = false;
API_Member.getMemberGroup(row.id).then((res) => {
if (res && res.success && res.result) {
formEdit.value = {
id: res.result.id,
groupName: res.result.groupName || "",
description: res.result.description || "",
};
} else {
formEdit.value = {
id: row.id,
groupName: row.groupName || "",
description: row.description || "",
};
}
});
}
function submitEdit() {
editForm.value.validate((valid) => {
if (!valid) return;
submitEditLoading.value = true;
const { id, groupName, description } = formEdit.value;
API_Member.updateMemberGroup(id, { groupName, description }).then((res) => {
submitEditLoading.value = false;
if (res && res.success) {
ElMessage.success("修改成功");
editFlag.value = false;
getData();
}
});
});
}
function remove(row) {
ElMessageBox.confirm("确定删除该分组?", "提示", { type: "warning" }).then(() => {
API_Member.deleteMemberGroup(row.id).then((res) => {
if (res && res.success) {
ElMessage.success("删除成功");
getData();
} else if (res && res.message) {
ElMessage.error(res.message);
}
});
}).catch(() => {});
}
onMounted(() => {
init();
});
</script>
<style scoped>

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -168,7 +168,7 @@
<el-dialog v-model="addFlag" title="添加会员" width="500px" destroy-on-close class="add-member-dialog">
<el-form
ref="addMemberForm"
ref="addMemberFormRef"
:model="addMemberForm"
:rules="addRule"
label-width="100px"
@@ -210,7 +210,7 @@
</el-dialog>
<el-dialog v-model="descFlag" :title="descTitle" width="500px" destroy-on-close>
<el-form ref="form" :model="form" :rules="ruleValidate" label-width="80px">
<el-form ref="formRef" :model="form" :rules="ruleValidate" label-width="80px">
<el-input v-model="form.id" style="display: none" />
<el-form-item label="头像">
<img :src="form.face || defaultPic" class="face" />
@@ -251,7 +251,7 @@
</el-dialog>
<el-dialog v-model="walletIncreaseFlag" title="增加余额" width="420px" destroy-on-close>
<el-form ref="walletIncreaseForm" :model="walletIncreaseForm" :rules="walletIncreaseRule" label-width="90px">
<el-form ref="walletIncreaseFormRef" :model="walletIncreaseForm" :rules="walletIncreaseRule" label-width="90px">
<el-form-item label="充值金额" prop="rechargeMoney">
<el-input-number v-model="walletIncreaseForm.rechargeMoney" :min="0.01" :precision="2" style="width: 240px" />
</el-form-item>
@@ -263,7 +263,7 @@
</el-dialog>
<el-dialog v-model="memberPointFlag" title="修改积分" width="420px" destroy-on-close>
<el-form ref="memberPointForm" :model="memberPointForm" :rules="memberPointRule" label-width="90px">
<el-form ref="memberPointFormRef" :model="memberPointForm" :rules="memberPointRule" label-width="90px">
<el-form-item label="类型" prop="type">
<el-radio-group v-model="memberPointForm.type">
<el-radio-button value="INCREASE">增加</el-radio-button>
@@ -281,7 +281,7 @@
</el-dialog>
<el-dialog v-model="memberGroupFlag" title="设定会员分组" width="420px" destroy-on-close>
<el-form ref="memberGroupForm" :model="memberGroupForm" :rules="memberGroupRule" label-width="90px">
<el-form ref="memberGroupFormRef" :model="memberGroupForm" :rules="memberGroupRule" label-width="90px">
<el-form-item label="会员分组" prop="groupId">
<el-select v-model="memberGroupForm.groupId" clearable filterable style="width: 240px">
<el-option
@@ -300,13 +300,14 @@
</el-dialog>
<el-dialog v-model="picModelFlag" width="1200px">
<ossManage ref="ossManage" @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" />
<ossManage ref="ossManageRef" @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" />
</el-dialog>
<multipleMap ref="map" @callback="selectedRegion" />
</div>
</template>
<script>
<script setup>
import { ref, watch, nextTick, onMounted } from "vue";
import { ArrowDown } from "@element-plus/icons-vue";
import multipleMap from "@/components/map/multiple-map";
import * as API_Member from "@/api/member.js";
@@ -314,451 +315,456 @@ import ossManage from "@/views/sys/oss-manage/ossManage";
import * as RegExp from "@/libs/RegExp.js";
import { ElMessage, ElMessageBox } from "element-plus";
import { customRouterPush } from "@/utils/filters";
import { md5 } from "@/utils/md5.js";
import defaultPic from "@/assets/default.png";
export default {
name: "member",
components: {
multipleMap,
ossManage,
ArrowDown,
defineOptions({ name: "member" });
const props = defineProps({
selectedMember: {
type: Boolean,
default: false,
},
props: {
selectedMember: {
type: Boolean,
default: false,
},
selectedList: {
type: null,
default: () => [],
},
checkboxSelect: {
type: Boolean,
default: false,
},
selectedList: {
type: null,
default: () => [],
},
data() {
return {
defaultPic,
descTitle: "",
descFlag: false,
loading: true,
addFlag: false,
addMemberForm: {
mobile: "",
username: "",
password: "",
},
searchForm: {
pageNumber: 1,
pageSize: 20,
order: "desc",
id: "",
username: "",
mobile: "",
disabled: "OPEN",
groupId: "",
},
picModelFlag: false,
form: {},
walletIncreaseFlag: false,
walletIncreaseLoading: false,
walletIncreaseForm: {
memberId: "",
rechargeMoney: null,
},
walletIncreaseRule: {
rechargeMoney: [
{ required: true, type: "number", message: "请输入充值金额", trigger: "change" },
{
validator: (rule, value, callback) => {
if (typeof value !== "number" || value <= 0) {
callback(new Error("充值金额必须大于0"));
return;
}
callback();
},
trigger: "change",
},
],
},
memberPointFlag: false,
memberPointLoading: false,
memberPointForm: {
memberId: "",
point: null,
type: "INCREASE",
},
selectedRows: [],
memberGroupFlag: false,
memberGroupLoading: false,
memberGroupForm: {
groupId: "",
},
memberGroupRule: {
groupId: [{ required: true, message: "请选择会员分组", trigger: "change" }],
},
memberGroupList: [],
memberGradeList: [],
memberPointRule: {
type: [{ required: true, message: "请选择类型", trigger: "change" }],
point: [
{ required: true, type: "number", message: "请输入积分", trigger: "change" },
{
validator: (rule, value, callback) => {
if (typeof value !== "number" || value <= 0) {
callback(new Error("积分必须大于0"));
return;
}
callback();
},
trigger: "change",
},
],
},
addRule: {
mobile: [
{ required: true, message: "请输入手机号码" },
{ pattern: RegExp.mobile, message: "请输入正确的手机号" },
],
username: [{ required: true, message: "请输入客户名称" }],
password: [{ required: true, message: "请输入密码" }],
},
ruleValidate: {},
data: [],
total: 0,
selectMember: [],
};
checkboxSelect: {
type: Boolean,
default: false,
},
watch: {
selectedList: {
handler(val) {
this.selectMember = JSON.parse(JSON.stringify(val));
this.init(this.data);
});
const emit = defineEmits(["callback"]);
// 模板 el-form/el-table 的模板 ref(原 ref="searchForm"/"addMemberForm"/"form" 等与 data 同名会互相覆盖,
// 改名为 xxxRef;ossManage 与 import 同名,改名 ossManageRef)
const searchFormRef = ref(null);
const table = ref(null);
const addMemberFormRef = ref(null);
const formRef = ref(null);
const walletIncreaseFormRef = ref(null);
const memberPointFormRef = ref(null);
const memberGroupFormRef = ref(null);
const ossManageRef = ref(null);
const descTitle = ref("");
const descFlag = ref(false);
const loading = ref(true);
const addFlag = ref(false);
const addMemberForm = ref({
mobile: "",
username: "",
password: "",
});
const searchForm = ref({
pageNumber: 1,
pageSize: 20,
order: "desc",
id: "",
username: "",
mobile: "",
disabled: "OPEN",
groupId: "",
});
const picModelFlag = ref(false);
const form = ref({});
const walletIncreaseFlag = ref(false);
const walletIncreaseLoading = ref(false);
const walletIncreaseForm = ref({
memberId: "",
rechargeMoney: null,
});
const walletIncreaseRule = ref({
rechargeMoney: [
{ required: true, type: "number", message: "请输入充值金额", trigger: "change" },
{
validator: (rule, value, callback) => {
if (typeof value !== "number" || value <= 0) {
callback(new Error("充值金额必须大于0"));
return;
}
callback();
},
deep: true,
immediate: true,
trigger: "change",
},
],
});
const memberPointFlag = ref(false);
const memberPointLoading = ref(false);
const memberPointForm = ref({
memberId: "",
point: null,
type: "INCREASE",
});
const selectedRows = ref([]);
const memberGroupFlag = ref(false);
const memberGroupLoading = ref(false);
const memberGroupForm = ref({
groupId: "",
});
const memberGroupRule = ref({
groupId: [{ required: true, message: "请选择会员分组", trigger: "change" }],
});
const memberGroupList = ref([]);
const memberGradeList = ref([]);
const memberPointRule = ref({
type: [{ required: true, message: "请选择类型", trigger: "change" }],
point: [
{ required: true, type: "number", message: "请输入积分", trigger: "change" },
{
validator: (rule, value, callback) => {
if (typeof value !== "number" || value <= 0) {
callback(new Error("积分必须大于0"));
return;
}
callback();
},
trigger: "change",
},
],
});
const addRule = ref({
mobile: [
{ required: true, message: "请输入手机号码" },
{ pattern: RegExp.mobile, message: "请输入正确的手机号" },
],
username: [{ required: true, message: "请输入客户名称" }],
password: [{ required: true, message: "请输入密码" }],
});
const ruleValidate = ref({});
const data = ref([]);
const total = ref(0);
const selectMember = ref([]);
watch(
() => props.selectedList,
(val) => {
selectMember.value = JSON.parse(JSON.stringify(val));
init(data.value);
},
methods: {
handleMoreCommand(name, row) {
if (name === "edit") this.editPerm(row);
if (name === "disabled") this.disabled(row);
if (name === "increaseWallet") this.openWalletIncrease(row);
if (name === "updatePoint") this.openMemberPoint(row);
},
onSelectionChange(selection) {
if (this.selectedMember && this.checkboxSelect) {
this.selectMember = selection || [];
return;
{ deep: true, immediate: true }
);
function handleMoreCommand(name, row) {
if (name === "edit") editPerm(row);
if (name === "disabled") disabled(row);
if (name === "increaseWallet") openWalletIncrease(row);
if (name === "updatePoint") openMemberPoint(row);
}
function onSelectionChange(selection) {
if (props.selectedMember && props.checkboxSelect) {
selectMember.value = selection || [];
return;
}
selectedRows.value = selection || [];
}
function getSelection() {
return selectMember.value || [];
}
function syncTableSelection() {
if (!props.selectedMember || !props.checkboxSelect) {
return;
}
nextTick(() => {
clearSelection();
data.value.forEach((row) => {
if (selectMember.value.some((member) => member.id === row.id)) {
table.value?.toggleRowSelection(row, true);
}
this.selectedRows = selection || [];
},
getSelection() {
return this.selectMember || [];
},
syncTableSelection() {
if (!this.selectedMember || !this.checkboxSelect) {
return;
});
});
}
function openSetMemberGroup() {
memberGroupFlag.value = true;
memberGroupLoading.value = false;
memberGroupForm.value = { groupId: "" };
nextTick(() => {
if (memberGroupFormRef.value) memberGroupFormRef.value.resetFields();
});
loadMemberGroupList();
}
function loadMemberGroupList() {
API_Member.getMemberGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
if (res && res.success && res.result) {
memberGroupList.value = res.result.records || [];
}
});
}
function loadMemberGradeList() {
API_Member.getMemberGradeByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
if (res && res.success && res.result) {
memberGradeList.value = res.result || [];
}
});
}
function clearSelection() {
table.value?.clearSelection();
}
function submitSetMemberGroup() {
if (selectedRows.value.length === 0) {
ElMessage.warning("请先选择会员");
return;
}
memberGroupFormRef.value.validate((valid) => {
if (!valid) return;
const memberIds = selectedRows.value.map((item) => item.id);
const groupId = memberGroupForm.value.groupId;
memberGroupLoading.value = true;
Promise.all(
memberIds.map((memberId) => API_Member.setMemberUserGroups(memberId, [groupId]))
)
.then((results) => {
memberGroupLoading.value = false;
const failed = results.find((res) => !res || !res.success);
if (failed) {
ElMessage.error(failed.message || "设置失败");
return;
}
ElMessage.success("设置成功");
memberGroupFlag.value = false;
selectedRows.value = [];
clearSelection();
getData();
})
.catch(() => {
memberGroupLoading.value = false;
ElMessage.error("设置失败,请稍后重试");
});
});
}
function callback(val) {
selectMember.value.forEach((item) => {
item.___selected = false;
});
val.___selected = !val.___selected;
let findUser = selectMember.value.find((item) => item.id == val.id);
if (!findUser) {
selectMember.value.push(val);
} else {
selectMember.value.map((item, index) => {
if (item.id == findUser.id) {
selectMember.value.splice(index, 1);
}
this.$nextTick(() => {
this.clearSelection();
this.data.forEach((row) => {
if (this.selectMember.some((member) => member.id === row.id)) {
this.$refs.table?.toggleRowSelection(row, true);
}
});
});
},
openSetMemberGroup() {
this.memberGroupFlag = true;
this.memberGroupLoading = false;
this.memberGroupForm = { groupId: "" };
this.$nextTick(() => {
if (this.$refs.memberGroupForm) this.$refs.memberGroupForm.resetFields();
});
this.loadMemberGroupList();
},
loadMemberGroupList() {
API_Member.getMemberGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
if (res && res.success && res.result) {
this.memberGroupList = res.result.records || [];
});
}
emit("callback", val);
}
function init(list) {
list.forEach((item) => {
if (selectMember.value.length != 0) {
selectMember.value.forEach((member) => {
if (member.id == item.id) {
item.___selected = true;
}
});
},
loadMemberGradeList() {
API_Member.getMemberGradeByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
if (res && res.success && res.result) {
this.memberGradeList = res.result || [];
} else {
item.___selected = false;
}
});
data.value = list;
}
function changePage() {
getData();
}
function changePageSize() {
searchForm.value.pageNumber = 1;
getData();
}
function handleSearch() {
searchForm.value.pageNumber = 1;
searchForm.value.pageSize = 20;
getData();
}
function editPerm(val) {
descTitle.value = `查看用户 ${val.username}`;
descFlag.value = true;
getMemberInfo(val.id);
}
function addMember() {
addMemberForm.value = {
mobile: "",
username: "",
password: "",
};
addFlag.value = true;
nextTick(() => {
addMemberFormRef.value?.clearValidate();
});
}
function getMemberInfo(id) {
API_Member.getMemberInfoData(id).then((res) => {
if (res.result) {
form.value = res.result;
}
});
}
function getData() {
loading.value = true;
if (!props.selectedMember) {
selectedRows.value = [];
clearSelection();
}
API_Member.getMemberListData(searchForm.value).then((res) => {
if (res.result.records) {
loading.value = false;
init(res.result.records);
total.value = res.result.total;
syncTableSelection();
}
});
}
function openPicSelector() {
picModelFlag.value = true;
nextTick(() => {
if (ossManageRef.value) {
ossManageRef.value.selectImage = true;
}
});
}
function callbackSelected(val) {
picModelFlag.value = false;
form.value.face = val.url;
}
function addMemberSubmit() {
addMemberForm.value.password = md5(addMemberForm.value.password);
addMemberFormRef.value.validate((valid) => {
if (valid) {
API_Member.addMember(addMemberForm.value).then((res) => {
if (res.result) {
addMemberFormRef.value.resetFields();
getData();
ElMessage.success("添加成功!");
addFlag.value = false;
}
});
},
clearSelection() {
this.$refs.table?.clearSelection();
},
submitSetMemberGroup() {
if (this.selectedRows.length === 0) {
ElMessage.warning("请先选择会员");
return;
}
});
}
function selectedRegion(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
form.value.region = paths;
form.value.regionId = ids;
} else {
form.value.region = val.data.addr;
form.value.regionId = val.data.addrId;
}
}
function detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
}
function disabled(v) {
let params = {
memberIds: [v.id],
disabled: false,
};
ElMessageBox.confirm("确认禁用此会员?", "提示", { type: "warning" }).then(() => {
API_Member.updateMemberStatus(params).then((res) => {
if (res.success) {
ElMessage.success("禁用成功");
getData();
}
this.$refs.memberGroupForm.validate((valid) => {
if (!valid) return;
const memberIds = this.selectedRows.map((item) => item.id);
const groupId = this.memberGroupForm.groupId;
this.memberGroupLoading = true;
Promise.all(
memberIds.map((memberId) => API_Member.setMemberUserGroups(memberId, [groupId]))
)
.then((results) => {
this.memberGroupLoading = false;
const failed = results.find((res) => !res || !res.success);
if (failed) {
ElMessage.error(failed.message || "设置失败");
return;
}
ElMessage.success("设置成功");
this.memberGroupFlag = false;
this.selectedRows = [];
this.clearSelection();
this.getData();
})
.catch(() => {
this.memberGroupLoading = false;
ElMessage.error("设置失败,请稍后重试");
});
});
},
callback(val) {
this.selectMember.forEach((item) => {
item.___selected = false;
});
val.___selected = !val.___selected;
let findUser = this.selectMember.find((item) => item.id == val.id);
if (!findUser) {
this.selectMember.push(val);
} else {
this.selectMember.map((item, index) => {
if (item.id == findUser.id) {
this.selectMember.splice(index, 1);
}
});
}
this.$emit("callback", val);
},
init(data) {
data.forEach((item) => {
if (this.selectMember.length != 0) {
this.selectMember.forEach((member) => {
if (member.id == item.id) {
item.___selected = true;
}
});
});
}).catch(() => {});
}
function openWalletIncrease(row) {
walletIncreaseLoading.value = false;
walletIncreaseForm.value = { memberId: row.id, rechargeMoney: null };
walletIncreaseFlag.value = true;
nextTick(() => {
walletIncreaseFormRef.value && walletIncreaseFormRef.value.resetFields();
});
}
function submitWalletIncrease() {
walletIncreaseFormRef.value.validate((valid) => {
if (!valid) return;
walletIncreaseLoading.value = true;
API_Member.increaseMemberWallet({
memberId: walletIncreaseForm.value.memberId,
rechargeMoney: walletIncreaseForm.value.rechargeMoney,
})
.then((res) => {
if (res && res.success) {
ElMessage.success("充值成功");
walletIncreaseFlag.value = false;
getData();
} else {
item.___selected = false;
ElMessage.error((res && res.message) || "充值失败");
}
})
.finally(() => {
walletIncreaseLoading.value = false;
});
this.data = data;
},
changePage() {
this.getData();
},
changePageSize() {
this.searchForm.pageNumber = 1;
this.getData();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getData();
},
editPerm(val) {
this.descTitle = `查看用户 ${val.username}`;
this.descFlag = true;
this.getMemberInfo(val.id);
},
addMember() {
this.addMemberForm = {
mobile: "",
username: "",
password: "",
};
this.addFlag = true;
this.$nextTick(() => {
this.$refs.addMemberForm?.clearValidate();
});
},
getMemberInfo(id) {
API_Member.getMemberInfoData(id).then((res) => {
if (res.result) {
this.form = res.result;
});
}
function openMemberPoint(row) {
memberPointLoading.value = false;
memberPointForm.value = { memberId: row.id, point: null, type: "INCREASE" };
memberPointFlag.value = true;
nextTick(() => {
memberPointFormRef.value && memberPointFormRef.value.resetFields();
});
}
function submitMemberPoint() {
memberPointFormRef.value.validate((valid) => {
if (!valid) return;
memberPointLoading.value = true;
API_Member.updateMemberPoint({
memberId: memberPointForm.value.memberId,
point: memberPointForm.value.point,
type: memberPointForm.value.type,
})
.then((res) => {
if (res && res.success) {
ElMessage.success("修改成功");
memberPointFlag.value = false;
getData();
} else {
ElMessage.error((res && res.message) || "修改失败");
}
})
.finally(() => {
memberPointLoading.value = false;
});
},
getData() {
this.loading = true;
if (!this.selectedMember) {
this.selectedRows = [];
this.clearSelection();
}
API_Member.getMemberListData(this.searchForm).then((res) => {
if (res.result.records) {
this.loading = false;
this.init(res.result.records);
this.total = res.result.total;
this.syncTableSelection();
}
});
},
openPicSelector() {
this.picModelFlag = true;
this.$nextTick(() => {
if (this.$refs.ossManage) {
this.$refs.ossManage.selectImage = true;
}
});
},
callbackSelected(val) {
this.picModelFlag = false;
this.form.face = val.url;
},
addMemberSubmit() {
this.addMemberForm.password = this.md5(this.addMemberForm.password);
this.$refs.addMemberForm.validate((valid) => {
if (valid) {
API_Member.addMember(this.addMemberForm).then((res) => {
if (res.result) {
this.$refs.addMemberForm.resetFields();
this.getData();
ElMessage.success("添加成功!");
this.addFlag = false;
}
});
}
});
},
selectedRegion(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
this.form.region = paths;
this.form.regionId = ids;
} else {
this.form.region = val.data.addr;
this.form.regionId = val.data.addrId;
}
},
detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
},
disabled(v) {
let params = {
memberIds: [v.id],
disabled: false,
};
ElMessageBox.confirm("确认禁用此会员?", "提示", { type: "warning" }).then(() => {
API_Member.updateMemberStatus(params).then((res) => {
if (res.success) {
ElMessage.success("禁用成功");
this.getData();
}
});
}).catch(() => {});
},
openWalletIncrease(row) {
this.walletIncreaseLoading = false;
this.walletIncreaseForm = { memberId: row.id, rechargeMoney: null };
this.walletIncreaseFlag = true;
this.$nextTick(() => {
this.$refs.walletIncreaseForm && this.$refs.walletIncreaseForm.resetFields();
});
},
submitWalletIncrease() {
this.$refs.walletIncreaseForm.validate((valid) => {
if (!valid) return;
this.walletIncreaseLoading = true;
API_Member.increaseMemberWallet({
memberId: this.walletIncreaseForm.memberId,
rechargeMoney: this.walletIncreaseForm.rechargeMoney,
})
.then((res) => {
if (res && res.success) {
ElMessage.success("充值成功");
this.walletIncreaseFlag = false;
this.getData();
} else {
ElMessage.error((res && res.message) || "充值失败");
}
})
.finally(() => {
this.walletIncreaseLoading = false;
});
});
},
openMemberPoint(row) {
this.memberPointLoading = false;
this.memberPointForm = { memberId: row.id, point: null, type: "INCREASE" };
this.memberPointFlag = true;
this.$nextTick(() => {
this.$refs.memberPointForm && this.$refs.memberPointForm.resetFields();
});
},
submitMemberPoint() {
this.$refs.memberPointForm.validate((valid) => {
if (!valid) return;
this.memberPointLoading = true;
API_Member.updateMemberPoint({
memberId: this.memberPointForm.memberId,
point: this.memberPointForm.point,
type: this.memberPointForm.type,
})
.then((res) => {
if (res && res.success) {
ElMessage.success("修改成功");
this.memberPointFlag = false;
this.getData();
} else {
ElMessage.error((res && res.message) || "修改失败");
}
})
.finally(() => {
this.memberPointLoading = false;
});
});
},
handleSubmitModal() {
const { nickName, sex, username, face, newPassword, id, regionId, region } = this.form;
let time = new Date(this.form.birthday);
let birthday =
this.form.birthday === undefined
? ""
: time.getFullYear() + "-" + (time.getMonth() + 1) + "-" + time.getDate();
let submit = {
regionId,
region,
nickName,
sex,
birthday,
face,
id,
};
if (newPassword) {
submit.password = this.md5(newPassword);
}
API_Member.updateMember(submit).then((res) => {
if (res.result) {
ElMessage.success("修改成功!");
this.descFlag = false;
this.getData();
}
});
},
},
mounted() {
this.getData();
this.loadMemberGroupList();
this.loadMemberGradeList();
},
};
});
}
function handleSubmitModal() {
const { nickName, sex, username, face, newPassword, id, regionId, region } = form.value;
let time = new Date(form.value.birthday);
let birthday =
form.value.birthday === undefined
? ""
: time.getFullYear() + "-" + (time.getMonth() + 1) + "-" + time.getDate();
let submit = {
regionId,
region,
nickName,
sex,
birthday,
face,
id,
};
if (newPassword) {
submit.password = md5(newPassword);
}
API_Member.updateMember(submit).then((res) => {
if (res.result) {
ElMessage.success("修改成功!");
descFlag.value = false;
getData();
}
});
}
onMounted(() => {
getData();
loadMemberGroupList();
loadMemberGradeList();
});
// 外部通过 ref 调用(promotions/coupon-activity/coupon-publish.vue 的 memberLayoutRef.getSelection())
defineExpose({ getSelection });
</script>
<style lang="scss" scoped>
.face {

View File

@@ -379,7 +379,7 @@
width="500px"
:close-on-click-modal="false"
>
<el-form ref="addressForm" :model="addressForm" label-width="100px" :rules="addressFormValidate">
<el-form ref="addressFormRef" :model="addressForm" label-width="100px" :rules="addressFormValidate">
<el-form-item label="收货人姓名" prop="name">
<el-input v-model="addressForm.name" maxlength="8" clearable style="width: 80%" />
</el-form-item>
@@ -388,7 +388,7 @@
</el-form-item>
<el-form-item label="收货人地址" prop="consigneeAddressPath">
<span>{{ addressForm.consigneeAddressPath || "暂无地址" }}</span>
<el-button style="margin-left: 10px" @click="$refs.map.open()">选择</el-button>
<el-button style="margin-left: 10px" @click="map.open()">选择</el-button>
</el-form-item>
<el-form-item label="详细地址" prop="detail">
<el-input v-model="addressForm.detail" maxlength="35" clearable style="width: 80%" />
@@ -412,7 +412,9 @@
</div>
</template>
<script>
<script setup>
import { ref, reactive, nextTick, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import * as API_Member from "@/api/member.js";
import ossManage from "@/views/sys/oss-manage/ossManage";
import multipleMap from "@/components/map/multiple-map";
@@ -420,374 +422,373 @@ import * as RegExp from "@/libs/RegExp.js";
import * as API_Order from "@/api/order.js";
import { ElMessage, ElMessageBox } from "element-plus";
export default {
name: "memberDetail",
components: {
ossManage,
multipleMap,
},
data() {
return {
id: "",
activeTab: "point",
loading: true,
addressLoading: false,
memberInfo: {},
memberWalletInfo: {},
addressModalTitle: "",
addressModalVisible: false,
addressForm: {
id: "",
isDefault: 0,
consigneeAddressPath: "",
consigneeAddressIdPath: "",
},
selectDate: null,
submitLoading: false,
addressFormValidate: {
name: [{ required: true, message: "收货人姓名不能为空" }],
mobile: [
{ required: true, message: "请输入收货人手机号码" },
{
pattern: RegExp.mobile,
message: "请输入正确的手机号",
},
],
consigneeAddressPath: [{ required: true, message: "收货人地址不能为空" }],
detail: [{ required: true, message: "收货人详细地址不能为空" }],
},
pointData: [],
pointTotal: 0,
pointSearchForm: {
pageNumber: 1,
pageSize: 20,
},
orderData: [],
orderTotal: 0,
orderSearchForm: {
pageNumber: 1,
pageSize: 20,
payStatus: "",
orderSn: "",
orderType: "",
},
addressData: [],
addressTotal: 0,
addressSearchForm: {
pageNumber: 1,
pageSize: 20,
},
walletSearchForm: {
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
},
walletData: [],
walletTotal: 0,
receiptRecordSearchForm: {
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
},
receiptRecordData: [],
receiptRecordTotal: 0,
};
},
methods: {
orderTypeText(v) {
const map = {
NORMAL: "普通订单",
VIRTUAL: "虚拟订单",
GIFT: "赠品订单",
PINTUAN: "拼团订单",
};
return map[v] || v || "";
},
clientTypeText(v) {
const map = {
H5: "移动端",
PC: "PC端",
WECHAT_MP: "小程序端",
APP: "移动应用端",
};
return map[v] || v || "";
},
orderStatusText(v) {
const map = {
UNPAID: "未付款",
PAID: "已付款",
UNDELIVERED: "待发货",
DELIVERED: "已发货",
COMPLETED: "已完成",
TAKE: "待核验",
CANCELLED: "已关闭",
};
return map[v] || v || "";
},
payStatusText(v) {
const map = {
UNPAID: "未付款",
PAID: "已付款",
};
return map[v] || v || "";
},
groupAfterSaleStatusText(v) {
const map = {
NEW: "未申请",
NOT_APPLIED: "未申请",
ALREADY_APPLIED: "已申请",
EXPIRED: "已失效",
};
return map[v] || v || "";
},
groupComplainStatusText(v) {
const map = {
NEW: "未申请",
NO_APPLY: "未申请",
APPLYING: "申请中",
COMPLETE: "已完成",
EXPIRED: "已失效",
CANCEL: "取消投诉",
};
return map[v] || v || "";
},
walletServiceTypeText(type) {
if (type === "WALLET_WITHDRAWAL") return "余额提现";
if (type === "WALLET_PAY") return "余额支付";
if (type === "WALLET_REFUND") return "余额退款";
if (type === "WALLET_RECHARGE") return "余额充值";
return "佣金提成";
},
init() {
this.getMemberInfo();
this.getPointData();
},
memberInfoChange(v) {
if (v == "point") {
this.getPointData();
}
if (v == "address") {
this.$nextTick(() => {
this.getAddressData();
});
}
if (v == "order") {
this.getOrderData();
}
if (v == "wallet") {
this.getMemberWalletData();
this.getDepositLogData();
}
if (v == "receipt") {
this.getReceiptRecordData();
}
},
getMemberInfo() {
API_Member.getMemberInfoData(this.id).then((res) => {
this.memberInfo = res.result;
});
},
memberStatusChange(v) {
let params = {
memberIds: [this.id],
disabled: v,
};
API_Member.updateMemberStatus(params).then((res) => {});
},
getMemberWalletData() {
this.loading = true;
let params = {
memberId: this.id,
};
API_Member.getMemberWallet(params).then((res) => {
this.loading = false;
if (res.success) {
this.memberWalletInfo = res.result;
}
});
this.loading = false;
},
getDepositLogData() {
this.loading = true;
this.walletSearchForm.memberId = this.id;
API_Member.getUserWallet(this.walletSearchForm).then((res) => {
this.loading = false;
if (res.success) {
this.walletData = res.result.records;
this.walletTotal = res.result.total;
}
});
this.loading = false;
},
getReceiptRecordData() {
this.loading = true;
this.receiptRecordSearchForm.pageNumber = 1;
this.receiptRecordSearchForm.pageSize = 20;
this.receiptRecordSearchForm.memberId = this.id;
API_Order.getReceiptPage(this.receiptRecordSearchForm).then((res) => {
this.loading = false;
if (res.success) {
this.receiptRecordData = res.result.records;
this.receiptRecordTotal = res.result.total;
}
});
this.loading = false;
},
getOrderData() {
this.loading = true;
this.orderSearchForm.pageNumber = 1;
this.orderSearchForm.pageSize = 20;
this.orderSearchForm.memberId = this.id;
API_Order.getOrderList(this.orderSearchForm).then((res) => {
this.loading = false;
if (res.success) {
this.orderData = res.result.records;
this.orderTotal = res.result.total;
}
});
this.loading = false;
},
orderDetail(v) {
this.$router.push({
name: "order-detail",
query: { sn: v },
});
},
getPointData() {
this.loading = true;
this.pointSearchForm.memberId = this.id;
API_Member.getHistoryPointData(this.pointSearchForm).then((res) => {
this.loading = false;
if (res.success) {
this.pointData = res.result.records;
this.pointTotal = res.result.total;
}
});
this.loading = false;
},
addressSubmit() {
this.addressForm.memberId = this.id;
this.$refs.addressForm.validate((valid) => {
if (valid) {
this.submitLoading = true;
let submit = JSON.parse(JSON.stringify(this.addressForm));
submit.isDefault ? (submit.isDefault = true) : (submit.isDefault = false);
if (submit.id != "") {
API_Member.editMemberAddress(submit).then((res) => {
this.submitLoading = false;
if (res && res.success) {
ElMessage.success("修改成功");
this.addressModalVisible = false;
this.getAddressData();
}
});
} else {
API_Member.addMemberAddress(submit).then((res) => {
this.submitLoading = false;
if (res && res.success) {
ElMessage.success("添加成功");
this.addressModalVisible = false;
this.getAddressData();
}
});
}
}
});
},
getAddress(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
defineOptions({ name: "memberDetail" });
this.addressForm.consigneeAddressPath = paths;
this.addressForm.consigneeAddressIdPath = ids;
const route = useRoute();
const router = useRouter();
const coord = val.data[val.data.length - 1].center.split(",");
this.addressForm.lat = coord[1];
this.addressForm.lon = coord[0];
} else {
this.addressForm.consigneeAddressPath = val.data.addr;
this.addressForm.consigneeAddressIdPath = val.data.addrId;
this.addressForm.lat = val.data.position.lat;
this.addressForm.lon = val.data.position.lng;
}
// 模板 el-form 的 ref(原 ref="addressForm",与 data 同名会互相覆盖,改名为 addressFormRef)
const addressFormRef = ref(null);
// 模板 multipleMap 的 ref(ref="map")
const map = ref(null);
const id = ref("");
const activeTab = ref("point");
const loading = ref(true);
const addressLoading = ref(false);
const memberInfo = ref({});
const memberWalletInfo = ref({});
const addressModalTitle = ref("");
const addressModalVisible = ref(false);
const addressForm = reactive({
id: "",
isDefault: 0,
consigneeAddressPath: "",
consigneeAddressIdPath: "",
});
const selectDate = ref(null);
const submitLoading = ref(false);
const addressFormValidate = reactive({
name: [{ required: true, message: "收货人姓名不能为空" }],
mobile: [
{ required: true, message: "请输入收货人手机号码" },
{
pattern: RegExp.mobile,
message: "请输入正确的手机号",
},
memberAddressRemove(v) {
ElMessageBox.confirm("确定要删除此收货地址?", "删除", { type: "warning" }).then(() => {
API_Member.removeMemberAddress(v.id).then((res) => {
if (res.success) {
ElMessage.success("删除成功");
this.getAddressData();
],
consigneeAddressPath: [{ required: true, message: "收货人地址不能为空" }],
detail: [{ required: true, message: "收货人详细地址不能为空" }],
});
const pointData = ref([]);
const pointTotal = ref(0);
const pointSearchForm = ref({
pageNumber: 1,
pageSize: 20,
});
const orderData = ref([]);
const orderTotal = ref(0);
const orderSearchForm = ref({
pageNumber: 1,
pageSize: 20,
payStatus: "",
orderSn: "",
orderType: "",
});
const addressData = ref([]);
const addressTotal = ref(0);
const addressSearchForm = ref({
pageNumber: 1,
pageSize: 20,
});
const walletSearchForm = ref({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
});
const walletData = ref([]);
const walletTotal = ref(0);
const receiptRecordSearchForm = ref({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
});
const receiptRecordData = ref([]);
const receiptRecordTotal = ref(0);
function orderTypeText(v) {
const map = {
NORMAL: "普通订单",
VIRTUAL: "虚拟订单",
GIFT: "赠品订单",
PINTUAN: "拼团订单",
};
return map[v] || v || "";
}
function clientTypeText(v) {
const map = {
H5: "移动端",
PC: "PC端",
WECHAT_MP: "小程序端",
APP: "移动应用端",
};
return map[v] || v || "";
}
function orderStatusText(v) {
const map = {
UNPAID: "未付款",
PAID: "已付款",
UNDELIVERED: "待发货",
DELIVERED: "已发货",
COMPLETED: "已完成",
TAKE: "待核验",
CANCELLED: "已关闭",
};
return map[v] || v || "";
}
function payStatusText(v) {
const map = {
UNPAID: "未付款",
PAID: "已付款",
};
return map[v] || v || "";
}
function groupAfterSaleStatusText(v) {
const map = {
NEW: "未申请",
NOT_APPLIED: "未申请",
ALREADY_APPLIED: "已申请",
EXPIRED: "已失效",
};
return map[v] || v || "";
}
function groupComplainStatusText(v) {
const map = {
NEW: "未申请",
NO_APPLY: "未申请",
APPLYING: "申请中",
COMPLETE: "已完成",
EXPIRED: "已失效",
CANCEL: "取消投诉",
};
return map[v] || v || "";
}
function walletServiceTypeText(type) {
if (type === "WALLET_WITHDRAWAL") return "余额提现";
if (type === "WALLET_PAY") return "余额支付";
if (type === "WALLET_REFUND") return "余额退款";
if (type === "WALLET_RECHARGE") return "余额充值";
return "佣金提成";
}
function init() {
getMemberInfo();
getPointData();
}
function memberInfoChange(v) {
if (v == "point") {
getPointData();
}
if (v == "address") {
nextTick(() => {
getAddressData();
});
}
if (v == "order") {
getOrderData();
}
if (v == "wallet") {
getMemberWalletData();
getDepositLogData();
}
if (v == "receipt") {
getReceiptRecordData();
}
}
function getMemberInfo() {
API_Member.getMemberInfoData(id.value).then((res) => {
memberInfo.value = res.result;
});
}
function memberStatusChange(v) {
let params = {
memberIds: [id.value],
disabled: v,
};
API_Member.updateMemberStatus(params).then((res) => {});
}
function getMemberWalletData() {
loading.value = true;
let params = {
memberId: id.value,
};
API_Member.getMemberWallet(params).then((res) => {
loading.value = false;
if (res.success) {
memberWalletInfo.value = res.result;
}
});
loading.value = false;
}
function getDepositLogData() {
loading.value = true;
walletSearchForm.value.memberId = id.value;
API_Member.getUserWallet(walletSearchForm.value).then((res) => {
loading.value = false;
if (res.success) {
walletData.value = res.result.records;
walletTotal.value = res.result.total;
}
});
loading.value = false;
}
function getReceiptRecordData() {
loading.value = true;
receiptRecordSearchForm.value.pageNumber = 1;
receiptRecordSearchForm.value.pageSize = 20;
receiptRecordSearchForm.value.memberId = id.value;
API_Order.getReceiptPage(receiptRecordSearchForm.value).then((res) => {
loading.value = false;
if (res.success) {
receiptRecordData.value = res.result.records;
receiptRecordTotal.value = res.result.total;
}
});
loading.value = false;
}
function getOrderData() {
loading.value = true;
orderSearchForm.value.pageNumber = 1;
orderSearchForm.value.pageSize = 20;
orderSearchForm.value.memberId = id.value;
API_Order.getOrderList(orderSearchForm.value).then((res) => {
loading.value = false;
if (res.success) {
orderData.value = res.result.records;
orderTotal.value = res.result.total;
}
});
loading.value = false;
}
function orderDetail(v) {
router.push({
name: "order-detail",
query: { sn: v },
});
}
function getPointData() {
loading.value = true;
pointSearchForm.value.memberId = id.value;
API_Member.getHistoryPointData(pointSearchForm.value).then((res) => {
loading.value = false;
if (res.success) {
pointData.value = res.result.records;
pointTotal.value = res.result.total;
}
});
loading.value = false;
}
function addressSubmit() {
addressForm.memberId = id.value;
addressFormRef.value.validate((valid) => {
if (valid) {
submitLoading.value = true;
let submit = JSON.parse(JSON.stringify(addressForm));
submit.isDefault ? (submit.isDefault = true) : (submit.isDefault = false);
if (submit.id != "") {
API_Member.editMemberAddress(submit).then((res) => {
submitLoading.value = false;
if (res && res.success) {
ElMessage.success("修改成功");
addressModalVisible.value = false;
getAddressData();
}
});
}).catch(() => {});
},
getAddressData() {
this.addressLoading = true;
API_Member.getMemberAddressData(this.id, this.addressSearchForm)
.then((res) => {
if (res.success) {
this.addressData = res.result.records;
this.addressTotal = res.result.total;
}
})
.finally(() => {
this.addressLoading = false;
});
},
pointChangePage(v) {
this.pointSearchForm.pageNumber = v;
this.getPointData();
},
pointChangePageSize(v) {
this.pointSearchForm.pageNumber = 1;
this.pointSearchForm.pageSize = v;
this.getPointData();
},
addressChangePage(v) {
this.addressSearchForm.pageNumber = v;
this.getAddressData();
},
addressChangePageSize(v) {
this.addressSearchForm.pageNumber = 1;
this.addressSearchForm.pageSize = v;
this.getAddressData();
},
walletChangePage(v) {
this.walletSearchForm.pageNumber = v;
this.getDepositLogData();
},
walletChangePageSize(v) {
this.walletSearchForm.pageNumber = 1;
this.walletSearchForm.pageSize = v;
this.getDepositLogData();
},
orderChangePage(v) {
this.orderSearchForm.pageNumber = v;
this.getOrderData();
},
orderChangePageSize(v) {
this.orderSearchForm.pageNumber = 1;
this.orderSearchForm.pageSize = v;
this.getOrderData();
},
selectDateRange(v) {
if (v && v.length === 2) {
this.orderSearchForm.startDate = v[0];
this.orderSearchForm.endDate = v[1];
} else {
delete this.orderSearchForm.startDate;
delete this.orderSearchForm.endDate;
API_Member.addMemberAddress(submit).then((res) => {
submitLoading.value = false;
if (res && res.success) {
ElMessage.success("添加成功");
addressModalVisible.value = false;
getAddressData();
}
});
}
},
},
mounted() {
this.id = this.$route.query.id;
this.init();
},
};
}
});
}
function getAddress(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
addressForm.consigneeAddressPath = paths;
addressForm.consigneeAddressIdPath = ids;
const coord = val.data[val.data.length - 1].center.split(",");
addressForm.lat = coord[1];
addressForm.lon = coord[0];
} else {
addressForm.consigneeAddressPath = val.data.addr;
addressForm.consigneeAddressIdPath = val.data.addrId;
addressForm.lat = val.data.position.lat;
addressForm.lon = val.data.position.lng;
}
}
function memberAddressRemove(v) {
ElMessageBox.confirm("确定要删除此收货地址?", "删除", { type: "warning" }).then(() => {
API_Member.removeMemberAddress(v.id).then((res) => {
if (res.success) {
ElMessage.success("删除成功");
getAddressData();
}
});
}).catch(() => {});
}
function getAddressData() {
addressLoading.value = true;
API_Member.getMemberAddressData(id.value, addressSearchForm.value)
.then((res) => {
if (res.success) {
addressData.value = res.result.records;
addressTotal.value = res.result.total;
}
})
.finally(() => {
addressLoading.value = false;
});
}
function pointChangePage(v) {
pointSearchForm.value.pageNumber = v;
getPointData();
}
function pointChangePageSize(v) {
pointSearchForm.value.pageNumber = 1;
pointSearchForm.value.pageSize = v;
getPointData();
}
function addressChangePage(v) {
addressSearchForm.value.pageNumber = v;
getAddressData();
}
function addressChangePageSize(v) {
addressSearchForm.value.pageNumber = 1;
addressSearchForm.value.pageSize = v;
getAddressData();
}
function walletChangePage(v) {
walletSearchForm.value.pageNumber = v;
getDepositLogData();
}
function walletChangePageSize(v) {
walletSearchForm.value.pageNumber = 1;
walletSearchForm.value.pageSize = v;
getDepositLogData();
}
function orderChangePage(v) {
orderSearchForm.value.pageNumber = v;
getOrderData();
}
function orderChangePageSize(v) {
orderSearchForm.value.pageNumber = 1;
orderSearchForm.value.pageSize = v;
getOrderData();
}
function selectDateRange(v) {
if (v && v.length === 2) {
orderSearchForm.value.startDate = v[0];
orderSearchForm.value.endDate = v[1];
} else {
delete orderSearchForm.value.startDate;
delete orderSearchForm.value.endDate;
}
}
onMounted(() => {
id.value = route.query.id;
init();
});
</script>
<style lang="scss" scoped>
@import "memberDetail.scss";

View File

@@ -2,7 +2,7 @@
<div class="search">
<el-card>
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -96,7 +96,7 @@
</el-card>
<el-dialog v-model="descFlag" :title="descTitle" width="500px" destroy-on-close>
<el-form ref="formValidate" :model="formValidate" :rules="ruleValidate" label-width="80px">
<el-form ref="formValidateRef" :model="formValidate" :rules="ruleValidate" label-width="80px">
<el-form-item label="头像">
<img :src="formValidate.face" class="face" />
<el-button
@@ -143,7 +143,7 @@
<el-dialog v-model="picModelFlag" width="1200px">
<ossManage
ref="ossManage"
ref="ossManageRef"
@callback="callbackSelected"
:isComponent="true"
:initialize="picModelFlag"
@@ -153,152 +153,156 @@
</div>
</template>
<script>
<script setup>
import { ref, nextTick, onMounted } from "vue";
import * as API_Member from "@/api/member.js";
import ossManage from "@/views/sys/oss-manage/ossManage";
import multipleMap from "@/components/map/multiple-map";
import { ElMessage, ElMessageBox } from "element-plus";
import { customRouterPush } from "@/utils/filters";
import { md5 } from "@/utils/md5.js";
export default {
name: "memberRecycle",
components: {
ossManage,
multipleMap,
},
data() {
return {
selectedMember: false,
descTitle: "",
descFlag: false,
openSearch: true,
loading: true,
searchForm: {
pageNumber: 1,
pageSize: 20,
order: "desc",
id: "",
username: "",
mobile: "",
disabled: "CLOSE",
},
picModelFlag: false,
formValidate: {},
ruleValidate: {},
data: [],
total: 0,
};
},
methods: {
callback(val) {
this.$emit("callback", val);
},
init() {
this.getData();
},
changePage() {
this.getData();
},
changePageSize() {
this.searchForm.pageNumber = 1;
this.getData();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getData();
},
editPerm(val) {
this.descTitle = `查看用户 ${val.username}`;
this.descFlag = true;
this.getMemberInfo(val.id);
},
getMemberInfo(id) {
API_Member.getMemberInfoData(id).then((res) => {
if (res.result) {
this.formValidate = res.result;
}
});
},
getData() {
this.loading = true;
API_Member.getMemberListData(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
openPicSelector() {
this.picModelFlag = true;
this.$nextTick(() => {
if (this.$refs.ossManage) {
this.$refs.ossManage.selectImage = true;
}
});
},
callbackSelected(val) {
this.picModelFlag = false;
this.formValidate.face = val.url;
},
selectedRegion(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
this.formValidate.region = paths;
this.formValidate.regionId = ids;
} else {
this.formValidate.region = val.data.addr;
this.formValidate.regionId = val.data.addrId;
defineOptions({ name: "memberRecycle" });
const emit = defineEmits(["callback"]);
// 模板 el-form 的 ref(原 ref="searchForm",与 data 同名会互相覆盖,改名为 searchFormRef)
const searchFormRef = ref(null);
const table = ref(null);
// 模板编辑弹窗 el-form 的 ref(原 ref="formValidate",与 data 同名会互相覆盖,改名为 formValidateRef)
const formValidateRef = ref(null);
// 模板 ossManage 组件的 ref(原 ref="ossManage",与组件 import 同名会冲突,改名为 ossManageRef)
const ossManageRef = ref(null);
const selectedMember = ref(false);
const descTitle = ref("");
const descFlag = ref(false);
const openSearch = ref(true);
const loading = ref(true);
const searchForm = ref({
pageNumber: 1,
pageSize: 20,
order: "desc",
id: "",
username: "",
mobile: "",
disabled: "CLOSE",
});
const picModelFlag = ref(false);
const formValidate = ref({});
const ruleValidate = ref({});
const data = ref([]);
const total = ref(0);
function callback(val) {
emit("callback", val);
}
function init() {
getData();
}
function changePage() {
getData();
}
function changePageSize() {
searchForm.value.pageNumber = 1;
getData();
}
function handleSearch() {
searchForm.value.pageNumber = 1;
searchForm.value.pageSize = 20;
getData();
}
function editPerm(val) {
descTitle.value = `查看用户 ${val.username}`;
descFlag.value = true;
getMemberInfo(val.id);
}
function getMemberInfo(id) {
API_Member.getMemberInfoData(id).then((res) => {
if (res.result) {
formValidate.value = res.result;
}
});
}
function getData() {
loading.value = true;
API_Member.getMemberListData(searchForm.value).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
function openPicSelector() {
picModelFlag.value = true;
nextTick(() => {
if (ossManageRef.value) {
ossManageRef.value.selectImage = true;
}
});
}
function callbackSelected(val) {
picModelFlag.value = false;
formValidate.value.face = val.url;
}
function selectedRegion(val) {
if (val.type === "select") {
const paths = val.data.map((item) => item.name).join(",");
const ids = val.data.map((item) => item.id).join(",");
formValidate.value.region = paths;
formValidate.value.regionId = ids;
} else {
formValidate.value.region = val.data.addr;
formValidate.value.regionId = val.data.addrId;
}
}
function detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
}
function enable(v) {
let params = {
memberIds: [v.id],
disabled: true,
};
ElMessageBox.confirm("确定启用此会员?", "提示", { type: "warning" }).then(() => {
API_Member.updateMemberStatus(params).then((res) => {
if (res.success) {
ElMessage.success("启用成功");
getData();
}
},
detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
},
enable(v) {
let params = {
memberIds: [v.id],
disabled: true,
};
ElMessageBox.confirm("确定启用此会员?", "提示", { type: "warning" }).then(() => {
API_Member.updateMemberStatus(params).then((res) => {
if (res.success) {
ElMessage.success("启用成功");
this.getData();
}
});
}).catch(() => {});
},
handleSubmitModal() {
const { nickName, sex, username, face, newPassword, id, regionId, region } = this.formValidate;
let time = new Date(this.formValidate.birthday);
let birthday = time.getFullYear() + "-" + (time.getMonth() + 1) + "-" + time.getDate();
let submit = {
regionId: regionId,
region: region,
nickName,
sex,
birthday,
face: face || "",
id,
};
if (newPassword) {
submit.password = this.md5(newPassword);
}
API_Member.updateMember(submit).then((res) => {
if (res.result) {
ElMessage.success("修改成功!");
this.descFlag = false;
this.init();
}
});
},
},
mounted() {
this.init();
},
};
});
}).catch(() => {});
}
function handleSubmitModal() {
const { nickName, sex, username, face, newPassword, id, regionId, region } = formValidate.value;
let time = new Date(formValidate.value.birthday);
let birthday = time.getFullYear() + "-" + (time.getMonth() + 1) + "-" + time.getDate();
let submit = {
regionId: regionId,
region: region,
nickName,
sex,
birthday,
face: face || "",
id,
};
if (newPassword) {
// 原 this.md5 为 main.js 注册的全局属性,改为具名导入(同 login.vue / userManage.vue)
submit.password = md5(newPassword);
}
API_Member.updateMember(submit).then((res) => {
if (res.result) {
ElMessage.success("修改成功!");
descFlag.value = false;
init();
}
});
}
onMounted(() => {
init();
});
</script>
<style lang="scss" scoped>
.face {

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-dialog v-model="wechatModal" title="微信设置" width="530px">
<el-form ref="wechatFormData" :model="wechatFormData" label-width="100px">
<el-form ref="wechatFormRef" :model="wechatFormData" label-width="100px">
<el-form-item v-if="tab === 'WECHAT'" label="模板名称">
<el-input v-model="wechatFormData.name" maxlength="9" disabled />
</el-form-item>
@@ -105,171 +105,169 @@
</div>
</template>
<script>
<script setup>
import { onMounted, reactive, ref } from "vue";
import {
wechatMessageSync,
getWechatMessagePage,
getWechatMessagePage as fetchWechatMessagePage,
editWechatMessageTemplate,
delWechatMessageTemplate,
wechatMPMessageSync,
getWechatMPMessagePage,
getWechatMPMessagePage as fetchWechatMPMessagePage,
editWechatMPMessageTemplate,
delWechatMPMessageTemplate,
} from "@/api/setting";
import { ElMessage, ElMessageBox } from "element-plus";
export default {
title: "wechat-message-manage",
data() {
return {
wechatModal: false,
wechatFormData: {},
wechatMPFormData: {},
tab: "WECHAT",
searchForm: { type: "WECHAT" },
loading: true,
id: "",
weChatSearchForm: { pageNumber: 1, pageSize: 20 },
weChatMPSearchForm: { pageNumber: 1, pageSize: 20 },
weChatData: [],
weChatMPData: [],
weChatTotal: 0,
weChatMPTotal: 0,
};
},
methods: {
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.type = this.tab;
if (this.tab === "WECHAT") {
this.weChatSearchForm.pageNumber = v;
this.getWechatMessagePage();
} else {
this.weChatMPSearchForm.pageNumber = v;
this.getWechatMPMessagePage();
}
},
changePageSize(v) {
this.searchForm.type = this.tab;
if (this.tab === "WECHAT") {
this.weChatSearchForm.pageSize = v;
this.getWechatMessagePage();
} else {
this.weChatMPSearchForm.pageSize = v;
this.getWechatMPMessagePage();
}
},
wechatSettingAlert(v) {
this.wechatFormData = v;
this.id = v.id;
this.wechatModal = true;
},
weChatSync(mp) {
ElMessageBox.confirm("确认要初始化微信小程序消息订阅?", "提示", { type: "warning" }).then(() => {
if (mp === "mp") {
wechatMPMessageSync().then((res) => {
if (res.success) {
ElMessage.success("微信小程序消息订阅初始化");
this.getWechatMPMessagePage();
}
});
} else {
wechatMessageSync().then((res) => {
if (res.success) {
ElMessage.success("微信消息模板初始化成功");
this.getWechatMessagePage();
}
});
}
}).catch(() => {});
},
wechatFormDataEdit() {
this.$refs.wechatFormData.validate((valid) => {
if (valid) {
if (!this.wechatFormData.updateTime) {
this.wechatFormData.updateTime = "";
}
editWechatMessageTemplate(this.id, this.wechatFormData).then((res) => {
if (res.message === "success") {
ElMessage.success("微信模板修改成功");
this.wechatModal = false;
this.getWechatMessagePage();
}
});
}
});
},
wechatMPFormDataEdit() {
this.$refs.wechatFormData.validate((valid) => {
if (valid) {
editWechatMPMessageTemplate(this.id, this.wechatMPFormData).then((res) => {
if (res.message === "success") {
ElMessage.success("微信消息订阅模板修改成功");
this.wechatModal = false;
this.getWechatMPMessagePage();
}
});
}
});
},
delWeChat(v) {
ElMessageBox.confirm("确定删除此模板?", "提示", { type: "warning" }).then(() => {
if (this.tab === "WECHAT") {
delWechatMessageTemplate(v.id).then((res) => {
if (res.success) {
ElMessage.success("微信模板删除成功");
this.getWechatMessagePage();
}
});
} else {
delWechatMPMessageTemplate(v.id).then((res) => {
if (res.success) {
ElMessage.success("微信消息订阅删除成功");
this.getWechatMPMessagePage();
}
});
}
}).catch(() => {});
},
getDataList() {
this.getWechatMessagePage();
},
getWechatMessagePage() {
this.loading = true;
getWechatMessagePage(this.weChatSearchForm).then((res) => {
this.loading = false;
defineOptions({ title: "wechat-message-manage" });
const wechatFormRef = ref(null);
const wechatModal = ref(false);
const wechatFormData = ref({});
const wechatMPFormData = ref({});
const tab = ref("WECHAT");
const searchForm = reactive({ type: "WECHAT" });
const loading = ref(true);
const id = ref("");
const weChatSearchForm = reactive({ pageNumber: 1, pageSize: 20 });
const weChatMPSearchForm = reactive({ pageNumber: 1, pageSize: 20 });
const weChatData = ref([]);
const weChatMPData = ref([]);
const weChatTotal = ref(0);
const weChatMPTotal = ref(0);
onMounted(() => {
init();
});
function init() {
getDataList();
}
function changePage(v) {
searchForm.type = tab.value;
if (tab.value === "WECHAT") {
weChatSearchForm.pageNumber = v;
getWechatMessagePage();
} else {
weChatMPSearchForm.pageNumber = v;
getWechatMPMessagePage();
}
}
function changePageSize(v) {
searchForm.type = tab.value;
if (tab.value === "WECHAT") {
weChatSearchForm.pageSize = v;
getWechatMessagePage();
} else {
weChatMPSearchForm.pageSize = v;
getWechatMPMessagePage();
}
}
function wechatSettingAlert(v) {
wechatFormData.value = v;
id.value = v.id;
wechatModal.value = true;
}
function weChatSync(mp) {
ElMessageBox.confirm("确认要初始化微信小程序消息订阅?", "提示", { type: "warning" }).then(() => {
if (mp === "mp") {
wechatMPMessageSync().then((res) => {
if (res.success) {
this.weChatData = res.result.records;
this.weChatTotal = res.result.total;
ElMessage.success("微信小程序消息订阅初始化");
getWechatMPMessagePage();
}
});
},
getWechatMPMessagePage() {
this.loading = true;
getWechatMPMessagePage(this.weChatMPSearchForm).then((res) => {
this.loading = false;
} else {
wechatMessageSync().then((res) => {
if (res.success) {
this.weChatMPData = res.result.records;
this.weChatMPTotal = res.result.total;
ElMessage.success("微信消息模板初始化成功");
getWechatMessagePage();
}
});
},
tabPaneChange(tab) {
const v = tab.paneName || this.tab;
this.searchForm.type = v;
if (v === "WECHAT") {
this.getWechatMessagePage();
} else if (v === "WECHATMP") {
this.getWechatMPMessagePage();
}
}).catch(() => {});
}
function wechatFormDataEdit() {
wechatFormRef.value.validate((valid) => {
if (valid) {
if (!wechatFormData.value.updateTime) {
wechatFormData.value.updateTime = "";
}
},
},
mounted() {
this.init();
},
};
editWechatMessageTemplate(id.value, wechatFormData.value).then((res) => {
if (res.message === "success") {
ElMessage.success("微信模板修改成功");
wechatModal.value = false;
getWechatMessagePage();
}
});
}
});
}
function wechatMPFormDataEdit() {
wechatFormRef.value.validate((valid) => {
if (valid) {
editWechatMPMessageTemplate(id.value, wechatMPFormData.value).then((res) => {
if (res.message === "success") {
ElMessage.success("微信消息订阅模板修改成功");
wechatModal.value = false;
getWechatMPMessagePage();
}
});
}
});
}
function delWeChat(v) {
ElMessageBox.confirm("确定删除此模板?", "提示", { type: "warning" }).then(() => {
if (tab.value === "WECHAT") {
delWechatMessageTemplate(v.id).then((res) => {
if (res.success) {
ElMessage.success("微信模板删除成功");
getWechatMessagePage();
}
});
} else {
delWechatMPMessageTemplate(v.id).then((res) => {
if (res.success) {
ElMessage.success("微信消息订阅删除成功");
getWechatMPMessagePage();
}
});
}
}).catch(() => {});
}
function getDataList() {
getWechatMessagePage();
}
function getWechatMessagePage() {
loading.value = true;
fetchWechatMessagePage(weChatSearchForm).then((res) => {
loading.value = false;
if (res.success) {
weChatData.value = res.result.records;
weChatTotal.value = res.result.total;
}
});
}
function getWechatMPMessagePage() {
loading.value = true;
fetchWechatMPMessagePage(weChatMPSearchForm).then((res) => {
loading.value = false;
if (res.success) {
weChatMPData.value = res.result.records;
weChatMPTotal.value = res.result.total;
}
});
}
function tabPaneChange(tabPane) {
const v = tabPane.paneName || tab.value;
searchForm.type = v;
if (v === "WECHAT") {
getWechatMessagePage();
} else if (v === "WECHATMP") {
getWechatMPMessagePage();
}
}
</script>
<style scoped>
.link-text {

View File

@@ -19,7 +19,7 @@
<el-tab-pane label="积分列表" name="pointList">
<el-card class="point-content-card">
<el-form
ref="memberSearchForm"
ref="memberSearchFormRef"
:model="memberSearchForm"
inline
label-width="70px"
@@ -131,7 +131,7 @@
<el-tab-pane label="积分增减记录" name="pointChangeRecord">
<el-card class="point-content-card">
<el-form
ref="searchForm"
ref="searchFormRef"
:model="searchForm"
inline
label-width="70px"
@@ -203,132 +203,135 @@
</div>
</template>
<script>
<script setup>
import { onMounted, reactive, ref } from "vue";
import * as API_Member from "@/api/member.js";
import { customRouterPush } from "@/utils/filters";
export default {
name: "point",
data() {
return {
activeTab: "pointList",
loading: true,
memberLoading: false,
pointsStatistics: {
totalPoint: 0,
unUsedPoint: 0,
},
searchForm: {
pageNumber: 1,
pageSize: 20,
},
memberSearchForm: {
pageNumber: 1,
pageSize: 20,
nickName: "",
username: "",
disabled: "",
minPoint: null,
maxPoint: null,
},
data: [],
memberData: [],
memberTotal: 0,
total: 0,
};
},
methods: {
callback(val) {
this.$emit("callback", val);
},
detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
},
init() {
this.getStatistics();
this.getMemberList();
this.getData();
},
getStatistics() {
API_Member.queryMemberPointsStatistics().then((res) => {
if (res && res.success && res.result) {
this.pointsStatistics = {
totalPoint: res.result.totalPoint || 0,
unUsedPoint: res.result.unUsedPoint || 0,
};
}
});
},
formatNumber(value) {
const numericValue = Number(value || 0);
if (!Number.isFinite(numericValue)) return "0";
return numericValue.toLocaleString();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getData();
},
changePageSize(v) {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = v;
this.getData();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getData();
},
handleMemberSearch() {
this.memberSearchForm.pageNumber = 1;
this.getMemberList();
},
changeMemberPage(v) {
this.memberSearchForm.pageNumber = v;
this.getMemberList();
},
changeMemberPageSize(v) {
this.memberSearchForm.pageNumber = 1;
this.memberSearchForm.pageSize = v;
this.getMemberList();
},
getMemberList() {
this.memberLoading = true;
const params = {
pageNumber: this.memberSearchForm.pageNumber,
pageSize: this.memberSearchForm.pageSize,
nickName: this.memberSearchForm.nickName || undefined,
username: this.memberSearchForm.username || undefined,
disabled: this.memberSearchForm.disabled || undefined,
minPoint: this.memberSearchForm.minPoint,
maxPoint: this.memberSearchForm.maxPoint,
defineOptions({ name: "point" });
const emit = defineEmits(["callback"]);
// 模板 ref,script 内未使用
const memberSearchFormRef = ref(null);
const searchFormRef = ref(null);
const table = ref(null);
const activeTab = ref("pointList");
const loading = ref(true);
const memberLoading = ref(false);
const pointsStatistics = ref({
totalPoint: 0,
unUsedPoint: 0,
});
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
});
const memberSearchForm = reactive({
pageNumber: 1,
pageSize: 20,
nickName: "",
username: "",
disabled: "",
minPoint: null,
maxPoint: null,
});
const data = ref([]);
const memberData = ref([]);
const memberTotal = ref(0);
const total = ref(0);
function callback(val) {
emit("callback", val);
}
function detail(row) {
customRouterPush({ name: "member-detail", query: { id: row.id } });
}
function init() {
getStatistics();
getMemberList();
getData();
}
function getStatistics() {
API_Member.queryMemberPointsStatistics().then((res) => {
if (res && res.success && res.result) {
pointsStatistics.value = {
totalPoint: res.result.totalPoint || 0,
unUsedPoint: res.result.unUsedPoint || 0,
};
API_Member.getMemberListData(params)
.then((res) => {
this.memberLoading = false;
if (res && res.success && res.result && res.result.records) {
this.memberData = res.result.records;
this.memberTotal = res.result.total;
}
})
.catch(() => {
this.memberLoading = false;
});
},
getData() {
this.loading = true;
API_Member.getHistoryPointData(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
},
mounted() {
this.init();
},
};
}
});
}
function formatNumber(value) {
const numericValue = Number(value || 0);
if (!Number.isFinite(numericValue)) return "0";
return numericValue.toLocaleString();
}
function changePage(v) {
searchForm.pageNumber = v;
getData();
}
function changePageSize(v) {
searchForm.pageNumber = 1;
searchForm.pageSize = v;
getData();
}
function handleSearch() {
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
getData();
}
function handleMemberSearch() {
memberSearchForm.pageNumber = 1;
getMemberList();
}
function changeMemberPage(v) {
memberSearchForm.pageNumber = v;
getMemberList();
}
function changeMemberPageSize(v) {
memberSearchForm.pageNumber = 1;
memberSearchForm.pageSize = v;
getMemberList();
}
function getMemberList() {
memberLoading.value = true;
const params = {
pageNumber: memberSearchForm.pageNumber,
pageSize: memberSearchForm.pageSize,
nickName: memberSearchForm.nickName || undefined,
username: memberSearchForm.username || undefined,
disabled: memberSearchForm.disabled || undefined,
minPoint: memberSearchForm.minPoint,
maxPoint: memberSearchForm.maxPoint,
};
API_Member.getMemberListData(params)
.then((res) => {
memberLoading.value = false;
if (res && res.success && res.result && res.result.records) {
memberData.value = res.result.records;
memberTotal.value = res.result.total;
}
})
.catch(() => {
memberLoading.value = false;
});
}
function getData() {
loading.value = true;
API_Member.getHistoryPointData(searchForm).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
onMounted(() => {
init();
});
</script>
<style lang="scss" scoped>
.points-statistics-card {