| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- <template>
- <div class="app-container">
- <el-form :model="jsInfos" ref="form" label-width="120px">
-
- <el-card class="box-card">
- <div slot="header" class="clearfix">
- <span class="section-title">基本信息</span>
- </div>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="姓名">
- <el-input v-model="jsInfos.cName" placeholder="请输入姓名"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="昵称">
- <el-input v-model="jsInfos.cNickName"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="电话">
- <el-input v-model="jsInfos.cPhone" placeholder="请输入电话"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="城市">
- <el-select
- v-model="jsInfos.deptId"
- placeholder="请选择城市"
- @change="handleSelectionChange"
- style="width: 100%"
- >
- <el-option
- v-for="item in options"
- :key="item.deptId"
- :label="item.deptName"
- :value="item.deptId"
- >
- </el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="性别">
- <el-radio-group v-model="jsInfos.nSex">
- <el-radio :label="0">女</el-radio>
- <el-radio :label="1">男</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="是否推荐">
- <el-radio-group v-model="jsInfos.nB1">
- <el-radio :label="0">否</el-radio>
- <el-radio :label="1">是</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24">
- <el-form-item label="地址">
- <el-input v-model="jsInfos.name" disabled placeholder="请在地图选择"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="定位选择">
- <Map
- :dataObj="addr"
- :newAddress="newAddress"
- @uploadAddress="uploadAddressData"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="个人简介">
- <el-input
- type="textarea"
- :rows="3"
- placeholder="请输入个人简介"
- v-model="jsInfos.cJianjie"
- >
- </el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="头像">
- <ImageUpload v-model="jsInfos.cPortrait" :limit="1" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="生活照">
- <ImageUpload v-model="jsInfos.cImgList" :limit="9" tipText="建议上传生活近照,最多9张" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="视频展示">
- <el-upload
- class="video-uploader"
- action="#"
- accept="video/*"
- :limit="1"
- list-type="picture-card"
- :http-request="handleVideoUpload"
- :before-upload="beforeVideoUpload"
- :show-file-list="false"
- >
- <video
- class="video-preview"
- v-if="jsInfos.cVideo"
- :src="getVideoUrl(jsInfos.cVideo)"
- controls
- ></video>
- <i v-else class="el-icon-plus"></i>
- <div class="el-upload__tip" slot="tip">支持MP4、AVI等格式,大小不超过100MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- </el-card>
- <el-card class="box-card" style="margin-top: 20px;">
- <div slot="header" class="clearfix">
- <span class="section-title">资质与详细信息</span>
- </div>
-
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="评分">
- <el-input v-model="jsInfos.nStar" type="number"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="点赞数">
- <el-input v-model="jsInfos.nZan" type="number"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="佣金比例">
- <el-input v-model="jsInfos.nBili">
- <template slot="append">%</template>
- </el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="已服务数量">
- <el-input v-model="jsInfos.nNum" type="number"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="虑拟订单数" prop="virtualOrderNumber">
- <el-input type="number" v-model="jsInfos.virtualOrderNumber" placeholder="请输入虑拟订单数" />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="虚拟技师数量" prop="virtualTechNumber">
- <el-input type="number" v-model="jsInfos.virtualTechNumber" placeholder="请输入虚拟技师数量" />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="服务项目">
- <el-select
- v-model="jsProjectList"
- multiple
- filterable
- allow-create
- collapse-tags
- value-key="cId"
- placeholder="请选择项目"
- style="width: 100%"
- >
- <el-option
- v-for="item in projectList"
- :key="item.cId"
- :label="item.cTitle"
- :value="item"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="身份证照片">
- <ImageUpload v-model="jsInfos.cSfzImg" :limit="2" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="健康证">
- <ImageUpload v-model="jsInfos.healthCertificate" :limit="1" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="资格证">
- <ImageUpload v-model="jsInfos.certification" :limit="1" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="营业执照">
- <ImageUpload v-model="jsInfos.businessLicense" :limit="1" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="无犯罪证明">
- <ImageUpload v-model="jsInfos.noCrime" :limit="1" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-card>
- <el-card class="box-card" style="margin-top: 20px;">
- <div slot="header" class="clearfix">
- <span class="section-title">承诺相关信息</span>
- </div>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="承诺书">
- <FileUpload
- :fileSize="10"
- :fileType="['pdf', 'jpg', 'jpeg', 'png']"
- v-model="jsInfos.commitment"
- />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="承诺录音">
- <FileUpload
- :fileSize="10"
- :fileType="['mp3', 'wav', 'wma']"
- v-model="jsInfos.recording"
- />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="承诺录像">
- <FileUpload
- :fileSize="50"
- :fileType="['mp4', 'mov', 'mkv', 'wmv']"
- v-model="jsInfos.videoRecording"
- />
- </el-form-item>
- </el-col>
- </el-row>
- </el-card>
- <div class="footer-actions">
- <el-button type="info" icon="el-icon-chat-dot-round" @click="addComplaintShow">添加评论</el-button>
-
- <el-button
- :type="jsInfos.nStatus2 == -1 ? 'success' : 'warning'"
- @click="work"
- >
- {{ jsInfos.nStatus2 == -1 ? '上 岗' : '下 岗' }}
- </el-button>
- <template v-if="jsInfos.nTong == 0">
- <el-button type="success" icon="el-icon-check" @click="auditJs(jsInfos.id)">审 核</el-button>
- <el-button type="danger" icon="el-icon-close" @click="returnJs(jsInfos.id)">退 回</el-button>
- </template>
- <el-button
- :type="jsInfos.nTong == 3 ? 'success' : 'danger'"
- @click="blacklist"
- >
- {{ jsInfos.nTong == 3 ? '恢 复' : '拉 黑' }}
- </el-button>
- <el-button type="primary" icon="el-icon-edit" @click="submitForm">保存修改</el-button>
- <el-button @click="$router.go(-1)">返 回</el-button>
- </div>
- </el-form>
- <el-dialog title="添加评论" :visible.sync="dialogFormVisible" width="500px">
- <el-form :model="complainForm" label-width="80px">
- <el-form-item label="评分">
- <el-rate v-model="complainForm.nStar" style="margin-top: 10px;"></el-rate>
- </el-form-item>
- <el-form-item label="内容">
- <el-input type="textarea" v-model="complainForm.cText" placeholder="请输入评论内容"></el-input>
- </el-form-item>
- <el-form-item label="时间">
- <el-date-picker
- v-model="complainForm.dTime"
- type="datetime"
- placeholder="选择日期时间"
- :picker-options="pickerOptions"
- style="width: 100%"
- >
- </el-date-picker>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button @click="dialogFormVisible = false">取 消</el-button>
- <el-button type="primary" @click="submitComplain">确 定</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import {
- getJs,
- updateJs,
- auditJs,
- repulseJs,
- addComplaint,
- getProject,
- changeWork,
- block,
- getDept,
- } from "@/api/system/js";
- import { uploadvideo } from "@/api/public";
- import Map from "@/components/map/map.vue";
- export default {
- name: "JsDetails",
- components: {
- Map,
- },
- data() {
- return {
- // 禁用未来日期
- pickerOptions: {
- disabledDate(time) {
- return time.getTime() > Date.now();
- },
- },
- options: [], // 城市/部门列表
- dialogFormVisible: false,
-
- // 主信息对象
- jsInfos: {
- cImgList: [], // 确保初始化为数组或若依组件需要的格式
- cSfzImg: [],
- nStatus2: 0,
- nTong: 0,
- },
-
- addr: { lat: "", lng: "" }, // 地图回显坐标
- newAddress: "太原", // 地图默认城市
-
- projectList: [], // 所有项目
- jsProjectList: [], // 当前选中的项目对象
-
- complainForm: {
- cNickName: "匿名评论",
- nStar: 5,
- cText: "",
- dTime: new Date(),
- },
- };
- },
- mounted() {
- const id = this.$route.query.id;
- if (id) {
- this.complainForm.cJsid = id;
- this.getJsInfo(id);
- }
- this.getProjictList();
- this.getDept();
- },
- methods: {
- /** 辅助函数:处理视频URL回显(如果是相对路径则加上base_api) */
- getVideoUrl(url) {
- if (!url) return '';
- if (url.indexOf("http") === 0) return url;
- return process.env.VUE_APP_BASE_API + url;
- },
- // 视频上传前的校验
- beforeVideoUpload(file) {
- const isVideo = file.type.includes("video/");
- const isLtSize = file.size / 1024 / 1024 < 100;
- if (!isVideo) {
- this.$message.error("只能上传视频文件!");
- }
- if (!isLtSize) {
- this.$message.error("视频大小不能超过100MB!");
- }
- return isVideo && isLtSize;
- },
- // 视频自定义上传
- handleVideoUpload(options) {
- const { file } = options;
- const formData = new FormData();
- formData.append("video", file);
- uploadvideo(formData).then((response) => {
- // 保存相对路径,显示时处理
- this.$set(this.jsInfos, 'cVideo', response.fileName);
- this.$message.success("视频上传成功");
- });
- },
- // 地图选点回调
- uploadAddressData(payload) {
- this.jsInfos.latitude = payload.latitude;
- this.jsInfos.longitude = payload.longitude;
- this.jsInfos.name = payload.addressName;
- },
- // 城市选择回调
- handleSelectionChange(deptId) {
- // 找到对应的 deptName
- const obj = this.options.find(item => item.deptId === deptId);
- if(obj) {
- this.jsInfos.city = obj.deptName;
- }
- },
- getDept() {
- getDept().then((res) => {
- if (res.code == 200) {
- this.options = res.data;
- }
- });
- },
- getProjictList() {
- getProject({}).then((res) => {
- if (res.code == 200) {
- this.projectList = res.data;
- }
- });
- },
- // 获取技师详情
- getJsInfo(id) {
- getJs({ id: id }).then((response) => {
- const data = response.data;
-
- // 1. 处理地图信息
- this.addr = {
- lat: data.latitude,
- lng: data.longitude
- };
-
- // 2. 处理项目回显
- this.jsProjectList = [];
- if (data.projects && data.projects.length > 0) {
- data.projects.forEach((item) => {
- this.jsProjectList.push({ cTitle: item.cTitle, cId: item.cId });
- });
- }
-
- // 3. 赋值给主对象
- // 注意:ImageUpload组件通常需要逗号分隔的字符串或数组(取决于版本),若依默认通常存相对路径
- // 这里假设后端返回的是相对路径,如果不是,ImageUpload会自动处理显示,但v-model最好绑定相对路径
- this.jsInfos = data;
- // 确保数组类型字段初始化,防止组件报错
- if (!this.jsInfos.cImgList) this.jsInfos.cImgList = [];
- if (!this.jsInfos.cSfzImg) this.jsInfos.cSfzImg = [];
- });
- },
- // 提交评论
- submitComplain() {
- if (!this.complainForm.nStar) return this.$message.warning("请输入评分");
- if (!this.complainForm.cText) return this.$message.warning("请输入评论内容");
- if (!this.complainForm.dTime) return this.$message.warning("请选择评论时间");
- addComplaint(this.complainForm).then((res) => {
- if (res.code == 200) {
- this.$message.success("提交成功");
- this.dialogFormVisible = false;
- } else {
- this.$message.error(res.msg);
- }
- });
- },
-
- addComplaintShow() {
- this.complainForm.name = this.jsInfos.cName;
- this.complainForm.cId = this.jsInfos.cId;
- this.dialogFormVisible = true;
- },
- // 上岗/下岗切换
- work() {
- let data = {
- id: this.jsInfos.id,
- nStatus2: this.jsInfos.nStatus2 == 0 ? "-1" : "0"
- };
- changeWork(data).then((res) => {
- if (res.code == 200) {
- this.$message.success(data.nStatus2 == 0 ? "已上岗" : "已下岗");
- this.getJsInfo(this.jsInfos.id); // 刷新数据
- } else {
- this.$message.error(res.msg);
- }
- });
- },
- // 拉黑/恢复
- blacklist() {
- let data = {
- id: this.jsInfos.id,
- nTong: this.jsInfos.nTong == 3 ? "0" : "3"
- };
- block(data).then((res) => {
- if (res.code == 200) {
- this.$message.success(data.nTong == 3 ? "拉黑成功" : "取消拉黑成功");
- this.getJsInfo(this.jsInfos.id);
- } else {
- this.$message.error(res.msg);
- }
- });
- },
- // 提交修改
- submitForm() {
- // 处理项目ID集合
- const projectIds = this.jsProjectList.map(item => item.cId).join(",");
- this.jsInfos.cBhList = projectIds;
-
- // ImageUpload 组件已经通过 v-model 更新了 jsInfos 中的图片字段
- // 注意:如果 ImageUpload 返回的是数组,而后端需要逗号分隔字符串,这里需要转换
- // 假设 cImgList 和 cSfzImg 是数组,其他单图是字符串
- let submitData = { ...this.jsInfos };
-
- // 如果后端要求图片是字符串而不是数组,进行转换(视若依版本而定,通用处理如下)
- if(Array.isArray(submitData.cImgList)) {
- submitData.cImgList = submitData.cImgList.join(',');
- }
- if(Array.isArray(submitData.cSfzImg)) {
- submitData.cSfzImg = submitData.cSfzImg.join(',');
- }
- updateJs(submitData).then((res) => {
- if (res.code == 200) {
- this.$message.success("修改成功");
- this.$router.go(-1);
- } else {
- this.$message.error(res.msg);
- }
- });
- },
- // 审核通过
- auditJs(id) {
- if (this.jsInfos.nTong != 0) return this.$message.warning("该技师已操作");
- auditJs({ id }).then(() => {
- this.$message.success("审核通过");
- this.getJsInfo(id);
- });
- },
- // 退回
- returnJs(id) {
- if (this.jsInfos.nTong != 0) return this.$message.warning("该技师已操作");
- this.$prompt("请输入退回原因", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- }).then(({ value }) => {
- repulseJs({ id, reasonRefusal: value }).then(() => {
- this.$message.success("已退回");
- this.getJsInfo(id);
- });
- }).catch(() => {});
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .app-container {
- padding: 20px;
- background-color: #f0f2f5;
- min-height: 100vh;
- }
- .box-card {
- margin-bottom: 20px;
- }
- .section-title {
- font-size: 16px;
- font-weight: bold;
- color: #303133;
- padding-left: 10px;
- border-left: 4px solid #409EFF;
- }
- .video-uploader {
- .video-preview {
- width: 240px;
- height: 100%;
- object-fit: contain;
- }
- }
- .footer-actions {
- padding: 10px 20px;
- text-align: right;
- background: #fff;
- box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 10;
- }
- </style>
|