标签儿管理
This commit is contained in:
@@ -29,22 +29,51 @@
|
||||
@click="switchTab('status')">
|
||||
<text>服务状态</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'performance' }"
|
||||
@click="switchTab('performance')">
|
||||
<text>服务表现</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'reception' }"
|
||||
@click="switchTab('reception')">
|
||||
<text>开始接待</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'tag' }"
|
||||
@click="switchTab('tag')">
|
||||
<text>标签管理</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 服务状态列表 -->
|
||||
<scroll-view class="service-status-list" scroll-y v-if="activeTab === 'status'">
|
||||
<scroll-view
|
||||
class="service-status-list"
|
||||
scroll-y
|
||||
v-if="activeTab === 'status'"
|
||||
@scrolltolower="onServiceStatusReachBottom">
|
||||
<view class="service-status-toolbar">
|
||||
<text class="toolbar-total">共{{ serviceStatusTotal }}条</text>
|
||||
<input
|
||||
class="toolbar-input"
|
||||
v-model="serviceStatusQuery.salesName"
|
||||
placeholder="所属销售姓名"
|
||||
placeholder-style="color: #b0b0b0"
|
||||
confirm-type="search"
|
||||
@confirm="onServiceStatusSearch"
|
||||
/>
|
||||
<input
|
||||
class="toolbar-input"
|
||||
v-model="serviceStatusQuery.customerName"
|
||||
placeholder="客户姓名"
|
||||
placeholder-style="color: #b0b0b0"
|
||||
confirm-type="search"
|
||||
@confirm="onServiceStatusSearch"
|
||||
/>
|
||||
<view class="toolbar-actions">
|
||||
<view class="toolbar-btn toolbar-btn--refresh" @click="onServiceStatusRefresh">
|
||||
<uni-icons type="refresh" size="18" color="#2A68FF"></uni-icons>
|
||||
<text>刷新</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="service-card"
|
||||
v-for="(item, index) in serviceStatusList"
|
||||
@@ -63,6 +92,11 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="customer-info">
|
||||
<text class="customer-name">客户:{{ item.customerName || '未知客户' }}</text>
|
||||
<text class="customer-phone" v-if="item.customerPhone">电话:{{ item.customerPhone }}</text>
|
||||
</view>
|
||||
|
||||
<view class="customer-tags">
|
||||
<view
|
||||
class="tag-item"
|
||||
@@ -92,16 +126,17 @@
|
||||
</view>
|
||||
|
||||
<view class="service-duration">
|
||||
<text>已服务 {{ item.duration }} 分钟</text>
|
||||
<text>{{ item.durationText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="service-status-empty" v-if="!serviceStatusLoading && !serviceStatusList.length">
|
||||
<text>暂无服务中记录</text>
|
||||
</view>
|
||||
<view class="service-status-loading-more" v-if="serviceStatusLoading && serviceStatusList.length">
|
||||
<text>正在加载更多...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 服务表现内容 -->
|
||||
<view class="performance-content" v-if="activeTab === 'performance'">
|
||||
<text class="empty-text">服务表现内容</text>
|
||||
</view>
|
||||
|
||||
<!-- 开始接待表单 -->
|
||||
<scroll-view class="reception-form" scroll-y v-if="activeTab === 'reception'">
|
||||
<view class="form-card">
|
||||
@@ -139,6 +174,15 @@
|
||||
placeholder="请输入客户来源"
|
||||
placeholder-style="color: #9ca3af"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">门店名称</text>
|
||||
<input
|
||||
class="form-item__input"
|
||||
v-model="receptionForm.dealershipName"
|
||||
placeholder="请输入门店名称"
|
||||
placeholder-style="color: #9ca3af"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">性别</text>
|
||||
@@ -208,6 +252,134 @@
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 标签管理 -->
|
||||
<view class="tag-management" v-if="activeTab === 'tag'">
|
||||
<!-- 标签列表 -->
|
||||
<scroll-view
|
||||
class="tag-list"
|
||||
scroll-y
|
||||
v-if="tagViewMode === 'list'">
|
||||
<view class="tag-list-header">
|
||||
<text class="tag-list-total">共{{ tagList.length }}条</text>
|
||||
<view class="tag-list-btn" @click="showAddTag">
|
||||
<uni-icons type="plus" size="18" color="#2A68FF"></uni-icons>
|
||||
<text>添加标签</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="tag-card"
|
||||
v-for="(item, index) in tagList"
|
||||
:key="index">
|
||||
<view class="tag-card-header">
|
||||
<text class="tag-card-name">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="tag-card-content">
|
||||
<view class="tag-card-item" v-if="item.detail">
|
||||
<text class="tag-card-label">详情:</text>
|
||||
<text class="tag-card-value">{{ item.detail }}</text>
|
||||
</view>
|
||||
<view class="tag-card-item" v-if="item.remark">
|
||||
<text class="tag-card-label">备注:</text>
|
||||
<text class="tag-card-value">{{ item.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tag-list-empty" v-if="!tagList.length">
|
||||
<text>暂无标签</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 添加标签表单 -->
|
||||
<scroll-view
|
||||
class="tag-form"
|
||||
scroll-y
|
||||
v-if="tagViewMode === 'add'">
|
||||
<view class="form-card">
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">所属行业</text>
|
||||
<input
|
||||
class="form-item__input"
|
||||
v-model="tagForm.industry"
|
||||
placeholder="请输入所属行业"
|
||||
placeholder-style="color: #9ca3af"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item tag-select-wrapper form-item--half">
|
||||
<text class="form-item__label">标签分类</text>
|
||||
<view
|
||||
class="tag-select"
|
||||
@click.stop="toggleTagTypeDropdown"
|
||||
>
|
||||
<text
|
||||
:class="tagForm.tagType ? 'form-item__picker-text' : 'form-item__picker-placeholder'"
|
||||
>
|
||||
{{ tagForm.tagType || "请选择标签分类" }}
|
||||
</text>
|
||||
<uni-icons type="bottom" size="16" color="#9ca3af"></uni-icons>
|
||||
</view>
|
||||
<view
|
||||
v-if="showTagTypeDropdown"
|
||||
class="tag-select-dropdown"
|
||||
@click.stop
|
||||
>
|
||||
<view
|
||||
class="tag-select-dropdown__item"
|
||||
v-for="option in tagTypeOptions"
|
||||
:key="option"
|
||||
@click="selectTagType(option)"
|
||||
>
|
||||
<text :class="{'active': option === tagForm.tagType}">
|
||||
{{ option }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">标签名</text>
|
||||
<input
|
||||
class="form-item__input"
|
||||
v-model="tagForm.name"
|
||||
placeholder="请输入标签名"
|
||||
placeholder-style="color: #9ca3af"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">详情</text>
|
||||
<textarea
|
||||
class="form-item__textarea"
|
||||
v-model="tagForm.detail"
|
||||
placeholder="请输入详情"
|
||||
placeholder-style="color: #9ca3af"
|
||||
:maxlength="500"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-item__label">备注</text>
|
||||
<textarea
|
||||
class="form-item__textarea"
|
||||
v-model="tagForm.remark"
|
||||
placeholder="请输入备注"
|
||||
placeholder-style="color: #9ca3af"
|
||||
:maxlength="500"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-actions">
|
||||
<view class="form-btn form-btn--cancel" @click="cancelAddTag">
|
||||
<text class="form-btn__text">取消</text>
|
||||
</view>
|
||||
<view class="form-btn form-btn--save" @click="saveTag">
|
||||
<text class="form-btn__text">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view
|
||||
v-if="showTagTypeDropdown"
|
||||
class="tag-select-mask"
|
||||
@click="closeTagTypeDropdown"
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -229,7 +401,18 @@ import { getApiUrl } from "@/common/config.js";
|
||||
activeTab: 'status',
|
||||
genderOptions: ["男", "女"],
|
||||
isFetchingContact: false,
|
||||
serviceStatusLoading: false,
|
||||
serviceStatusTotal: 0,
|
||||
serviceStatusPage: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
serviceStatusQuery: {
|
||||
salesName: '',
|
||||
customerName: ''
|
||||
},
|
||||
receptionForm: {
|
||||
id: "",
|
||||
customerName: "",
|
||||
contact: "",
|
||||
customerSource: "",
|
||||
@@ -247,50 +430,148 @@ import { getApiUrl } from "@/common/config.js";
|
||||
detailedAddress: "",
|
||||
contactCount: 0
|
||||
},
|
||||
serviceStatusList: [
|
||||
{
|
||||
staffName: '三多',
|
||||
status: '服务中',
|
||||
duration: 60,
|
||||
tags: [
|
||||
{ text: '首次到访', color: 'blue' },
|
||||
{ text: '新房交付', color: 'blue' },
|
||||
{ text: '想买床', color: 'orange' }
|
||||
],
|
||||
alert: {
|
||||
type: 'risk',
|
||||
title: '投诉风险',
|
||||
message: '客户情绪激动,有投诉风险,请及时介入'
|
||||
}
|
||||
},
|
||||
{
|
||||
staffName: '雅秋',
|
||||
status: '服务中',
|
||||
duration: 55,
|
||||
tags: [
|
||||
{ text: '新婚夫妇', color: 'blue' },
|
||||
{ text: '收纳需求', color: 'blue' },
|
||||
{ text: '毛坯房', color: 'blue' },
|
||||
{ text: '关注环保', color: 'orange' }
|
||||
],
|
||||
alert: {
|
||||
type: 'reminder',
|
||||
title: '关单提醒',
|
||||
messages: [
|
||||
'服务已超过2小时,有关单意向',
|
||||
'但价格敏感,提起多次竞品品牌'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
serviceStatusList: [],
|
||||
// 标签管理
|
||||
tagViewMode: 'list', // 'list' 或 'add'
|
||||
tagList: [],
|
||||
tagForm: {
|
||||
industry: '家居行业',
|
||||
tagType: '',
|
||||
name: '',
|
||||
detail: '',
|
||||
remark: ''
|
||||
},
|
||||
tagTypeOptions: ["接待客户", "质检SOP", "客户画像"],
|
||||
showTagTypeDropdown: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.fetchServiceStatusList();
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
switchTab(tab) {
|
||||
this.activeTab = tab;
|
||||
if (tab === 'status') {
|
||||
this.fetchServiceStatusList();
|
||||
} else if (tab === 'tag') {
|
||||
this.tagViewMode = 'list';
|
||||
this.fetchTagList();
|
||||
}
|
||||
},
|
||||
onServiceStatusSearch() {
|
||||
if (this.activeTab !== 'status') {
|
||||
this.activeTab = 'status';
|
||||
}
|
||||
this.serviceStatusPage.current = 1;
|
||||
this.fetchServiceStatusList({ force: true });
|
||||
},
|
||||
onServiceStatusRefresh() {
|
||||
this.serviceStatusPage.current = 1;
|
||||
this.fetchServiceStatusList({ force: true });
|
||||
},
|
||||
onServiceStatusReachBottom() {
|
||||
// 已在加载中或全部加载完成则不再触发
|
||||
if (this.serviceStatusLoading) return;
|
||||
if (this.serviceStatusList.length >= this.serviceStatusTotal) return;
|
||||
this.serviceStatusPage.current += 1;
|
||||
this.fetchServiceStatusList();
|
||||
},
|
||||
async fetchServiceStatusList({ force = false } = {}) {
|
||||
if (this.serviceStatusLoading && !force) {
|
||||
return;
|
||||
}
|
||||
this.serviceStatusLoading = true;
|
||||
try {
|
||||
const queryParams = {
|
||||
current: this.serviceStatusPage.current,
|
||||
size: this.serviceStatusPage.size,
|
||||
syncStatus: '服务中'
|
||||
};
|
||||
const trimmedSalesName = this.serviceStatusQuery?.salesName?.trim();
|
||||
const trimmedCustomerName = this.serviceStatusQuery?.customerName?.trim();
|
||||
if (trimmedSalesName) {
|
||||
queryParams.salesName = trimmedSalesName;
|
||||
}
|
||||
if (trimmedCustomerName) {
|
||||
queryParams.customerName = trimmedCustomerName;
|
||||
}
|
||||
const queryString = Object.keys(queryParams)
|
||||
.map(key => `${key}=${encodeURIComponent(queryParams[key])}`)
|
||||
.join('&');
|
||||
const url = `${getApiUrl('/api/audioManagement/list')}?${queryString}`;
|
||||
const res = await uni.request({
|
||||
url,
|
||||
method: 'GET',
|
||||
timeout: 10000
|
||||
});
|
||||
if (res.statusCode === 200 && res.data && res.data.success) {
|
||||
const records = Array.isArray(res.data.data) ? res.data.data : [];
|
||||
const mapped = records.map(item => this.buildServiceStatusItem(item));
|
||||
// 第一页或强制刷新时重置列表,否则追加
|
||||
if (this.serviceStatusPage.current === 1 || force) {
|
||||
this.serviceStatusList = mapped;
|
||||
} else {
|
||||
this.serviceStatusList = this.serviceStatusList.concat(mapped);
|
||||
}
|
||||
this.serviceStatusTotal = Number(res.data.total) || 0;
|
||||
} else {
|
||||
this.serviceStatusList = [];
|
||||
this.serviceStatusTotal = 0;
|
||||
uni.showToast({
|
||||
title: res.data?.message || '获取服务中列表失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取服务中列表失败:', error);
|
||||
uni.showToast({
|
||||
title: '获取服务状态失败,请稍后重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.serviceStatusLoading = false;
|
||||
}
|
||||
},
|
||||
buildServiceStatusItem(record = {}) {
|
||||
const formattedUpdateTime = this.formatDateTime(record.updateTime || record.createTime);
|
||||
const tags = [];
|
||||
if (record.recordingName) {
|
||||
tags.push({ text: `录音:${record.recordingName}`, color: 'blue' });
|
||||
}
|
||||
if (record.intentionLevel) {
|
||||
tags.push({ text: `意向:${record.intentionLevel}`, color: 'orange' });
|
||||
}
|
||||
if (record.projectName) {
|
||||
tags.push({ text: `项目:${record.projectName}`, color: 'blue' });
|
||||
}
|
||||
return {
|
||||
id: record.id,
|
||||
staffName: record.salesName || '未分配销售',
|
||||
status: record.syncStatus || '服务中',
|
||||
customerName: record.customerName || '',
|
||||
customerPhone: record.customerPhone || '',
|
||||
tags,
|
||||
durationText: formattedUpdateTime ? `最近更新时间:${formattedUpdateTime}` : '最近暂无更新时间'
|
||||
};
|
||||
},
|
||||
formatDateTime(value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return '';
|
||||
}
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
},
|
||||
viewServiceDetail(item) {
|
||||
// 查看服务详情
|
||||
@@ -300,13 +581,34 @@ import { getApiUrl } from "@/common/config.js";
|
||||
this.receptionForm.gender = e.detail.value;
|
||||
},
|
||||
onContactBlur() {
|
||||
const contact = this.receptionForm.contact?.trim();
|
||||
if (!contact) {
|
||||
return;
|
||||
}
|
||||
if (!this.isValidPhoneNumber(contact)) {
|
||||
uni.showToast({
|
||||
title: "请输入有效的手机号",
|
||||
icon: "none"
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.fetchCustomerByContact();
|
||||
},
|
||||
isValidPhoneNumber(phone) {
|
||||
const normalizedPhone = phone?.trim();
|
||||
if (!normalizedPhone) {
|
||||
return false;
|
||||
}
|
||||
return /^1[3-9]\d{9}$/.test(normalizedPhone);
|
||||
},
|
||||
async fetchCustomerByContact() {
|
||||
const contact = this.receptionForm.contact?.trim();
|
||||
if (!contact || this.isFetchingContact) {
|
||||
return;
|
||||
}
|
||||
if (!this.isValidPhoneNumber(contact)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.isFetchingContact = true;
|
||||
// 统一使用 getApiUrl,根据 env.js 配置自动切换环境
|
||||
@@ -319,21 +621,28 @@ import { getApiUrl } from "@/common/config.js";
|
||||
const list = res.data?.data;
|
||||
if (res.statusCode === 200 && res.data?.success && Array.isArray(list) && list.length) {
|
||||
const customer = list[0];
|
||||
const retrievedId = customer.id || customer.customerId || "";
|
||||
const resolvedSalesPhone = customer.salesPhone
|
||||
|| customer.salesMobile
|
||||
|| customer.salesTel
|
||||
|| this.receptionForm.salesPhone
|
||||
|| "";
|
||||
this.receptionForm = {
|
||||
...this.receptionForm,
|
||||
id: retrievedId ? String(retrievedId) : this.receptionForm.id,
|
||||
customerName: customer.customerName || this.receptionForm.customerName,
|
||||
customerSource: customer.customerSource || this.receptionForm.customerSource,
|
||||
dealershipId: customer.dealershipId || "",
|
||||
dealershipName: customer.dealershipName || "",
|
||||
salesId: customer.salesId || "",
|
||||
salesName: customer.salesName || "",
|
||||
salesPhone: customer.salesPhone || "",
|
||||
recordingCount: customer.recordingCount ?? 0,
|
||||
intendedModel: customer.intendedModel || "",
|
||||
infoCard: customer.infoCard || "",
|
||||
remark: customer.remark || "",
|
||||
detailedAddress: customer.detailedAddress || "",
|
||||
contactCount: customer.contactCount ?? 0
|
||||
dealershipId: customer.dealershipId || this.receptionForm.dealershipId,
|
||||
dealershipName: customer.dealershipName || this.receptionForm.dealershipName,
|
||||
salesId: customer.salesId || this.receptionForm.salesId,
|
||||
salesName: customer.salesName || this.receptionForm.salesName,
|
||||
salesPhone: String(resolvedSalesPhone),
|
||||
recordingCount: customer.recordingCount ?? this.receptionForm.recordingCount,
|
||||
intendedModel: customer.intendedModel || this.receptionForm.intendedModel,
|
||||
infoCard: customer.infoCard || this.receptionForm.infoCard,
|
||||
remark: customer.remark || this.receptionForm.remark,
|
||||
detailedAddress: customer.detailedAddress || this.receptionForm.detailedAddress,
|
||||
contactCount: customer.contactCount ?? this.receptionForm.contactCount
|
||||
};
|
||||
uni.showToast({
|
||||
title: "已填充客户信息",
|
||||
@@ -351,6 +660,7 @@ import { getApiUrl } from "@/common/config.js";
|
||||
onCancel() {
|
||||
// 重置表单
|
||||
this.receptionForm = {
|
||||
id: "",
|
||||
customerName: "",
|
||||
contact: "",
|
||||
customerSource: "",
|
||||
@@ -389,11 +699,29 @@ import { getApiUrl } from "@/common/config.js";
|
||||
});
|
||||
return;
|
||||
}
|
||||
const trimmedContact = this.receptionForm.contact?.trim();
|
||||
if (!this.isValidPhoneNumber(trimmedContact)) {
|
||||
uni.showToast({
|
||||
title: "请输入有效的客户电话",
|
||||
icon: "none"
|
||||
});
|
||||
return;
|
||||
}
|
||||
const trimmedSalesPhone = this.receptionForm.salesPhone?.trim();
|
||||
if (trimmedSalesPhone && !this.isValidPhoneNumber(trimmedSalesPhone)) {
|
||||
uni.showToast({
|
||||
title: "请输入有效的销售电话",
|
||||
icon: "none"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建请求参数
|
||||
const normalizedCustomerId = this.receptionForm.id?.toString().trim() || "";
|
||||
const params = {
|
||||
id: normalizedCustomerId,
|
||||
customerName: this.receptionForm.customerName?.trim(),
|
||||
contact: this.receptionForm.contact?.trim(),
|
||||
contact: trimmedContact,
|
||||
customerSource: this.receptionForm.customerSource?.trim() || "",
|
||||
dealershipId: this.receptionForm.dealershipId?.trim() || "",
|
||||
dealershipName: this.receptionForm.dealershipName?.trim() || "",
|
||||
@@ -404,7 +732,7 @@ import { getApiUrl } from "@/common/config.js";
|
||||
infoCard: this.receptionForm.infoCard?.trim() || "",
|
||||
remark: this.receptionForm.remark?.trim() || "",
|
||||
detailedAddress: this.receptionForm.detailedAddress?.trim() || "",
|
||||
salesPhone: this.receptionForm.salesPhone?.trim() || "",
|
||||
salesPhone: trimmedSalesPhone || "",
|
||||
contactCount: Number(this.receptionForm.contactCount) || 0,
|
||||
operationType: action
|
||||
};
|
||||
@@ -444,6 +772,99 @@ import { getApiUrl } from "@/common/config.js";
|
||||
icon: "none"
|
||||
});
|
||||
}
|
||||
},
|
||||
// 标签管理相关方法
|
||||
fetchTagList() {
|
||||
// TODO: 从API获取标签列表
|
||||
// 目前使用模拟数据
|
||||
this.tagList = [];
|
||||
},
|
||||
showAddTag() {
|
||||
this.tagViewMode = 'add';
|
||||
this.showTagTypeDropdown = false;
|
||||
this.tagForm = {
|
||||
industry: '家居行业',
|
||||
tagType: '',
|
||||
name: '',
|
||||
detail: '',
|
||||
remark: ''
|
||||
};
|
||||
},
|
||||
cancelAddTag() {
|
||||
this.tagViewMode = 'list';
|
||||
this.showTagTypeDropdown = false;
|
||||
this.tagForm = {
|
||||
industry: '家居行业',
|
||||
tagType: '',
|
||||
name: '',
|
||||
detail: '',
|
||||
remark: ''
|
||||
};
|
||||
},
|
||||
toggleTagTypeDropdown() {
|
||||
this.showTagTypeDropdown = !this.showTagTypeDropdown;
|
||||
},
|
||||
selectTagType(option) {
|
||||
this.tagForm.tagType = option;
|
||||
this.showTagTypeDropdown = false;
|
||||
},
|
||||
closeTagTypeDropdown() {
|
||||
this.showTagTypeDropdown = false;
|
||||
},
|
||||
async saveTag() {
|
||||
// 表单验证
|
||||
if (!this.tagForm.name || !this.tagForm.name.trim()) {
|
||||
uni.showToast({
|
||||
title: "请输入标签名",
|
||||
icon: "none"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: "保存中..."
|
||||
});
|
||||
|
||||
const payload = {
|
||||
industry: this.tagForm.industry?.trim() || '',
|
||||
tagType: this.tagForm.tagType?.trim() || '',
|
||||
tagName: this.tagForm.name.trim(),
|
||||
tagDetail: this.tagForm.detail?.trim() || '',
|
||||
remark: this.tagForm.remark?.trim() || ''
|
||||
};
|
||||
|
||||
const res = await uni.request({
|
||||
url: getApiUrl('/api/industryTags/add'),
|
||||
method: "POST",
|
||||
data: payload,
|
||||
header: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
timeout: 10000
|
||||
});
|
||||
|
||||
const { statusCode, data } = res;
|
||||
if (statusCode === 200 && data && (data.success || data.code === 200)) {
|
||||
uni.showToast({
|
||||
title: data?.message || "保存成功",
|
||||
icon: "success"
|
||||
});
|
||||
// 保存成功后返回列表并刷新
|
||||
this.tagViewMode = 'list';
|
||||
this.fetchTagList();
|
||||
} else {
|
||||
throw new Error(data?.message || "保存失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("保存标签失败:", error);
|
||||
uni.showToast({
|
||||
title: error?.message || "保存失败,请重试",
|
||||
icon: "none"
|
||||
});
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -525,6 +946,52 @@ import { getApiUrl } from "@/common/config.js";
|
||||
background-color: #F5F5F5;
|
||||
padding: 24rpx 32rpx;
|
||||
}
|
||||
|
||||
.service-status-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 16rpx 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
background-color: #F8F8FA;
|
||||
border-radius: 16rpx;
|
||||
border: 1px solid #EFEFF2;
|
||||
}
|
||||
|
||||
.toolbar-total {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.toolbar-input {
|
||||
flex: 1;
|
||||
min-width: 150rpx;
|
||||
background-color: #F5F6FA;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 24rpx;
|
||||
font-size: 28rpx;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
padding: 0 16rpx;
|
||||
height: 72rpx;
|
||||
color: #2A68FF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background-color: #FFFFFF;
|
||||
@@ -586,6 +1053,19 @@ import { getApiUrl } from "@/common/config.js";
|
||||
margin-bottom: 20rpx;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.customer-info {
|
||||
margin-bottom: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.customer-name,
|
||||
.customer-phone {
|
||||
font-size: 28rpx;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
padding: 8rpx 16rpx;
|
||||
@@ -706,16 +1186,12 @@ import { getApiUrl } from "@/common/config.js";
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 服务表现内容 */
|
||||
.performance-content {
|
||||
padding: 40rpx;
|
||||
|
||||
.service-status-empty {
|
||||
padding: 48rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 开始接待表单样式 */
|
||||
@@ -769,6 +1245,10 @@ import { getApiUrl } from "@/common/config.js";
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-item--half {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.form-item__input {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
@@ -823,6 +1303,67 @@ import { getApiUrl } from "@/common/config.js";
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.tag-select-wrapper {
|
||||
position: relative;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.tag-select {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
background-color: #f9fafb;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.tag-select-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 160rpx;
|
||||
width: calc(100% - 160rpx);
|
||||
min-width: 260rpx;
|
||||
max-width: none;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 12rpx 30rpx rgba(15, 23, 42, 0.1);
|
||||
margin-top: 8rpx;
|
||||
z-index: 11;
|
||||
padding: 12rpx 0;
|
||||
}
|
||||
|
||||
.tag-select-dropdown__item {
|
||||
padding: 20rpx 32rpx;
|
||||
}
|
||||
|
||||
.tag-select-dropdown__item text {
|
||||
font-size: 28rpx;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.tag-select-dropdown__item text.active {
|
||||
color: #2A68FF;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tag-select-dropdown__item:active {
|
||||
background-color: #f5f7fb;
|
||||
}
|
||||
|
||||
.tag-select-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: transparent;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
@@ -866,4 +1407,113 @@ import { getApiUrl } from "@/common/config.js";
|
||||
.form-btn--save .form-btn__text {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* 标签管理样式 */
|
||||
.tag-management {
|
||||
height: calc(100vh - 300rpx);
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.tag-list {
|
||||
height: 100%;
|
||||
padding: 24rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tag-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tag-list-total {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tag-list-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
background-color: #E3F2FD;
|
||||
border-radius: 12rpx;
|
||||
color: #2A68FF;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.tag-card {
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tag-card-header {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tag-card-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tag-card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.tag-card-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.tag-card-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tag-card-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
width: 40%;
|
||||
max-width: 40%;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.tag-list-empty {
|
||||
padding: 48rpx 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.tag-form {
|
||||
height: 100%;
|
||||
padding: 24rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-item__textarea {
|
||||
flex: 1;
|
||||
min-height: 200rpx;
|
||||
background-color: #f9fafb;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user