Refactor SaleSection component: Simplify sell item and sell all logic, remove unnecessary state management, and improve UI feedback. Update translations and clean up unused code in i18n files. Optimize price loading in BranchView and remove legacy product loading in MoneyHistoryView. Streamline PoliticsView by removing own character ID handling and related logic.
This commit is contained in:
@@ -93,8 +93,6 @@ class FalukantController {
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
this.setHeir = this._wrapWithUser((userId, req) => this.service.setHeir(userId, req.body.childCharacterId));
|
this.setHeir = this._wrapWithUser((userId, req) => this.service.setHeir(userId, req.body.childCharacterId));
|
||||||
this.getPotentialHeirs = this._wrapWithUser((userId) => this.service.getPotentialHeirs(userId));
|
|
||||||
this.selectHeir = this._wrapWithUser((userId, req) => this.service.selectHeir(userId, req.body.heirId));
|
|
||||||
this.acceptMarriageProposal = this._wrapWithUser((userId, req) => this.service.acceptMarriageProposal(userId, req.body.proposalId));
|
this.acceptMarriageProposal = this._wrapWithUser((userId, req) => this.service.acceptMarriageProposal(userId, req.body.proposalId));
|
||||||
this.getGifts = this._wrapWithUser((userId) => {
|
this.getGifts = this._wrapWithUser((userId) => {
|
||||||
console.log('🔍 getGifts called with userId:', userId);
|
console.log('🔍 getGifts called with userId:', userId);
|
||||||
@@ -118,12 +116,6 @@ class FalukantController {
|
|||||||
}, { successStatus: 201 });
|
}, { successStatus: 201 });
|
||||||
this.getParties = this._wrapWithUser((userId) => this.service.getParties(userId));
|
this.getParties = this._wrapWithUser((userId) => this.service.getParties(userId));
|
||||||
|
|
||||||
this.getReputationActions = this._wrapWithUser((userId) => this.service.getReputationActions(userId));
|
|
||||||
this.executeReputationAction = this._wrapWithUser((userId, req) => {
|
|
||||||
const { actionTypeId } = req.body;
|
|
||||||
return this.service.executeReputationAction(userId, actionTypeId);
|
|
||||||
}, { successStatus: 201 });
|
|
||||||
|
|
||||||
this.getNotBaptisedChildren = this._wrapWithUser((userId) => this.service.getNotBaptisedChildren(userId));
|
this.getNotBaptisedChildren = this._wrapWithUser((userId) => this.service.getNotBaptisedChildren(userId));
|
||||||
this.baptise = this._wrapWithUser((userId, req) => {
|
this.baptise = this._wrapWithUser((userId, req) => {
|
||||||
const { characterId: childId, firstName } = req.body;
|
const { characterId: childId, firstName } = req.body;
|
||||||
@@ -148,20 +140,6 @@ class FalukantController {
|
|||||||
|
|
||||||
this.getPoliticsOverview = this._wrapWithUser((userId) => this.service.getPoliticsOverview(userId));
|
this.getPoliticsOverview = this._wrapWithUser((userId) => this.service.getPoliticsOverview(userId));
|
||||||
this.getOpenPolitics = this._wrapWithUser((userId) => this.service.getOpenPolitics(userId));
|
this.getOpenPolitics = this._wrapWithUser((userId) => this.service.getOpenPolitics(userId));
|
||||||
|
|
||||||
// Church career endpoints
|
|
||||||
this.getChurchOverview = this._wrapWithUser((userId) => this.service.getChurchOverview(userId));
|
|
||||||
this.getAvailableChurchPositions = this._wrapWithUser((userId) => this.service.getAvailableChurchPositions(userId));
|
|
||||||
this.applyForChurchPosition = this._wrapWithUser((userId, req) => {
|
|
||||||
const { officeTypeId, regionId } = req.body;
|
|
||||||
return this.service.applyForChurchPosition(userId, officeTypeId, regionId);
|
|
||||||
}, { successStatus: 201 });
|
|
||||||
this.getSupervisedApplications = this._wrapWithUser((userId) => this.service.getSupervisedApplications(userId));
|
|
||||||
this.decideOnChurchApplication = this._wrapWithUser((userId, req) => {
|
|
||||||
const { applicationId, decision } = req.body;
|
|
||||||
return this.service.decideOnChurchApplication(userId, applicationId, decision);
|
|
||||||
});
|
|
||||||
this.hasChurchCareer = this._wrapWithUser((userId) => this.service.hasChurchCareer(userId));
|
|
||||||
this.getElections = this._wrapWithUser((userId) => this.service.getElections(userId));
|
this.getElections = this._wrapWithUser((userId) => this.service.getElections(userId));
|
||||||
this.vote = this._wrapWithUser((userId, req) => this.service.vote(userId, req.body.votes));
|
this.vote = this._wrapWithUser((userId, req) => this.service.vote(userId, req.body.votes));
|
||||||
this.applyForElections = this._wrapWithUser((userId, req) => this.service.applyForElections(userId, req.body.electionIds));
|
this.applyForElections = this._wrapWithUser((userId, req) => this.service.applyForElections(userId, req.body.electionIds));
|
||||||
@@ -176,18 +154,6 @@ class FalukantController {
|
|||||||
}
|
}
|
||||||
return this.service.getProductPriceInRegion(userId, productId, regionId);
|
return this.service.getProductPriceInRegion(userId, productId, regionId);
|
||||||
});
|
});
|
||||||
this.getProductPricesInRegionBatch = this._wrapWithUser((userId, req) => {
|
|
||||||
const productIds = req.query.productIds;
|
|
||||||
const regionId = parseInt(req.query.regionId, 10);
|
|
||||||
if (!productIds || Number.isNaN(regionId)) {
|
|
||||||
throw new Error('productIds (comma-separated) and regionId are required');
|
|
||||||
}
|
|
||||||
const productIdArray = productIds.split(',').map(id => parseInt(id.trim(), 10)).filter(id => !Number.isNaN(id));
|
|
||||||
if (productIdArray.length === 0) {
|
|
||||||
throw new Error('At least one valid productId is required');
|
|
||||||
}
|
|
||||||
return this.service.getProductPricesInRegionBatch(userId, productIdArray, regionId);
|
|
||||||
});
|
|
||||||
this.getProductPricesInCities = this._wrapWithUser((userId, req) => {
|
this.getProductPricesInCities = this._wrapWithUser((userId, req) => {
|
||||||
const productId = parseInt(req.query.productId, 10);
|
const productId = parseInt(req.query.productId, 10);
|
||||||
const currentPrice = parseFloat(req.query.currentPrice);
|
const currentPrice = parseFloat(req.query.currentPrice);
|
||||||
|
|||||||
@@ -10,11 +10,20 @@ RegionData.init({
|
|||||||
allowNull: false},
|
allowNull: false},
|
||||||
regionTypeId: {
|
regionTypeId: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: RegionType,
|
||||||
|
key: 'id',
|
||||||
|
schema: 'falukant_type'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
parentId: {
|
parentId: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: true
|
allowNull: true,
|
||||||
|
references: {
|
||||||
|
model: 'region',
|
||||||
|
key: 'id',
|
||||||
|
schema: 'falukant_data'}
|
||||||
},
|
},
|
||||||
map: {
|
map: {
|
||||||
type: DataTypes.JSONB,
|
type: DataTypes.JSONB,
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ class FalukantStock extends Model { }
|
|||||||
FalukantStock.init({
|
FalukantStock.init({
|
||||||
branchId: {
|
branchId: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false
|
allowNull: false,
|
||||||
|
defaultValue: 0
|
||||||
},
|
},
|
||||||
stockTypeId: {
|
stockTypeId: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
|
|||||||
@@ -16,6 +16,17 @@ ProductType.init({
|
|||||||
sellCost: {
|
sellCost: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false}
|
allowNull: false}
|
||||||
|
,
|
||||||
|
sellCostMinNeutral: {
|
||||||
|
type: DataTypes.DECIMAL,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sell_cost_min_neutral'
|
||||||
|
},
|
||||||
|
sellCostMaxNeutral: {
|
||||||
|
type: DataTypes.DECIMAL,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sell_cost_max_neutral'
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
sequelize,
|
sequelize,
|
||||||
modelName: 'ProductType',
|
modelName: 'ProductType',
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ router.get('/directors', falukantController.getAllDirectors);
|
|||||||
router.post('/directors', falukantController.updateDirector);
|
router.post('/directors', falukantController.updateDirector);
|
||||||
router.post('/family/acceptmarriageproposal', falukantController.acceptMarriageProposal);
|
router.post('/family/acceptmarriageproposal', falukantController.acceptMarriageProposal);
|
||||||
router.post('/family/set-heir', falukantController.setHeir);
|
router.post('/family/set-heir', falukantController.setHeir);
|
||||||
router.get('/heirs/potential', falukantController.getPotentialHeirs);
|
|
||||||
router.post('/heirs/select', falukantController.selectHeir);
|
|
||||||
router.get('/family/gifts', falukantController.getGifts);
|
router.get('/family/gifts', falukantController.getGifts);
|
||||||
router.get('/family/children', falukantController.getChildren);
|
router.get('/family/children', falukantController.getChildren);
|
||||||
router.post('/family/gift', falukantController.sendGift);
|
router.post('/family/gift', falukantController.sendGift);
|
||||||
@@ -55,16 +53,8 @@ router.post('/houses', falukantController.buyUserHouse);
|
|||||||
router.get('/party/types', falukantController.getPartyTypes);
|
router.get('/party/types', falukantController.getPartyTypes);
|
||||||
router.post('/party', falukantController.createParty);
|
router.post('/party', falukantController.createParty);
|
||||||
router.get('/party', falukantController.getParties);
|
router.get('/party', falukantController.getParties);
|
||||||
router.get('/reputation/actions', falukantController.getReputationActions);
|
|
||||||
router.post('/reputation/actions', falukantController.executeReputationAction);
|
|
||||||
router.get('/family/notbaptised', falukantController.getNotBaptisedChildren);
|
router.get('/family/notbaptised', falukantController.getNotBaptisedChildren);
|
||||||
router.post('/church/baptise', falukantController.baptise);
|
router.post('/church/baptise', falukantController.baptise);
|
||||||
router.get('/church/overview', falukantController.getChurchOverview);
|
|
||||||
router.get('/church/positions/available', falukantController.getAvailableChurchPositions);
|
|
||||||
router.post('/church/positions/apply', falukantController.applyForChurchPosition);
|
|
||||||
router.get('/church/applications/supervised', falukantController.getSupervisedApplications);
|
|
||||||
router.post('/church/applications/decide', falukantController.decideOnChurchApplication);
|
|
||||||
router.get('/church/career/check', falukantController.hasChurchCareer);
|
|
||||||
router.get('/education', falukantController.getEducation);
|
router.get('/education', falukantController.getEducation);
|
||||||
router.post('/education', falukantController.sendToSchool);
|
router.post('/education', falukantController.sendToSchool);
|
||||||
router.get('/bank/overview', falukantController.getBankOverview);
|
router.get('/bank/overview', falukantController.getBankOverview);
|
||||||
@@ -82,7 +72,6 @@ router.get('/politics/open', falukantController.getOpenPolitics);
|
|||||||
router.post('/politics/open', falukantController.applyForElections);
|
router.post('/politics/open', falukantController.applyForElections);
|
||||||
router.get('/cities', falukantController.getRegions);
|
router.get('/cities', falukantController.getRegions);
|
||||||
router.get('/products/price-in-region', falukantController.getProductPriceInRegion);
|
router.get('/products/price-in-region', falukantController.getProductPriceInRegion);
|
||||||
router.get('/products/prices-in-region-batch', falukantController.getProductPricesInRegionBatch);
|
|
||||||
router.get('/products/prices-in-cities', falukantController.getProductPricesInCities);
|
router.get('/products/prices-in-cities', falukantController.getProductPricesInCities);
|
||||||
router.get('/branches/:branchId/taxes', falukantController.getBranchTaxes);
|
router.get('/branches/:branchId/taxes', falukantController.getBranchTaxes);
|
||||||
router.get('/vehicles/types', falukantController.getVehicleTypes);
|
router.get('/vehicles/types', falukantController.getVehicleTypes);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -282,7 +282,11 @@ async function initializeFalukantProducts() {
|
|||||||
{ labelTr: 'ox', category: 5, productionTime: 5, sellCost: 60 },
|
{ labelTr: 'ox', category: 5, productionTime: 5, sellCost: 60 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const productsToInsert = baseProducts;
|
const productsToInsert = baseProducts.map(p => ({
|
||||||
|
...p,
|
||||||
|
sellCostMinNeutral: Math.ceil(p.sellCost * factorMin),
|
||||||
|
sellCostMaxNeutral: Math.ceil(p.sellCost * factorMax),
|
||||||
|
}));
|
||||||
|
|
||||||
await ProductType.bulkCreate(productsToInsert, {
|
await ProductType.bulkCreate(productsToInsert, {
|
||||||
ignoreDuplicates: true,
|
ignoreDuplicates: true,
|
||||||
|
|||||||
@@ -104,14 +104,6 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t('falukant.branch.director.starttransport') }}
|
{{ $t('falukant.branch.director.starttransport') }}
|
||||||
</label>
|
</label>
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
v-model="director.mayRepairVehicles"
|
|
||||||
@change="saveSetting('mayRepairVehicles', director.mayRepairVehicles)"
|
|
||||||
/>
|
|
||||||
{{ $t('falukant.branch.director.repairVehicles') }}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@@ -181,7 +173,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<NewDirectorDialog ref="newDirectorDialog" @directorHired="handleDirectorHired" />
|
<NewDirectorDialog ref="newDirectorDialog" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -276,11 +268,6 @@ export default {
|
|||||||
this.$refs.newDirectorDialog.open(this.branchId);
|
this.$refs.newDirectorDialog.open(this.branchId);
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleDirectorHired() {
|
|
||||||
// Nach dem Einstellen eines Direktors die Daten neu laden
|
|
||||||
await this.loadDirector();
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateDirector() {
|
async updateDirector() {
|
||||||
if (!this.director || this.editIncome == null) return;
|
if (!this.director || this.editIncome == null) return;
|
||||||
try {
|
try {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -20,10 +20,8 @@
|
|||||||
<td>{{ item.quality }}</td>
|
<td>{{ item.quality }}</td>
|
||||||
<td>{{ item.totalQuantity }}</td>
|
<td>{{ item.totalQuantity }}</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" v-model.number="item.sellQuantity" :min="1" :max="item.totalQuantity" :disabled="sellingItemIndex === index" />
|
<input type="number" v-model.number="item.sellQuantity" :min="1" :max="item.totalQuantity" />
|
||||||
<button @click="sellItem(index)" :disabled="sellingItemIndex === index || sellingAll">
|
<button @click="sellItem(index)">{{ $t('falukant.branch.sale.sellButton') }}</button>
|
||||||
{{ sellingItemIndex === index ? $t('falukant.branch.sale.selling') : $t('falukant.branch.sale.sellButton') }}
|
|
||||||
</button>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div v-if="item.betterPrices && item.betterPrices.length > 0" class="price-cities">
|
<div v-if="item.betterPrices && item.betterPrices.length > 0" class="price-cities">
|
||||||
@@ -38,12 +36,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<button @click="sellAll" :disabled="sellingAll || sellingItemIndex !== null">
|
<button @click="sellAll">{{ $t('falukant.branch.sale.sellAllButton') }}</button>
|
||||||
{{ sellingAll ? $t('falukant.branch.sale.selling') : $t('falukant.branch.sale.sellAllButton') }}
|
|
||||||
</button>
|
|
||||||
<div v-if="sellAllStatus" class="sell-all-status" :class="sellAllStatus.type">
|
|
||||||
{{ sellAllStatus.message }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<p>{{ $t('falukant.branch.sale.noInventory') }}</p>
|
<p>{{ $t('falukant.branch.sale.noInventory') }}</p>
|
||||||
@@ -190,9 +183,6 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
inventory: [],
|
inventory: [],
|
||||||
sellingItemIndex: null,
|
|
||||||
sellingAll: false,
|
|
||||||
sellAllStatus: null,
|
|
||||||
transportForm: {
|
transportForm: {
|
||||||
sourceKey: null,
|
sourceKey: null,
|
||||||
vehicleTypeId: null,
|
vehicleTypeId: null,
|
||||||
@@ -261,6 +251,13 @@
|
|||||||
return new Date(a.eta).getTime() - new Date(b.eta).getTime();
|
return new Date(a.eta).getTime() - new Date(b.eta).getTime();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
speedLabel(value) {
|
||||||
|
const key = value == null ? 'unknown' : String(value);
|
||||||
|
const tKey = `falukant.branch.transport.speed.${key}`;
|
||||||
|
const translated = this.$t(tKey);
|
||||||
|
if (!translated || translated === tKey) return value;
|
||||||
|
return translated;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.loadInventory();
|
await this.loadInventory();
|
||||||
@@ -277,22 +274,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
speedLabel(value) {
|
|
||||||
// Muss in methods liegen (Vue3): in computed wäre es ein Getter und keine aufrufbare Funktion.
|
|
||||||
const key = value == null ? 'unknown' : String(value);
|
|
||||||
const tKey = `falukant.branch.transport.speed.${key}`;
|
|
||||||
const translated = this.$t(tKey);
|
|
||||||
if (!translated || translated === tKey) return value;
|
|
||||||
return translated;
|
|
||||||
},
|
|
||||||
async loadInventory() {
|
async loadInventory() {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.get(`/api/falukant/inventory/${this.branchId}`);
|
const response = await apiClient.get(`/api/falukant/inventory/${this.branchId}`);
|
||||||
this.inventory = response.data.map(item => ({
|
this.inventory = response.data.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
sellQuantity: item.totalQuantity,
|
sellQuantity: item.totalQuantity,
|
||||||
// Vue3: besserPrices direkt als Property setzen (statt this.$set)
|
|
||||||
betterPrices: Array.isArray(item.betterPrices) ? item.betterPrices : [],
|
|
||||||
}));
|
}));
|
||||||
await this.loadPricesForInventory();
|
await this.loadPricesForInventory();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -313,11 +300,10 @@
|
|||||||
currentPrice: currentPrice
|
currentPrice: currentPrice
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Vue3: direkte Zuweisung ist reaktiv
|
this.$set(item, 'betterPrices', data || []);
|
||||||
item.betterPrices = Array.isArray(data) ? data : [];
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error loading prices for item ${itemKey}:`, error);
|
console.error(`Error loading prices for item ${itemKey}:`, error);
|
||||||
item.betterPrices = [];
|
this.$set(item, 'betterPrices', []);
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingPrices.delete(itemKey);
|
this.loadingPrices.delete(itemKey);
|
||||||
}
|
}
|
||||||
@@ -334,61 +320,23 @@
|
|||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
}).format(price);
|
}).format(price);
|
||||||
},
|
},
|
||||||
async sellItem(index) {
|
sellItem(index) {
|
||||||
if (this.sellingItemIndex !== null || this.sellingAll) return;
|
|
||||||
|
|
||||||
const item = this.inventory[index];
|
const item = this.inventory[index];
|
||||||
const quantityToSell = item.sellQuantity || item.totalQuantity;
|
const quantityToSell = item.sellQuantity || item.totalQuantity;
|
||||||
this.sellingItemIndex = index;
|
apiClient.post(`/api/falukant/sell`, {
|
||||||
|
branchId: this.branchId,
|
||||||
try {
|
productId: item.product.id,
|
||||||
await apiClient.post(`/api/falukant/sell`, {
|
quantity: quantityToSell,
|
||||||
branchId: this.branchId,
|
quality: item.quality,
|
||||||
productId: item.product.id,
|
}).catch(() => {
|
||||||
quantity: quantityToSell,
|
|
||||||
quality: item.quality,
|
|
||||||
});
|
|
||||||
// UI sofort freigeben (Label/Disabled zurücksetzen), dann Inventory refreshen
|
|
||||||
this.sellingItemIndex = null;
|
|
||||||
await this.loadInventory();
|
|
||||||
} catch (error) {
|
|
||||||
alert(this.$t('falukant.branch.sale.sellError'));
|
alert(this.$t('falukant.branch.sale.sellError'));
|
||||||
} finally {
|
});
|
||||||
this.sellingItemIndex = null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async sellAll() {
|
sellAll() {
|
||||||
if (this.sellingAll || this.sellingItemIndex !== null) return;
|
apiClient.post(`/api/falukant/sell/all`, { branchId: this.branchId })
|
||||||
|
.catch(() => {
|
||||||
this.sellingAll = true;
|
alert(this.$t('falukant.branch.sale.sellAllError'));
|
||||||
this.sellAllStatus = null;
|
});
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await apiClient.post(`/api/falukant/sell/all`, { branchId: this.branchId });
|
|
||||||
const revenue = response.data?.revenue || 0;
|
|
||||||
// UI sofort freigeben + Status setzen, danach Inventory refreshen
|
|
||||||
this.sellingAll = false;
|
|
||||||
this.sellAllStatus = {
|
|
||||||
type: 'success',
|
|
||||||
message: this.$t('falukant.branch.sale.sellAllSuccess', { revenue: this.formatMoney(revenue) })
|
|
||||||
};
|
|
||||||
// Inventory neu laden nach erfolgreichem Verkauf
|
|
||||||
await this.loadInventory();
|
|
||||||
} catch (error) {
|
|
||||||
// UI sofort freigeben + Fehlerstatus setzen
|
|
||||||
this.sellingAll = false;
|
|
||||||
this.sellAllStatus = {
|
|
||||||
type: 'error',
|
|
||||||
message: this.$t('falukant.branch.sale.sellAllError')
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
// Falls noch nicht freigegeben (z.B. wenn ein unerwarteter Fehler vor Response passiert)
|
|
||||||
this.sellingAll = false;
|
|
||||||
// Status nach 5 Sekunden löschen
|
|
||||||
setTimeout(() => {
|
|
||||||
this.sellAllStatus = null;
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
inventoryOptions() {
|
inventoryOptions() {
|
||||||
return this.inventory.map((item, index) => ({
|
return this.inventory.map((item, index) => ({
|
||||||
@@ -627,11 +575,11 @@
|
|||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
.city-price-green {
|
.city-price-green {
|
||||||
background-color: var(--color-primary-green);
|
background-color: #90EE90;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.city-price-orange {
|
.city-price-orange {
|
||||||
background-color: var(--color-primary-orange);
|
background-color: #FFA500;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.city-price-red {
|
.city-price-red {
|
||||||
@@ -642,19 +590,5 @@
|
|||||||
color: #999;
|
color: #999;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
.sell-all-status {
|
|
||||||
margin-top: 10px;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.sell-all-status.success {
|
|
||||||
background-color: #d4edda;
|
|
||||||
color: #155724;
|
|
||||||
border: 1px solid #c3e6cb;
|
|
||||||
}
|
|
||||||
.sell-all-status.error {
|
|
||||||
background-color: #f8d7da;
|
|
||||||
color: #721c24;
|
|
||||||
border: 1px solid #f5c6cb;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -32,9 +32,8 @@
|
|||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"notify_election_created": "Es wurde eine neue Wahl ausgeschrieben.",
|
"notify_election_created": "Es wurde eine neue Wahl ausgeschrieben.",
|
||||||
"notify_office_filled": "Ein politisches Amt wurde neu besetzt.",
|
|
||||||
"production": {
|
"production": {
|
||||||
"overproduction": "Überproduktion: Deine Produktion liegt {value} Einheiten über dem Bedarf{branch_info}."
|
"overproduction": "Überproduktion: Deine Produktion liegt {value}% über dem Bedarf."
|
||||||
},
|
},
|
||||||
"transport": {
|
"transport": {
|
||||||
"waiting": "Transport wartet"
|
"waiting": "Transport wartet"
|
||||||
@@ -136,14 +135,6 @@
|
|||||||
"store": "Verkauf",
|
"store": "Verkauf",
|
||||||
"fullstack": "Produktion mit Verkauf"
|
"fullstack": "Produktion mit Verkauf"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"heirSelection": {
|
|
||||||
"title": "Charakter verloren - Erben auswählen",
|
|
||||||
"description": "Dein Charakter wurde durch einen Fehler verloren. Bitte wähle einen Erben aus deiner Hauptregion aus, um fortzufahren.",
|
|
||||||
"loading": "Lade mögliche Erben...",
|
|
||||||
"noHeirs": "Es wurden keine passenden Erben gefunden.",
|
|
||||||
"select": "Als Erben wählen",
|
|
||||||
"error": "Fehler beim Auswählen des Erben."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
@@ -241,7 +232,6 @@
|
|||||||
"produce": "Darf produzieren",
|
"produce": "Darf produzieren",
|
||||||
"sell": "Darf verkaufen",
|
"sell": "Darf verkaufen",
|
||||||
"starttransport": "Darf Transporte veranlassen",
|
"starttransport": "Darf Transporte veranlassen",
|
||||||
"repairVehicles": "Darf Fahrzeuge reparieren",
|
|
||||||
"emptyTransport": {
|
"emptyTransport": {
|
||||||
"title": "Transport ohne Produkte",
|
"title": "Transport ohne Produkte",
|
||||||
"description": "Bewege Transportmittel von dieser Niederlassung zu einer anderen, um sie besser zu nutzen.",
|
"description": "Bewege Transportmittel von dieser Niederlassung zu einer anderen, um sie besser zu nutzen.",
|
||||||
@@ -270,10 +260,6 @@
|
|||||||
"sell": "Verkauf",
|
"sell": "Verkauf",
|
||||||
"sellButton": "Verkaufen",
|
"sellButton": "Verkaufen",
|
||||||
"sellAllButton": "Alles verkaufen",
|
"sellAllButton": "Alles verkaufen",
|
||||||
"selling": "Verkauf läuft...",
|
|
||||||
"sellError": "Fehler beim Verkauf des Produkts.",
|
|
||||||
"sellAllError": "Fehler beim Verkauf aller Produkte.",
|
|
||||||
"sellAllSuccess": "Alle Produkte wurden erfolgreich verkauft. Einnahmen: {revenue}",
|
|
||||||
"transportTitle": "Transport anlegen",
|
"transportTitle": "Transport anlegen",
|
||||||
"transportSource": "Artikel",
|
"transportSource": "Artikel",
|
||||||
"transportSourcePlaceholder": "Artikel wählen",
|
"transportSourcePlaceholder": "Artikel wählen",
|
||||||
@@ -321,10 +307,7 @@
|
|||||||
"current": "Laufende Produktionen",
|
"current": "Laufende Produktionen",
|
||||||
"product": "Produkt",
|
"product": "Produkt",
|
||||||
"remainingTime": "Verbleibende Zeit (Sekunden)",
|
"remainingTime": "Verbleibende Zeit (Sekunden)",
|
||||||
"noProductions": "Keine laufenden Produktionen.",
|
"noProductions": "Keine laufenden Produktionen."
|
||||||
"status": "Status",
|
|
||||||
"sleep": "Zurückgestellt",
|
|
||||||
"active": "Aktiv"
|
|
||||||
},
|
},
|
||||||
"columns": {
|
"columns": {
|
||||||
"city": "Stadt",
|
"city": "Stadt",
|
||||||
@@ -595,7 +578,6 @@
|
|||||||
"Production cost": "Produktionskosten",
|
"Production cost": "Produktionskosten",
|
||||||
"Sell all products": "Alle Produkte verkauft",
|
"Sell all products": "Alle Produkte verkauft",
|
||||||
"sell products": "Produkte verkauft",
|
"sell products": "Produkte verkauft",
|
||||||
"taxFromSaleProduct": "Steuer aus Verkauf: {product}",
|
|
||||||
"director starts production": "Direktor beginnt Produktion",
|
"director starts production": "Direktor beginnt Produktion",
|
||||||
"director payed out": "Direktorgehalt ausgezahlt",
|
"director payed out": "Direktorgehalt ausgezahlt",
|
||||||
"Buy storage (type: field)": "Lagerplatz gekauft (Typ: Feld)",
|
"Buy storage (type: field)": "Lagerplatz gekauft (Typ: Feld)",
|
||||||
@@ -614,9 +596,6 @@
|
|||||||
"new nobility title": "Neuer Adelstitel",
|
"new nobility title": "Neuer Adelstitel",
|
||||||
"partyOrder": "Fest bestellt",
|
"partyOrder": "Fest bestellt",
|
||||||
"renovation_all": "Haus komplett renoviert",
|
"renovation_all": "Haus komplett renoviert",
|
||||||
"reputationAction": {
|
|
||||||
"school_funding": "Sozialstatus: Schule/Lehrstuhl finanziert"
|
|
||||||
},
|
|
||||||
"health": {
|
"health": {
|
||||||
"pill": "Gesundheitsmaßnahme: Tablette",
|
"pill": "Gesundheitsmaßnahme: Tablette",
|
||||||
"doctor": "Gesundheitsmaßnahme: Arztbesuch",
|
"doctor": "Gesundheitsmaßnahme: Arztbesuch",
|
||||||
@@ -759,8 +738,7 @@
|
|||||||
"reputation": {
|
"reputation": {
|
||||||
"title": "Reputation",
|
"title": "Reputation",
|
||||||
"overview": {
|
"overview": {
|
||||||
"title": "Übersicht",
|
"title": "Übersicht"
|
||||||
"current": "Deine aktuelle Reputation"
|
|
||||||
},
|
},
|
||||||
"party": {
|
"party": {
|
||||||
"title": "Feste",
|
"title": "Feste",
|
||||||
@@ -799,34 +777,6 @@
|
|||||||
"type": "Festart",
|
"type": "Festart",
|
||||||
"cost": "Kosten",
|
"cost": "Kosten",
|
||||||
"date": "Datum"
|
"date": "Datum"
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"title": "Aktionen",
|
|
||||||
"description": "Mit diesen Aktionen kannst du Reputation gewinnen. Je öfter du dieselbe Aktion ausführst, desto weniger Reputation bringt sie (unabhängig von den Kosten).",
|
|
||||||
"action": "Aktion",
|
|
||||||
"cost": "Kosten",
|
|
||||||
"gain": "Reputation",
|
|
||||||
"timesUsed": "Bereits genutzt",
|
|
||||||
"execute": "Ausführen",
|
|
||||||
"running": "Läuft...",
|
|
||||||
"none": "Keine Aktionen verfügbar.",
|
|
||||||
"dailyLimit": "Heute noch verfügbar: {remaining} / {cap} Reputation (durch Aktionen).",
|
|
||||||
"cooldown": "Nächste Sozialstatus-Aktion in ca. {minutes} Minuten möglich.",
|
|
||||||
"success": "Aktion erfolgreich! Reputation +{gain}, Kosten {cost}.",
|
|
||||||
"successSimple": "Aktion erfolgreich!",
|
|
||||||
"type": {
|
|
||||||
"library_donation": "Spende für eine Bibliothek",
|
|
||||||
"orphanage_build": "Waisenhaus aufbauen",
|
|
||||||
"statue_build": "Statue errichten",
|
|
||||||
"hospital_donation": "Krankenhaus/Heilhaus stiften",
|
|
||||||
"school_funding": "Schule/Lehrstuhl finanzieren",
|
|
||||||
"well_build": "Brunnen/Wasserwerk bauen",
|
|
||||||
"bridge_build": "Straßen-/Brückenbau finanzieren",
|
|
||||||
"soup_kitchen": "Armenspeisung organisieren",
|
|
||||||
"patronage": "Kunst & Mäzenatentum",
|
|
||||||
"church_hospice": "Hospiz-/Kirchenspende",
|
|
||||||
"scholarships": "Stipendienfonds finanzieren"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"party": {
|
"party": {
|
||||||
@@ -838,58 +788,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"church": {
|
"church": {
|
||||||
"title": "Kirche",
|
|
||||||
"tabs": {
|
|
||||||
"current": "Aktuelle Positionen",
|
|
||||||
"available": "Verfügbare Positionen",
|
|
||||||
"applications": "Bewerbungen"
|
|
||||||
},
|
|
||||||
"current": {
|
|
||||||
"office": "Amt",
|
|
||||||
"region": "Region",
|
|
||||||
"holder": "Inhaber",
|
|
||||||
"supervisor": "Vorgesetzter",
|
|
||||||
"none": "Keine aktuellen Positionen vorhanden."
|
|
||||||
},
|
|
||||||
"available": {
|
|
||||||
"office": "Amt",
|
|
||||||
"region": "Region",
|
|
||||||
"supervisor": "Vorgesetzter",
|
|
||||||
"seats": "Verfügbare Plätze",
|
|
||||||
"action": "Aktion",
|
|
||||||
"apply": "Bewerben",
|
|
||||||
"applySuccess": "Bewerbung erfolgreich eingereicht.",
|
|
||||||
"applyError": "Fehler beim Einreichen der Bewerbung.",
|
|
||||||
"none": "Keine verfügbaren Positionen."
|
|
||||||
},
|
|
||||||
"applications": {
|
|
||||||
"office": "Amt",
|
|
||||||
"region": "Region",
|
|
||||||
"applicant": "Bewerber",
|
|
||||||
"date": "Datum",
|
|
||||||
"action": "Aktion",
|
|
||||||
"approve": "Annehmen",
|
|
||||||
"reject": "Ablehnen",
|
|
||||||
"approveSuccess": "Bewerbung angenommen.",
|
|
||||||
"rejectSuccess": "Bewerbung abgelehnt.",
|
|
||||||
"decideError": "Fehler bei der Entscheidung.",
|
|
||||||
"none": "Keine Bewerbungen vorhanden."
|
|
||||||
},
|
|
||||||
"offices": {
|
|
||||||
"village-priest": "Dorfgeistlicher",
|
|
||||||
"parish-priest": "Pfarrer",
|
|
||||||
"dean": "Dekan",
|
|
||||||
"archdeacon": "Erzdiakon",
|
|
||||||
"bishop": "Bischof",
|
|
||||||
"archbishop": "Erzbischof",
|
|
||||||
"cardinal": "Kardinal",
|
|
||||||
"pope": "Papst"
|
|
||||||
},
|
|
||||||
"application": {
|
|
||||||
"received": "Neue Bewerbung erhalten",
|
|
||||||
"approved": "Bewerbung angenommen",
|
|
||||||
"rejected": "Bewerbung abgelehnt"
|
|
||||||
},
|
|
||||||
"title": "Kirche",
|
"title": "Kirche",
|
||||||
"baptism": {
|
"baptism": {
|
||||||
"title": "Taufen",
|
"title": "Taufen",
|
||||||
@@ -985,9 +883,6 @@
|
|||||||
"success": "Erfolg",
|
"success": "Erfolg",
|
||||||
"selectMeasure": "Maßnahme",
|
"selectMeasure": "Maßnahme",
|
||||||
"perform": "Durchführen",
|
"perform": "Durchführen",
|
||||||
"errors": {
|
|
||||||
"tooClose": "Aktionen zu dicht hintereinander (maximal 1× pro 24 Stunden)."
|
|
||||||
},
|
|
||||||
"measures": {
|
"measures": {
|
||||||
"pill": "Tablette",
|
"pill": "Tablette",
|
||||||
"doctor": "Arztbesuch",
|
"doctor": "Arztbesuch",
|
||||||
|
|||||||
@@ -18,9 +18,8 @@
|
|||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"notify_election_created": "A new election has been scheduled.",
|
"notify_election_created": "A new election has been scheduled.",
|
||||||
"notify_office_filled": "A political office has been filled.",
|
|
||||||
"production": {
|
"production": {
|
||||||
"overproduction": "Overproduction: your production is {value} units above demand{branch_info}."
|
"overproduction": "Overproduction: your production is {value}% above demand."
|
||||||
},
|
},
|
||||||
"transport": {
|
"transport": {
|
||||||
"waiting": "Transport waiting"
|
"waiting": "Transport waiting"
|
||||||
@@ -101,12 +100,6 @@
|
|||||||
"bad": "Bad",
|
"bad": "Bad",
|
||||||
"very_bad": "Very bad"
|
"very_bad": "Very bad"
|
||||||
},
|
},
|
||||||
"healthview": {
|
|
||||||
"title": "Health",
|
|
||||||
"errors": {
|
|
||||||
"tooClose": "Actions too close together (max once per 24 hours)."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"moneyHistory": {
|
"moneyHistory": {
|
||||||
"title": "Money history",
|
"title": "Money history",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
@@ -123,7 +116,6 @@
|
|||||||
"Production cost": "Production cost",
|
"Production cost": "Production cost",
|
||||||
"Sell all products": "Sell all products",
|
"Sell all products": "Sell all products",
|
||||||
"sell products": "Sell products",
|
"sell products": "Sell products",
|
||||||
"taxFromSaleProduct": "Tax from product sale: {product}",
|
|
||||||
"director starts production": "Director starts production",
|
"director starts production": "Director starts production",
|
||||||
"director payed out": "Director salary paid out",
|
"director payed out": "Director salary paid out",
|
||||||
"Buy storage (type: field)": "Bought storage (type: field)",
|
"Buy storage (type: field)": "Bought storage (type: field)",
|
||||||
@@ -142,9 +134,6 @@
|
|||||||
"new nobility title": "New title of nobility",
|
"new nobility title": "New title of nobility",
|
||||||
"partyOrder": "Party ordered",
|
"partyOrder": "Party ordered",
|
||||||
"renovation_all": "House fully renovated",
|
"renovation_all": "House fully renovated",
|
||||||
"reputationAction": {
|
|
||||||
"school_funding": "Social status: funded a school/chair"
|
|
||||||
},
|
|
||||||
"health": {
|
"health": {
|
||||||
"pill": "Health measure: pill",
|
"pill": "Health measure: pill",
|
||||||
"doctor": "Health measure: doctor",
|
"doctor": "Health measure: doctor",
|
||||||
@@ -174,8 +163,7 @@
|
|||||||
},
|
},
|
||||||
"director": {
|
"director": {
|
||||||
"income": "Income",
|
"income": "Income",
|
||||||
"incomeUpdated": "Salary has been successfully updated.",
|
"incomeUpdated": "Salary has been successfully updated."
|
||||||
"repairVehicles": "May repair vehicles"
|
|
||||||
},
|
},
|
||||||
"vehicles": {
|
"vehicles": {
|
||||||
"cargo_cart": "Cargo cart",
|
"cargo_cart": "Cargo cart",
|
||||||
@@ -193,31 +181,8 @@
|
|||||||
"storage": "Storage",
|
"storage": "Storage",
|
||||||
"transport": "Transport",
|
"transport": "Transport",
|
||||||
"taxes": "Taxes"
|
"taxes": "Taxes"
|
||||||
},
|
}
|
||||||
"production": {
|
,"taxes": {
|
||||||
"title": "Production",
|
|
||||||
"info": "Details about production in the branch.",
|
|
||||||
"selectProduct": "Select product",
|
|
||||||
"quantity": "Quantity",
|
|
||||||
"storageAvailable": "Free storage",
|
|
||||||
"cost": "Cost",
|
|
||||||
"duration": "Duration",
|
|
||||||
"revenue": "Revenue",
|
|
||||||
"start": "Start production",
|
|
||||||
"success": "Production started successfully!",
|
|
||||||
"error": "Error starting production.",
|
|
||||||
"minutes": "Minutes",
|
|
||||||
"ending": "Completed:",
|
|
||||||
"time": "Time",
|
|
||||||
"current": "Running productions",
|
|
||||||
"product": "Product",
|
|
||||||
"remainingTime": "Remaining time (seconds)",
|
|
||||||
"noProductions": "No running productions.",
|
|
||||||
"status": "Status",
|
|
||||||
"sleep": "Suspended",
|
|
||||||
"active": "Active"
|
|
||||||
},
|
|
||||||
"taxes": {
|
|
||||||
"title": "Taxes",
|
"title": "Taxes",
|
||||||
"loading": "Loading tax data...",
|
"loading": "Loading tax data...",
|
||||||
"loadingError": "Failed to load tax data: {error}",
|
"loadingError": "Failed to load tax data: {error}",
|
||||||
@@ -230,80 +195,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overview": {
|
|
||||||
"title": "Falukant - Overview",
|
|
||||||
"metadata": {
|
|
||||||
"title": "Personal",
|
|
||||||
"name": "Name",
|
|
||||||
"money": "Wealth",
|
|
||||||
"age": "Age",
|
|
||||||
"mainbranch": "Home City",
|
|
||||||
"nobleTitle": "Status"
|
|
||||||
},
|
|
||||||
"productions": {
|
|
||||||
"title": "Productions"
|
|
||||||
},
|
|
||||||
"stock": {
|
|
||||||
"title": "Stock"
|
|
||||||
},
|
|
||||||
"branches": {
|
|
||||||
"title": "Branches",
|
|
||||||
"level": {
|
|
||||||
"production": "Production",
|
|
||||||
"store": "Store",
|
|
||||||
"fullstack": "Production with Store"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"heirSelection": {
|
|
||||||
"title": "Character Lost - Select Heir",
|
|
||||||
"description": "Your character was lost due to an error. Please select an heir from your main region to continue.",
|
|
||||||
"loading": "Loading potential heirs...",
|
|
||||||
"noHeirs": "No suitable heirs were found.",
|
|
||||||
"select": "Select as Heir",
|
|
||||||
"error": "Error selecting heir."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nobility": {
|
"nobility": {
|
||||||
"cooldown": "You can only advance again on {date}."
|
"cooldown": "You can only advance again on {date}."
|
||||||
},
|
},
|
||||||
"reputation": {
|
|
||||||
"title": "Reputation",
|
|
||||||
"overview": {
|
|
||||||
"title": "Overview",
|
|
||||||
"current": "Your current reputation"
|
|
||||||
},
|
|
||||||
"party": {
|
|
||||||
"title": "Parties"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"title": "Actions",
|
|
||||||
"description": "These actions let you gain reputation. The more often you repeat the same action, the less reputation it yields (independent of cost).",
|
|
||||||
"action": "Action",
|
|
||||||
"cost": "Cost",
|
|
||||||
"gain": "Reputation",
|
|
||||||
"timesUsed": "Times used",
|
|
||||||
"execute": "Execute",
|
|
||||||
"running": "Running...",
|
|
||||||
"none": "No actions available.",
|
|
||||||
"dailyLimit": "Available today: {remaining} / {cap} reputation (from actions).",
|
|
||||||
"cooldown": "Next social status action available in about {minutes} minutes.",
|
|
||||||
"success": "Action successful! Reputation +{gain}, cost {cost}.",
|
|
||||||
"successSimple": "Action successful!",
|
|
||||||
"type": {
|
|
||||||
"library_donation": "Donate to a library",
|
|
||||||
"orphanage_build": "Build an orphanage",
|
|
||||||
"statue_build": "Erect a statue",
|
|
||||||
"hospital_donation": "Found a hospital/infirmary",
|
|
||||||
"school_funding": "Fund a school/chair",
|
|
||||||
"well_build": "Build a well/waterworks",
|
|
||||||
"bridge_build": "Fund roads/bridges",
|
|
||||||
"soup_kitchen": "Organize a soup kitchen",
|
|
||||||
"patronage": "Arts & patronage",
|
|
||||||
"church_hospice": "Hospice/church donation",
|
|
||||||
"scholarships": "Fund scholarships"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"branchProduction": {
|
"branchProduction": {
|
||||||
"storageAvailable": "Free storage"
|
"storageAvailable": "Free storage"
|
||||||
},
|
},
|
||||||
@@ -377,76 +271,6 @@
|
|||||||
"assessor": "Assessor"
|
"assessor": "Assessor"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"church": {
|
|
||||||
"title": "Church",
|
|
||||||
"tabs": {
|
|
||||||
"current": "Current Positions",
|
|
||||||
"available": "Available Positions",
|
|
||||||
"applications": "Applications"
|
|
||||||
},
|
|
||||||
"current": {
|
|
||||||
"office": "Office",
|
|
||||||
"region": "Region",
|
|
||||||
"holder": "Holder",
|
|
||||||
"supervisor": "Supervisor",
|
|
||||||
"none": "No current positions available."
|
|
||||||
},
|
|
||||||
"available": {
|
|
||||||
"office": "Office",
|
|
||||||
"region": "Region",
|
|
||||||
"supervisor": "Supervisor",
|
|
||||||
"seats": "Available Seats",
|
|
||||||
"action": "Action",
|
|
||||||
"apply": "Apply",
|
|
||||||
"applySuccess": "Application submitted successfully.",
|
|
||||||
"applyError": "Error submitting application.",
|
|
||||||
"none": "No available positions."
|
|
||||||
},
|
|
||||||
"applications": {
|
|
||||||
"office": "Office",
|
|
||||||
"region": "Region",
|
|
||||||
"applicant": "Applicant",
|
|
||||||
"date": "Date",
|
|
||||||
"action": "Action",
|
|
||||||
"approve": "Approve",
|
|
||||||
"reject": "Reject",
|
|
||||||
"approveSuccess": "Application approved.",
|
|
||||||
"rejectSuccess": "Application rejected.",
|
|
||||||
"decideError": "Error making decision.",
|
|
||||||
"none": "No applications available."
|
|
||||||
},
|
|
||||||
"offices": {
|
|
||||||
"village-priest": "Village Priest",
|
|
||||||
"parish-priest": "Parish Priest",
|
|
||||||
"dean": "Dean",
|
|
||||||
"archdeacon": "Archdeacon",
|
|
||||||
"bishop": "Bishop",
|
|
||||||
"archbishop": "Archbishop",
|
|
||||||
"cardinal": "Cardinal",
|
|
||||||
"pope": "Pope"
|
|
||||||
},
|
|
||||||
"application": {
|
|
||||||
"received": "New application received",
|
|
||||||
"approved": "Application approved",
|
|
||||||
"rejected": "Application rejected"
|
|
||||||
},
|
|
||||||
"baptism": {
|
|
||||||
"title": "Baptism",
|
|
||||||
"table": {
|
|
||||||
"name": "First Name",
|
|
||||||
"gender": "Gender",
|
|
||||||
"age": "Age",
|
|
||||||
"baptise": "Baptize (50)",
|
|
||||||
"newName": "Suggest Name"
|
|
||||||
},
|
|
||||||
"gender": {
|
|
||||||
"male": "Boy",
|
|
||||||
"female": "Girl"
|
|
||||||
},
|
|
||||||
"success": "The child has been baptized.",
|
|
||||||
"error": "The child could not be baptized."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"family": {
|
"family": {
|
||||||
"children": {
|
"children": {
|
||||||
"title": "Children",
|
"title": "Children",
|
||||||
|
|||||||
@@ -572,49 +572,27 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.products || this.products.length === 0) {
|
// Lade Preise für alle Produkte in der aktuellen Region
|
||||||
this.productPricesCache = {};
|
const prices = {};
|
||||||
return;
|
for (const product of this.products) {
|
||||||
}
|
try {
|
||||||
|
const { data } = await apiClient.get('/api/falukant/products/price-in-region', {
|
||||||
// OPTIMIERUNG: Lade alle Preise in einem Batch-Request
|
params: {
|
||||||
try {
|
productId: product.id,
|
||||||
const productIds = this.products.map(p => p.id).join(',');
|
regionId: this.selectedBranch.regionId
|
||||||
const { data } = await apiClient.get('/api/falukant/products/prices-in-region-batch', {
|
}
|
||||||
params: {
|
});
|
||||||
productIds: productIds,
|
prices[product.id] = data.price;
|
||||||
regionId: this.selectedBranch.regionId
|
} catch (error) {
|
||||||
}
|
console.error(`Error loading price for product ${product.id}:`, error);
|
||||||
});
|
// Fallback auf Standard-Berechnung
|
||||||
this.productPricesCache = data || {};
|
const knowledgeFactor = product.knowledges?.[0]?.knowledge || 0;
|
||||||
} catch (error) {
|
const maxPrice = product.sellCost;
|
||||||
console.error('Error loading prices in batch:', error);
|
const minPrice = maxPrice * 0.6;
|
||||||
// Fallback: Lade Preise einzeln (aber parallel)
|
prices[product.id] = minPrice + (maxPrice - minPrice) * (knowledgeFactor / 100);
|
||||||
const pricePromises = this.products.map(async (product) => {
|
}
|
||||||
try {
|
|
||||||
const { data } = await apiClient.get('/api/falukant/products/price-in-region', {
|
|
||||||
params: {
|
|
||||||
productId: product.id,
|
|
||||||
regionId: this.selectedBranch.regionId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { productId: product.id, price: data.price };
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Error loading price for product ${product.id}:`, err);
|
|
||||||
// Fallback auf Standard-Berechnung
|
|
||||||
const knowledgeFactor = product.knowledges?.[0]?.knowledge || 0;
|
|
||||||
const maxPrice = product.sellCost;
|
|
||||||
const minPrice = maxPrice * 0.6;
|
|
||||||
return { productId: product.id, price: minPrice + (maxPrice - minPrice) * (knowledgeFactor / 100) };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const results = await Promise.all(pricePromises);
|
|
||||||
this.productPricesCache = {};
|
|
||||||
results.forEach(({ productId, price }) => {
|
|
||||||
this.productPricesCache[productId] = price;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
this.productPricesCache = prices;
|
||||||
},
|
},
|
||||||
|
|
||||||
formatPercent(value) {
|
formatPercent(value) {
|
||||||
@@ -714,10 +692,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
conditionLabel(value) {
|
conditionLabel(value) {
|
||||||
// 0 ist ein gültiger Zustand (z.B. komplett kaputt) und darf nicht als "Unbekannt" enden.
|
const v = Number(value) || 0;
|
||||||
if (value === null || value === undefined) return 'Unbekannt';
|
|
||||||
const v = Number(value);
|
|
||||||
if (!Number.isFinite(v)) return 'Unbekannt';
|
|
||||||
if (v >= 95) return 'Ausgezeichnet'; // 95–100
|
if (v >= 95) return 'Ausgezeichnet'; // 95–100
|
||||||
if (v >= 72) return 'Sehr gut'; // 72–94
|
if (v >= 72) return 'Sehr gut'; // 72–94
|
||||||
if (v >= 54) return 'Gut'; // 54–71
|
if (v >= 54) return 'Gut'; // 54–71
|
||||||
@@ -725,7 +700,7 @@ export default {
|
|||||||
if (v >= 22) return 'Schlecht'; // 22–38
|
if (v >= 22) return 'Schlecht'; // 22–38
|
||||||
if (v >= 6) return 'Sehr schlecht'; // 6–21
|
if (v >= 6) return 'Sehr schlecht'; // 6–21
|
||||||
if (v >= 1) return 'Katastrophal'; // 1–5
|
if (v >= 1) return 'Katastrophal'; // 1–5
|
||||||
return 'Katastrophal'; // 0 oder kleiner
|
return 'Unbekannt';
|
||||||
},
|
},
|
||||||
|
|
||||||
speedLabel(value) {
|
speedLabel(value) {
|
||||||
@@ -1039,15 +1014,12 @@ export default {
|
|||||||
});
|
});
|
||||||
await this.loadVehicles();
|
await this.loadVehicles();
|
||||||
this.closeRepairAllVehiclesDialog();
|
this.closeRepairAllVehiclesDialog();
|
||||||
// Statt JS-alert: Dialog schließen und MessageDialog anzeigen
|
alert(this.$t('falukant.branch.transport.repairAllSuccess'));
|
||||||
this.$root.$refs.messageDialog?.open('tr:falukant.branch.transport.repairAllSuccess');
|
|
||||||
this.$refs.statusBar?.fetchStatus();
|
this.$refs.statusBar?.fetchStatus();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error repairing all vehicles:', error);
|
console.error('Error repairing all vehicles:', error);
|
||||||
const errorMessage = error.response?.data?.message || this.$t('falukant.branch.transport.repairAllError');
|
const errorMessage = error.response?.data?.message || this.$t('falukant.branch.transport.repairAllError');
|
||||||
// Bestätigungsdialog ebenfalls schließen und Fehler im MessageDialog anzeigen
|
alert(errorMessage);
|
||||||
this.closeRepairAllVehiclesDialog();
|
|
||||||
this.$root.$refs.messageDialog?.open(String(errorMessage), this.$t('error.title'));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1104,15 +1076,12 @@ export default {
|
|||||||
await apiClient.post(`/api/falukant/vehicles/${this.repairVehicleDialog.vehicle.id}/repair`);
|
await apiClient.post(`/api/falukant/vehicles/${this.repairVehicleDialog.vehicle.id}/repair`);
|
||||||
await this.loadVehicles();
|
await this.loadVehicles();
|
||||||
this.closeRepairVehicleDialog();
|
this.closeRepairVehicleDialog();
|
||||||
// Statt JS-alert: Dialog schließen und MessageDialog anzeigen
|
alert(this.$t('falukant.branch.transport.repairSuccess'));
|
||||||
this.$root.$refs.messageDialog?.open('tr:falukant.branch.transport.repairSuccess');
|
|
||||||
this.$refs.statusBar?.fetchStatus();
|
this.$refs.statusBar?.fetchStatus();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error repairing vehicle:', error);
|
console.error('Error repairing vehicle:', error);
|
||||||
const errorMessage = error.response?.data?.message || this.$t('falukant.branch.transport.repairError');
|
const errorMessage = error.response?.data?.message || this.$t('falukant.branch.transport.repairError');
|
||||||
// Bestätigungsdialog ebenfalls schließen und Fehler im MessageDialog anzeigen
|
alert(errorMessage);
|
||||||
this.closeRepairVehicleDialog();
|
|
||||||
this.$root.$refs.messageDialog?.open(String(errorMessage), this.$t('error.title'));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -67,28 +67,12 @@ export default {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
},
|
},
|
||||||
productsById: {},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await Promise.all([this.loadProducts(), this.fetchMoneyHistory(1)]);
|
await this.fetchMoneyHistory(1);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async loadProducts() {
|
|
||||||
try {
|
|
||||||
const { data } = await apiClient.get('/api/falukant/products');
|
|
||||||
const map = {};
|
|
||||||
for (const p of (data || [])) {
|
|
||||||
if (p && p.id != null && p.labelTr) {
|
|
||||||
map[String(p.id)] = p.labelTr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.productsById = map;
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error loading products for money history', e);
|
|
||||||
this.productsById = {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async fetchMoneyHistory(page) {
|
async fetchMoneyHistory(page) {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post('/api/falukant/moneyhistory', {
|
const response = await apiClient.post('/api/falukant/moneyhistory', {
|
||||||
@@ -101,25 +85,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
translateActivity(activity) {
|
translateActivity(activity) {
|
||||||
try {
|
|
||||||
const raw = String(activity ?? '');
|
|
||||||
// Handle legacy format: "tax from sale product 3"
|
|
||||||
const m = raw.match(/^tax\s+from\s+sale\s+product\s+(\d+)$/i);
|
|
||||||
if (m && m[1]) {
|
|
||||||
const id = m[1];
|
|
||||||
const labelTr = this.productsById[String(id)];
|
|
||||||
const productName = labelTr ? this.$t(`falukant.product.${labelTr}`) : `#${id}`;
|
|
||||||
return this.$t('falukant.moneyHistory.activities.taxFromSaleProduct', { product: productName });
|
|
||||||
}
|
|
||||||
// New/structured format: "taxFromSaleProduct.<labelTr>"
|
|
||||||
if (raw.startsWith('taxFromSaleProduct.')) {
|
|
||||||
const labelTr = raw.substring('taxFromSaleProduct.'.length);
|
|
||||||
const productName = labelTr ? this.$t(`falukant.product.${labelTr}`) : labelTr;
|
|
||||||
return this.$t('falukant.moneyHistory.activities.taxFromSaleProduct', { product: productName });
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
// ignore and fall back
|
|
||||||
}
|
|
||||||
// Handle nested keys like "health.pill" -> "health.pill"
|
// Handle nested keys like "health.pill" -> "health.pill"
|
||||||
const key = `falukant.moneyHistory.activities.${activity}`;
|
const key = `falukant.moneyHistory.activities.${activity}`;
|
||||||
const translation = this.$t(key);
|
const translation = this.$t(key);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="pos in currentPositions" :key="pos.id" :class="{ 'own-position': isOwnPosition(pos) }">
|
<tr v-for="pos in currentPositions" :key="pos.id">
|
||||||
<td>{{ $t(`falukant.politics.offices.${pos.officeType.name}`) }}</td>
|
<td>{{ $t(`falukant.politics.offices.${pos.officeType.name}`) }}</td>
|
||||||
<td>{{ pos.region.name }}</td>
|
<td>{{ pos.region.name }}</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -193,7 +193,6 @@ export default {
|
|||||||
elections: [],
|
elections: [],
|
||||||
selectedCandidates: {},
|
selectedCandidates: {},
|
||||||
selectedApplications: [],
|
selectedApplications: [],
|
||||||
ownCharacterId: null,
|
|
||||||
loading: {
|
loading: {
|
||||||
current: false,
|
current: false,
|
||||||
openPolitics: false,
|
openPolitics: false,
|
||||||
@@ -210,8 +209,7 @@ export default {
|
|||||||
return this.elections.some(e => !e.voted);
|
return this.elections.some(e => !e.voted);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
mounted() {
|
||||||
await this.loadOwnCharacterId();
|
|
||||||
this.loadCurrentPositions();
|
this.loadCurrentPositions();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -332,24 +330,6 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadOwnCharacterId() {
|
|
||||||
try {
|
|
||||||
const { data } = await apiClient.get('/api/falukant/info');
|
|
||||||
if (data.character && data.character.id) {
|
|
||||||
this.ownCharacterId = data.character.id;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error loading own character ID', err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isOwnPosition(pos) {
|
|
||||||
if (!this.ownCharacterId || !pos.character) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return pos.character.id === this.ownCharacterId;
|
|
||||||
},
|
|
||||||
|
|
||||||
async submitApplications() {
|
async submitApplications() {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post(
|
const response = await apiClient.post(
|
||||||
@@ -431,11 +411,6 @@ h2 {
|
|||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.politics-table tbody tr.own-position {
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|||||||
Reference in New Issue
Block a user