Long пре 2 недеља
родитељ
комит
6bc419eab1

+ 10 - 0
src/api/live/liveFeedbackLog.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询主播反馈列表
+export function listLiveFeedbackLog(query) {
+  return request({
+    url: '/live/liveFeedbackLog/list',
+    method: 'get',
+    params: query
+  })
+}

+ 44 - 0
src/api/live/liveFeedbackType.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询直播反馈类型列表
+export function listLiveFeedbackType(query) {
+  return request({
+    url: '/live/liveFeedbackType/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询直播反馈类型详细
+export function getLiveFeedbackType(typeId) {
+  return request({
+    url: '/live/liveFeedbackType/' + typeId,
+    method: 'get'
+  })
+}
+
+// 新增直播反馈类型
+export function addLiveFeedbackType(data) {
+  return request({
+    url: '/live/liveFeedbackType',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改直播反馈类型
+export function updateLiveFeedbackType(data) {
+  return request({
+    url: '/live/liveFeedbackType',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除直播反馈类型
+export function delLiveFeedbackType(typeId) {
+  return request({
+    url: '/live/liveFeedbackType/' + typeId,
+    method: 'delete'
+  })
+}

+ 152 - 0
src/views/live/liveFeedbackLog/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
+      <el-form-item label="主播名称" prop="streamerName">
+        <el-input
+          v-model="queryParams.streamerName"
+          placeholder="请输入主播名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="反馈类型" prop="typeId">
+        <el-select v-model="queryParams.typeId" placeholder="请选择反馈类型" clearable size="small">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.id"
+            :label="item.typeName"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table
+      v-loading="loading"
+      :data="logList"
+      border
+    >
+      <el-table-column label="ID" align="center" prop="id"/>
+      <el-table-column label="主播ID" align="center" prop="streamerId"/>
+      <el-table-column label="主播名称" align="center" prop="streamerName"/>
+      <el-table-column label="反馈类型" align="center" prop="typeList" width="500">
+        <template slot-scope="scope">
+          <el-tag v-for="item in scope.row.typeList" :key="item">{{ item }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="反馈内容" align="center" prop="content" :show-overflow-tooltip="true"  width="500"/>
+      <el-table-column label="反馈时间" align="center" prop="createTime">
+        <template slot-scope="scope">
+          <span>{{ formatDateTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listLiveFeedbackLog } from "@/api/live/liveFeedbackLog";
+import { listLiveFeedbackType } from "@/api/live/liveFeedbackType";
+
+export default {
+  name: "LiveFeedbackLog",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 主播反馈日志表格数据
+      logList: [],
+      // 反馈类型选项
+      typeOptions: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示查看弹出层
+      viewOpen: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        streamerName: null,
+        typeId: null
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.getTypeOptions();
+  },
+  methods: {
+    /** 查询主播反馈日志列表 */
+    getList() {
+      this.loading = true;
+      listLiveFeedbackLog(this.queryParams).then(response => {
+        this.logList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 获取反馈类型选项
+    getTypeOptions() {
+      listLiveFeedbackType({}).then(response => {
+        this.typeOptions = response.rows || [];
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 格式化日期时间
+    formatDateTime(dateTime) {
+      if (!dateTime) return '-';
+      try {
+        const date = new Date(dateTime);
+        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}`;
+      } catch (e) {
+        console.error('日期格式化错误:', e);
+        return dateTime; // 如果解析失败,返回原始值
+      }
+    },
+  }
+};
+</script>
+
+<style scoped>
+
+</style>

+ 376 - 0
src/views/live/liveFeedbackType/index.vue

@@ -0,0 +1,376 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
+      <el-form-item label="类型名称" prop="typeName">
+        <el-input
+          v-model="queryParams.typeName"
+          placeholder="请输入类型名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="类型状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['live:liveFeedbackType:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          :disabled="!ids.length"
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleBatchDelete"
+          v-hasPermi="['live:liveFeedbackType:remove']"
+        >批量删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      border
+      :data="typeList"
+      row-key="id"
+      @selection-change="handleSelectionChange"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column type="selection" width="50" align="center" />
+      <el-table-column prop="typeName" label="类型名称" :show-overflow-tooltip="true"/>
+      <el-table-column prop="status" align="center" label="状态">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
+            {{ statusFormat(scope.row) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ formatDateTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="更新时间" align="center" prop="updateTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ formatDateTime(scope.row.updateTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['live:liveFeedbackType:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['live:liveFeedbackType:add']"
+          >新增</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['live:liveFeedbackType:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加或修改直播反馈类型对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="上级类型" prop="parentId">
+              <treeselect
+                v-model="form.parentId"
+                :options="typeOptions"
+                :normalizer="normalizer"
+                :show-count="true"
+                placeholder="选择上级类型"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="类型名称" prop="typeName">
+              <el-input v-model="form.typeName" placeholder="请输入类型名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="状态">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{dict.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listLiveFeedbackType, getLiveFeedbackType, delLiveFeedbackType, addLiveFeedbackType, updateLiveFeedbackType, treeselect } from "@/api/live/liveFeedbackType";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "LiveFeedbackType",
+  components: { Treeselect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 状态选项
+      statusOptions: [
+        { dictValue: '1', dictLabel: '正常' },
+        { dictValue: '0', dictLabel: '禁用' }
+      ],
+      // 类型表格数据
+      typeList: [],
+      // 类型树选项
+      typeOptions: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        typeName: undefined,
+        status: undefined
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        typeName: [
+          { required: true, message: "类型名称不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询直播反馈类型列表 */
+    getList() {
+      this.loading = true;
+      listLiveFeedbackType(this.queryParams).then(response => {
+        const {code,rows} = response
+        if (code === 200 && rows) {
+          this.typeList = this.handleTree(rows);
+          this.loading = false;
+        }
+      })
+    },
+    /** 转换类型数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.id,
+        label: node.typeName,
+        children: node.children
+      };
+    },
+    /** 查询类型下拉树结构 */
+    getTreeselect() {
+      listLiveFeedbackType().then(response => {
+        if (response.code === 200 && response.rows) {
+          this.typeOptions = [{
+            id: 0,
+            typeName: '主类目',
+            children: this.handleTree(response.rows)
+          }];
+        } else {
+          this.typeOptions = [];
+        }
+      }).catch(() => {
+        this.typeOptions = [];
+      });
+    },
+    // 状态字典翻译
+    statusFormat(row) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+    // 批量删除按钮操作
+    handleBatchDelete() {
+      this.$confirm(`是否确认删除选中的${this.ids.length}条数据?`, "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return delLiveFeedbackType(this.ids.join(','));
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    // 格式化日期时间
+    formatDateTime(dateTime) {
+      if (!dateTime) return '-';
+      try {
+        const date = new Date(dateTime);
+        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}`;
+      } catch (e) {
+        console.error('日期格式化错误:', e);
+        return dateTime; // 如果解析失败,返回原始值
+      }
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: undefined,
+        parentId: 0,
+        typeName: undefined,
+        status: '1',
+        isDel: 0,
+        createTime: undefined,
+        updateTime: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null && row.id) {
+        this.form.parentId = row.id;
+      } else {
+        this.form.parentId = 0;
+      }
+      this.open = true;
+      this.title = "添加反馈类型";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      getLiveFeedbackType(row.id).then(response => {
+        this.form = {...response.data, status: response.data.status + ''};
+        this.open = true;
+        this.title = "修改反馈类型";
+      });
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != undefined) {
+            updateLiveFeedbackType(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addLiveFeedbackType(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      this.$confirm('是否确认删除名称为"' + row.typeName + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delLiveFeedbackType(row.id);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+.mb8 {
+  margin-bottom: 15px;
+}
+</style>

+ 47 - 0
src/views/system/config/liveStreamerConfig.vue

@@ -0,0 +1,47 @@
+<template>
+  <div class="app-container">
+    <el-tabs v-model="activeName">
+      <el-tab-pane
+        v-for="item in tabs"
+        :key="item.name"
+        :label="item.label"
+        :name="item.name">
+        <component :is="item.component" :isActive="activeName === item.name"/>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import StreamerAgreement from './modules/streamerAgreement.vue'
+import StreamerSms from './modules/streamerSms.vue'
+
+export default {
+  name: 'liveStreamerConfig',
+  components: {
+    StreamerAgreement,
+    StreamerSms
+  },
+  data() {
+    return {
+      activeName: 'StreamerAgreement',
+      tabs: [
+        {
+          name: 'StreamerAgreement',
+          label: '主播协议配置',
+          component: 'StreamerAgreement'
+        },
+        {
+          name: 'StreamerSms',
+          label: '主播短信配置',
+          component: 'StreamerSms'
+        }
+      ]
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 133 - 0
src/views/system/config/modules/streamerAgreement.vue

@@ -0,0 +1,133 @@
+<template>
+  <el-form :model="form" :rules="rules" ref="form" label-width="100px" v-loading="loading">
+    <el-form-item label="主播协议" prop="userAgreement">
+      <editor ref="editor1" @on-text-change="updateUserAgreement" />
+    </el-form-item>
+    <el-form-item label="隐私协议" prop="privacyPolicy">
+      <editor ref="editor2" @on-text-change="updatePrivacyPolicy" />
+    </el-form-item>
+    <div class="footer">
+      <el-button type="primary" :disabled="submitting" @click="submitForm">提  交</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script>
+import Editor from '@/components/Editor/wang';
+import { addConfig, getConfigByKey, updateConfigByKey } from '@/api/system/config'
+
+export default {
+  name: 'StreamerAgreement',
+  components: {
+    Editor
+  },
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      submitting: false,
+      configId: null,
+      configKey: null,
+      configName: null,
+      form: {
+        userAgreement: '',
+        privacyPolicy: ''
+      },
+      rules: {}
+    }
+  },
+  watch: {
+    isActive: {
+      immediate: true,
+      handler(newVal) {
+        if (newVal) {
+          this.getConfigByKey("liveStreamer.agreement")
+        }
+      }
+    }
+  },
+  methods: {
+    getConfigByKey(key){
+      this.loading = true
+      getConfigByKey(key).then(response => {
+        const data = response?.data || {}
+
+        this.configId = data.configId ?? null
+        this.configKey = data.configKey ?? key
+        this.configName = data.configName ?? '主播协议配置'
+        this.form = this.safeParseJson(data.configValue, {})
+
+        this.$refs.editor1.setText(this.form.userAgreement);
+        this.$refs.editor2.setText(this.form.privacyPolicy);
+        this.loading = false
+      })
+    },
+    safeParseJson(value, defaultValue = {}) {
+      if (!value || typeof value !== 'string') {
+        return defaultValue
+      }
+      try {
+        return JSON.parse(value)
+      } catch (e) {
+        console.warn('JSON parse failed:', value)
+        return defaultValue
+      }
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.submitting) {
+            return
+          }
+          this.submitting = true
+
+          const param = {
+            configId: this.configId,
+            configKey: this.configKey,
+            configName: this.configName,
+            configValue: JSON.stringify(this.form)
+          }
+
+          if (this.configId) {
+            updateConfigByKey(param).then(response => {
+              const {code} = response
+              if (code === 200) {
+                this.msgSuccess("修改成功");
+              }
+              this.submitting = false
+            });
+          } else {
+            addConfig(param).then(response => {
+              const {code} = response
+              if (code === 200) {
+                this.msgSuccess("添加成功");
+              }
+              this.submitting = false
+            })
+          }
+        }
+      });
+    },
+    updateUserAgreement(text) {
+      this.form.userAgreement = text;
+    },
+    updatePrivacyPolicy(text) {
+      this.form.privacyPolicy = text;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer{
+  width: 100%;
+  display: flex;
+  align-items: flex-end;
+  justify-content: flex-end;
+}
+</style>

+ 176 - 0
src/views/system/config/modules/streamerSms.vue

@@ -0,0 +1,176 @@
+<template>
+  <el-form :model="form" :rules="rules" ref="form" label-width="150px" v-loading="loading">
+    <el-form-item label="短信服务商" prop="type">
+      <el-radio-group v-model="form.type">
+        <el-radio label="rf">重庆润芳</el-radio>
+        <el-radio label="dh">重庆大汉</el-radio>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳通知账号" prop="rfAccount1">
+      <el-input   v-model="form.rfAccount1"  label="请输入润芳通知账号"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳通知code" prop="rfCode1">
+      <el-input   v-model="form.rfCode1"  label="请输入润芳通知code"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳通知密码" prop="rfPassword1">
+      <el-input   v-model="form.rfPassword1"  label="请输入润芳通知密码"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type ==='rf'" label="润芳通知地址" prop="rfUrl1">
+      <el-input   v-model="form.rfUrl1"  label="请输入润芳通知地址"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳营销账号" prop="rfAccount2">
+      <el-input   v-model="form.rfAccount2"  label="请输入润芳营销账号"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳营销code" prop="rfCode2">
+      <el-input   v-model="form.rfCode2"  label="请输入润芳营销code"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳通知密码" prop="rfPassword2">
+      <el-input   v-model="form.rfPassword2"  label="请输入润芳通知密码"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳通知地址" prop="rfUrl2">
+      <el-input   v-model="form.rfUrl2"  label="请输入润芳营销地址"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'rf'" label="润芳签名" prop="rfSign">
+      <el-input   v-model="form.rfSign"  label="请输入润芳签名"></el-input>
+    </el-form-item>
+
+    <el-form-item  v-if="form.type === 'dh'" label="大汉通知账号" prop="dhAccount1">
+      <el-input   v-model="form.dhAccount1"  label="请输入大汉通知账号"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'dh'" label="大汉通知密码" prop="dhPassword1">
+      <el-input   v-model="form.dhPassword1"  label="请输入大汉通知密码"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'dh'" label="大汉营销账号" prop="dhAccount2">
+      <el-input   v-model="form.dhAccount2"  label="请输入大汉营销账号"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'dh'" label="大汉通知密码" prop="dhPassword2">
+      <el-input   v-model="form.dhPassword2"  label="请输入大汉通知密码"></el-input>
+    </el-form-item>
+    <el-form-item  v-if="form.type === 'dh'" label="大汉签名" prop="dhSign">
+      <el-input   v-model="form.dhSign"  label="请输入大汉签名"></el-input>
+    </el-form-item>
+    <div class="footer">
+      <el-button type="primary" :disabled="submitting" @click="submitForm">提  交</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script>
+import { addConfig, getConfigByKey, updateConfigByKey } from '@/api/system/config'
+
+export default {
+  name: 'StreamerSms',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      submitting: false,
+      configId: null,
+      configKey: null,
+      configName: null,
+      form: {
+        type: null,
+        rfAccount1: null,
+        rfCode1: null,
+        rfPassword1: null,
+        rfUrl1: null,
+        rfAccount2: null,
+        rfCode2: null,
+        rfPassword2: null,
+        rfUrl2: null,
+        rfSign: null,
+        dhAccount1: null,
+        dhPassword1: null,
+        dhAccount2: null,
+        dhPassword2: null,
+        dhSign: null
+      },
+      rules: {}
+    }
+  },
+  watch: {
+    isActive: {
+      immediate: true,
+      handler(newVal) {
+        if (newVal) {
+          this.getConfigByKey("his.sms")
+        }
+      }
+    }
+  },
+  methods: {
+    getConfigByKey(key){
+      this.loading = true
+      getConfigByKey(key).then(response => {
+        const data = response?.data || {}
+
+        this.configId = data.configId ?? null
+        this.configKey = data.configKey ?? key
+        this.configName = data.configName ?? '主播短信配置'
+        this.form = this.safeParseJson(data.configValue, {})
+        this.loading = false
+      })
+    },
+    safeParseJson(value, defaultValue = {}) {
+      if (!value || typeof value !== 'string') {
+        return defaultValue
+      }
+      try {
+        return JSON.parse(value)
+      } catch (e) {
+        console.warn('JSON parse failed:', value)
+        return defaultValue
+      }
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.submitting) {
+            return
+          }
+          this.submitting = true
+
+          const param = {
+            configId: this.configId,
+            configKey: this.configKey,
+            configName: this.configName,
+            configValue: JSON.stringify(this.form)
+          }
+
+          if (this.configId) {
+            updateConfigByKey(param).then(response => {
+              const {code} = response
+              if (code === 200) {
+                this.msgSuccess("修改成功");
+              }
+              this.submitting = false
+            });
+          } else {
+            addConfig(param).then(response => {
+              const {code} = response
+              if (code === 200) {
+                this.msgSuccess("添加成功");
+              }
+              this.submitting = false
+            })
+          }
+        }
+      });
+    },
+  }
+}
+</script>
+
+<style scoped>
+.footer{
+  width: 100%;
+  display: flex;
+  align-items: flex-end;
+  justify-content: flex-end;
+}
+</style>