Commit 90164b0b by yuzhenWang

Merge branch 'test' into 'feature-20250827wyz-写业务'

Test

See merge request !46
parents 48ce4bc3 b1596447
...@@ -412,8 +412,15 @@ export function exportPayRecord(data) { ...@@ -412,8 +412,15 @@ export function exportPayRecord(data) {
responseType: 'blob' responseType: 'blob'
}) })
} }
// 入账检核重新比对
export function compareCommissionEntry(data){
return request({
url: '/csf/api/commission/compare?commissionBizId=' + data,
method: 'get',
})
}
// 应付款报表 // 应付款查询,按照保单期数维度
export function payableReport(data) { export function payableReport(data) {
return request({ return request({
url: '/csf/api/expectedFortune/payable_report', url: '/csf/api/expectedFortune/payable_report',
...@@ -422,11 +429,11 @@ export function payableReport(data) { ...@@ -422,11 +429,11 @@ export function payableReport(data) {
}) })
} }
// 应收款报表 // 应收款报表查询,按照保单期数维度
export function receivableReport(data) { export function receivableReport(data) {
return request({ return request({
url: '/csf/api/CommissionExpected/receivable_report', url: '/csf/api/CommissionExpected/receivable_report',
method: 'post', method: 'post',
data: data, data: data
}) })
} }
\ No newline at end of file
...@@ -27,7 +27,7 @@ export function updateToPolicyLib(data) { ...@@ -27,7 +27,7 @@ export function updateToPolicyLib(data) {
data: data data: data
}) })
} }
// 更新新单跟进 // 更新新单跟进-基本信息
export function updatePolicyfollow(data) { export function updatePolicyfollow(data) {
return request({ return request({
url: '/csf/api/policy_follow/update', url: '/csf/api/policy_follow/update',
...@@ -221,3 +221,38 @@ export function signName(data) { ...@@ -221,3 +221,38 @@ export function signName(data) {
data: data data: data
}) })
} }
// 保存首期缴费
export function saveInitialPayment(data) {
return request({
url: '/csf/api/policy_follow/save_initial_payment',
method: 'post',
data: data
})
}
// 保存邮寄信息
export function saveMailingInfo(data) {
return request({
url: '/csf/api/policy_follow/save_mailing_info',
method: 'post',
data: data
})
}
// 批量保存介绍人
export function batchSaveBrokers(data) {
return request({
url: '/csf/api/policy_follow/batch_save_brokers',
method: 'post',
data: data
})
}
// 通过保险公司、险种查询产品列表及参数
export function getProductList(data) {
return request({
url: '/product/api/relProjectProductLaunch/parameter/page',
method: 'post',
data: data
})
}
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
class="upload-file-uploader" class="upload-file-uploader"
ref="fileUpload" ref="fileUpload"
:drag="drag" :drag="drag"
:name="name"
v-if="!disabled" v-if="!disabled"
> >
<!-- 上传按钮 --> <!-- 上传按钮 -->
...@@ -49,6 +50,11 @@ import Sortable from 'sortablejs' ...@@ -49,6 +50,11 @@ import Sortable from 'sortablejs'
export default { export default {
name: "FileUpload", name: "FileUpload",
props: { props: {
// 上传文件名称
name: {
type: String,
default: "file"
},
// 上传按钮文字 // 上传按钮文字
uploadBtnText: { uploadBtnText: {
type: String, type: String,
......
<template>
<div class="editable-table">
<el-form ref="formRef" :model="{}" label-width="120px" size="small">
<el-button type="primary" size="default" style="margin: 12px 0" @click="addRow" :disabled="disabled">
添加一行
</el-button>
<el-table :data="internalData" border style="width: 100%" :row-style="{ height: '48px' }"
:cell-style="{ padding: '6px 0' }">
<el-table-column v-for="field in rowConfig" :key="field.prop" :label="field.label" :width="field.width"
:min-width="field.minWidth">
<template #default="{ row }">
<component :is="getFieldComponent(field.type)" v-bind="getFieldProps(field, row.data)"
@update:model-value="val => handleFieldChange(val, field, row)"
@option-change="option => handleOptionChange(option, field, row)"
@focus="() => loadRemoteOptions(field)"
@filter-change="keyword => handleFilterChange(keyword, field)"
:disabled="!!field.disabled || disabled" />
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ $index }">
<el-button type="danger" size="small" link @click="removeRow($index)" :disabled="disabled">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <el-button
type="success"
size="small"
style="margin-left: 12px"
@click="batchSave"
:disabled="disabled"
>
批量保存
</el-button> -->
</el-form>
</div>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
import SelectField from '@/components/csf-form/fields/SelectField.vue'
import InputField from '@/components/csf-form/fields/InputField.vue'
import UploadField from '@/components/csf-form/fields/UploadField.vue'
import { deepEqual } from '@/utils/csf-deepEqual'
import request from '@/utils/request'
const props = defineProps({
modelValue: {
type: Array,
default: () => []
},
rowConfig: {
type: Array,
required: true
},
disabled: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:modelValue', 'batch-save'])
const formRef = ref()
const internalData = ref([])
// 远程加载状态 & 缓存
const remoteLoading = ref({})
const optionsCache = ref(new Map()) // prop -> options
// 初始化 internalData
watch(
() => props.modelValue,
(newVal) => {
if (!Array.isArray(newVal)) {
console.warn('[EditableTable] modelValue is not an array, reset to empty array')
internalData.value = []
return
}
const currentPlain = internalData.value.map(row => {
const { id, ...rest } = row.data
return { ...rest, id: row.id }
})
if (!deepEqual(newVal, currentPlain)) {
internalData.value = newVal.map((item, index) => ({
id: item.id || Symbol(`row-${index}`),
data: { ...(item || {}) }
}))
}
},
{ immediate: true }
)
// 同步 internalData → modelValue
let isEmitting = false
watch(
internalData,
(newVal) => {
if (isEmitting) return
const plainData = newVal.map(row => {
const { id, ...rest } = row.data
return { ...rest, id: row.id }
})
if (!deepEqual(plainData, props.modelValue)) {
isEmitting = true
emit('update:modelValue', plainData)
nextTick(() => {
isEmitting = false
})
}
},
{ deep: true }
)
// 字段组件映射
function getFieldComponent(type) {
switch (type) {
case 'select':
return SelectField
case 'input':
return InputField
case 'upload':
return UploadField
default:
return InputField
}
}
// 获取字段属性
function getFieldProps(field, rowData) {
const base = {
modelValue: rowData[field.prop],
'onUpdate:modelValue': (val) => {
rowData[field.prop] = val
}
}
switch (field.type) {
case 'select':
return {
...base,
multiple: !!field.multiple,
clearable: true,
filterable: true,
loading: remoteLoading.value[field.prop] || false,
options: optionsCache.value.get(field.prop) || field.options || [],
placeholder: field.placeholder || `请选择${field.label}`
}
case 'input':
return {
...base,
placeholder: field.placeholder || `请输入${field.label}`
}
case 'upload':
return {
...base,
uploadUrl: field.uploadUrl,
maxCount: field.maxCount || 1,
showFileList: field.showFileList !== false
}
default:
return base
}
}
// 处理字段变更(基础)
function handleFieldChange(val, field, row) {
row.data[field.prop] = val
}
// 处理 select 选中(带完整 option)
function handleOptionChange(option, field, row) {
if (!option || !field.onChangeExtraFields) return
// 兼容对象和数组格式
let extras = []
if (Array.isArray(field.onChangeExtraFields)) {
extras = field.onChangeExtraFields
} else if (typeof field.onChangeExtraFields === 'object') {
extras = Object.entries(field.onChangeExtraFields).map(([targetProp, sourceKey]) => ({
targetProp,
sourceKey
}))
}
for (const { targetProp, sourceKey } of extras) {
if (!targetProp || sourceKey == null) continue
const getValue = (obj, path) => path.split('.').reduce((o, k) => o?.[k], obj)
const extraValue = getValue(option, sourceKey)
row.data[targetProp] = extraValue
}
}
// 加载远程选项(初始加载)
async function loadRemoteOptions(field) {
if (!field.api || optionsCache.value.has(field.prop)) return
const key = field.prop
remoteLoading.value[key] = true
try {
const params = {
...(field.requestParams || {}),
[field.keywordField || 'keyword']: ''
}
const res = await request(field.api, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(params)
}).then(r => r)
const list = field.transform ? field.transform(res) : (res?.data?.records || [])
optionsCache.value.set(key, list)
} catch (err) {
console.error(`Failed to load options for ${field.prop}:`, err)
} finally {
remoteLoading.value[key] = false
}
}
// 搜索过滤(暂不实现,可扩展)
function handleFilterChange(keyword, field) {
// 可在此实现远程搜索
}
// 行操作
function addRow() {
internalData.value.push({
data: {}
})
}
function removeRow(index) {
internalData.value.splice(index, 1)
}
function batchSave() {
emit('batch-save', internalData.value.map(row => ({ ...row.data, id: row.id })))
}
</script>
<style scoped>
.editable-table :deep(.el-input__wrapper),
.editable-table :deep(.el-select__wrapper) {
box-shadow: none !important;
}
</style>
\ No newline at end of file
<template>
<el-form
ref="formRef"
:model="localModel"
:rules="formRules"
label-width="auto"
v-bind="$attrs"
:validate-on-rule-change="false"
>
<el-row :gutter="20">
<el-col
v-for="item in visibleConfig"
:key="item.prop"
:span="item.span || 6"
:class="{ 'search-form-item': isSearch }"
>
<el-form-item
:label="item.label"
:prop="item.prop"
:label-position="item.labelPosition || 'top'"
>
<component
:is="getFieldComponent(item.type)"
v-bind="getFieldProps(item)"
@update:model-value="val => handleModelChange(val, item)"
@focus="() => loadRemoteOptions(item)"
@filter-change="keyword => handleFilterChange(keyword, item)"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
import { onMounted } from 'vue'
import { useSearchFormLogic } from '@/composables/useSearchFormLogic'
// 字段组件映射
import InputField from './fields/InputField.vue'
import SelectField from './fields/SelectField.vue'
import DateField from './fields/DateField.vue'
import MonthField from './fields/MonthField.vue'
import DateRangeField from './fields/DateRangeField.vue'
import CheckboxGroupField from './fields/CheckboxGroupField.vue'
import TextareaField from './fields/TextareaField.vue'
import UploadField from './fields/UploadField.vue'
const fieldMap = {
input: InputField,
select: SelectField,
date: DateField,
month: MonthField,
daterange: DateRangeField,
'checkbox-group': CheckboxGroupField,
textarea: TextareaField,
upload: UploadField
}
const props = defineProps({
modelValue: { type: Object, default: () => ({}) },
config: { type: Array, default: () => [] },
isSearch: { type: Boolean, default: false }
})
const emit = defineEmits([
'update:modelValue',
'selectChange',
'uploadSuccess'
])
const {
formRef,
localModel,
visibleConfig,
formRules,
handleModelChange,
getSelectOptions,
getDisabledDateFn,
loadRemoteOptions,
handleFilterChange,
remoteLoading,
init,
getFormData,
validate,
resetForm
} = useSearchFormLogic(props, emit)
// 暴露方法给父组件
defineExpose({ getFormData, validate, resetForm })
// 初始化
onMounted(() => {
init()
})
// 获取字段组件
function getFieldComponent(type) {
return fieldMap[type] || 'span'
}
// 构建字段 props
function getFieldProps(item) {
const base = {
modelValue: localModel.value[item.prop],
disabled: item.disabled,
placeholder: item.placeholder
}
switch (item.type) {
case 'input':
return {
...base,
inputType: item.inputType,
decimalDigits: item.decimalDigits
}
case 'select':
return {
...base,
multiple: !!item.multiple,
clearable: true,
filterable: true,
loading: remoteLoading.value[item.prop] || false,
options: getSelectOptions(item),
placeholder: item.placeholder || `请选择${item.label}`
}
case 'date':
return {
...base,
valueFormat: item.valueFormat || 'YYYY-MM-DD',
disabledDate: getDisabledDateFn(item),
placeholder: `选择${item.label}`
}
case 'month':
return {
...base,
valueFormat: item.valueFormat || 'YYYY-MM',
disabledDate: getDisabledDateFn(item),
placeholder: `选择${item.label}`
}
case 'daterange':
return {
...base,
valueFormat: item.valueFormat || 'YYYY-MM-DD',
disabledDate: getDisabledDateFn(item)
}
case 'checkbox-group':
return {
...base,
options: getSelectOptions(item)
}
case 'textarea':
return {
...base,
clearable: true
}
case 'upload':
return {
...base,
action: item.action,
headers: item.headers,
multiple: !!item.multiple,
limit: item.limit || (item.multiple ? 999 : 1),
accept: item.accept,
listType: item.listType || 'text',
showFileList: item.showFileList,
uploadType: item.uploadType,
link: item.link,
maxSize: item.maxSize
}
default:
return base
}
}
</script>
<style scoped>
.search-form-item {
margin-bottom: 20px;
}
</style>
\ No newline at end of file
<template>
<el-checkbox-group :model-value="modelValue" :disabled="disabled" @update:model-value="handleChange">
<el-checkbox v-for="opt in options" :key="opt.value" :label="opt.value">
{{ opt.label }}
</el-checkbox>
</el-checkbox-group>
</template>
<script setup>
const props = defineProps({
modelValue: String,
disabled: Boolean,
options: { type: Array, default: () => [] }
})
const emit = defineEmits(['update:modelValue'])
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<!-- src/components/search-form/fields/DateField.vue -->
<template>
<el-date-picker
:model-value="modelValue"
type="date"
:placeholder="placeholder"
:disabled="disabled"
:value-format="valueFormat"
:disabled-date="disabledDate"
style="width: 100%"
@update:model-value="handleChange"
/>
</template>
<script setup>
const props = defineProps({
modelValue: String, // 注意:不能是 required,因为可能为 null
placeholder: String,
disabled: Boolean,
valueFormat: String,
disabledDate: Function
})
const emit = defineEmits(['update:modelValue'])
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<template>
<el-date-picker
:model-value="modelValue"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:value-format="valueFormat"
:disabled="disabled"
:disabled-date="disabledDate"
style="width: 100%"
@update:model-value="handleChange"
/>
</template>
<script setup>
const props = defineProps({
modelValue: Array,
valueFormat: String,
disabled: Boolean,
disabledDate: Function
})
const emit = defineEmits(['update:modelValue'])
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<template>
<el-input
:model-value="innerValue"
:placeholder="placeholder"
:clearable="clearable"
:disabled="disabled"
@input="handleInput"
@update:model-value="handleChange"
/>
</template>
<script setup>
import { ref, watch } from 'vue'
const props = defineProps({
modelValue: String,
placeholder: String,
clearable: Boolean,
disabled: Boolean,
inputType: { type: String, default: 'text' },
decimalDigits: { type: Number, default: 2 }
})
const emit = defineEmits(['update:modelValue'])
const innerValue = ref(props.modelValue)
watch(() => props.modelValue, val => {
innerValue.value = val
})
function handleInput(value) {
let result = String(value ?? '').trim()
if (props.inputType === 'integer') {
result = result.replace(/[^\d]/g, '')
} else if (props.inputType === 'decimal') {
result = result.replace(/[^\d.]/g, '')
if (result.startsWith('.')) result = '0.' + result.slice(1)
const parts = result.split('.')
if (parts.length > 2) result = parts[0] + '.' + parts.slice(1).join('')
if (result.includes('.')) {
const [int, dec] = result.split('.')
if (dec.length > props.decimalDigits) {
result = int + '.' + dec.slice(0, props.decimalDigits)
}
}
}
innerValue.value = result
emit('update:modelValue', result)
}
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<template>
<el-date-picker
:model-value="modelValue"
type="month"
:placeholder="placeholder"
:disabled="disabled"
:value-format="valueFormat"
:disabled-date="disabledDate"
style="width: 100%"
@update:model-value="handleChange"
/>
</template>
<script setup>
const props = defineProps({
modelValue: String,
placeholder: String,
disabled: Boolean,
valueFormat: String,
disabledDate: Function
})
const emit = defineEmits(['update:modelValue'])
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<template>
<el-select
:model-value="modelValue"
:multiple="multiple"
:placeholder="placeholder"
:clearable="clearable"
:filterable="filterable"
:disabled="disabled"
:loading="loading"
@update:model-value="handleChange"
@change="handleChangeWithOption"
@focus="$emit('focus')"
@filter-change="$emit('filter-change', $event)"
>
<el-option
v-for="opt in options"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
</template>
<script setup>
const props = defineProps({
modelValue: [String, Number, Array, null],
multiple: Boolean,
placeholder: String,
clearable: Boolean,
filterable: Boolean,
disabled: Boolean,
loading: Boolean,
options: {
type: Array,
default: () => []
}
})
const emit = defineEmits([
'update:modelValue',
'focus',
'filter-change',
'option-change' // 新增:emit 完整 option 对象
])
function handleChange(value) {
emit('update:modelValue', value)
}
function handleChangeWithOption(value) {
// 单选:value 是 primitive;多选:value 是 array
if (props.multiple) {
// 多选暂不支持 extra fields(可按需扩展)
return
}
const option = props.options.find(opt => opt.value === value)
emit('option-change', option)
}
</script>
\ No newline at end of file
<template>
<el-input
:model-value="modelValue"
type="textarea"
:autosize="{ minRows: 2 }"
:disabled="disabled"
:clearable="clearable"
placeholder="请输入"
style="width: 240px"
@update:model-value="handleChange"
/>
</template>
<script setup>
const props = defineProps({
modelValue: String,
disabled: Boolean,
clearable: Boolean
})
const emit = defineEmits(['update:modelValue'])
function handleChange(value) {
emit('update:modelValue', value)
}
</script>
\ No newline at end of file
<!-- src/components/search-form/fields/UploadField.vue -->
<template>
<el-upload
:file-list="innerFileList"
:action="action"
:headers="headers"
:multiple="multiple"
:limit="limit"
:accept="accept"
:list-type="listType"
:disabled="disabled"
:auto-upload="true"
:show-file-list="showFileList"
:on-exceed="handleExceed"
:before-upload="beforeUpload"
:on-success="handleSuccess"
:on-error="handleError"
:on-remove="handleRemove"
>
<el-icon v-if="uploadType === 'image'" class="iconStyle" :size="20">
<Upload />
</el-icon>
<el-button v-else size="small" type="primary" :link="link" :disabled="disabled">
点击上传文件
</el-button>
<template #tip v-if="maxSize || accept">
<div class="el-upload__tip">
<span v-if="maxSize">大小不超过 {{ formatFileSize(maxSize) }}</span>
<span v-if="accept">支持格式:{{ accept }}</span>
</div>
</template>
</el-upload>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload } from '@element-plus/icons-vue'
import { deepEqual } from '@/utils/csf-deepEqual'
const props = defineProps({
modelValue: {
type: Array,
default: () => []
},
action: String,
headers: Object,
multiple: Boolean,
limit: Number,
accept: String,
listType: { type: String, default: 'text' },
disabled: Boolean,
showFileList: Boolean,
uploadType: String,
link: Boolean,
maxSize: Number
})
const emit = defineEmits(['update:modelValue'])
// 内部状态:不能直接改 props.modelValue
const innerFileList = ref([...props.modelValue])
// 监听外部 modelValue 变化(如重置表单)
watch(
() => props.modelValue,
(newVal, oldVal) => {
if (!deepEqual(newVal, oldVal)) {
innerFileList.value = [...(newVal || [])]
}
},
{ deep: true }
)
// 格式化文件大小
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
// 文件上传前校验
function beforeUpload(file) {
if (props.maxSize && file.size > props.maxSize) {
ElMessage.error(`文件 ${file.name} 超出大小限制(最大 ${formatFileSize(props.maxSize)})`)
return false
}
if (props.accept) {
const allowed = props.accept.split(',').map(ext => ext.trim().toLowerCase())
const fileExt = '.' + file.name.split('.').pop().toLowerCase()
if (!allowed.includes(fileExt)) {
ElMessage.error(`文件类型不支持,仅支持:${props.accept}`)
return false
}
}
return true
}
// 上传成功
function handleSuccess(response, file) {
const data = response.data || response
const url = data.url || data.fileUrl || data.path
const name = data.name || data.fileName || file.name
if (!url) {
ElMessage.error('上传成功但未返回文件地址')
return
}
// 找到当前文件并更新 url 和 name
const target = innerFileList.value.find(f => f.uid === file.uid)
if (target) {
target.url = url
target.name = name
}
// 同步回父组件
emit('update:modelValue', [...innerFileList.value])
ElMessage.success(`文件 ${file.name} 上传成功`)
}
// 超出数量限制
function handleExceed() {
ElMessage.warning('超出文件数量限制')
}
// 上传失败
function handleError(err, file) {
ElMessage.error(`文件 ${file.name} 上传失败`)
console.error('Upload error:', err)
}
// 删除文件
function handleRemove(file) {
emit('update:modelValue', [...innerFileList.value])
}
// 暴露内部 fileList(可选,用于高级控制)
defineExpose({
fileList: innerFileList
})
</script>
<style scoped>
.iconStyle {
color: #409eff;
}
</style>
\ No newline at end of file
...@@ -21,10 +21,14 @@ const appointmentInfo = [ ...@@ -21,10 +21,14 @@ const appointmentInfo = [
sm: 12, //栅格布局份数 sm: 12, //栅格布局份数
lg: 8 //栅格布局份数 lg: 8 //栅格布局份数
}, },
{ {
label: '签单日', label: '签单日',
key: 'signDate', key: 'signDate',
domType: 'DatePicker', domType: 'datetimePicker',
dateValue: '', //YYYY-MM-DD
timeValue: '', //HH:mm
compositionTime: true, //是否组合时间
finishTime: '',
required: true, required: true,
disabled: false, disabled: false,
placeholder: '请选择', placeholder: '请选择',
......
// utils/deepEqual.js
export function deepEqual(a, b) {
if (a === b) return true
if (a == null || b == null) return false
if (typeof a !== typeof b) return false
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false
for (let i = 0; i < a.length; i++) {
if (!deepEqual(a[i], b[i])) return false
}
return true
}
if (typeof a === 'object' && typeof b === 'object') {
const keysA = Object.keys(a)
const keysB = Object.keys(b)
if (keysA.length !== keysB.length) return false
for (const key of keysA) {
if (!deepEqual(a[key], b[key])) return false
}
return true
}
return false
}
\ No newline at end of file
...@@ -32,6 +32,7 @@ export function useDict(...args) { ...@@ -32,6 +32,7 @@ export function useDict(...args) {
*/ */
export function useDictLists(typeLists) { export function useDictLists(typeLists) {
let params = { typeList: typeLists } let params = { typeList: typeLists }
console.log(params)
let dictArray = [] let dictArray = []
return (() => { return (() => {
getMoreDicts(params).then(resp => { getMoreDicts(params).then(resp => {
......
...@@ -152,22 +152,22 @@ watch(drawer, val => { ...@@ -152,22 +152,22 @@ watch(drawer, val => {
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-drawer__header { :deep(.el-drawer__header ) {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
::v-deep .el-drawer__footer { :deep(.el-drawer__footer ) {
padding: 0; padding: 0;
} }
.addressInput ::v-deep .el-input__wrapper { .addressInput :deep(.el-input__wrapper ) {
box-shadow: none !important; box-shadow: none !important;
} }
.addressInput ::v-deep .el-input__inner::placeholder { .addressInput :deep(.el-input__inner::placeholder ) {
text-align: right; text-align: right;
} }
.addressInput ::v-deep .el-input__inner { .addressInput :deep(.el-input__inner ) {
text-align: right; text-align: right;
} }
.addressInput ::v-deep .el-input__wrapper { .addressInput :deep(.el-input__wrapper ) {
padding: 0 !important; padding: 0 !important;
} }
.drawerContent { .drawerContent {
......
...@@ -250,17 +250,17 @@ watch(countryDrawer, val => { ...@@ -250,17 +250,17 @@ watch(countryDrawer, val => {
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-drawer__header { :deep(.el-drawer__header ) {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.searchInput ::v-deep .el-input__wrapper { .searchInput :deep(.el-input__wrapper ) {
box-shadow: none !important; box-shadow: none !important;
background-color: #fafbfd !important; background-color: #fafbfd !important;
} }
.searchInput ::v-deep .el-input__inner::placeholder { .searchInput :deep(.el-input__inner::placeholder ) {
text-align: left !important; text-align: left !important;
} }
.searchInput ::v-deep .el-input__inner { .searchInput :deep(.el-input__inner ) {
text-align: left !important; text-align: left !important;
} }
.countryContent { .countryContent {
...@@ -339,7 +339,7 @@ watch(countryDrawer, val => { ...@@ -339,7 +339,7 @@ watch(countryDrawer, val => {
box-sizing: border-box; box-sizing: border-box;
margin-left: 20px; margin-left: 20px;
border-left: 2px solid #d8ebff; border-left: 2px solid #d8ebff;
::v-deep(.el-anchor) { :deep(.el-anchor) {
.el-anchor__link { .el-anchor__link {
padding: 4px 0; padding: 4px 0;
...@@ -354,7 +354,7 @@ watch(countryDrawer, val => { ...@@ -354,7 +354,7 @@ watch(countryDrawer, val => {
} }
} }
} }
::v-deep(.el-anchor__marker) { :deep(.el-anchor__marker) {
height: 10px !important; height: 10px !important;
left: -6px !important; left: -6px !important;
border-radius: 50% !important; border-radius: 50% !important;
......
...@@ -174,22 +174,22 @@ watch( ...@@ -174,22 +174,22 @@ watch(
) )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-drawer__header { :deep(.el-drawer__header ) {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
::v-deep .el-drawer__footer { :deep(.el-drawer__footer ) {
padding: 0; padding: 0;
} }
.phoneInput ::v-deep .el-input__wrapper { .phoneInput :deep(.el-input__wrapper ) {
box-shadow: none !important; box-shadow: none !important;
} }
.phoneInput ::v-deep .el-input__inner::placeholder { .phoneInput :deep(.el-input__inner::placeholder ) {
text-align: right; text-align: right;
} }
.phoneInput ::v-deep .el-input__inner { .phoneInput :deep(.el-input__inner ) {
text-align: right; text-align: right;
} }
.phoneInput ::v-deep .el-input__wrapper { .phoneInput :deep(.el-input__wrapper ) {
padding: 0 !important; padding: 0 !important;
} }
.drawerContent { .drawerContent {
......
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
</template> </template>
<!-- 列表区域 --> <!-- 列表区域 -->
<template #table> <template #table>
<!-- 统计信息卡片 --> <!-- 统计信息卡片 v-if="statisticsData.totalInAmount > 0"-->
<div class="statistics-container" v-if="statisticsData.totalInAmount > 0"> <div class="statistics-container">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="4" :lg="4"> <el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">入账金额</div> <div class="card-label">入账金额</div>
<div class="card-value">{{ statisticsData.totalInAmount }}</div> <div class="card-value">{{ statisticsData.totalInAmount ? formatCurrency(statisticsData.totalInAmount) : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">总保单数</div> <div class="card-label">总保单数</div>
<div class="card-value">{{ statisticsData.totalPolicyCount }}</div> <div class="card-value">{{ statisticsData.totalPolicyCount ? statisticsData.totalPolicyCount : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">总保费(HKD)</div> <div class="card-label">总保费(HKD)</div>
<div class="card-value">{{ statisticsData.totalPremium }}</div> <div class="card-value">{{ statisticsData.totalPremium ? formatCurrency(statisticsData.totalPremium) : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">待出账金额</div> <div class="card-label">待出账金额</div>
<div class="card-value">{{ statisticsData.pendingOutAmount }}</div> <div class="card-value">{{ statisticsData.pendingOutAmount ? formatCurrency(statisticsData.pendingOutAmount) : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">可出账金额</div> <div class="card-label">可出账金额</div>
<div class="card-value">{{ statisticsData.availableOutAmount }}</div> <div class="card-value">{{ statisticsData.availableOutAmount ? formatCurrency(statisticsData.availableOutAmount) : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<el-card shadow="hover" class="statistics-card"> <el-card shadow="hover" class="statistics-card">
<div class="card-content"> <div class="card-content">
<div class="card-label">差额(估)</div> <div class="card-label">差额(估)</div>
<div class="card-value">{{ formatCurrency(statisticsData.differenceAmount) }}</div> <div class="card-value">{{ statisticsData.differenceAmount ? formatCurrency(statisticsData.differenceAmount) : 0 }}</div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
<el-table-column prop="policyNo" label="保单号" width="120" sortable /> <el-table-column prop="policyNo" label="保单号" width="120" sortable />
<el-table-column prop="insuranceCompany" label="保险公司" width="120" sortable /> <el-table-column prop="insuranceCompany" label="保险公司" width="120" sortable />
<el-table-column prop="commissionPaidAmount" label="累积已入账金额" width="120" sortable /> <el-table-column prop="commissionPaidAmount" label="累积已入账金额" width="120" sortable />
<el-table-column prop="commissionPaidRatio" label="累积已入账比例" width="120" sortable :formatter="(row) => `${row.commissionPaidRatio }%`" /> <el-table-column prop="commissionPaidRatio" label="累积已入账比例" width="120" sortable :formatter="(row) => `${row.commissionPaidRatio ? row.commissionPaidRatio : 0 }%`" />
<el-table-column prop="fortuneName" label="出账项目" width="130" sortable /> <el-table-column prop="fortuneName" label="出账项目" width="130" sortable />
<el-table-column prop="fortunePeriod" label="出账期数" width="130" sortable /> <el-table-column prop="fortunePeriod" label="出账期数" width="130" sortable />
<el-table-column prop="fortuneTotalPeriod" label="总期数" width="120" sortable /> <el-table-column prop="fortuneTotalPeriod" label="总期数" width="120" sortable />
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
<el-table-column prop="fortuneUnpaidRatio" label="剩余出账比例" width="120" sortable :formatter="(row) => `${row.fortuneUnpaidRatio }%`" /> <el-table-column prop="fortuneUnpaidRatio" label="剩余出账比例" width="120" sortable :formatter="(row) => `${row.fortuneUnpaidRatio }%`" />
<el-table-column prop="status" label="出账状态" width="120" sortable> <el-table-column prop="status" label="出账状态" width="120" sortable>
<template #default="{ row }"> <template #default="{ row }">
{{ getDictLabel('csf_fortune_status', row.status) }} {{ selectDictLabel(csf_fortune_status, row.status) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="premium" label="期交保费" width="120" sortable /> <el-table-column prop="premium" label="期交保费" width="120" sortable />
...@@ -148,7 +148,10 @@ import { Select } from '@element-plus/icons-vue' ...@@ -148,7 +148,10 @@ import { Select } from '@element-plus/icons-vue'
// 接口 // 接口
import { getPolicyFortuneList, addCheckRecordaddBatch, updatePayoutAmount, downloadPolicyFortuneAccount } from '@/api/financial/commission' import { getPolicyFortuneList, addCheckRecordaddBatch, updatePayoutAmount, downloadPolicyFortuneAccount } from '@/api/financial/commission'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { loadDicts, getDictLabel } from '@/utils/useDict'
const { proxy } = getCurrentInstance()
const { csf_fortune_status } = proxy.useDict('csf_fortune_status')
const userStore = useUserStore() const userStore = useUserStore()
// 分页相关 // 分页相关
...@@ -182,7 +185,7 @@ const searchConfig = ref([ ...@@ -182,7 +185,7 @@ const searchConfig = ref([
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
multiple: true, multiple: true,
valueKey: 'insuranceCompanyBizId', valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation', labelKey: 'fullName',
transform: (res) => { transform: (res) => {
console.log(res) console.log(res)
return res?.data.records || [] return res?.data.records || []
...@@ -535,15 +538,8 @@ const onSubmit = (data) => { ...@@ -535,15 +538,8 @@ const onSubmit = (data) => {
// 调用保存 API // 调用保存 API
} }
// 获取入账状态,字典值转化方法
onMounted(async () => { onMounted(async () => {
try {
await loadDicts(['csf_fortune_status'])
} catch (error) {
console.error('字典加载失败', error)
} finally {
loading.value = false
}
}) })
</script> </script>
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
<el-table-column type="selection" width="40" :selectable="selectableFn" /> <el-table-column type="selection" width="40" :selectable="selectableFn" />
<el-table-column prop="commissionStatus" label="比对状态" width="120" sortable fixed="left"> <el-table-column prop="commissionStatus" label="比对状态" width="120" sortable fixed="left">
<template #default="{ row }"> <template #default="{ row }">
{{ getDictLabel('csf_commission_status', row.commissionStatus) }} {{ selectDictLabel(csf_commission_status, row.commissionStatus) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="commissionBizType" label="业务类型" width="120" sortable> <el-table-column prop="commissionBizType" label="业务类型" width="120" sortable>
...@@ -103,8 +103,11 @@ ...@@ -103,8 +103,11 @@
<el-table-column prop="policyNo" label="保单号" width="120" sortable /> <el-table-column prop="policyNo" label="保单号" width="120" sortable />
<el-table-column prop="reconciliationCompany" label="对账公司" width="120" sortable /> <el-table-column prop="reconciliationCompany" label="对账公司" width="120" sortable />
<el-table-column prop="commissionDate" label="入账日" width="120" sortable /> <el-table-column prop="commissionDate" label="入账日" width="120" sortable />
<el-table-column prop="commissionExpectedStatus" label="入账状态" width="120" sortable <el-table-column prop="commissionExpectedStatus" label="入账状态" width="120" sortable>
:formatter="formatStatus" /> <template #default="{ row }">
{{ selectDictLabel(csf_expected_commission_status, row.commissionExpectedStatus) }}
</template>
</el-table-column>
<el-table-column prop="currentCommissionRatio" label="本次入账比例" width="130" sortable :formatter="formatRatio" /> <el-table-column prop="currentCommissionRatio" label="本次入账比例" width="130" sortable :formatter="formatRatio" />
<el-table-column prop="paidRatio" label="累积入账比例" width="130" sortable :formatter="formatRatio" /> <el-table-column prop="paidRatio" label="累积入账比例" width="130" sortable :formatter="formatRatio" />
<el-table-column prop="pendingRatio" label="待入账比例" width="120" sortable :formatter="formatRatio" /> <el-table-column prop="pendingRatio" label="待入账比例" width="120" sortable :formatter="formatRatio" />
...@@ -194,7 +197,7 @@ ...@@ -194,7 +197,7 @@
<el-table-column prop="policyNo" label="关联保单号" width="120" /> <el-table-column prop="policyNo" label="关联保单号" width="120" />
<el-table-column prop="commissionStatus" label="比对状态" width="120" fixed="left"> <el-table-column prop="commissionStatus" label="比对状态" width="120" fixed="left">
<template #default="{ row }"> <template #default="{ row }">
{{ getDictLabel('csf_commission_status', row.commissionStatus) }} {{ selectDictLabel(csf_commission_status, row.commissionStatus) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="commissionPeriod" label="佣金期数" width="120" /> <el-table-column prop="commissionPeriod" label="佣金期数" width="120" />
...@@ -206,15 +209,19 @@ ...@@ -206,15 +209,19 @@
<el-table-column prop="commissionName" label="入账项目" width="120" /> <el-table-column prop="commissionName" label="入账项目" width="120" />
<el-table-column prop="reconciliationCompany" label="对账公司" width="120" /> <el-table-column prop="reconciliationCompany" label="对账公司" width="120" />
<!-- <el-table-column prop="zip" label="入账状态" width="120" /> --> <!-- <el-table-column prop="zip" label="入账状态" width="120" /> -->
<el-table-column fixed="right" label="操作" min-width="180"> <el-table-column fixed="right" label="操作" min-width="240">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" size="default" @click="checkRecordEdit(row)"> <el-button type="primary" text size="small" @click="compareCommissionEntryapi(row)">
重新比对
</el-button>
<el-button type="primary" text size="small" @click="checkRecordEdit(row)">
修改 修改
</el-button> </el-button>
<el-popconfirm confirm-button-text="Yes" cancel-button-text="No" :icon="InfoFilled" icon-color="#626AEF" <el-popconfirm confirm-button-text="Yes" cancel-button-text="No" :icon="InfoFilled" icon-color="#626AEF"
title="确认要删除吗?" @confirm="deletePolicyCommissionApi(row)"> title="确认要删除吗?" @confirm="deletePolicyCommissionApi(row)">
<template #reference> <template #reference>
<el-button>删除</el-button> <el-button text type="danger" size="small">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
...@@ -286,12 +293,18 @@ import { formatCurrency } from '@/utils/number' ...@@ -286,12 +293,18 @@ import { formatCurrency } from '@/utils/number'
// 接口 // 接口
import { import {
getPolicyCommissionList, generateCommissionRecord, getPolicyCommissionList, generateCommissionRecord,
addPayrollCheckRecord, commissionExpectedRecord, updateCompareStatus, updateCommissionRecord, deletePolicyCommission, syncExpectedCommission addPayrollCheckRecord, commissionExpectedRecord, updateCompareStatus, updateCommissionRecord, deletePolicyCommission, syncExpectedCommission, compareCommissionEntry
} from '@/api/financial/commission' } from '@/api/financial/commission'
import { InfoFilled, Select, Upload, Plus } from '@element-plus/icons-vue' import { InfoFilled, Select, Upload, Plus } from '@element-plus/icons-vue'
import FileUpload from '@/components/FileUpload/index.vue' import FileUpload from '@/components/FileUpload/index.vue'
import { loadDicts, getDictLabel } from '@/utils/useDict' import { loadDicts, getDictLabel } from '@/utils/useDict'
const { proxy } = getCurrentInstance()
const { csf_expected_commission_status } = proxy.useDict('csf_expected_commission_status')
const { csf_commission_status } = proxy.useDict('csf_commission_status')
const formatRatio = (row, column, cellValue, index) => { const formatRatio = (row, column, cellValue, index) => {
if (cellValue == null || cellValue == '' || cellValue == 0) { if (cellValue == null || cellValue == '' || cellValue == 0) {
return '-' return '-'
...@@ -374,7 +387,7 @@ const searchConfig = ref([ ...@@ -374,7 +387,7 @@ const searchConfig = ref([
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
multiple: true, multiple: true,
valueKey: 'insuranceCompanyBizId', valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation', labelKey: 'fullName',
transform: (res) => { transform: (res) => {
console.log(res) console.log(res)
return res?.data.records || [] return res?.data.records || []
...@@ -474,20 +487,11 @@ const deletePolicyCommissionApi = async (row) => { ...@@ -474,20 +487,11 @@ const deletePolicyCommissionApi = async (row) => {
// 生成可出账记录按钮 // 生成可出账记录按钮
const updatePayRollStatusDisable = ref(true) const updatePayRollStatusDisable = ref(true)
// 获取入账状态,字典值转化方法
onMounted(async () => { onMounted(async () => {
try {
await loadDicts(['csf_expected_commission_status', 'csf_commission_status'])
} catch (error) {
console.error('字典加载失败', error)
} finally {
loading.value = false
}
}) })
// 格式化函数(每次渲染都会调用,所以能拿到最新字典)
const formatStatus = (row, column, cellValue, index) => {
return getDictLabel('csf_expected_commission_status', cellValue) // 实时查缓存
}
// 应收单类型 // 应收单类型
const commissionBizTypeOptions = [ const commissionBizTypeOptions = [
{ value: 'R', label: '关联保单应收单' }, { value: 'R', label: '关联保单应收单' },
...@@ -620,7 +624,7 @@ const handleAddCheckRecord = async () => { ...@@ -620,7 +624,7 @@ const handleAddCheckRecord = async () => {
// ✅ 统一从子组件获取完整表单数据(含 extra 字段) // ✅ 统一从子组件获取完整表单数据(含 extra 字段)
await nextTick() // 确保子组件已同步 await nextTick() // 确保子组件已同步
const formData = addCheckRecordFormRef.value.getFormData() const formData = addCheckRecordFormRef.value.getFormData()
console.log('======',formData) console.log('===========', formData)
let params let params
if (editStatus.value === 'edit') { if (editStatus.value === 'edit') {
params = { params = {
...@@ -635,20 +639,23 @@ const handleAddCheckRecord = async () => { ...@@ -635,20 +639,23 @@ const handleAddCheckRecord = async () => {
} }
await addPayrollCheckRecord([params]) await addPayrollCheckRecord([params])
} }
ElMessage.success(editStatus.value === 'edit' ? '更新成功' : '新增成功') ElMessage.success(editStatus.value === 'edit' ? '更新成功' : '新增成功')
addCheckRecordDialogFlag.value = false addCheckRecordDialogFlag.value = false
resetForm('addReceivablesFormModel') addCheckRecordFormRef.value.resetForm()
checkRecordQuery() checkRecordQuery()
} catch (error) { } catch (error) {
console.error('操作失败', error) console.error('操作失败', error)
ElMessage.error('操作失败') ElMessage.error('操作失败')
} }
} }
const resetForm = (type) => { const clearForm = (type) => {
if (type === 'addReceivablesFormModel') if (type === 'addReceivablesFormModel')
addReceivablesFormModel.value = {} if (addCheckRecordFormRef.value) {
addCheckRecordFormRef.value.resetForm() addReceivablesFormModel.value = {}
addCheckRecordFormRef.value.resetForm()
}
} }
...@@ -842,7 +849,7 @@ const handleAddCheckList = () => { ...@@ -842,7 +849,7 @@ const handleAddCheckList = () => {
editStatus.value = 'add' editStatus.value = 'add'
addReceivablesFormModel.value = { ...selectedRow.value } addReceivablesFormModel.value = { ...selectedRow.value }
addCheckRecordDialogFlag.value = true addCheckRecordDialogFlag.value = true
resetForm('addReceivablesFormModel') clearForm('addReceivablesFormModel')
} }
// 设置比对状态api // 设置比对状态api
...@@ -911,6 +918,22 @@ const closthDialog = () => { ...@@ -911,6 +918,22 @@ const closthDialog = () => {
checkFormData.value = {} checkFormData.value = {}
checkRecordTableData.value = [] checkRecordTableData.value = []
} }
// 重新比对
const compareCommissionEntryapi = async (row) => {
try {
const res = await compareCommissionEntry(row.commissionBizId)
if (res.code === 200) {
ElMessage.success('重新比对成功')
checkRecordQuery()
} else {
ElMessage.error(res.msg || '重新比对失败')
}
} catch (error) {
console.error('重新比对失败', error)
ElMessage.error('重新比对失败')
}
}
</script> </script>
<style scoped> <style scoped>
......
...@@ -319,7 +319,7 @@ const searchConfig = ref([ ...@@ -319,7 +319,7 @@ const searchConfig = ref([
placeholder: '输入保险公司名称搜索', placeholder: '输入保险公司名称搜索',
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
valueKey: 'insuranceCompanyBizId', valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation', labelKey: 'fullName',
transform: (res) => { transform: (res) => {
console.log(res) console.log(res)
return res?.data.records || [] return res?.data.records || []
...@@ -421,9 +421,8 @@ const addPayRecordFormConfig = [ ...@@ -421,9 +421,8 @@ const addPayRecordFormConfig = [
type: 'input', type: 'input',
prop: 'amount', prop: 'amount',
label: '出账金额', label: '出账金额',
inputType: 'decimal',
rules: [ rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' } { pattern: /^-?\d+(\.\d{1,2})?$/, message: '小数(最多两位)', trigger: 'blur' }
] ]
}, { }, {
type: 'select', type: 'select',
...@@ -726,6 +725,7 @@ const handleConfirmSetPayRecordStatus = async () => { ...@@ -726,6 +725,7 @@ const handleConfirmSetPayRecordStatus = async () => {
onMounted(async () => { onMounted(async () => {
try { try {
await loadDicts(['csf_expected_fortune_status']) await loadDicts(['csf_expected_fortune_status'])
loadTableData()
} catch (error) { } catch (error) {
console.error('字典加载失败', error) console.error('字典加载失败', error)
} finally { } finally {
......
...@@ -410,7 +410,7 @@ const searchConfig = ref([ ...@@ -410,7 +410,7 @@ const searchConfig = ref([
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
multiple: true, multiple: true,
valueKey: 'insuranceCompanyBizId', valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation', labelKey: 'fullName',
transform: (res) => { transform: (res) => {
return res?.data.records || [] return res?.data.records || []
} }
...@@ -736,6 +736,7 @@ const handleConfirmSetStatus = () => { ...@@ -736,6 +736,7 @@ const handleConfirmSetStatus = () => {
onMounted(async () => { onMounted(async () => {
try { try {
await loadDicts(['csf_expected_commission_status']) await loadDicts(['csf_expected_commission_status'])
loadTableData()
} catch (error) { } catch (error) {
console.error('字典加载失败', error) console.error('字典加载失败', error)
} finally { } finally {
......
...@@ -529,11 +529,11 @@ const handleSuccess = info => { ...@@ -529,11 +529,11 @@ const handleSuccess = info => {
getDictsData() getDictsData()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-card { :deep(.el-card ) {
border: none !important; border: none !important;
} }
::v-deep .el-input-group__append, :deep(.el-input-group__append ),
.el-input-group__prepend { :deep(.el-input-group__prepend ) {
background-color: #fff !important; background-color: #fff !important;
} }
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</el-col> </el-col>
<el-col :sm="12" :lg="6" :xs="24"> <el-col :sm="12" :lg="6" :xs="24">
<el-form-item label="状态" prop="status"> <el-form-item label="流程状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择" clearable> <el-select v-model="queryParams.status" placeholder="请选择" clearable>
<el-option <el-option
v-for="dict in csf_fna_status" v-for="dict in csf_fna_status"
...@@ -75,19 +75,13 @@ ...@@ -75,19 +75,13 @@
border border
max-height="380px" max-height="380px"
> >
<el-table-column type="index" width="50" label="序号" /> <el-table-column type="index" width="60" label="序号" />
<el-table-column label="客户姓名" align="center" prop="customerName" width="100" /> <el-table-column label="客户姓名" align="center" prop="customerName" width="100" />
<el-table-column label="状态" align="center" width="150"> <el-table-column label="中文姓名" align="center" prop="customerNameCn" width="100" />
<!-- <el-table-column label="状态" align="center" prop="status" width="100" :formatter="getDictLabel('csf_fna_status')"/> -->
<el-table-column label="流程状态" sortable align="center" prop="status" width="200">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.status == 'UNCOMPLETED'"> <span>{{ selectDictLabel(csf_fna_status, scope.row.status) }}</span>
<span style="color: #ff7d00" class="iconfont icon-yanqiweiwancheng"></span> 未完成
</span>
<span v-if="scope.row.status == 'COMPLETED'"
><span style="color: #43cf7c" class="iconfont icon-yiwancheng"></span> 已完成
</span>
<span v-if="scope.row.status == 'DRAFT'"
><span style="color: #86909c" class="iconfont icon-genjinjilu"></span> 草稿
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
>取消预约</el-button >取消预约</el-button
> >
</div> </div>
<div v-else="appointmentSummeryInfo.status !== '2'" style="margin-right: 10px"> <div v-else-if="appointmentSummeryInfo.status !== '2'" style="margin-right: 10px">
<el-button <el-button
v-if="pageSource !== 'policyList' && editStatus" v-if="pageSource !== 'policyList' && editStatus"
type="primary" type="primary"
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
</el-row> </el-row>
<el-tabs v-model="activeName" type="card" class="demo-tabs" :before-leave="beforeTabLeave"> <el-tabs v-model="activeName" type="card" class="demo-tabs" :before-leave="beforeTabLeave">
<el-tab-pane <el-tab-pane
v-for="(tab, index) in tabsList" v-for="tab in tabsList"
:key="tab.name" :key="tab.name"
:label="tab.label" :label="tab.label"
:name="tab.name" :name="tab.name"
...@@ -914,9 +914,6 @@ const handleSubmit = async type => { ...@@ -914,9 +914,6 @@ const handleSubmit = async type => {
if (appointmentInfoRef.value) { if (appointmentInfoRef.value) {
const result = await appointmentInfoRef.value[0].handleFormValues() const result = await appointmentInfoRef.value[0].handleFormValues()
submitAppointmentObj.value.apiAppointmentInfoDto = result submitAppointmentObj.value.apiAppointmentInfoDto = result
console.log('====================================')
console.log('预约', result)
console.log('====================================')
if (!submitAppointmentObj.value.apiAppointmentInfoDto) return if (!submitAppointmentObj.value.apiAppointmentInfoDto) return
} }
if (productPlanRef.value) { if (productPlanRef.value) {
...@@ -1450,11 +1447,11 @@ onUnmounted(() => { ...@@ -1450,11 +1447,11 @@ onUnmounted(() => {
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-card { :deep(.el-card ) {
border: none !important; border: none !important;
} }
::v-deep .el-input-group__append, :deep(.el-input-group__append ),
.el-input-group__prepend { :deep(.el-input-group__prepend ) {
background-color: #fff !important; background-color: #fff !important;
} }
.noembed-container { .noembed-container {
......
...@@ -302,6 +302,7 @@ import { getBankList } from '@/api/common' ...@@ -302,6 +302,7 @@ import { getBankList } from '@/api/common'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { loadDicts, getDictLabel } from '@/utils/useDict' import { loadDicts, getDictLabel } from '@/utils/useDict'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { getNowTime, formatToDate, formatToDateTime } from '@/utils/date'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const userStore = useUserStore() const userStore = useUserStore()
// 分页相关 // 分页相关
...@@ -493,7 +494,7 @@ const affirmConfig = [ ...@@ -493,7 +494,7 @@ const affirmConfig = [
placeholder: '请选择', placeholder: '请选择',
maxDate: 'today', maxDate: 'today',
visible: formData => visible: formData =>
formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) <= 0, formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) < 0 || Number(formData.remainingUnpaidAmount) == 0,
rules: [{ required: true, message: '请输入', trigger: 'blur' }] rules: [{ required: true, message: '请输入', trigger: 'blur' }]
}, },
{ {
...@@ -504,7 +505,7 @@ const affirmConfig = [ ...@@ -504,7 +505,7 @@ const affirmConfig = [
maxDate: 'today', maxDate: 'today',
rules: [{ required: true, message: '请输入', trigger: 'blur' }], rules: [{ required: true, message: '请输入', trigger: 'blur' }],
visible: formData => visible: formData =>
formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) <= 0 formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) < 0 || Number(formData.remainingUnpaidAmount) == 0,
}, },
{ {
type: 'select', type: 'select',
...@@ -512,7 +513,7 @@ const affirmConfig = [ ...@@ -512,7 +513,7 @@ const affirmConfig = [
label: '保单状态', label: '保单状态',
dictType: 'csf_policy_status_new', dictType: 'csf_policy_status_new',
visible: formData => visible: formData =>
formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) <= 0 formData.remainingUnpaidAmount && Number(formData.remainingUnpaidAmount) < 0 || Number(formData.remainingUnpaidAmount) == 0,
} }
] ]
//计算待付金额 //计算待付金额
...@@ -534,6 +535,7 @@ const calculateAmount = async () => { ...@@ -534,6 +535,7 @@ const calculateAmount = async () => {
const confirmAffirm = async () => { const confirmAffirm = async () => {
try { try {
const formData = await affirmFormRef.value.validate() const formData = await affirmFormRef.value.validate()
console.log(formData.value)
let newObj = JSON.parse(JSON.stringify(formData)) let newObj = JSON.parse(JSON.stringify(formData))
for (const key in newObj) { for (const key in newObj) {
if (/Date/.test(key)) { if (/Date/.test(key)) {
...@@ -667,10 +669,10 @@ const remittanceConfig = [ ...@@ -667,10 +669,10 @@ const remittanceConfig = [
type: 'select', type: 'select',
prop: 'policyNo', prop: 'policyNo',
label: '保单号码', label: '保单号码',
api: '/csf/api/policy/list/page/vo', api: '/csf/api/policy_follow/policyNos',
keywordField: 'policyNo', keywordField: 'policyNo',
requestParams: { pageNo: 1, pageSize: 20 }, requestParams: { pageNo: 1, pageSize: 100 },
placeholder: '输入转介人名称搜索', placeholder: '输入保单号码搜索',
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
valueKey: 'policyNo', valueKey: 'policyNo',
labelKey: 'policyNo', labelKey: 'policyNo',
...@@ -1046,10 +1048,10 @@ const addCheckRecordConfig = [ ...@@ -1046,10 +1048,10 @@ const addCheckRecordConfig = [
type: 'select', type: 'select',
prop: 'policyNo', prop: 'policyNo',
label: '保单号码', label: '保单号码',
api: '/csf/api/policy/list/page/vo', api: '/csf/api/policy_follow/policyNos',
keywordField: 'policyNo', keywordField: 'policyNo',
requestParams: { pageNo: 1, pageSize: 20 }, requestParams: { pageNo: 1, pageSize: 100 },
placeholder: '输入转介人名称搜索', placeholder: '输入保单号码搜索',
debounceWait: 500, // 自定义防抖时间 debounceWait: 500, // 自定义防抖时间
valueKey: 'policyNo', valueKey: 'policyNo',
labelKey: 'policyNo', labelKey: 'policyNo',
......
...@@ -177,11 +177,11 @@ if (route.query.type == 'edit') { ...@@ -177,11 +177,11 @@ if (route.query.type == 'edit') {
getDictsData() getDictsData()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-card { :deep(.el-card ) {
border: none !important; border: none !important;
} }
::v-deep .el-input-group__append, :deep(.el-input-group__append ),
.el-input-group__prepend { :deep(.el-input-group__prepend ) {
background-color: #fff !important; background-color: #fff !important;
} }
......
...@@ -1226,20 +1226,20 @@ getUserList() ...@@ -1226,20 +1226,20 @@ getUserList()
} }
/* 选项卡头部:消除默认样式,重构凹陷效果 */ /* 选项卡头部:消除默认样式,重构凹陷效果 */
::v-deep .el-tabs__header { :deep(.el-tabs__header ) {
line-height: 1; /* 重置行高,避免影响高度计算 */ line-height: 1; /* 重置行高,避免影响高度计算 */
padding: 0; /* 清除默认内边距 */ padding: 0; /* 清除默认内边距 */
} }
/* 选项卡导航容器:核心凹陷逻辑 */ /* 选项卡导航容器:核心凹陷逻辑 */
::v-deep .el-tabs__nav { :deep(.el-tabs__nav ) {
display: flex; display: flex;
margin: 0; /* 清除默认 margin */ margin: 0; /* 清除默认 margin */
border-bottom: 1px solid var(--border-color); /* 底部边框 */ border-bottom: 1px solid var(--border-color); /* 底部边框 */
} }
/* 选项卡 item 基础样式 */ /* 选项卡 item 基础样式 */
::v-deep .el-tabs__item { :deep(.el-tabs__item ) {
position: relative; position: relative;
padding: 12px 24px; padding: 12px 24px;
margin-right: 0; /* 清除默认间距 */ margin-right: 0; /* 清除默认间距 */
...@@ -1253,7 +1253,7 @@ getUserList() ...@@ -1253,7 +1253,7 @@ getUserList()
} }
/* 激活态:凹陷 + 高亮 */ /* 激活态:凹陷 + 高亮 */
::v-deep .el-tabs__item.is-active { :deep(.el-tabs__item.is-active ) {
color: var(--active-tab-color); color: var(--active-tab-color);
background-color: var(--active-tab-bg); background-color: var(--active-tab-bg);
/* 上、左、右边框 + 底部无边框,模拟“凹陷” */ /* 上、左、右边框 + 底部无边框,模拟“凹陷” */
...@@ -1266,23 +1266,23 @@ getUserList() ...@@ -1266,23 +1266,23 @@ getUserList()
} }
/* 未激活态:悬浮效果 */ /* 未激活态:悬浮效果 */
::v-deep .el-tabs__item:not(.is-active):hover { :deep(.el-tabs__item:not(.is-active):hover ) {
color: #409eff; color: #409eff;
background-color: #eaf2ff; background-color: #eaf2ff;
} }
/* 左侧边框处理(仅第一个 tab 左侧圆角) */ /* 左侧边框处理(仅第一个 tab 左侧圆角) */
::v-deep .el-tabs__item:first-child { :deep(.el-tabs__item:first-child ) {
border-top-left-radius: var(--radius); border-top-left-radius: var(--radius);
} }
/* 右侧边框处理(仅最后一个 tab 右侧圆角) */ /* 右侧边框处理(仅最后一个 tab 右侧圆角) */
::v-deep .el-tabs__item:last-child { :deep(.el-tabs__item:last-child ) {
border-top-right-radius: var(--radius); border-top-right-radius: var(--radius);
} }
/* 激活态:覆盖父容器的底部边框,实现“凹陷” */ /* 激活态:覆盖父容器的底部边框,实现“凹陷” */
::v-deep .el-tabs__item.is-active::before { :deep(.el-tabs__item.is-active::before ) {
content: ""; content: "";
position: absolute; position: absolute;
bottom: -1px; /* 覆盖父容器的 border-bottom */ bottom: -1px; /* 覆盖父容器的 border-bottom */
...@@ -1293,7 +1293,7 @@ getUserList() ...@@ -1293,7 +1293,7 @@ getUserList()
} }
/* 内容区域:和选项卡无缝衔接 */ /* 内容区域:和选项卡无缝衔接 */
::v-deep .el-tabs__content { :deep(.el-tabs__content ) {
padding: 20px; padding: 20px;
background-color: #fff; background-color: #fff;
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
......
...@@ -1617,20 +1617,20 @@ getList() ...@@ -1617,20 +1617,20 @@ getList()
} }
/* 选项卡头部:消除默认样式,重构凹陷效果 */ /* 选项卡头部:消除默认样式,重构凹陷效果 */
::v-deep .el-tabs__header { :deep(.el-tabs__header ) {
line-height: 1; /* 重置行高,避免影响高度计算 */ line-height: 1; /* 重置行高,避免影响高度计算 */
padding: 0; /* 清除默认内边距 */ padding: 0; /* 清除默认内边距 */
} }
/* 选项卡导航容器:核心凹陷逻辑 */ /* 选项卡导航容器:核心凹陷逻辑 */
::v-deep .el-tabs__nav { :deep(.el-tabs__nav ) {
display: flex; display: flex;
margin: 0; /* 清除默认 margin */ margin: 0; /* 清除默认 margin */
border-bottom: 1px solid var(--border-color); /* 底部边框 */ border-bottom: 1px solid var(--border-color); /* 底部边框 */
} }
/* 选项卡 item 基础样式 */ /* 选项卡 item 基础样式 */
::v-deep .el-tabs__item { :deep(.el-tabs__item ) {
position: relative; position: relative;
padding: 12px 24px; padding: 12px 24px;
margin-right: 0; /* 清除默认间距 */ margin-right: 0; /* 清除默认间距 */
...@@ -1644,7 +1644,7 @@ getList() ...@@ -1644,7 +1644,7 @@ getList()
} }
/* 激活态:凹陷 + 高亮 */ /* 激活态:凹陷 + 高亮 */
::v-deep .el-tabs__item.is-active { :deep(.el-tabs__item.is-active ) {
color: var(--active-tab-color); color: var(--active-tab-color);
background-color: var(--active-tab-bg); background-color: var(--active-tab-bg);
/* 上、左、右边框 + 底部无边框,模拟“凹陷” */ /* 上、左、右边框 + 底部无边框,模拟“凹陷” */
...@@ -1657,23 +1657,23 @@ getList() ...@@ -1657,23 +1657,23 @@ getList()
} }
/* 未激活态:悬浮效果 */ /* 未激活态:悬浮效果 */
::v-deep .el-tabs__item:not(.is-active):hover { :deep(.el-tabs__item:not(.is-active):hover ) {
color: #409eff; color: #409eff;
background-color: #eaf2ff; background-color: #eaf2ff;
} }
/* 左侧边框处理(仅第一个 tab 左侧圆角) */ /* 左侧边框处理(仅第一个 tab 左侧圆角) */
::v-deep .el-tabs__item:first-child { :deep(.el-tabs__item:first-child ) {
border-top-left-radius: var(--radius); border-top-left-radius: var(--radius);
} }
/* 右侧边框处理(仅最后一个 tab 右侧圆角) */ /* 右侧边框处理(仅最后一个 tab 右侧圆角) */
::v-deep .el-tabs__item:last-child { :deep(.el-tabs__item:last-child ) {
border-top-right-radius: var(--radius); border-top-right-radius: var(--radius);
} }
/* 激活态:覆盖父容器的底部边框,实现“凹陷” */ /* 激活态:覆盖父容器的底部边框,实现“凹陷” */
::v-deep .el-tabs__item.is-active::before { :deep(.el-tabs__item.is-active::before ) {
content: ''; content: '';
position: absolute; position: absolute;
bottom: -1px; /* 覆盖父容器的 border-bottom */ bottom: -1px; /* 覆盖父容器的 border-bottom */
...@@ -1684,7 +1684,7 @@ getList() ...@@ -1684,7 +1684,7 @@ getList()
} }
/* 内容区域:和选项卡无缝衔接 */ /* 内容区域:和选项卡无缝衔接 */
::v-deep .el-tabs__content { :deep(.el-tabs__content ) {
padding: 20px; padding: 20px;
background-color: #fff; background-color: #fff;
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
......
...@@ -375,10 +375,10 @@ const gap = ref('10px') ...@@ -375,10 +375,10 @@ const gap = ref('10px')
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-card { :deep(.el-card ) {
border: none !important; border: none !important;
} }
::v-deep .el-carousel__button { :deep(.el-carousel__button ) {
width: 10px !important ; width: 10px !important ;
} }
.app-container { .app-container {
......
...@@ -62,6 +62,16 @@ export default defineConfig(({ mode, command }) => { ...@@ -62,6 +62,16 @@ export default defineConfig(({ mode, command }) => {
// proxyReq.setHeader('host', '139.224.145.34:9002') // proxyReq.setHeader('host', '139.224.145.34:9002')
// }) // })
// } // }
},'/product': {
target: 'http://139.224.145.34:9002',
changeOrigin: true,
secure: false,
// 如果后端需要 host 头
// configure: (proxy, options) => {
// proxy.on('proxyReq', (proxyReq, req, res) => {
// proxyReq.setHeader('host', '139.224.145.34:9002')
// })
// }
}, },
// springdoc proxy // springdoc proxy
'^/v3/api-docs/(.*)': { '^/v3/api-docs/(.*)': {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment