完善班组模型功能迁移
Some checks failed
Release pipeline / publish (push) Has been cancelled
Release pipeline / Always run job (push) Has been cancelled

This commit is contained in:
sheng
2026-06-25 22:33:17 +08:00
parent 257e3f4d08
commit 8f13054d68
6 changed files with 118 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
import { request } from '@/api/_service' import { request } from '@/api/_service'
import qs from 'qs'
const BASE = 'system_settings/organization/production_shift_management/' const BASE = 'system_settings/organization/production_shift_management/'
@@ -6,8 +7,12 @@ function params (method, data = {}) {
return { method: `system_settings_organization_production_shift_management_${method}`, platform: 'background', ...data } return { method: `system_settings_organization_production_shift_management_${method}`, platform: 'background', ...data }
} }
function stringifyParams (method, data = {}) {
return qs.stringify(params(method, data), { arrayFormat: 'brackets', allowDots: true, encode: false })
}
export function getShiftAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) } export function getShiftAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) }
export function getShiftList (data) { return request({ url: BASE + 'list', method: 'get', params: params('list', data) }) } export function getShiftList (data) { return request({ url: BASE + 'list?' + stringifyParams('list', data), method: 'get', params: {} }) }
export function createShift (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) } export function createShift (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) }
export function editShift (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) } export function editShift (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) }
export function deleteShift (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) } export function deleteShift (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) }

View File

@@ -1,4 +1,5 @@
import { request } from '@/api/_service' import { request } from '@/api/_service'
import qs from 'qs'
const BASE = 'system_settings/organization/production_team_manage/' const BASE = 'system_settings/organization/production_team_manage/'
const MEMBER_BASE = 'system_settings/organization/production_members_manage/' const MEMBER_BASE = 'system_settings/organization/production_members_manage/'
@@ -11,8 +12,12 @@ function memberParams (method, data = {}) {
return { method: `system_settings_organization_production_members_manage_${method}`, platform: 'background', ...data } return { method: `system_settings_organization_production_members_manage_${method}`, platform: 'background', ...data }
} }
function stringifyParams (method, data = {}) {
return qs.stringify(params(method, data), { arrayFormat: 'brackets', allowDots: true, encode: false })
}
export function getTeamAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) } export function getTeamAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) }
export function getTeamList (data) { return request({ url: BASE + 'list', method: 'get', params: params('list', data) }) } export function getTeamList (data) { return request({ url: BASE + 'list?' + stringifyParams('list', data), method: 'get', params: {} }) }
export function createTeam (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) } export function createTeam (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) }
export function editTeam (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) } export function editTeam (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) }
export function deleteTeam (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) } export function deleteTeam (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) }

View File

@@ -641,6 +641,10 @@
"select_shift_end_time": "Please select shift end time", "select_shift_end_time": "Please select shift end time",
"production_team_binding": "Team Binding", "production_team_binding": "Team Binding",
"production_team_can_only_bind_one_shift": "One team can only bind one shift", "production_team_can_only_bind_one_shift": "One team can only bind one shift",
"rotation_count": "Rotation Count",
"rotation_unit": "Rotation Unit",
"please_select_valid_time": "Please select a valid time",
"shift_time_conflict": "Shift time range conflicts",
"please_enter_shift_plan_name": "Please enter shift plan name", "please_enter_shift_plan_name": "Please enter shift plan name",
"please_enter_shift_plan_code": "Please enter shift plan code", "please_enter_shift_plan_code": "Please enter shift plan code",
"please_enter_shift_name_row": "Please enter shift name, row: ", "please_enter_shift_name_row": "Please enter shift name, row: ",

View File

@@ -641,6 +641,10 @@
"select_shift_end_time": "请选择班次结束时间", "select_shift_end_time": "请选择班次结束时间",
"production_team_binding": "生产班组绑定", "production_team_binding": "生产班组绑定",
"production_team_can_only_bind_one_shift": "一个生产班组只能绑定一个班次", "production_team_can_only_bind_one_shift": "一个生产班组只能绑定一个班次",
"rotation_count": "轮转次数",
"rotation_unit": "轮转单位",
"please_select_valid_time": "请选择有效时间",
"shift_time_conflict": "班次时间段存在冲突",
"please_enter_shift_plan_name": "请输入班次计划名称", "please_enter_shift_plan_name": "请输入班次计划名称",
"please_enter_shift_plan_code": "请输入班次计划编码", "please_enter_shift_plan_code": "请输入班次计划编码",
"please_enter_shift_name_row": "请输入班次名称,行号:", "please_enter_shift_name_row": "请输入班次名称,行号:",

View File

@@ -38,8 +38,8 @@
<el-button size="mini" type="success" icon="el-icon-plus" @click="addShiftDetail">{{ $t(key('add_shift')) }}</el-button> <el-button size="mini" type="success" icon="el-icon-plus" @click="addShiftDetail">{{ $t(key('add_shift')) }}</el-button>
<el-table :data="shiftsData" border style="width:100%;margin-top:10px"> <el-table :data="shiftsData" border style="width:100%;margin-top:10px">
<el-table-column :label="$t(key('shift_name'))"><template slot-scope="scope"><el-input v-model="shiftsData[scope.$index].name" :placeholder="$t(key('enter_shift_name'))" /></template></el-table-column> <el-table-column :label="$t(key('shift_name'))"><template slot-scope="scope"><el-input v-model="shiftsData[scope.$index].name" :placeholder="$t(key('enter_shift_name'))" /></template></el-table-column>
<el-table-column :label="$t(key('shift_start_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].start_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_start_time'))" /></template></el-table-column> <el-table-column :label="$t(key('shift_start_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].start_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_start_time'))" @change="val => changeShiftTime(val, scope.$index, 'start_time')" /></template></el-table-column>
<el-table-column :label="$t(key('shift_end_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].finish_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_end_time'))" /></template></el-table-column> <el-table-column :label="$t(key('shift_end_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].finish_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_end_time'))" @change="val => changeShiftTime(val, scope.$index, 'finish_time')" /></template></el-table-column>
<el-table-column :label="$t(key('production_team_binding'))"><template slot-scope="scope"><el-select v-model="shiftsData[scope.$index].production_team_id" clearable filterable :placeholder="$t(key('please_select'))" @change="val => changeProductionTeam(val, scope.$index)"><el-option v-for="item in selectableTeams" :key="item.id" :label="item.name" :value="item.id" /></el-select></template></el-table-column> <el-table-column :label="$t(key('production_team_binding'))"><template slot-scope="scope"><el-select v-model="shiftsData[scope.$index].production_team_id" clearable filterable :placeholder="$t(key('please_select'))" @change="val => changeProductionTeam(val, scope.$index)"><el-option v-for="item in selectableTeams" :key="item.id" :label="item.name" :value="item.id" /></el-select></template></el-table-column>
<el-table-column :label="$t(key('operation'))" width="120"><template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="shiftsData.splice(scope.$index, 1)">{{ $t(key('delete')) }}</el-button></template></el-table-column> <el-table-column :label="$t(key('operation'))" width="120"><template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="shiftsData.splice(scope.$index, 1)">{{ $t(key('delete')) }}</el-button></template></el-table-column>
</el-table> </el-table>
@@ -49,7 +49,7 @@
<el-dialog :title="$t(key('shift_plan_data_import'))" :visible.sync="importVisible" width="80%" :close-on-click-modal="false"> <el-dialog :title="$t(key('shift_plan_data_import'))" :visible.sync="importVisible" width="80%" :close-on-click-modal="false">
<el-alert :title="$t(key('upload_file_alert_title'))" :description="$t(key('upload_file_alert_description'))" :closable="false" type="warning" /> <el-alert :title="$t(key('upload_file_alert_title'))" :description="$t(key('upload_file_alert_description'))" :closable="false" type="warning" />
<el-upload action="" :multiple="false" :auto-upload="false" :show-file-list="true" :file-list="importFileList" accept=".xls,.xlsx" :on-change="onImportFileChange"><el-button slot="trigger" size="mini" type="success">{{ $t(key('select_file')) }}</el-button><el-button style="margin-left:10px" size="mini" type="primary" :loading="importLoading" @click.stop="downloadTemplate">{{ $t(key('download_template')) }}</el-button></el-upload> <el-upload action="" :multiple="false" :auto-upload="false" :show-file-list="true" :file-list="importFileList" accept=".xls,.xlsx" :on-change="onImportFileChange"><el-button slot="trigger" size="mini" type="success">{{ $t(key('select_file')) }}</el-button><el-button style="margin-left:10px" size="mini" type="primary" :loading="importLoading" @click.stop="downloadTemplate">{{ $t(key('download_template')) }}</el-button></el-upload>
<el-table :data="importRows" height="330" border style="margin-top:12px" v-loading="importTableLoading"><el-table-column prop="name" :label="$t(key('shift_plan_name'))" /><el-table-column prop="code" :label="$t(key('shift_plan_code'))" /><el-table-column prop="start_time" :label="$t(key('start_time'))" /><el-table-column prop="finish_time" :label="$t(key('end_time'))" /><el-table-column prop="status" :label="$t(key('status'))" /><el-table-column prop="shift_name" :label="$t(key('shift_name'))" /></el-table> <el-table :data="importRows" height="330" border style="margin-top:12px" v-loading="importTableLoading"><el-table-column prop="name" :label="$t(key('shift_plan_name'))" /><el-table-column prop="code" :label="$t(key('shift_plan_code'))" /><el-table-column prop="start_time" :label="$t(key('start_time'))" /><el-table-column prop="finish_time" :label="$t(key('end_time'))" /><el-table-column prop="production_team_ids" :label="$t(key('production_team'))" /><el-table-column prop="cycle_length" :label="$t(key('rotation_count'))" /><el-table-column prop="cycle_unit" :label="$t(key('rotation_unit'))" /><el-table-column prop="weekly_rest_days" :label="$t(key('rest_day_setting'))" /><el-table-column prop="status" :label="$t(key('status'))" /><el-table-column prop="shift_name" :label="$t(key('shift_name'))" /><el-table-column prop="shift_start_time" :label="$t(key('shift_start_time'))" /><el-table-column prop="shift_finish_time" :label="$t(key('shift_end_time'))" /><el-table-column prop="production_team_id" :label="$t(key('production_team_binding'))" /></el-table>
<span slot="footer"><el-button @click="importVisible = false">{{ $t(key('cancel')) }}</el-button><el-button type="primary" @click="submitImport">{{ $t(key('confirm')) }}</el-button></span> <span slot="footer"><el-button @click="importVisible = false">{{ $t(key('cancel')) }}</el-button><el-button type="primary" @click="submitImport">{{ $t(key('confirm')) }}</el-button></span>
</el-dialog> </el-dialog>
</d2-container> </d2-container>
@@ -122,7 +122,12 @@ export default {
methods: { methods: {
defaultFormData () { return { name: '', code: '', time_range: '', status: 1, remark: '', weekly_rest_days: [6, 7], cycle: { unit: 'day', length: 0 }, productionTeamIds: [] } }, defaultFormData () { return { name: '', code: '', time_range: '', status: 1, remark: '', weekly_rest_days: [6, 7], cycle: { unit: 'day', length: 0 }, productionTeamIds: [] } },
async loadTeams () { const res = await getTeamAll({}); this.teamOptions = (res && res.data) || res || [] }, async loadTeams () { const res = await getTeamAll({}); this.teamOptions = (res && res.data) || res || [] },
async fetchData () { this.loading = true; try { const res = await getShiftList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size }); const { list, total } = readPageData(res); this.tableData = list; this.pagination.total = total } finally { this.loading = false } }, buildSearchParams () {
const params = { ...this.search }
if (!Array.isArray(params.create_time) || !params.create_time.length) delete params.create_time
return params
},
async fetchData () { this.loading = true; try { const res = await getShiftList({ ...this.buildSearchParams(), page_no: this.pagination.current, page_size: this.pagination.size }); const { list, total } = readPageData(res); this.tableData = list; this.pagination.total = total } finally { this.loading = false } },
onSearch () { this.pagination.current = 1; this.fetchData() }, onSearch () { this.pagination.current = 1; this.fetchData() },
onReset () { this.search = { name: '', code: '', create_time: '' }; this.pagination.current = 1; this.fetchData() }, onReset () { this.search = { name: '', code: '', create_time: '' }; this.pagination.current = 1; this.fetchData() },
onPageChange (page) { this.pagination.current = page.current; this.pagination.size = page.size; this.fetchData() }, onPageChange (page) { this.pagination.current = page.current; this.pagination.size = page.size; this.fetchData() },
@@ -130,16 +135,47 @@ export default {
openEdit (row) { this.handleType = 'edit'; this.dialogTitle = this.key('edit_shift_plan'); this.editId = row.id; this.formData = { name: row.name, code: row.code, time_range: [row.start_time, row.finish_time], status: Number(row.status), remark: row.remark || '', weekly_rest_days: safeJson(row.weekly_rest_days, []), cycle: safeJson(row.cycle, { unit: 'day', length: 0 }), productionTeamIds: safeJson(row.production_team_ids, []) }; this.shiftsData = safeJson(row.shifts, []); this.dialogVisible = true }, openEdit (row) { this.handleType = 'edit'; this.dialogTitle = this.key('edit_shift_plan'); this.editId = row.id; this.formData = { name: row.name, code: row.code, time_range: [row.start_time, row.finish_time], status: Number(row.status), remark: row.remark || '', weekly_rest_days: safeJson(row.weekly_rest_days, []), cycle: safeJson(row.cycle, { unit: 'day', length: 0 }), productionTeamIds: safeJson(row.production_team_ids, []) }; this.shiftsData = safeJson(row.shifts, []); this.dialogVisible = true },
addShiftDetail () { this.shiftsData.push({ name: '', start_time: '', finish_time: '', production_team_id: '' }) }, addShiftDetail () { this.shiftsData.push({ name: '', start_time: '', finish_time: '', production_team_id: '' }) },
changeProductionTeam (value, index) { if (!value) return; if (this.shiftsData.some((item, i) => i !== index && item.production_team_id === value)) { this.shiftsData[index].production_team_id = ''; this.$message.warning(this.$t(this.key('production_team_can_only_bind_one_shift'))) } }, changeProductionTeam (value, index) { if (!value) return; if (this.shiftsData.some((item, i) => i !== index && item.production_team_id === value)) { this.shiftsData[index].production_team_id = ''; this.$message.warning(this.$t(this.key('production_team_can_only_bind_one_shift'))) } },
changeShiftTime (value, index, field) {
if (!value) {
this.$message.warning(this.$t(this.key('please_select_valid_time')))
this.shiftsData[index][field] = ''
return
}
const current = this.shiftsData[index]
if (!current.start_time || !current.finish_time) return
if (this.hasShiftTimeConflict(current, index)) {
this.$message.error(this.$t(this.key('shift_time_conflict')))
this.shiftsData[index][field] = ''
}
},
toMinute (value) {
const [hour, minute] = String(value || '').split(':').map(Number)
return hour * 60 + minute
},
getShiftRanges (shift) {
const start = this.toMinute(shift.start_time)
const finish = this.toMinute(shift.finish_time)
if (finish < start) return [[start, 24 * 60], [0, finish]]
return [[start, finish]]
},
hasShiftTimeConflict (current, currentIndex) {
const currentRanges = this.getShiftRanges(current)
return this.shiftsData.some((item, index) => {
if (index === currentIndex || !item.start_time || !item.finish_time) return false
const ranges = this.getShiftRanges(item)
return currentRanges.some(([start, finish]) => ranges.some(([itemStart, itemFinish]) => start < itemFinish && itemStart < finish))
})
},
validateShifts () { for (let i = 0; i < this.shiftsData.length; i++) { const item = this.shiftsData[i]; if (!item.name) return this.$t(this.key('please_enter_shift_name_row')) + (i + 1); if (!item.start_time) return this.$t(this.key('please_select_shift_start_time_row')) + (i + 1); if (!item.finish_time) return this.$t(this.key('please_select_shift_end_time_row')) + (i + 1) } return '' }, validateShifts () { for (let i = 0; i < this.shiftsData.length; i++) { const item = this.shiftsData[i]; if (!item.name) return this.$t(this.key('please_enter_shift_name_row')) + (i + 1); if (!item.start_time) return this.$t(this.key('please_select_shift_start_time_row')) + (i + 1); if (!item.finish_time) return this.$t(this.key('please_select_shift_end_time_row')) + (i + 1) } return '' },
submitDialog () { this.$refs.form.validate(async valid => { if (!valid) return; const error = this.validateShifts(); if (error) { this.$message.error(error); return } this.submitting = true; try { const payload = { ...this.formData, start_time: this.formData.time_range[0], finish_time: this.formData.time_range[1], is_shift: Number(this.formData.cycle.length) > 0 ? 1 : 0, rest_enabled: this.formData.weekly_rest_days.length !== 7 ? 1 : 0, shiftsData: JSON.stringify(this.shiftsData) }; if (this.handleType === 'create') await createShift(payload); else await editShift({ ...payload, id: this.editId }); this.$message.success(this.$t(this.key('operation_successful'))); this.closeDialog(); this.fetchData() } finally { this.submitting = false } }) }, submitDialog () { this.$refs.form.validate(async valid => { if (!valid) return; const error = this.validateShifts(); if (error) { this.$message.error(error); return } if (this.shiftsData.some((item, index) => this.hasShiftTimeConflict(item, index))) { this.$message.error(this.$t(this.key('shift_time_conflict'))); return } this.submitting = true; try { const payload = { ...this.formData, start_time: this.formData.time_range[0], finish_time: this.formData.time_range[1], is_shift: Number(this.formData.cycle.length) > 0 ? 1 : 0, rest_enabled: this.formData.weekly_rest_days.length !== 7 ? 1 : 0, shiftsData: JSON.stringify(this.shiftsData) }; if (this.handleType === 'create') await createShift(payload); else await editShift({ ...payload, id: this.editId }); this.$message.success(this.$t(this.key('operation_successful'))); this.closeDialog(); this.fetchData() } finally { this.submitting = false } }) },
closeDialog () { this.dialogVisible = false; this.formData = this.defaultFormData(); this.shiftsData = []; this.editId = '' }, closeDialog () { this.dialogVisible = false; this.formData = this.defaultFormData(); this.shiftsData = []; this.editId = '' },
async handleDelete (row) { const cancelled = await this.$confirmAction({ message: this.key('delete_department_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: [row.id] })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() }, async handleDelete (row) { const cancelled = await this.$confirmAction({ message: this.key('delete_department_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: [row.id] })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() },
async handleBatchDelete () { if (!this.selectedRows.length) { this.$message.error(this.$t(this.key('please_select_table_data'))); return } const cancelled = await this.$confirmAction({ message: this.key('batch_delete_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: this.selectedRows.map(item => item.id) })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() }, async handleBatchDelete () { if (!this.selectedRows.length) { this.$message.error(this.$t(this.key('please_select_table_data'))); return } const cancelled = await this.$confirmAction({ message: this.key('batch_delete_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: this.selectedRows.map(item => item.id) })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() },
openImport () { this.importFileList = []; this.importRows = []; this.importVisible = true }, openImport () { this.importFileList = []; this.importRows = []; this.importVisible = true },
async downloadTemplate () { this.importLoading = true; try { const res = await getShiftImportTemplate({}); downloadRename(res, 'xlsx', this.$t(this.key('shift_plan_data_import_template'))) } finally { this.importLoading = false } }, async downloadTemplate () { this.importLoading = true; try { const res = await getShiftImportTemplate({}); downloadRename(res, 'xlsx', this.$t(this.key('shift_plan_data_import_template'))) } finally { this.importLoading = false } },
async onImportFileChange (file) { if (!file || !/\.(xls|xlsx)$/i.test(file.name)) { this.$message.error(this.$t(this.key('upload_format_error'))); return } this.importFileList = [file]; this.importTableLoading = true; try { const rows = await readExcel(file.raw); this.importRows = rows.map(row => ({ name: row[this.$t(this.key('shift_plan_name'))], code: row[this.$t(this.key('shift_plan_code'))], start_time: row[this.$t(this.key('start_time'))], finish_time: row[this.$t(this.key('end_time'))], status: row[this.$t(this.key('status'))], shift_name: row[this.$t(this.key('shift_name'))], shifts: { name: row[this.$t(this.key('shift_name'))], start_time: row[this.$t(this.key('shift_start_time'))], finish_time: row[this.$t(this.key('shift_end_time'))], production_team_id: row[this.$t(this.key('production_team_binding'))] } })) } finally { this.importTableLoading = false } }, async onImportFileChange (file) { if (!file || !/\.(xls|xlsx)$/i.test(file.name)) { this.$message.error(this.$t(this.key('upload_format_error'))); return } this.importFileList = [file]; this.importTableLoading = true; try { const rows = await readExcel(file.raw); this.importRows = rows.map(row => { const shift = { name: row[this.$t(this.key('shift_name'))], start_time: row[this.$t(this.key('shift_start_time'))], finish_time: row[this.$t(this.key('shift_end_time'))], production_team_id: row[this.$t(this.key('production_team_binding'))] }; return { name: row[this.$t(this.key('shift_plan_name'))], code: row[this.$t(this.key('shift_plan_code'))], start_time: row[this.$t(this.key('start_time'))], finish_time: row[this.$t(this.key('end_time'))], production_team_ids: row[this.$t(this.key('production_team'))], cycle: { length: row[this.$t(this.key('rotation_count'))], unit: row[this.$t(this.key('rotation_unit'))] }, cycle_length: row[this.$t(this.key('rotation_count'))], cycle_unit: row[this.$t(this.key('rotation_unit'))], weekly_rest_days: row[this.$t(this.key('rest_day_setting'))], status: row[this.$t(this.key('status'))], shift_name: shift.name, shift_start_time: shift.start_time, shift_finish_time: shift.finish_time, production_team_id: shift.production_team_id, shifts: shift } }) } finally { this.importTableLoading = false } },
async submitImport () { if (!this.importRows.length) { this.$message.error(this.$t(this.key('please_import_department_data'))); return } await importShiftData({ import_data: JSON.stringify(this.importRows) }); this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData() }, async submitImport () { if (!this.importRows.length) { this.$message.error(this.$t(this.key('please_import_department_data'))); return } await importShiftData({ import_data: JSON.stringify(this.importRows) }); this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData() },
async handleExport () { const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportShiftTask({ ...this.search, action: 'download' })); if (cancelled) return; this.$message.success(this.$t(this.key('download_task_created'))) } async handleExport () { const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportShiftTask({ ...this.buildSearchParams(), action: 'download' })); if (cancelled) return; this.$message.success(this.$t(this.key('download_task_created'))) }
} }
} }
</script> </script>

View File

@@ -62,6 +62,17 @@
<template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="deleteMember(scope.row, scope.$index)">{{ $t(key('delete')) }}</el-button></template> <template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="deleteMember(scope.row, scope.$index)">{{ $t(key('delete')) }}</el-button></template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-pagination
v-if="memberPagination.total > memberPagination.size"
:current-page="memberPagination.current"
:page-size="memberPagination.size"
:page-sizes="[8, 20, 50, 100]"
:total="memberPagination.total"
layout="total, sizes, prev, pager, next, jumper"
class="member-pagination"
@size-change="onMemberSizeChange"
@current-change="onMemberCurrentChange"
/>
<span slot="footer"> <span slot="footer">
<el-button @click="closeDialog">{{ $t(key('cancel')) }}</el-button> <el-button @click="closeDialog">{{ $t(key('cancel')) }}</el-button>
<el-button type="primary" :loading="submitting" @click="submitDialog">{{ $t(key('confirm')) }}</el-button> <el-button type="primary" :loading="submitting" @click="submitDialog">{{ $t(key('confirm')) }}</el-button>
@@ -134,6 +145,7 @@ export default {
leaderIndex: undefined, leaderIndex: undefined,
formData: { name: '', area_id: '', line_id: '' }, formData: { name: '', area_id: '', line_id: '' },
membersData: [], membersData: [],
memberPagination: { current: 1, size: 8, total: 0 },
importVisible: false, importVisible: false,
importFileList: [], importFileList: [],
importRows: [], importRows: [],
@@ -195,10 +207,15 @@ export default {
}, },
onSearchAreaChange (areaId) { this.search.line_id = ''; this.loadLines(areaId, 'searchLineOptions') }, onSearchAreaChange (areaId) { this.search.line_id = ''; this.loadLines(areaId, 'searchLineOptions') },
onFormAreaChange (areaId) { this.formData.line_id = ''; this.loadLines(areaId, 'formLineOptions') }, onFormAreaChange (areaId) { this.formData.line_id = ''; this.loadLines(areaId, 'formLineOptions') },
buildSearchParams () {
const params = { ...this.search }
if (!Array.isArray(params.create_time) || !params.create_time.length) delete params.create_time
return params
},
async fetchData () { async fetchData () {
this.loading = true this.loading = true
try { try {
const res = await getTeamList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size }) const res = await getTeamList({ ...this.buildSearchParams(), page_no: this.pagination.current, page_size: this.pagination.size })
const { list, total } = readPageData(res) const { list, total } = readPageData(res)
this.tableData = list this.tableData = list
this.pagination.total = total this.pagination.total = total
@@ -212,12 +229,30 @@ export default {
this.handleType = 'edit'; this.dialogTitle = this.key('edit_team'); this.editId = row.id this.handleType = 'edit'; this.dialogTitle = this.key('edit_team'); this.editId = row.id
this.formData = { name: row.name, area_id: row.area_id, line_id: row.line_id } this.formData = { name: row.name, area_id: row.area_id, line_id: row.line_id }
await this.loadLines(row.area_id, 'formLineOptions') await this.loadLines(row.area_id, 'formLineOptions')
const res = await getTeamMemberList({ production_team_id: row.id, page_no: 1, page_size: 10000 }) this.memberPagination.current = 1
await this.loadMembers()
this.dialogVisible = true
},
async loadMembers () {
const res = await getTeamMemberList({
production_team_id: this.editId,
page_no: this.memberPagination.current,
page_size: this.memberPagination.size
})
const { list } = readPageData(res) const { list } = readPageData(res)
this.membersData = list.map(item => ({ ...item, is_main: Number(item.is_main) })) this.membersData = list.map(item => ({ ...item, is_main: Number(item.is_main) }))
this.memberPagination.total = readPageData(res).total
this.leaderIndex = this.membersData.findIndex(item => Number(item.is_main) === 1) this.leaderIndex = this.membersData.findIndex(item => Number(item.is_main) === 1)
if (this.leaderIndex < 0) this.leaderIndex = undefined if (this.leaderIndex < 0) this.leaderIndex = undefined
this.dialogVisible = true },
onMemberSizeChange (size) {
this.memberPagination.size = size
this.memberPagination.current = 1
if (this.editId) this.loadMembers()
},
onMemberCurrentChange (current) {
this.memberPagination.current = current
if (this.editId) this.loadMembers()
}, },
addMember () { this.membersData.push({ user_id: '', is_main: 0 }) }, addMember () { this.membersData.push({ user_id: '', is_main: 0 }) },
onLeaderChange (val, index) { onLeaderChange (val, index) {
@@ -228,7 +263,12 @@ export default {
else if (Number(val) === 1) this.leaderIndex = index else if (Number(val) === 1) this.leaderIndex = index
}, },
async deleteMember (row, index) { async deleteMember (row, index) {
if (row.id) { await deleteTeamMember({ id: [row.id] }); this.$message.success(this.$t(this.key('operation_successful'))) } if (row.id) {
await deleteTeamMember({ id: [row.id] })
this.$message.success(this.$t(this.key('operation_successful')))
await this.loadMembers()
return
}
this.membersData.splice(index, 1) this.membersData.splice(index, 1)
}, },
submitDialog () { submitDialog () {
@@ -244,7 +284,15 @@ export default {
} finally { this.submitting = false } } finally { this.submitting = false }
}) })
}, },
closeDialog () { this.dialogVisible = false; this.formData = { name: '', area_id: '', line_id: '' }; this.membersData = []; this.formLineOptions = []; this.leaderIndex = undefined; this.editId = '' }, closeDialog () {
this.dialogVisible = false
this.formData = { name: '', area_id: '', line_id: '' }
this.membersData = []
this.formLineOptions = []
this.memberPagination = { current: 1, size: 8, total: 0 }
this.leaderIndex = undefined
this.editId = ''
},
async handleDelete (row) { async handleDelete (row) {
const cancelled = await this.$confirmAction({ message: this.key('delete_team_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteTeam({ id: [row.id] })) const cancelled = await this.$confirmAction({ message: this.key('delete_team_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteTeam({ id: [row.id] }))
if (cancelled) return if (cancelled) return
@@ -273,7 +321,7 @@ export default {
this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData() this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData()
}, },
async handleExport () { async handleExport () {
const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportTeamTask({ ...this.search, action: 'download' })) const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportTeamTask({ ...this.buildSearchParams(), action: 'download' }))
if (cancelled) return if (cancelled) return
this.$message.success(this.$t(this.key('download_task_created'))) this.$message.success(this.$t(this.key('download_task_created')))
} }
@@ -283,5 +331,6 @@ export default {
<style scoped> <style scoped>
.search-bar { padding: 10px 0; } .search-bar { padding: 10px 0; }
.member-pagination { margin-top: 12px; text-align: right; }
/deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; } /deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; }
</style> </style>